Type to search pages and rules.

Browse pages

Principles

These principles settle a design choice when no narrower provision prefers one design. LiteSpec defines a strict specification model of linked records beside graded engineering provisions, with git as the decision record. Apply this page when two designs both satisfy the narrower pages, and read the layers page for the boundaries these principles govern.

Markdown31 provisions

Stack: any Layer: records

Concepts#

Top-Down Writing#

Each record layer is written from the record layer above it: Intent states the promises, Behavior states how the system keeps them, Implementation builds what Behavior states, and Proof shows that it holds. Code and tests point up to the record they serve, through a mark naming that record. Nothing above Implementation is computed from code.

Commitments Flow Down and Facts Flow Up#

A commitment made in Intent travels down: Behavior fulfills it, Implementation builds it, and Proof checks it. A fact learned from the world, such as a provider behavior, a regulation, or an incident, enters Intent as research or a constraint, cited and dated. What a lower record layer needs, and the upper record layer does not say, goes to the owner as a question or to the backlog board outside the repository, never quietly into the lower record layer. Nothing travels up from code.

The Spec Wins Where Intent Has Spoken#

Where Intent states a promise, the record wins over the code: code that disagrees is the defect. Where Intent is silent, working code is evidence for a question to the owner, and the answer lands in Intent first. Silence is a gap to ask about, not a defect to delete and not a source to copy quietly.

Derivation Between Records Only#

One record derives from another: generic refusals derive from access and input, and views derive from the records they list. Derivation runs between records, in one direction, from the authored source to what cites it. Code is not a source for a record.

Declared Edges, Not Mechanism Bans#

Every edge between use cases, reactions, jobs, notifications, integration events, and external systems is declared on the record that holds it, and an undeclared edge is the defect. The effect graph holds no cycles except through domain events with a stated end condition. An inline edge states whether it shares the caller's transaction, and atomic consistency spans no async edge. A workflow engine carries a saga only through the workflow-engine extension, where each engine step maps to exactly one use case with its compensation. A project that wants stricter rules keeps them as a cited convention.

Honest Opinion#

LiteSpec favors modules, aggregates, domain events, use cases, reactions, and jobs, and it does not claim to be neutral about that choice. Other mechanisms live in extensions, which state how they compose with the core fields. A project that needs another mechanism selects the extension that holds it.

One Source for Each Fact#

Each fact lives in exactly one home: a requirement on its requirement page, a rule on its home page, a use case on its page, a term in the glossary, stack versions in the manifest. Completion derives from the model; nobody types it by hand. The model page defines the common fields and the computed links.

Mechanical Proof of Boundaries#

A boundary stated only in prose holds until the first change that ignores it. Structural boundaries carry mechanical proof: a project or package reference, compiler visibility, an architecture test, a behavior test, a permission guard, a store constraint, or a lint rule. Specifications explain the decisions that need judgment; tools prove the constraints that do not.

Restraint About New Machinery#

Each package, project, wrapper, background process, cache, queue, or distributed pattern adds maintenance, failure modes, and concepts every later reader learns. New machinery arrives only for a current documented requirement. Preference and possible future need justify nothing.

Naming Boundary Intent#

Boundaries are where components meet and where future readers orient themselves. Boundary names state the business action they guard, so a newcomer places the interaction without opening either side. Generic names collect unrelated responsibility behind them with every change.

Git Is the Decision Record#

A record in the repository is decided, and the pull request that changes it is its review. A record nobody wants is deleted; git keeps its history. Who changed what and when comes from git, so records carry no history of their own.

The Specification Is Closed#

An agent builds what the specification states and nothing more. Something that seems missing becomes a question to the owner or a backlog item, never code. Ideas live on the backlog board outside the repository until they are specified.

Every Record Is About the Software#

Every record states what the application does, holds, refuses at runtime, or runs on. Goals, problems, features, research, and constraints all qualify when they translate into code, results, tests, or infrastructure, and none qualifies when it is about running the company. A goal is a software goal that translates into code, results, and infrastructure, never a business goal.

Completion Is Computed#

What a reader asks first is how much of a thing exists and is proven. The model computes it from code, tests, and passing scenarios, and nobody types it. The book shows completion first, derived from the runs.

Guidance States Its Strength#

The specification model is strict: a record follows its schema, links resolve, and code and tests mark the records they serve, and a violation is a defect. Every provision beside the model says whether it is a rule, a default, or advice, and where it applies. A check is an aid where one is cheap and sure, never the condition for a provision to exist.

Tools Stay Small#

A command, check, generated file, or package exists because the owner approved it, and it is removed when nothing uses it. Each tool adds maintenance, failure modes, and concepts every later reader learns. Preference and possible future need justify nothing.

Work in Progress#

A branch may be incomplete; what merges is complete. litespec model check reports reachability locally and blocks on it in the pull-request check. A record that must stay unreached past a merge carries an exception with expiresOn, which parks reachability for that record until it expires.

Standards#

Write Each Layer from the Layer Above#

rulerulecheckable
litespec/core/principles#write-each-layer-from-the-layer-above
Statement

A consumer MUST write each record layer from the record layer above it, from Intent down to Proof.

Applies toartifact: any

Why

A record layer written from the record layer above inherits decided promises instead of inventing its own: Behavior fulfills Intent, Implementation builds Behavior, and Proof checks Implementation. A record layer written from below restates guesses as rules, and the next upper record-layer change leaves two versions of one promise.

Example

A use case names the requirement it fulfills before its handler exists.

Checkchecked by a tool

Checked bylitespec model check reports no record-link-missing finding on the changed records.

Marked checkable: the tool named here checks it.

Take Every Name from the Intent Above It#

ruleruleguidance
litespec/core/principles#take-every-name-from-the-intent-above-it
Statement

Every layer below a record MUST carry the name that record gives an act, a name chosen for what the act does in the business.

Applies toartifact: any

Why

A name is a claim about what happens. The right name comes from asking what the act really does, including how it can end, and the record that states the act decides it; the use case, the aggregate method, the event, the permission, the route and the screen label then repeat it. A check that reports two names for one act reports drift, not the answer: the fix brings every layer to the name the intent states, and the intent changes first when its own word is wrong. A rename made only to quiet a check, or a name kept in one layer while the others move, leaves one act with two names.

Example

In the Claimwick product, finance staff send an approved expense's payout to the bank, and the bank can refuse it when the company account cannot cover it. The act is a submission, not a payment: the use case is submit-payout, the method SubmitPayout, the event PayoutSubmitted, the permission submit-payout, and the screen's button reads "Submit payout". A later command records whether the bank paid or refused.

Checka reviewer answers

Reviewed forWhich act carries a different name in its use case, method, event, permission, route or screen label than the record above it states? Compare the names of one act across its record, its handler, its endpoint and its screen.

Marked guidance: a reviewer answers this question.

Compute Nothing Above Implementation from Code#

ruleruleguidance
litespec/core/principles#compute-nothing-above-implementation-from-code
Statement

A consumer MUST NOT compute a record above Implementation from code.

Applies toartifact: any

Why

A record computed from code turns what exists into what is promised, so drift becomes the plan and the record restates what the code already does. Records above Implementation state decided promises, and code points up to the record it serves through a mark naming that record.

Checka reviewer answers

Reviewed forWhich records above Implementation restate code instead of a decided promise? Compare each new record with the code beside it.

Marked guidance: a reviewer answers this question.

Derive Records Only from Records#

ruleruleguidance
litespec/core/principles#derive-records-only-from-records
Statement

A record MUST take each derived value from another record.

Applies toartifact: any

Why

Derivation between records keeps one authored source behind every value: the source changes once and each derived view follows. Generic refusals derive from access and input, and each view derives from the records it lists, so readers trace every derived value to the record that states it.

Checka reviewer answers

Reviewed forWhich derived values lack an authored source record? Trace each derived value to the record it cites.

Marked guidance: a reviewer answers this question.

Enter Facts from the World as Research or Constraints#

ruleruleguidance
litespec/core/principles#enter-facts-from-the-world-as-research-or-constraints
Statement

A consumer MUST enter each fact learned from the world as research or a constraint, cited and dated.

Applies toartifact: any

Why

A provider behavior, a regulation, or an incident is evidence from outside the project, and entering it as research or a constraint keeps the citation and the date beside the fact. A fact typed straight into Behavior or code loses its source, and later readers treat an observation as a decision.

Example

An agent records a slower payout settlement as research, then writes the constraint that cites it.

Checka reviewer answers

Reviewed forWhich outside facts lack a cited and dated source? Look at the research and constraint records beside the change.

Marked guidance: a reviewer answers this question.

Raise What a Lower Layer Needs to the Owner#

ruleruleguidance
litespec/core/principles#raise-what-a-lower-layer-needs-to-the-owner
Statement

A consumer MUST raise what a lower record layer needs, and the upper record layer does not state, to the owner as a question or to the backlog board, never quietly in the lower record layer.

Applies toartifact: any

Why

A need that goes to the owner reaches the person who decides it, and a need placed on the backlog board stays visible outside the repository. A need filled in quietly at the lower record layer becomes an undecided promise that later readers trust.

Example

A use case that needs a price its requirements do not state raises an owner question naming the missing price.

Checka reviewer answers

Reviewed forWhich needs from a lower record layer lack an owner question or a backlog item? Look at the owner questions and the backlog board beside the records that need them.

Marked guidance: a reviewer answers this question.

Follow Intent Where It Has Spoken#

ruleruleguidance
litespec/core/principles#follow-intent-where-it-has-spoken
Statement

Behavior and Implementation MUST follow Intent where Intent states the promise.

Applies toartifact: any

Why

Intent holds the decided promises, so Behavior that fulfills them and code that builds them keep one chain from promise to product. Where Intent states the promise, code that disagrees is the defect, and the fix changes the code.

Checka reviewer answers

Reviewed forWhich code disagrees with a stated promise? Compare the changed code with the Intent records it serves.

Marked guidance: a reviewer answers this question.

Treat Code Beyond Silent Intent as Evidence for an Owner Question#

ruleruleguidance
litespec/core/principles#treat-code-beyond-silent-intent-as-evidence-for-an-owner-question
Statement

A consumer MUST treat working code that Intent does not cover as evidence for a question to the owner, not as a defect to delete and not as a source to copy into Intent.

Applies toartifact: any

Why

Silent Intent plus working code means a decision nobody recorded: deleting the code destroys behavior users rely on, and copying it quietly into Intent turns code into a promise nobody stated. A question carries the behavior to the owner with the code as evidence, and the answer lands in Intent first.

Example

A positivity guard in code that no rule states becomes an owner question citing the guard, and the code stays until the answer lands in Intent.

Checka reviewer answers

Reviewed forWhich working code outside Intent lacks an owner question carrying it? Look at the owner questions beside the uncovered code.

Marked guidance: a reviewer answers this question.

Declare Every Edge#

ruleruleguidance
litespec/core/principles#declare-every-edge
Statement

A consumer MUST declare every edge between use cases, reactions, jobs, notifications, integration events, and external systems on the record that holds it.

Applies toartifact: any

Why

An edge declared on its record is checked: the builder verifies its target, its timing, and its failure handling. An undeclared edge is the defect, because it runs behavior no record names and no review saw.

Example

A use case that reminds a manager declares a sends edge to the notification with its timing and failure handling.

Checka reviewer answers

Reviewed forWhich edges lack a declaration on their record? Look at the effects entries with runs, sends, emits, or calls beside the changed records.

Marked guidance: a reviewer answers this question.

End Every Effect Cycle in a Domain Event#

rulerulecheckable
litespec/core/principles#end-every-effect-cycle-in-a-domain-event
Statement

An effect graph MUST NOT hold a cycle except through a domain event with a stated end condition.

Applies toartifact: any

Why

A cycle without an end condition runs until something outside the records stops it, so no reader can state when the work finishes. Routing each cycle through a domain event with a stated end condition names the loop and its exit in the records the graph checks.

Checkchecked by a tool

Checked bylitespec model check reports no effect-loop-invalid finding on the changed records.

Marked checkable: the tool named here checks it.

State Transaction Sharing on Every Inline Edge#

rulerulecheckable
litespec/core/principles#state-transaction-sharing-on-every-inline-edge
Statement

An inline edge MUST state whether it shares the caller's transaction.

Applies toartifact: any

Why

Two inline edges that look alike run in one transaction or two, and the difference decides what a failure leaves behind. Stating the sharing on the edge keeps transaction honesty where the edge is declared.

Example

An inline runs edge states sharesTransaction: true, so a failure in the use case it runs rolls back the caller.

Checkchecked by a tool

Checked bylitespec model check reports no record-invalid finding on the changed inline edges.

Marked checkable: the tool named here checks it.

Confine Atomic Consistency to Synchronous Edges#

ruleruleguidance
litespec/core/principles#confine-atomic-consistency-to-synchronous-edges
Statement

Atomic consistency MUST NOT span an async edge.

Applies toartifact: record:use-case

Why

An async edge crosses a commit boundary, so work past it can fail after the caller succeeded. Atomic consistency promises one shared outcome, which holds only while every edge stays synchronous.

Checka reviewer answers

Reviewed forWhich atomic use cases span an async edge? Look at the consistency and effects fields beside the changed use cases.

Marked guidance: a reviewer answers this question.

Map Each Engine Step to One Use Case#

rulerulecheckable
litespec/core/principles#map-each-engine-step-to-one-use-case
Statement

A saga carried by a workflow engine MUST map each engine step to exactly one use case with its compensation.

Applies toartifact: record:use-case

Why

The engine carries the saga while the records state it: one use case per step keeps the promise, the refusal codes, and the undo in the records the checks read. An engine step without its use case runs behavior no record names, and a step without its compensation leaves a failure with no stated undo.

Example

An engine step that reimburses an expense maps to the reimburse-expense use case, whose compensation voids the payout.

Checkchecked by a tool

Checked bylitespec model check reports no behavior-unrecorded finding on engine steps without a use case.

Marked checkable: the tool named here checks it.

Record Stricter Edge Rules as Conventions#

ruleruleguidance
litespec/core/principles#record-stricter-edge-rules-as-conventions
Statement

A project that keeps a stricter edge rule MUST record it as a cited convention.

Applies toartifact: any

Why

LiteSpec checks declared edges and leaves stricter taste to each project. A stricter rule recorded as a cited convention stays visible and checkable beside the records it constrains, instead of living as habit in a few heads.

Checka reviewer answers

Reviewed forWhich stricter edge rules lack a cited convention? Look at the project conventions beside the changed records.

Marked guidance: a reviewer answers this question.

Cover Other Mechanisms with Extensions#

ruleruleguidance
litespec/core/principles#cover-other-mechanisms-with-extensions
Statement

A mechanism outside modules, aggregates, domain events, use cases, reactions, and jobs MUST live in an extension.

Applies toartifact: any

Why

LiteSpec favors one set of mechanisms and states that choice openly instead of claiming neutrality. An extension states how its mechanism composes with the core fields, so a project that needs it selects one place that holds the whole contract.

Checka reviewer answers

Reviewed forWhich mechanisms outside the favored set lack an extension? Look at the selected extensions beside the changed records.

Marked guidance: a reviewer answers this question.

Keep One Authored Source#

ruleruleguidance
litespec/core/principles#keep-one-authored-source
Statement

A consumer MUST author each record once in its home file and derive every other appearance from the model.

Applies toartifact: any

Why

Two homes for one fact become two facts with the next edit: each copy changes on its own schedule while readers guess which one rules. Deriving every other appearance from the model keeps the authored record as the single place a change lands. Completion computed from the model stays true without anyone typing it by hand.

Checka reviewer answers

Reviewed forEach fact on the changed pages traces to one authored record, with every other appearance derived from the model.

Marked guidance: a reviewer answers this question.

Locate Package Versions in the Manifest#

rulerulecheckable
litespec/core/principles#locate-package-versions-in-the-manifest
Statement

A consumer MUST resolve the standards-selected stack versions from litespec.manifest.json.

Applies toartifact: any

Why

The manifest is the version authority for the stack the standards select, so every consumer resolves the same tested combination. A version pinned in prose or remembered by an agent drifts from that authority with the next manifest change. Consumer dependencies still live in package manifests and lockfiles; only the standards-selected stack versions resolve from litespec.manifest.json.

Checkchecked by a tool

Checked bylitespec model check fails a project whose stack versions do not resolve from the manifest.

Marked checkable: the tool named here checks it.

Prove Scenarios with Tests#

ruleruleguidance
litespec/core/principles#prove-scenarios-with-tests
Statement

A test MUST prove a scenario only by calling its use case and asserting its result.

Applies toartifact: test

Why

A passing test that skips the use case proves nothing about the behavior it claims. Calling the use case and asserting its result ties the proof to the shipped path. A scenario without such a test carries a gap exception with an expiry date, not silent coverage. The model page defines the proves link.

Checka reviewer answers

Reviewed forEach scenario in the model links a passing test that calls its use case and asserts its result.

Marked guidance: a reviewer answers this question.

Keep Git as the Decision Record#

ruleruleguidance
litespec/core/principles#keep-git-as-the-decision-record
Statement

A consumer MUST treat a record in the repository as decided, with the pull request that changes it as its review.

Applies toartifact: any

Why

A record in git is the decision, and the pull request that changes it is its review. A record nobody wants is deleted, and git keeps who changed what and when. Records carry no history of their own.

Example

A feature nobody wants is deleted from the repository; its history stays in git.

Checka reviewer answers

Reviewed forWhich changed records bypass their pull request? Look at the pull request behind the change.

Marked guidance: a reviewer answers this question.

Build Only What the Specification States#

ruleruleguidance
litespec/core/principles#build-only-what-the-specification-states
Statement

A consumer MUST build what the specification states and nothing more.

Applies toartifact: any

Why

The specification is closed: something that seems missing becomes a question to the owner or a backlog item, never code. Code without a record behind it is a promise nobody stated.

Example

An agent that finds no payout rule asks the owner instead of coding a guessed guard.

Checka reviewer answers

Reviewed forWhich code has no specification record behind it? Compare the changed code with the records it serves.

Marked guidance: a reviewer answers this question.

Write Every Record About the Software#

ruleruleguidance
litespec/core/principles#write-every-record-about-the-software
Statement

Every record MUST state what the application does, holds, refuses at runtime, or runs on.

Applies toartifact: any

Why

Goals, problems, features, research, and constraints all qualify when they translate into code, results, tests, or infrastructure. Running the company stays out; it enters only as a constraint or as dated research.

Example

A goal that translates into payout code and tests qualifies; a sales target does not.

Checka reviewer answers

Reviewed forWhich records state company business instead of the software? Compare each new record with the code, results, tests, or infrastructure it translates into.

Marked guidance: a reviewer answers this question.

Compute Completion from Code and Tests#

ruleruleguidance
litespec/core/principles#compute-completion-from-code-and-tests
Statement

A consumer MUST NOT write completion by hand, because the model computes it from code, tests, and passing scenarios.

Applies toartifact: any; conformance: traced

Why

What a reader asks first is how much of a thing exists and is proven. Completion typed by hand turns the plan into a completion report that the next commit falsifies. The model page defines what the model computes.

Example

The book shows a use case complete when its handler exists and its scenarios pass, with the model deriving that from the runs.

Checka reviewer answers

Reviewed forWhich records state their own completion? Compare the record fields with the completion the model computes.

Marked guidance: a reviewer answers this question.

State the Strength of Every Provision#

ruleruleguidance
litespec/core/principles#state-the-strength-of-every-provision
Statement

Every provision MUST state whether it is a rule, a default, or advice, and where it applies.

Applies toartifact: any

Why

Strength words work only when each one means exactly one thing: an agent tells binding from advisory without a check existing. A check is an aid where one is cheap and sure, never the condition for a provision to exist.

Checka reviewer answers

Reviewed forWhich provisions leave their strength or scope unstated? Look at the provisions the change adds.

Marked guidance: a reviewer answers this question.

Keep Tools Small#

ruleruleguidance
litespec/core/principles#keep-tools-small
Statement

A command, check, generated file, or package MUST exist only while the owner approves it and something uses it.

Applies toartifact: any

Why

Each command, check, generated file, or package adds maintenance, failure modes, and concepts every later reader learns. A tool nothing uses is removed instead of kept beside its replacement.

Example

A check nobody runs is removed with its command.

Checka reviewer answers

Reviewed forWhich commands, checks, generated files, or packages lack an owner approval or a user? Look at the tooling the change adds beside its users.

Marked guidance: a reviewer answers this question.

Complete Work Before Merging#

rulerulecheckable
litespec/core/principles#complete-work-before-merging
Statement

What merges MUST be complete.

Applies toartifact: any

Why

A branch may be incomplete; what merges is complete. A record that must stay unreached past a merge carries an exception with expiresOn, which parks reachability for that record until it expires.

Example

A use case with no endpoint stays on its branch until the endpoint lands or an exception with expiresOn parks it.

Checkchecked by a tool

Checked bylitespec model check reports unreached records locally and blocks on them in the pull-request check.

Marked checkable: the tool named here checks it.

Prove Enforceable Boundaries Mechanically#

ruleruleguidance
litespec/core/principles#prove-enforceable-boundaries-mechanically
Statement

A consumer MUST prove each enforceable boundary mechanically: a reference, visibility, an architecture test, a behavior test, or a lint rule.

Applies toartifact: any; conformance: traced

Why

A boundary stated only in prose holds until the first commit that ignores it. Mechanical proof, such as a reference, a visibility rule, an architecture test, a behavior test, or a lint rule, fails the build or the check the day the boundary breaks. Specifications then explain the decisions that need judgment, while tools guard the constraints that do not. Enforceable boundaries include project and package references, compiler visibility, permission guards, store constraints, and lint rules.

Example

A project-reference test proves Domain has no Infrastructure reference.

Checka reviewer answers

Reviewed forEach changed enforceable boundary names a reference, test, or lint rule that proves it.

Marked guidance: a reviewer answers this question.

Require Current Complexity Activation#

ruleruleguidance
litespec/core/principles#require-current-complexity-activation
Statement

A consumer MUST add packages, projects, wrappers, background processes, caches, queues, or distributed patterns only for a current documented requirement.

Applies toartifact: any

Why

Each package, project, wrapper, background process, cache, queue, or distributed pattern adds maintenance, failure modes, and concepts every later reader must learn. A current use case, decision, or requirement names the activation criterion that justifies that cost. Preference and possible future need justify nothing, so speculative machinery stays out.

Checka reviewer answers

Reviewed forEach added package, project, wrapper, process, cache, queue, or pattern cites a current use case, decision, or requirement.

Marked guidance: a reviewer answers this question.

Name Boundary Intent#

ruleruleguidance
litespec/core/principles#name-boundary-intent
Statement

A consumer MUST use business operation names, specific command and query mediators, and business-action external ports at boundaries.

Applies toartifact: any

Why

Boundaries are where components meet and where future readers orient themselves. Business operation names, specific command and query mediators, and business-action external ports state the purpose at that meeting point. A precise name lets a newcomer place the interaction without opening either side.

Checka reviewer answers

Reviewed forEach changed boundary name states its business action.

Marked guidance: a reviewer answers this question.

Avoid Generic Boundary Names#

ruleruleguidance
litespec/core/principles#avoid-generic-boundary-names
Statement

A consumer MUST NOT use generic bus, manager, helper, processor, or service names when a narrower name exists.

Applies toartifact: any

Why

Names such as bus, manager, helper, processor, and service say nothing about the business action, so unrelated responsibility collects behind them with every change. The narrower name keeps each boundary to the action it names.

Example

A notifier named for post publication names its action; one named only service does not.

Checka reviewer answers

Reviewed forEach changed boundary name carries the narrowest accurate business name, with no bare bus, manager, helper, processor, or service.

Marked guidance: a reviewer answers this question.

Conventions#

Prefer Direct Owned Dependencies#

conventiondefaultguidance
litespec/core/principles#prefer-direct-owned-dependencies
Default

Use a selected framework type directly inside the architecture layer that owns it until an architectural boundary exists.

ReplacementA consumer records a wrapping convention naming the architecture layers that use project-owned abstractions.

Applies toartifact: any

Why

Using a selected framework type directly keeps one concept where two would add nothing: the abstraction and what it hides. A project-owned abstraction earns its place for provider replacement, a test boundary, a stable domain concept, or an architecture boundary. Wrapping the framework everywhere else doubles the API the team maintains without isolating any real change.

Checka reviewer answers

Reviewed forEach new abstraction names the boundary that justifies it, or the wrapping convention that permits it.

Marked guidance: a reviewer answers this question.

Prefer Local Code Until Reuse Is Real#

conventiondefaultguidance
litespec/core/principles#prefer-local-code-until-reuse-is-real
Default

Keep operation-specific code in its operation folder until two real consumers need the same precise behavior.

ReplacementA consumer records a sharing convention naming when operation code moves to shared units.

Applies toartifact: any

Why

Operation-specific code kept beside its operation stays easy to change with the operation. Shared code needs a name and responsibility that stay accurate for both consumers, and the first consumer rarely knows what the second needs. Waiting for two real consumers means the shared unit covers behavior both actually need.

Checka reviewer answers

Reviewed forEach new shared unit serves two real consumers under one accurate name, or the sharing convention permits it.

Marked guidance: a reviewer answers this question.

Reference Example#

This informative example demonstrates litespec/core/principles#prefer-direct-owned-dependencies and litespec/core/principles#prefer-local-code-until-reuse-is-real.

  • A query handler uses the selected stack data-access type directly, because no architectural boundary separates the handler from the stack, so no wrapper isolates a change.
  • Repository interfaces stay project-owned where the architecture keeps persistence out of the domain layer: the boundary justifies the abstraction.
  • A two-line mapping used once stays beside its endpoint until a second consumer needs the same behavior.