Type to search pages and rules.

Browse pages

The Project Model

Every project describes itself with records of fixed types joined by fixed links.

Markdown19 provisions

Intent#

Every project describes itself with records of fixed types joined by fixed links. People and agents write the intent records. The builder reads the code, screens, tests, and test runs, and computes the links between the two.

Concepts#

Record types#

Each type answers one question. Small projects keep the rows marked small. Large projects also keep the rows marked large. Optional rows switch on for each project.

TypeKeptQuestion
productsmallWhat is built, for whom, and never?
constraintoptional, answered alwaysWhich outside rules hold?
researchoptionalWhich outside facts inform a choice?
decisionsmallWhich choice holds, and what changes it?
requirementsmallWhat does the product do or guarantee?
problemlargeWhich pain does someone have today?
featurelargeWhat is offered against a problem?
actorsmallWho or what touches the product?
rolesmallWhich permission sets exist?
permissionsmallWhich single actions are allowed?
journeylargeWhich ordered steps reach one goal?
modulesmallWhich business areas exist?
business-recordsmallWhich things stay consistent?
rulesmallWhat holds?
use-casesmallWhich operations exist?
resultsmallHow does a use case end?
caselargeWhich example proves the result?
eventsmallWhat happened?
entry-pointsmallHow do people reach the product?
limitoptional, required from first productionWhich bounds hold in production?
runbookoptional, required from first productionHow is it run or recovered?
standardsmallHow is it built?
exceptionsmallWhere does it depart, and until when?
known-gapsmallWhat is missing, owned, until when?
termsmallWhich word means what?

The record types group by the question each answers, from intent through operation to project records.

Record types grouped by the question each answers Seven groups from the record type table. Why holds product, constraint, research, decision, requirement, and problem. What is offered holds feature. Who acts holds actor, role, and permission. How they arrive holds journey and entry-point. How the business works holds module, business-record, rule, use-case, result, case, and event. Operation holds limit and runbook. How the project builds and speaks holds standard, exception, known-gap, and term. Why What is offered Who acts How they arrive How the business works Operation How the project builds and speaks product, constraint, research, decision, requirement, problem feature actor, role, permission journey, entry-point module, business-record, rule, use-case, result, case, event limit, runbook standard, exception, known-gap, term Each row groups the record types that answer one question, from the record type table.
Record types grouped by the question each answers: why holds product, constraint, research, decision, requirement, and problem; what is offered holds feature; who acts holds actor, role, and permission; how they arrive holds journey and entry-point; how the business works holds module, business-record, rule, use-case, result, case, and event; operation holds limit and runbook; how the project builds and speaks holds standard, exception, known-gap, and term.

Pages and entries#

A page record is a Markdown file whose opening block names a record type. An entry record is an object in the records array of that block. Terms are the exception: they live in the language record, one entry per term. Each type has one home.

TypeStored asHome
productpage, exactly onedocs/product/brief.md
constraintpagedocs/product/constraints/<name>.md
researchpagedocs/research/<name>.md
decisionpagedocs/product/decisions/<number>-<name>.md
requiremententrydocs/product/<area>/<topic>.md
problempagedocs/product/problems/<name>.md
featurepagedocs/product/features/<name>.md
actorpagedocs/domain/actors/<name>.md
rolepagedocs/domain/roles/<name>.md
permissionentrydocs/domain/permissions.md
journeypagedocs/product/journeys/<name>.md
modulepagedocs/domain/modules/<module>/README.md
business-recordpagedocs/domain/modules/<module>/<records>/README.md
ruleentrydocs/domain/rules/<name>.md
use-casepagedocs/domain/modules/<module>/<records>/<use-case>.md
resultentryIn its use case page
caseentryIn its use case page
evententryOn its business record page
entry-pointentrydocs/domain/entry-points.md
limitentrydocs/operations/limits.md
runbookpagedocs/runbooks/<name>.md
standardshared provisions, or entries on rule pagesdocs/domain/rules/<name>.md
exceptionpagedocs/exceptions/<name>.md
known-gappagedocs/known-gaps/<name>.md
termentry in the language recorddocs/language.json

Common fields#

Every written record carries the shared fields. Entries inherit owner and status from their page unless they set their own.

FieldWrittenMeaning
typealwaysThe record type in kebab case
idalwaysThe identifier
titlealwaysThe display title, free to change
ownerpages; entries inheritOne name from the closed owner list
statuspages; entries inheritDraft, approved, or retired
decideron draftsThe owner deciding by the date
decideByon draftsThe decision date in ISO form
replacesdecision, when replacingThe decision this decision replaces
termswhen usedThe term identifiers the record uses

Written links live as fields on the record they start from.

FieldWritten onPoints at
decidesdecisionRequirements, features, rules, constraints, and the permissions, roles, actors, exceptions, standards, entry points, limits, or decisions an engineering choice settles
basedOndecision, requirement, ruleConstraints, research
affectsproblemActors
solvesfeatureProblems
fulfillsrule, use case, journeyRequirements
governsruleBusiness records, use cases
resultsuse caseIts result entries
casesuse caseIts case entries; each names its result
raisesuse caseEvents
reactsTouse caseEvents it reacts to
holdsactorRoles at a scope
allowsrolePermissions
needsuse casePermissions
reachedThroughuse caseEntry points
stepsjourneyOrdered use cases with actors
dependsOnmoduleModules
termsany recordTerms
replacesdecisionThe replaced decision

Containment follows the identifier: a business record belongs to its module, and a result belongs to the use case named in its identifier. The builder computes the remaining links from code, routes, and tests: implements, calls, and proves.

Authority#

Intent flows down one order: constraint, product, requirement, rule, and use case. A decision explains a choice and is replaced, never edited. Research, examples, and prose carry no authority.

Truth about today comes from code, screens, and test runs. The higher record owner owns the defect when intent and truth mismatch.

A record stays unapproved while a decision behind it stays draft. An accepted gap becomes a known gap; its check reports without failing until the end date. Access flows from actor to role to permission to use case. Module order states dependencies and grants no authority.

Statuses#

Draft means the record awaits its decider; approved means it holds; retired means a replacement holds. A draft names its decider and decideBy date.

Implemented and verified are computed: code grants the first, passing proof grants the second.

Size and stacks#

Small projects keep the small rows; large projects also keep the large rows. Optional types switch on for each project; limits and runbooks join at first production.

Each frontend declares one stack, and the backend declares its own. Every project answers whether constraints apply, possibly with none. Owners form a closed list; extensions name replacements and switched-on types.

The model builder#

The model builder reads records, code, routes, tests, and test runs into one model. It writes the model file, runs the model checks, and renders generated regions.

Generated regions sit inside fences that only the builder writes and prose checks skip. Each project runs the builder in its own gate.

Standards#

Write every record in its home#

rulecheckable

Requirement A project MUST keep every record in the home its type names.

Rationale One home per type tells a reader and the builder where a record lives.

Example A decision lives at docs/product/decisions/0047-extend-loan-period.md.

litespec/core/model#write-every-record-in-its-home

State the common fields on every record#

rulecheckable

Requirement Every written record MUST carry its type, identifier, title, owner, and status.

Rationale Shared fields let the builder join records across pages.

litespec/core/model#state-the-common-fields-on-every-record
rulecheckable

Requirement A link MUST live as fields on the record it starts from.

Rationale One writing site keeps a link and its source in one edit.

litespec/core/model#write-links-on-the-record-that-points

Follow the authority order#

ruleguidance

Requirement A conflict MUST resolve toward the higher authority.

Rationale Constraint outranks product, product outranks requirement, requirement outranks rule, and rule outranks use case. Decisions explain a choice and carry no rank; research and prose carry none.

litespec/core/model#follow-the-authority-order

Resolve ties by the later decision#

ruleguidance

Requirement A tie MUST resolve toward the later approved decision.

Rationale The shared owner decides when no later decision separates the records.

litespec/core/model#resolve-ties-by-the-later-decision

Hold approval behind draft decisions#

rulecheckable

Requirement A record MUST NOT stand approved behind a draft decision.

Rationale Approval means the reasoning behind the record already holds. The builder also writes each record's effectiveStatus: draft when the record, a decision deciding it, or a requirement it fulfills is a draft. A result or a case takes its use case's effective status.

litespec/core/model#hold-approval-behind-draft-decisions

Record accepted gaps as known gaps#

rulecheckable

Requirement An accepted gap MUST live as a known gap with owner and end date.

Rationale A dated owner turns missing work into a visible promise.

Example The running library example accepts that retiring a copy has no handler yet, so the gap lives as a known gap with an owner and an end date in docs/known-gaps/retire-copy-unimplemented.md.

JSON
{
  "type": "known-gap",
  "id": "known-gap/retire-copy-unimplemented",
  "title": "Retire copy unimplemented",
  "owner": "lending-team",
  "status": "approved",
  "check": "use-case-unimplemented",
  "subject": ["use-case/lending.retire-copy"],
  "endsBy": "2027-06-01",
  "reason": "Retirement waits for the weeding policy."
}

The use-case-unimplemented check reports without failing until 2027-06-01, and the lending team answers for closing the gap, which satisfies this provision.

litespec/core/model#record-accepted-gaps-as-known-gaps

Apply guidance precedence#

ruleguidance

Requirement A conflict MUST resolve toward the project exception, the extension, the deeper page, or the shallower page, in that order.

Rationale A project requirement never overrides a shared standard; the conflict becomes an exception.

Example The running library example needs its morning import to skip the quiet shelf check, so it records a project exception that outranks the shared standard in docs/exceptions/shelf-check-bypass.md.

JSON
{
  "type": "exception",
  "id": "exception/shelf-check-bypass",
  "title": "Shelf check bypass",
  "owner": "lending-team",
  "status": "approved",
  "standard": "standard/lending.quiet-shelf-check",
  "reason": "The import runs before opening.",
  "reviewBy": "2027-01-01",
  "removeWhen": "The import moves after opening."
}

The record names the standard it departs from, the reason, and the review date, so the departure stays visible and dated, which satisfies this provision.

litespec/core/model#apply-guidance-precedence

Authorize access through the permission chain#

rulecheckable

Requirement A use case MUST name the permissions it needs.

Rationale Actors hold roles at a scope, roles allow permissions, and entry points may restrict them.

Example An anonymous use case sets anonymous and names no permission.

litespec/core/model#authorize-access-through-the-permission-chain

Express module order as depends on#

ruleguidance

Requirement Module order MUST live as dependsOn links between modules.

Rationale A link states the dependency without ranking one module above another.

litespec/core/model#express-module-order-as-depends-on

Keep one owner and status on every record#

rulecheckable

Requirement Every page MUST name one owner and one status.

Rationale Entries inherit both from their page unless they set their own.

Example A draft names its decider and decideBy date.

The three statuses and what each allows: a draft awaits its decider, approved holds, and retired means a replacement holds.

Record statuses and what each allows Three statuses in order: draft, approved, retired. A draft awaits its decider and names its decider and decide-by date. Approved holds; a decision is replaced, never edited. Retired means a replacement holds and the old record stands beside the new one. An arrow points from each status to the status that follows it. Draft Approved Retired awaits its decider; names decider and decide-by date holds; a decision is replaced, never edited a replacement holds; kept beside the new record An arrow points from a status to the status that follows it.
Three record statuses in order: a draft awaits its decider and names its decider and decide-by date; approved holds, and a decision is replaced rather than edited; retired means a replacement holds with the old record beside the new one.
litespec/core/model#keep-one-owner-and-status-on-every-record

Retire records with replaces#

rulecheckable

Requirement A replacing decision MUST name the decision it replaces, and no other record type carries replaces.

Rationale Decisions alone keep the past: the old one stands retired beside the new one. Every other record changes in place, and a rename rewrites every citation in the same change.

litespec/core/model#retire-records-with-replaces

Name what every decision decides#

rulecheckable

Requirement Every decision that is not retired MUST name at least one record it settles in decides.

Rationale The draft gate and the computed effective status follow decides. A decision that names nothing holds back nothing, so its approval state means nothing.

litespec/core/model#name-what-every-decision-decides
rulecheckable

Requirement Every Markdown link outside code on a page under the record roots MUST point at an existing file, by its relative path.

Rationale A link shaped like an identifier, or to a moved file, reads as navigation and leads nowhere. An identifier is cited in backticks, and a link names a file.

litespec/core/model#resolve-every-page-link

Declare size stacks and optional types#

rulecheckable

Requirement A project MUST declare its size, stacks, and optional types.

Rationale Size decides the required record types and test projects; stacks decide the technology pages.

Example A library loan system declares small with a single backend stack.

litespec/core/model#declare-size-stacks-and-optional-types

Give every use case its results#

rulecheckable

Requirement A use case MUST end in a success result and name its refusals.

Rationale Callers branch on named endings, and cases prove one ending each.

Example A loan use case names loaned and book-not-available.

The running library example carries this in use-case/lending.borrow-copy, which names result/borrow-copy.borrowed and result/borrow-copy.copy-unavailable in results and case/borrow-copy.borrowing-an-available-copy-succeeds in cases:

JSON
"records": [
  {
    "type": "result",
    "id": "result/borrow-copy.borrowed",
    "title": "Borrowed",
    "owner": "lending-team",
    "outcome": "success",
    "httpStatus": 201,
    "meaning": "The copy is lent."
  },
  {
    "type": "result",
    "id": "result/borrow-copy.copy-unavailable",
    "title": "Copy unavailable",
    "owner": "lending-team",
    "outcome": "refusal",
    "code": "failure/lending.copy_not_available",
    "httpStatus": 409,
    "meaning": "The copy is unavailable."
  },
  {
    "type": "case",
    "id": "case/borrow-copy.borrowing-an-available-copy-succeeds",
    "title": "Borrowing an available copy succeeds",
    "owner": "lending-team",
    "status": "approved",
    "situation": "A copy sits available on its shelf.",
    "action": "The reader borrows the copy.",
    "result": "result/borrow-copy.borrowed",
    "expect": "The loan is active."
  }
]

Success ends with 201, the refusal carries the failure code failure/lending.copy_not_available with 409, and the case pairs one situation with the success result, which satisfies this provision.

litespec/core/model#give-every-use-case-its-results

Cover every public use case from a journey#

rulecheckable

Requirement A public use case MUST sit in a journey or name its background caller.

Rationale Reachability shows readers how each operation is found.

litespec/core/model#cover-every-public-use-case-from-a-journey

Read truth from code screens and test runs#

rulecheckable

Requirement Implemented and verified MUST come from the builder, never from handwriting.

Rationale The builder joins handlers, routes, scenarios, and test runs to the written records.

Example A use case reads implemented when its handler exists.

litespec/core/model#read-truth-from-code-screens-and-test-runs

Conventions#

Render generated regions from the model#

conventionguidance

Default Generated regions on a page come from the model builder.

Replacement A project with no builder run records its own generation step.

Rationale Fenced regions keep handwritten prose and computed views apart.

litespec/core/model#render-generated-regions-from-the-model

Verification#

IDMarkEvidence
litespec/core/model#write-every-record-in-its-homecheckablelitespec model check reports record-shape.
litespec/core/model#state-the-common-fields-on-every-recordcheckablelitespec model check reports record-shape.
litespec/core/model#write-links-on-the-record-that-pointscheckablelitespec model check reports reference-unresolved.
litespec/core/model#follow-the-authority-orderguidanceDoes each conflict resolve toward the higher authority?
litespec/core/model#resolve-ties-by-the-later-decisionguidanceDoes the later approved decision settle each tie?
litespec/core/model#hold-approval-behind-draft-decisionscheckablelitespec model check reports draft-gate.
litespec/core/model#record-accepted-gaps-as-known-gapscheckablelitespec model check reports record-shape and known-gap-expired.
litespec/core/model#apply-guidance-precedenceguidanceDoes intent override a standard anywhere without an exception?
litespec/core/model#authorize-access-through-the-permission-chaincheckablelitespec model check reports record-shape and reference-unresolved.
litespec/core/model#express-module-order-as-depends-onguidanceDoes any record rank modules instead of linking them?
litespec/core/model#keep-one-owner-and-status-on-every-recordcheckablelitespec model check reports owner-unknown and draft-without-decider.
litespec/core/model#retire-records-with-replacescheckablelitespec model check reports invalid-field for replaces outside a decision and reference-unresolved for an unknown target.
litespec/core/model#name-what-every-decision-decidescheckablelitespec model check reports decision-decides-nothing.
litespec/core/model#resolve-every-page-linkcheckablelitespec model check reports link-unresolved.
litespec/core/model#declare-size-stacks-and-optional-typescheckablelitespec model check reports size-type-missing and record-shape.
litespec/core/model#give-every-use-case-its-resultscheckablelitespec model check reports use-case-without-success and case-result-unresolved.
litespec/core/model#cover-every-public-use-case-from-a-journeycheckablelitespec model check reports journey-reach.
litespec/core/model#read-truth-from-code-screens-and-test-runscheckablelitespec model check reports use-case-unimplemented, proves-unconfirmed, and refusal-not-thrown.
litespec/core/model#render-generated-regions-from-the-modelguidanceAre generated regions current, or is a replacement recorded?