Browse pages
Use Cases
Use Cases states what the system does and what it answers: the commands and queries, their verbs, inputs, effects, endings, scenarios, and the settings they read. Agents write these records from Intent, and code carries them. The Behavior overview maps the five Behavior pages, and the record language page states how each field, value and record name is written.
Stack: any Layer: records
Concepts#
Use Cases#
A use case is one goal a single test proves through the public boundary: a page beside its aggregate with one kind. A command changes the product; a query reads without changing. Each use case names the journey steps it serves in serves, the requirements it carries in fulfills, who may act in access, the entry points reaching it in reachedThrough, the aggregates it touches in changes and reads, the events it raises in raises, and how it ends in its results.
| Field | Meaning |
|---|---|
access | { grant, tenant }: grant of permission/<name>, self(permission/<name>), anonymous, or system; tenant of own, cross, public, or none. The door the call arrives through declares auth, as the Access page states. |
input | { name, meaning, type, of, many, required, rules, origin, classification } entries; type is text, integer, decimal, money, boolean, date, date-time, duration, email, choice, or id; of names the record an id refers to or the choices of a choice; many is true when the field holds a list of values of its type; required states whether the caller sends the field; origin is caller, claim, or derived. |
changes, reads | Aggregate ids changed, and aggregate and setting ids read, including store aggregates. |
consistency | { mode, cites }: mode of atomic, per-record, or compensated. An atomic write across aggregates cites its atomicity rule in cites. |
effects | { runs / sends / emits / calls, timing, onFailure, onExhausted, before, forEach } entries with exactly one verb; timing is inline, after-commit, or async. |
idempotency | { mode, key, scope, reason }: mode of key, state, not-pending, or none; key templates {field} placeholders over the input field names; scope is tenant, account, login, or global. |
audit | { level, target } with level of required, optional, or none, or { exempt } with its justification. A level of none is not audited; async work audits at request time. |
background | The shared Given every scenario starts from, optional. |
Each consistency mode defines its promise and the effect timings it permits:
| Mode | Means | Effects allowed |
|---|---|---|
atomic | Every write in changes commits as one group | any timing |
per-record | Each write commits on its own; a failure leaves earlier writes in place | after-commit, async |
compensated | Each write names the undo that runs when a later write fails | after-commit, async |
Each effect entry carries the one onFailure shape: { mode, retry, then, deadLetter, surfacesIn, runbook } with mode of retry, skip-and-log, or discard; retry and then accompany mode: retry, and deadLetter, surfacesIn, and runbook stay optional. onExhausted names the act when retries run out. before orders the entry ahead of another named target with its reason, and forEach names the items the entry repeats over.
summary states what the use case is, in one paragraph. Each use case carries summary, and a command describes its steps under What Happens in its explanation file, as Write Prose on Every Use Case states. exposure states what the use case exposes and what protects it. Example and Notes live in the explanation file beside the record file.
Queries#
A query reads without changing and declares what its readers receive. Its output groups fields into named include groups, each with its fields, classification, the aggregates it reads, and freshness. Freshness is an object whose mode names the case: { "mode": "immediate" }, { "mode": "snapshot" }, { "mode": "bounded", "within": "PT5M" }, or { "mode": "advisory", "authority": "<record id>" } naming the record holding the authoritative value and exposing the gap as a typed output field. A query whose aggregates lag reads from a read model: data shaped for the query, served without loading an aggregate. A command may declare its output as a list of { name, meaning }.
| Field | Meaning |
|---|---|
output.include | Named groups of { fields, classification, reads, freshness, visibleWhen, cites }; each field carries name and meaning. |
visibleWhen, cites | The optional visibility condition and the requirement widening visibility beyond the aggregates in reads. |
paging | `{ "mode": "pages", order, cursor |
builtAsynchronously | Present on a query whose aggregates lag, with a { "mode": "bounded", "within": "..." } or { "mode": "advisory", "authority": "..." } freshness and a lag scenario. |
Use-Case Verbs#
A use-case name starts with a verb, and each verb keeps one meaning and one kind across the project. LiteSpec ships the baseline vocabulary below; a project records its domain verbs as conventions, as Start Every Use Case with a Declared Verb states.
| Verb | Kind | Means |
|---|---|---|
read | query | One record, or one composed view, by its identity. |
list | query | A page of records matching a filter. |
search | query | A page of records matching free text. |
export | query | A generated file of many records. |
download | query | The stored or rendered document of one record. |
answer, draft, summarize, translate | either | Text a model writes for a person to check. |
create | command | A new aggregate root. |
add, remove | command | A part inside an existing record. |
change | command | Data of an existing record. |
duplicate | command | A new record copied from an existing one. |
open, close | command | A period, case or shift that runs between the two. |
start, complete | command | Work that runs to an end. |
publish, withdraw | command | What readers or the public can see. |
pause, resume | command | A temporary stop a person chooses. |
suspend, reinstate | command | A stop an operator imposes. |
enable, disable | command | A switch. |
grant, revoke | command | Access. |
request, approve, refuse | command | A request someone else decides. |
issue, void | command | A document or credential. |
retire, restore | command | The end of a record's life, and its return inside the restore window. |
cancel | command | An intention or booking that will not happen. |
expire | command | What time ended; started by a job. |
record | command | Something that happened outside the system: a provider answer, a delivery result, a scan. |
send | command | A message to a person. |
post, reverse | command | A ledger transaction and its correction. |
retry, verify | command | Work run again, and a check run again. |
The baseline vocabulary retires these synonyms: get, fetch, lookup and count become read; browse becomes list; find becomes search; update, edit, modify, revise, set, adjust, configure and rename become change; define, compose, save and new become create; delete becomes remove; notify, remind and email become send; suggest and ask become answer; mark, note and log become record; end becomes close; finish becomes complete; abandon becomes cancel; lapse becomes expire; clone and copy become duplicate; replay becomes retry; recheck becomes verify; archive becomes retire; reject and deny become refuse; unpublish and hide become withdraw.
A reaction is named for its trigger and a job for the use case it runs, as the Automation page states.
Results and Refusals#
Each use case ends in named results: child records with an outcome of success or refusal, a code on a refusal, and a meaning. Refusals stand in precedence order with the derived refusals first, as Order Every Refusal List by Precedence states. A refusal is a rejection or error in industry words; the record word stays refusal. A code in use is retired with its replacement named and never reused, as Retire Refusal Codes with Their Replacements states.
| Field | Meaning |
|---|---|
code, meaning | The stable refusal code, such as spending.receipt-missing, and what it means. |
recorded | Set where the attempt and its reason are stored; a validating refusal stores nothing. |
codes | The closed list of recorded outcomes inside a success. |
Generic refusals for forbidden access and invalid input are derived from access and input and never written as records. A derived generic result is result/<use-case>.forbidden or result/<use-case>.invalid-input, and scenarios may point at derived results.
Scenarios#
A scenario proves one ending: a child record with given, when, then, an optional examples table, and the result it ends in. One test proves each scenario through the public boundary, and a proof goes stale when either of its proof hashes changes. The book groups scenarios under their result.
| Field | Meaning |
|---|---|
given, when, then | The situation, the action, and the assertion. |
examples | The worked example rows. |
result | The written or derived result the scenario ends in. |
exercises | The rules the scenario shows, optional. |
Settings#
A setting is one tunable value with its type, range, unit, setter, and bound behavior. A default or figure that is commercial, legal, or differs by tenant, market, or date fulfills a requirement; a model invariant is a rule instead. A product-wide setting lives at product level. The setting-set page style holds many settings. A setting set carries summary, and its explanation file holds Notes.
| Field | Meaning |
|---|---|
valueType | integer, duration, money, boolean, text, or choice. A money setting holds an amount with an ISO 4217 currency, as the Record Language states. |
default, range, unit | The value, the min-max or choices, and the unit. |
setBy | product, operator, or tenant. |
key | The configuration path an operator setting binds from, such as Spending:ApprovalReminderDelay. Operator settings name it, as Name the Configuration Key of Every Operator Setting states. |
atBound | refuse, truncate, or degrade. |
secret | Whether the value is secret. |
fulfills | The requirements carried. |
Standards#
Give Each Use Case a Command or Query Kind#
rulerulecheckablelitespec/core/use-cases#give-each-use-case-a-command-or-query-kindEach use case MUST declare one kind: command or query.
Applies toartifact: record:use-case
Why
The kind decides what the use case is allowed to touch: a command changes, a query reads. A use case with no kind leaves each reader to allow it everything, and the checks no shape to confirm. When-X-do-Y behavior and work without a request are reaction and job records, as the Automation page states.
Checkchecked by a tool
Checked bylitespec model check reports record-invalid for a use-case page without kind or with an unknown kind.
Marked checkable: the tool named here checks it.
Start Every Use Case with a Declared Verb#
ruleruleguidancelitespec/core/use-cases#start-every-use-case-with-a-declared-verbEach use case MUST start with a verb from the baseline vocabulary or the domain verbs the project records as conventions.
Applies toartifact: record:use-case
Why
One verb per meaning keeps use cases findable: read versus get and change versus update stop competing when every project starts from one closed baseline vocabulary and adds only its domain verbs. A shared first word groups related behavior in every listing, and a retired synonym points at its replacement instead of spreading silently. When the act verb is in neither list, the author first records it as a convention in the same change, and then scaffolds the use case. litespec new scaffolds a use-case page without checking its verb, so the convention lands before the scaffold rather than after a refusal from the scaffold command. A project never redefines a baseline verb. The use-case-verb-unknown check reports a use-case name starting outside the baseline vocabulary and the project verbs, and names the replacement of a retired synonym.
Example
The project records borrow and check-in as domain verbs, so use-case/lending.borrow-copy and use-case/lending.check-in-copy pass, use-case/lending.list-loans passes on the baseline vocabulary, and use-case/lending.update-copy is told to use change.
Checka reviewer answers
Reviewed forWhich use-case names open outside the baseline vocabulary and the recorded project verbs? Look at the first word of each use-case name.
Marked guidance: a reviewer answers this question.
Keep One Kind per Verb#
ruleruleguidancelitespec/core/use-cases#keep-one-kind-per-verbEach use case MUST open with a verb of its own kind, or with an either verb.
Applies toartifact: record:use-case
Why
The first word is the first thing a reader trusts. A query named change-... or a command named read-... makes every listing lie about what the use case may touch, and a reader stops trusting names at all. The baseline vocabulary gives each verb a kind of query, command, or either; an either verb opens either kind. A project records which of its domain verbs read; its other domain verbs open either kind. The use-case-verb-invalid check reports a use case whose verb names the other kind.
Example
use-case/lending.list-loans is a query and passes; use-case/lending.answer-inquiry opens either kind on an either verb and passes; use-case/lending.read-overdue-count declared as a command is reported, and so is use-case/lending.change-copy declared as a query.
Checka reviewer answers
Reviewed forWhich queries open with a changing verb, or which commands open with a reading verb? Look at the first word of each use-case name beside its kind.
Marked guidance: a reviewer answers this question.
Name What a Use Case Acts on from the Model#
ruleruleguidancelitespec/core/use-cases#name-what-a-use-case-acts-on-from-the-modelEach use case MUST name, after its verb, an aggregate, a declared part, or a glossary term.
Applies toartifact: record:use-case
Why
The noun groups behavior by the business record it changes; a free synonym hides which record that is and breeds a second word for the concept.
Example
use-case/lending.borrow-copy names the copy aggregate, and use-case/sales.add-line names the declared line part; use-case/lending.borrow-volume names no model word and is reported.
Checka reviewer answers
Reviewed forWhich use-case names carry no aggregate, declared part, or glossary term after their verb? Look at the words after the verb in each use-case name.
Marked guidance: a reviewer answers this question.
Name a Use Case for the Act Its Aggregate Performs#
ruleruleguidancelitespec/core/use-cases#name-a-use-case-for-the-act-its-aggregate-performsEach command use case MUST share its verb with the aggregate method its handler calls.
Applies toartifact: record:use-case
Why
The use case is the doorway into one aggregate act. A different word at the door and at the act means two meanings have merged, or the use case is misnamed, and each reader guesses which word tells the truth. A handler calling no aggregate method answers to no act, so queries and ports stay out of this rule. A command that records a request for work an event handler finishes after the commit, as litespec/backend/application#call-external-systems-through-their-ports requires, performs the request: its method starts with Request and passes.
Example
use-case/orders.void-order whose handler calls Abandon is reported; the project renames the use case to the domain word, or the method and its event to Void and OrderVoidedEvent.
Checka reviewer answers
Reviewed forWhich command handlers call aggregate methods starting with neither the use-case verb nor Request? Look at the methods each command handler calls.
Marked guidance: a reviewer answers this question.
Connect Each Use Case to Intent#
rulerulecheckablelitespec/core/use-cases#connect-each-use-case-to-intentEach use case MUST name a journey step in serves or a requirement in fulfills.
Applies toartifact: record:use-case
Why
A use case serving nothing and fulfilling nothing is behavior nobody asked for: it ships without a promise behind it and stays when the promise changes. Naming a journey step or a requirement ties each behavior to the intent it carries. The record-link-missing check reports a use case with neither field, and step-use-case-missing reports a journey step no use case serves.
Example
The reimburse-expense command serves journey/submit-and-reimburse#s4 and fulfills requirement/approval-reminders.single-reimbursement.
Checkchecked by a tool
Checked bylitespec model check reports record-link-missing for a use case with neither serves nor fulfills.
Marked checkable: the tool named here checks it.
Grant Each Use Case Scoped Access#
rulerulecheckablelitespec/core/use-cases#grant-each-use-case-scoped-accessEach use case MUST declare its grant and its tenant scope in access.
Applies toartifact: record:use-case
Why
Access split across prose and code is widened silently: a new caller arrives, the grant stretches, and no record shows it. Declaring the grant of permission/<name>, self(permission/<name>), anonymous, or system, and the tenant scope of own, cross, public, or none states who may act and how far the call reaches beside the behavior. The Access page states the grant forms and the tenant meanings, and the door the call arrives through states how the caller proved identity. The authorization guard enforces the grant (litespec/backend/application#enforce-target-authorization-in-the-pipeline), and LS2012 reports a handler that authorizes itself.
Example
The reimburse-expense command declares the reimburse-expense permission with own tenant scope, reached through a session door, while the self-checkout scan declares a system grant through a device door.
Checkchecked by a tool
Checked bylitespec model check reports record-invalid for a use-case page without access carrying grant and tenant scope.
Marked checkable: the tool named here checks it.
Name the Entry Points That Reach Each Use Case#
rulerulecheckablelitespec/core/use-cases#name-the-entry-points-that-reach-each-use-caseEach use case a caller reaches from outside MUST name the entry points that reach it in reachedThrough.
Applies toartifact: record:use-case
Why
A use case with no named door is reachable from anywhere or nowhere: readers cannot tell a public operation from an internal one. Naming the entry points shows how callers arrive at each behavior. A use case that only a reaction, a job, or another use case runs has no door of its own, and its runs edge already shows how it is reached.
Checkchecked by a tool
Checked bylitespec model check reports record-invalid for a live use case that names no entry point and that nothing runs, and reference-unknown for a reachedThrough entry naming no entry point.
Marked checkable: the tool named here checks it.
Describe Every Use Case Input with Origin and Classification#
rulerulecheckablelitespec/core/use-cases#describe-every-use-case-input-with-origin-and-classificationEach use-case input MUST declare its name, meaning, type, origin, and classification.
Applies toartifact: record:use-case
Why
An input without an origin is trusted on faith: caller-asserted values pass as verified claims, and money moves on an unchecked figure. Declaring the name, the meaning, the type from text, integer, decimal, money, boolean, date, date-time, duration, email, choice, and id, the origin of caller, claim, or derived, and the classification states what arrives, what it is, and how far to trust it. An id field names the record it refers to in of, and a choice field names its choices there; other types carry no of. required states whether the caller sends the field, and a money field carries an amount with an ISO 4217 currency, as the Record Language states. A type on each field lets the builder compare the records with the generated contract and lets agents generate the right code first time. Settled by decision/0016-typed-contracts-and-privacy on the evidence in research/lower-layers-practice.
Example
"input": [
{ "name": "expenseId", "type": "id", "of": "aggregate/spending.expense", "origin": "caller" },
{ "name": "amount", "type": "money", "rules": ["the amount is positive"], "origin": "caller" }
]Checkchecked by a tool
Checked bylitespec model check reports record-invalid for a use-case input without name, meaning, or type, without of on an id or choice field, or with of on another type.
Marked checkable: the tool named here checks it.
Bound Every Caller-Supplied Input Value#
ruleruleguidancelitespec/core/use-cases#bound-every-caller-supplied-input-valueEach input value with origin: caller on a money or access path MUST cite the rule bounding it.
Applies toartifact: record:use-case
Why
A caller-asserted figure on a money or access path is an open till: a replacement amount arrives negative, a quantity arrives absurd, and the code obliges. Citing the rule bounding it ties each such value to the guard holding it.
Example
The replacement net amount cites the positivity rule bounding it.
Checka reviewer answers
Reviewed forWhich caller-supplied money or access inputs lack a cited bounding rule? Look beside each input with origin: caller on a money or access path.
Marked guidance: a reviewer answers this question.
Name Every Aggregate a Use Case Changes or Reads#
rulerulecheckablelitespec/core/use-cases#name-every-aggregate-a-use-case-changes-or-readsEach use case MUST name every aggregate it changes in changes and every aggregate it reads in reads.
Applies toartifact: record:use-case
Why
A write no record names is invisible: the handler touches a second aggregate, the second aggregate changes, and no diff shows it. Naming every touched aggregate, including store aggregates, states the read and write footprint beside the behavior. The write-undeclared check reports a write outside changes.
Checkchecked by a tool
Checked bylitespec model check reports write-undeclared for a write outside changes and reference-unknown for an unknown aggregate.
Marked checkable: the tool named here checks it.
State the Consistency of Every Use Case#
rulerulecheckablelitespec/core/use-cases#state-the-consistency-of-every-use-caseEach use case MUST declare its write consistency in consistency.
Applies toartifact: record:use-case
Why
Consistency left unsaid defaults to hope: a multi-aggregate write is read as atomic until it fails halfway. Declaring the mode states the promise: atomic commits every write in changes as one group, per-record commits each write on its own, and compensated names the undo of each write. An atomic write across aggregates cites its atomicity rule in cites, and changes holds exactly the aggregates the rule binds; a group above 4 aggregates is reported. Atomic consistency never spans an async edge. The Domain Model page states the atomicity rule. The consistency-cites-missing check reports an atomic multi-aggregate write with no cites, atomic-group-drift reports changes differing from the bound group, and atomic-group-invalid reports a group above 4 aggregates.
Example
The reimburse-expense command declares atomic consistency citing the reimbursed-once rule, while the self-checkout scan declares per-record consistency across its attempts.
Checkchecked by a tool
Checked bylitespec model check reports consistency-cites-missing for an atomic multi-aggregate write with no cites, atomic-group-drift for changes differing from the bound group, atomic-group-invalid (level A) for a group above 4 aggregates, and atomic-group-duplicate (level A) for a command saving more than one atomic write group.
Marked checkable: the tool named here checks it.
Declare Every Effect with One Verb and Its Timing#
rulerulecheckablelitespec/core/use-cases#declare-every-effect-with-one-verb-and-its-timingEach effect entry MUST carry exactly one verb and its timing.
Applies toartifact: record:use-case
Why
An edge no record declares is the defect: hidden calls between use cases, reactions, jobs, notifications, integration events, and external systems. Declaring each edge with exactly one verb of runs, sends, emits, or calls, with its timing of inline, after-commit, or async, and its failure handling states every coupling as data. Timing is required on every use-case effect. On a command, a sends or calls effect carries after-commit or async timing, and an event handler runs the consequence after the commit. The effect-undeclared check reports an edge the records never declared.
Example
The reimburse-expense command emits the reimbursed integration event after commit.
Checkchecked by a tool
Checked bylitespec model check reports effect-undeclared for an edge the records never declared and effect-timing-invalid for a command sends or calls effect with inline timing; litespec model check reports record-invalid for an effect entry without exactly one verb or its timing.
Marked checkable: the tool named here checks it.
State the Transaction Sharing of Every Inline Call#
rulerulecheckablelitespec/core/use-cases#state-the-transaction-sharing-of-every-inline-callEach inline runs effect MUST state whether it shares the caller transaction in sharesTransaction.
Applies toartifact: record:use-case
Why
An inline call without a stated transaction is a coin toss at failure: the caller rolls back while the issued work stands, or the reverse. Stating whether the call shares the caller transaction makes the failure shape reviewable beside the edge.
Checkchecked by a tool
Checked bylitespec model check reports record-invalid for an inline runs effect without sharesTransaction.
Marked checkable: the tool named here checks it.
Keep the Effect Graph Free of Cycles#
rulerulecheckablelitespec/core/use-cases#keep-the-effect-graph-free-of-cyclesThe effect graph MUST hold no cycle except through a domain event carrying its end condition.
Applies toartifact: any
Why
A cycle without an end condition runs until something breaks: a reaction runs a use case raising the event triggering the reaction. Forbidding cycles except through a domain event with a stated end condition keeps every loop a loop with an exit. The effect-loop-invalid check reports a cycle with no stated end.
Checkchecked by a tool
Checked bylitespec model check reports effect-loop-invalid for a cycle with no stated end condition.
Marked checkable: the tool named here checks it.
Name the Events Each Use Case Raises#
ruleruleguidancelitespec/core/use-cases#name-the-events-each-use-case-raisesEach use case MUST name the domain events it raises in raises.
Applies toartifact: record:use-case
Why
An event raised but unnamed leaves reactions waiting: downstream behavior answers a fact no behavior admits raising. Naming the raised events ties each fact to the behavior announcing it.
Checka reviewer answers
Reviewed forWhich use cases raise domain events that raises does not name? Look at raises beside each use-case page.
Marked guidance: a reviewer answers this question.
Name the Idempotency of Every Use Case#
rulerulecheckablelitespec/core/use-cases#name-the-idempotency-of-every-use-caseEach use case MUST declare its idempotency mode with the key, scope, or reason that mode needs.
Applies toartifact: record:use-case
Why
A retried call without a stated idempotency runs twice: a double payout, a double loan, a double notice. Declaring the mode of key, state, or not-pending, with its key template and scope, states how repeats collapse; none carries the reason repeats cannot happen. The key templates {field} placeholders over the record's input field names, and the scope is tenant, account, login, or global. A reaction key names fields of the triggering event and a job key names fields of its run window instead, which the record does not list, so its placeholders are not checked. The self-checkout scan keys on {nonce} scoped to the login.
Checkchecked by a tool
Checked bylitespec model check reports record-invalid for a use case without an idempotency mode or without the key, scope, or reason its mode needs; litespec model check reports record-invalid for a key with no {field} placeholder, a placeholder naming no input field, or a scope outside tenant, account, login, and global.
Marked checkable: the tool named here checks it.
State the Audit Position of Every Command#
rulerulecheckablelitespec/core/use-cases#state-the-audit-position-of-every-commandEach command MUST declare its audit level and target, or its exemption with its justification.
Applies toartifact: record:use-case
Why
An unaudited change with no exemption is a gap nobody admitted: money moves, holds lapse, and no record says who asked. Declaring the level of required, optional, or none with its target, or the exemption with its justification, states the audit beside the change. A level of none is not audited; async work audits at request time.
Checkchecked by a tool
Checked bylitespec model check reports record-invalid for a command without an audit level and target or an exemption with its justification.
Marked checkable: the tool named here checks it.
Declare Every Query Output#
rulerulecheckablelitespec/core/use-cases#declare-every-query-outputEach query MUST declare its output in named include groups.
Applies toartifact: record:use-case
Why
A query without a declared output returns whatever its author fetched: readers and screens guess the shape from code. Declaring the output in named groups with fields, classifications, the aggregates each group reads, and freshness states what readers receive, so the shape is reviewable before anything implements it. The query-output-missing check reports a query with no declared output.
Example
The list-expenses query declares open and decided groups with { "mode": "immediate" } freshness.
Checkchecked by a tool
Checked bylitespec model check reports query-output-missing for a query with no declared output.
Marked checkable: the tool named here checks it.
Justify Every Wider Visibility#
rulerulecheckablelitespec/core/use-cases#justify-every-wider-visibilityEach include group visible to more roles than the aggregates it reads MUST cite the requirement widening it in cites.
Applies toartifact: record:use-case
Why
A read showing more than the aggregates it reads is a quiet widening: roles see figures their own grants never allowed, and no requirement states the view. Citing the requirement in cites keeps the widening a decided choice, and visibleWhen states the condition where one narrows it. The widening-cites-missing check reports a widened group with no cited requirement.
Checkchecked by a tool
Checked bylitespec model check reports widening-cites-missing for a widened include group with no cited requirement.
Marked checkable: the tool named here checks it.
Declare Paging on Every Collection Query#
rulerulecheckablelitespec/core/use-cases#declare-paging-on-every-collection-queryEach collection query MUST declare its paging with mode of pages, or { "mode": "none", "reason": "..." } with its reason.
Applies toartifact: record:use-case
Why
A collection without paging is a promise the data outgrows: the first hundred rows return, the next ten thousand time out. Declaring the order, the cursor or offset, and the default and maximum limits with mode of pages states the paging beside the read, and { "mode": "none", "reason": "..." } with its reason states why a query returns one object. The paging-undeclared check reports a collection query with no paging.
Checkchecked by a tool
Checked bylitespec model check reports paging-undeclared for a collection query with no paging.
Marked checkable: the tool named here checks it.
Mark Every Lagging Query as Built Asynchronously#
ruleruleguidancelitespec/core/use-cases#mark-every-lagging-query-as-built-asynchronouslyEach query reading lagging aggregates MUST set builtAsynchronously with a { "mode": "bounded", "within": "..." } or { "mode": "advisory", "authority": "..." } freshness and a lag scenario.
Applies toartifact: record:use-case
Why
A read built asynchronously without a mark is trusted as fresh: screens show yesterday figures as now, and nobody warned them. Marking the query, with a { "mode": "bounded", "within": "..." } or { "mode": "advisory", "authority": "..." } freshness and one scenario covering the lag, states the staleness beside the promise.
Checka reviewer answers
Reviewed forWhich lagging queries lack builtAsynchronously with a bounded or advisory freshness and a lag scenario? Look at the queries beside the aggregates they read.
Marked guidance: a reviewer answers this question.
End Every Use Case in Named Results#
rulerulecheckablelitespec/core/use-cases#end-every-use-case-in-named-resultsEach use case MUST declare its success result and every refusal with its code.
Applies toartifact: record:result
Why
Callers branch on named endings: success, or one refusal with its stable code. A use case with no named success leaves readers guessing what good looks like, and a refusal without a code leaves each architecture layer reporting the same breach another way. The use-case-success-missing check reports a use case with no success result, and result-undeclared reports a code the records never declared.
Example
The reimburse-expense command declares reimbursed with spending.not-approved and spending.already-reimbursed.
Checkchecked by a tool
Checked bylitespec model check reports use-case-success-missing for a use case with no success result; each refusal entry on the use-case page carries its code.
Marked checkable: the tool named here checks it.
Name Each Refusal Code for the State That Refuses#
ruleruleguidancelitespec/core/use-cases#name-each-refusal-code-for-the-state-that-refusesEach refusal code MUST read <module>.<noun>-<state> and name the state, not the failure.
Applies toartifact: record:result
Why
The code is a public contract; invalid, failed or error tell an integrator nothing to do. A code naming the state tells what holds and what to change. The prefix names the module that owns the refused state, which may differ from the module of the refusing use case; a shared kernel declares its prefix in refusals.prefixes, and a code built at run time from a key, such as the conflict for a lost uniqueness key, declares its template in refusals.composed.
Example
spending.receipt-missing names the missing receipt; spending.receipt-invalid hides the state behind a vague word and is reported.
Checka reviewer answers
Reviewed forWhich refusal codes fall outside <module>.<noun>-<state> or hide their state behind a vague word? Look at the refusal codes on each use-case page.
Marked guidance: a reviewer answers this question.
Retire Refusal Codes with Their Replacements#
ruleruleguidancelitespec/core/use-cases#retire-refusal-codes-with-their-replacementsA refusal code in use MUST be retired with its replacement named, never renamed or reused.
Applies toartifact: record:result
Why
The code is a public contract; clients branch on it. Renaming a code in use silently breaks them, and reusing a retired code for another state sends old clients down the new branch. Retiring the code with its replacement named keeps every past refusal readable and every new client on the new code.
Example
The retired spending.receipt-missing result names spending.receipt-absent as its replacement, and no later refusal reuses the old code.
Checka reviewer answers
Reviewed forWhich refusal codes in use were renamed or reused instead of retired with a named replacement? Look at the refusal codes beside their results.
Marked guidance: a reviewer answers this question.
Order Every Refusal List by Precedence#
ruleruleguidancelitespec/core/use-cases#order-every-refusal-list-by-precedenceEach use case MUST list its refusals so the first match wins.
Applies toartifact: record:result
Why
Two refusals matching one call need an order: without precedence, each architecture layer picks its own refusal, and callers branch on a different code per stack. The derived refusals come first, forbidden then invalid input, followed by the written refusals in the order the page lists them, so the first match is the one every architecture layer reports.
Checka reviewer answers
Reviewed forWhich refusal lists stand out of precedence order, or place a written refusal ahead of a derived one? Look at the refusal entries on each use-case page.
Marked guidance: a reviewer answers this question.
Record Attempts Behind Recorded Refusals#
ruleruleguidancelitespec/core/use-cases#record-attempts-behind-recorded-refusalsEach refusal carrying recorded: true MUST store the attempt with its reason.
Applies toartifact: record:result
Why
Some denials are forensics: a loan denial, a limit refusal, a fraud block. Storing the attempt with its reason keeps the evidence the business answers with, while a validating refusal such as a malformed code stores nothing.
Example
The self-checkout scan records unknown, retired, and already-lent barcodes with their reasons, while a malformed scan stores nothing.
Checka reviewer answers
Reviewed forWhich refusals carrying recorded: true store no attempt with its reason? Look at the recorded refusals beside their use-case pages.
Marked guidance: a reviewer answers this question.
List Recorded Outcomes Inside Success Codes#
ruleruleguidancelitespec/core/use-cases#list-recorded-outcomes-inside-success-codesEach success result with recorded outcomes MUST list them in codes.
Applies toartifact: record:result
Why
A success hiding several recorded outcomes forces callers to guess: borrow and renew both succeed, but the due date and the analytics differ. Listing the closed codes inside the success states each recorded outcome beside the ending.
Example
The checked-out result lists borrow and renew.
Checka reviewer answers
Reviewed forWhich success results with recorded outcomes list no codes? Look at the success results beside their use-case pages.
Marked guidance: a reviewer answers this question.
Derive Generic Refusals Instead of Writing Them#
ruleruleguidancelitespec/core/use-cases#derive-generic-refusals-instead-of-writing-themA use case MUST NOT write a generic forbidden or invalid-input refusal as a record.
Applies toartifact: record:result
Why
Hand-written generic refusals multiply: hundreds of pages each declare their own forbidden, and each drifts in wording and code. Deriving them from the grant in access and the rules in input keeps one forbidden and one invalid input per use case, current with the grant: the builder derives result/<use-case>.forbidden and result/<use-case>.invalid-input. Scenarios point at the derived results without anyone writing them.
Checka reviewer answers
Reviewed forWhich use-case pages write a generic forbidden or invalid-input refusal as a record? Look at the results on each use-case page beside the derived names.
Marked guidance: a reviewer answers this question.
Name the Result Each Scenario Ends In#
rulerulecheckablelitespec/core/use-cases#name-the-result-each-scenario-ends-inEach scenario MUST name the result it ends in, written or derived.
Applies toartifact: record:scenario
Why
A scenario that names no result illustrates behavior without asserting an ending: it reads well and proves nothing. Naming the result ties each example to the ending it walks toward, so every test knows what to assert. The scenario-result-unknown check reports a scenario ending in an unknown result.
Checkchecked by a tool
Checked bylitespec model check reports record-invalid for a scenario entry without result, and scenario-result-unknown for a scenario ending in an unknown result.
Marked checkable: the tool named here checks it.
Prove Every Written Result with a Scenario#
rulerulecheckablelitespec/core/use-cases#prove-every-written-result-with-a-scenarioEach written result MUST be shown by at least one scenario of its use case.
Applies toartifact: record:result
Why
A written result no scenario shows is an ending nobody proved: it reads on the page and is asserted in no test, so it drifts from the code with the next change. One scenario per result pins each ending as a checked fact, including the refusals a caller can meet.
Example
The reimburse-expense command declares the already-reimbursed refusal, and a scenario walks an approved expense claimed twice to that refusal.
Checkchecked by a tool
Checked bylitespec model check reports result-scenario-missing, level G for a success result and level A for a refusal.
Marked checkable: the tool named here checks it.
Write Every Scenario in Given When Then#
rulerulecheckablelitespec/core/use-cases#write-every-scenario-in-given-when-thenEach scenario MUST state its given, when, and then.
Applies toartifact: record:scenario
Why
The three steps separate the situation from the action and the action from the assertion: collapsing them blurs what was true, what moved, and what the test checks. Stating all three keeps each example readable by a person and provable by a test.
Example
{
"type": "scenario",
"id": "scenario/submit-expense.submitting-with-a-receipt-succeeds",
"title": "Submitting with a receipt succeeds",
"given": "An employee paid for a train ticket and kept the receipt.",
"when": "The employee submits the expense with the receipt.",
"then": "The expense is submitted.",
"result": "result/submit-expense.submitted"
}Checkchecked by a tool
Checked bylitespec model check reports record-invalid for a scenario entry without given, when, or then.
Marked checkable: the tool named here checks it.
Exercise Rules from Scenarios#
ruleruleguidancelitespec/core/use-cases#exercise-rules-from-scenariosA scenario MAY name the rules it shows in exercises.
Applies toartifact: record:scenario
Why
A rule proved only through a test mark hides which example walks it: readers open the rule and find no story. Naming the shown rules in exercises ties each example to the rules it walks, so every rule meets its stories.
Example
A scenario walking a second hold on one copy names rule/lending.one-hold-per-copy in exercises.
Checka reviewer answers
Reviewed forWhich scenarios show rules without naming them in exercises? Look at the scenarios beside the rules they walk.
Marked guidance: a reviewer answers this question.
Share Scenario Setup in Background#
ruleruleguidancelitespec/core/use-cases#share-scenario-setup-in-backgroundA use case MAY hold the shared Given of its scenarios in background.
Applies toartifact: record:use-case
Why
Every scenario repeating the same setup buries the step that differs: readers reread one Given on each story. Holding the shared Given once in background leaves each scenario its own situation, action, and assertion.
Example
background holds that the employee has a session and one submitted expense awaits approval, and each approval scenario starts there.
Checka reviewer answers
Reviewed forWhich use cases repeat shared setup across scenarios instead of holding it in background? Look at the givens beside each use-case page.
Marked guidance: a reviewer answers this question.
Write Prose on Every Use Case#
rulerulecheckablelitespec/core/use-cases#write-prose-on-every-use-caseEach use case MUST carry summary.
Applies toartifact: record:use-case
Why
A use case states what it is in one paragraph, so a reader landing cold learns the act before its fields. The steps live under What Happens in the explanation file beside a command, where they stay readable without a shape a check must parse.
Example
The submit-expense summary states that an employee files a work expense for approval, and its What Happens section walks validation, storage, and the approver notice in order.
Checkchecked by a tool
Checked bylitespec model check reports prose-missing for a use case without summary.
Marked checkable: the tool named here checks it.
Hold Every Setting Default to a Requirement#
rulerulecheckablelitespec/core/use-cases#hold-every-setting-default-to-a-requirementEach setting MUST declare its value type, range, unit, setter, and bound behavior, with the requirement behind a commercial, legal, or varying default.
Applies toartifact: record:setting
Why
A default no requirement holds is a figure nobody stated: a price, a fee, a term, or a limit nobody decided. Declaring the value type, the range, the unit, the setter of product, operator, or tenant, and the bound behavior of refuse, truncate, or degrade states the tunable beside its promise, and a commercial, legal, or tenant-, market-, or date-varying default cites its requirement. The setting-requirement-missing check reports such a default with no cited requirement.
Example
The receipt threshold declares money with a product-set default of EUR 25, refusing an expense above the line with no receipt, behind its requirement.
Checkchecked by a tool
Checked bylitespec model check reports setting-requirement-missing for a commercial, legal, or varying default with no cited requirement.
Marked checkable: the tool named here checks it.
Name the Settings Each Use Case Reads#
ruleruleguidancelitespec/core/use-cases#name-the-settings-each-use-case-readsEach use case MUST name the settings it reads in reads.
Applies toartifact: record:use-case
Why
A setting read by a use case no record names is a coupling readers cannot see: the tunable moves, the reader breaks, and no diff shows the pair. Naming the settings in reads beside the use case states the coupling where the reader lives, so each change to the range or default meets its readers. The setting's readers are computed as the inverse, never written. Settled by decision/0012-use-cases-read-their-settings on the evidence in research/behavior-containment-evidence and research/field-naming-evidence.
Example
The submit-expense use case names setting/spending.receipt-threshold in reads, so a move of the threshold meets the submission story.
Checka reviewer answers
Reviewed forWhich use cases read a setting that reads does not name? Look at the use cases beside the settings they read.
Marked guidance: a reviewer answers this question.
Name the Configuration Key of Every Operator Setting#
rulerulecheckablelitespec/core/use-cases#name-the-configuration-key-of-every-operator-settingA setting the operator sets MUST name its configuration path in key.
Applies toartifact: record:setting
Why
An operator setting reaches the product through configuration, so the record and the configuration meet at one path: the record states the default and the bounds, and the configuration names the value. Without the key, a renamed section silently falls back to a default nobody chose, and no reader can tell which configuration value a promise rests on. A setting a tenant or the product sets is held as data by an aggregate instead, and names no key.
Example
Claimwick's setting/spending.approval-reminder-delay is set by the operator and carries key Spending:ApprovalReminderDelay.
Checkchecked by a tool
Checked bylitespec model check reports setting-key-missing (level G) for a setting with setBy: operator and no key.
Marked checkable: the tool named here checks it.
Bind Every Keyed Setting in One Marked Options Class#
rulerulecheckablelitespec/core/use-cases#bind-every-keyed-setting-in-one-marked-options-classA setting with a key MUST be bound by an options class that carries an implements mark naming the setting and whose section and property spell the key.
Applies toartifact: record:setting
Why
The options class is where configuration becomes a typed value the code reads, so it is the code element that implements the setting. Marking it names the promise the class holds, and comparing its section name and property with the record's key finds the renamed section or the typo before the product starts with a default.
Example
Claimwick's SpendingOptions declares SectionName = "Spending", an ApprovalReminderDelay property, and /// <implements>setting/spending.approval-reminder-delay</implements>.
Checkchecked by a tool
Checked bylitespec model check reports setting-unimplemented (level S) for a keyed setting no options class marks, and setting-key-drift (level S) for a marked options class whose SectionName constant and property do not spell the setting's key.
Marked checkable: the tool named here checks it.
State the Unit of Every Quantity Setting#
rulerulecheckablelitespec/core/use-cases#state-the-unit-of-every-quantity-settingEach setting whose value is a number or a duration MUST declare its unit.
Applies toartifact: record:setting
Why
A number without a unit is a guess: minutes read as seconds, a count reads as money. Declaring the unit states the measure beside the value.
Example
The retry backoff declares unit: seconds; a timeout with valueType: duration and no unit is reported.
Checkchecked by a tool
Checked bylitespec model check reports setting-unit-missing (level A) for a numeric or duration setting declaring no unit.
Marked checkable: the tool named here checks it.
Conventions#
None.