Spec Studio

Architectural significance is annotated where it is realized

spec:decisions.architectural-annotationDecision Record · featureready floor ready

Packs: pack:self-hosting-v1

Design: no design entries · no pinned declarations · no decisions

Findings: no errors, no warnings

specs/decisions/architectural-annotation.sdp.md

No open questions and no blocking questions; implementation binding none, verifier binding none, and expected-outcome oracle none.

Intent
outcome
Let a code anchor state the architectural role its unit plays, and let a component anchor state its layer and bounded context, so the graph answers architecture questions from the code that realizes the architecture, without a status, a second vocabulary registry, or a second architecture file.
Decision
context
Two rulings carried the structural half of the anchor: structural anchors confer nothing (MD-30) admitted component and uses as the only structural fields, and architectural significance rides existing primitives (MD-34) refused a vocabulary beyond them and gave up CodeNode-grain roles. Both cited gen 1's shrinking tag vocabulary as the failure of an open structural vocabulary. The annotation scout under docs/lineage/ corrects that account: the reduction was a cleanup of gen 1's formal vocabulary that never shipped as a runtime registry, and what drifted there was duplicate identities, scan scope, and syntax handling. The original design declared a Component with layer and bounded_context (docs/lineage/v0-design/03-graph-metamodel.md §2.5), and gen 1 carried a role on each annotated unit. The owner's direction was to bring back the value of annotating architecturally significant units and their relationships in code.
decision
Architectural significance is annotated on the anchor of the unit that realizes it. A code anchor may carry role, the architectural pattern the unit plays; a component: anchor may additionally carry layer, one of edge, application, domain, adapter, or infrastructure, and context, its bounded context. The component: anchor is anchored architecture: it is the declared component, and there is no separate architecture file, because the anchor sits where the component is realized. It is not the original design's declared Component that could exist before code; an unrealized component lives in Specs and never as an invented CodeNode. A role is a free, corpus-owned vocabulary whose taxonomy the census renders with counts from the graph; service, decider, projection, read-model, codec, contract, barrel, and utility are the lineage set, not a closed list. layer is a closed set, and a value outside it is an envelope error; layer or context on a non-component anchor is an envelope error. All three attributes are optional, and omission is lawful.
rationale
  • Hard to reverse: the anchor envelope and the CodeNode fields are contracts for the extractor, the census, the Design Review, and every adopter's anchors. Surprising without context: the replaced rulings refused exactly these attributes on the strength of a drift account the scout found inaccurate, so the reversal reads as a repeat of gen 1 until the correction is on the table. Real trade-off: a free role vocabulary can drift across a corpus and no validator will say so; in exchange, the role, layer, and context live on the one anchor at the one site, and the census taxonomy makes drift visible without a registry.
  • This record replaced both rulings, and both records were deleted because nothing in them still needed its own text; they read in git at 90c75dd. What survives from them is restated here as consequences: the component and uses semantics and their validation rules, structural non-conferral, no inference from imports, no status or readiness on code, significance never selects a Spec kind, no pattern: namespace, and the engine significance criterion.
consequences
  • component?: ComponentAnchorId and uses?: readonly CodeAnchorId[] stay closed graph-ID references deriving only anchored memberOf and uses edges; neither accepts a free string or an enum detached from graph identity, and there are no per-namespace sibling builders.
  • Every component and uses target exists as a CodeNode, and a dangling graph id is an error.
  • Membership is one level: a memberOf edge runs only from an impl: or api: CodeNode to a component: CodeNode, each source has at most one component, and a component: node is never itself a member.
  • A uses edge runs between CodeNode endpoints in the impl:, api:, or component: namespace; a present uses is non-empty and unique, structural edges are unique, and structural self-reference is an error.
  • Multi-node uses cycles remain authored data for the census, never findings; validators infer no transitive edge and reject no cycle.
  • A malformed or non-static structural field, an unknown layer, or layer or context on a non-component anchor refuses the whole anchor at reification rather than yielding a partial declaration; the envelope stays closed.
  • Structural edges and the three attributes confer no intent, delivery fact, or readiness effect; satisfies stays the only code-to-Spec realization slot and no implements field is admitted.
  • Architecture is never inferred from imports as anchored or declared structure; an inferred structural layer, if one arrives, stays advisory under its own claim, and derivation adds no fourth claim.
  • No status, readiness, intent, behavior, or verification is carried on code; role, layer, and context describe what the unit is, never where it stands.
  • The Protocol ships no anchor-required lint; an optional corpus lint for unanchored code stays warn-level, and the absence of an anchor is evidence, never a workflow gate.
  • Architectural significance never selects a Spec kind; the Spec states the kind of truth it carries, and relationships among such Specs are the existing relations, with dependsOn reserved for genuine semantic need, supersedes for actual replacement, and scheduling-flavored edges refused (planning truths live in ruled graph homes, MD-33).
  • Negative architecture constraints, a layer that must not use another, stay declared intent in a Spec, never a finding of the Protocol's validators; a corpus that wants one enforced checks its declared uses, layer, and context in its own gate.
  • No pattern term, kind, or pattern: namespace is admitted; a role is an attribute of a CodeNode, not a node; grouping is derived from id families and the component graph, not new Packs.
  • The engine significance criterion requires exported public surface or cross-component reach whose contract or responsibility a designer or builder must understand, as spec:model.structural-patterns defines it; export status or import rank alone is insufficient, so the criterion asks for no anchor on every export and changes no validator. Code never satisfies a decision Spec directly (the binding-grain ruling, MD-37), and an anchor is never pointed at an unfinished Spec to manufacture coverage.
  • role and context values are one lowercase kebab token matching ^[a-z][a-z0-9-]*$, with no normalization, so read-model, readModel, and Read Model cannot coexist as three categories; a value outside the token grammar is an envelope error.
  • The census derives its structural rows and taxonomy from graph edges and runtime constants on every run; it re-derives no validation finding, owns no hand-kept taxonomy, and may group uses cycles as data.
  • Code reaches a decision that shapes it through the satisfies to decidedBy join, and a unit may name a decision it follows directly through references.
  • The census links each role, layer, and context value to the units that carry it, so an owner can reconcile two spellings of one category by editing the anchors; nothing forces a label, and an unlabelled unit does not populate the taxonomy.
  • The five layers, one line each: edge is the transport and presentation boundary; application is use cases and orchestration; domain is the model and its rules; adapter is the implementations of ports toward external systems; infrastructure is runtime, persistence, and platform plumbing.
  • A package may hold several layers or several contexts; the package-to-component mapping is reviewed, and one component per package is a choice, never a rule.
  • Retained limitation: there is no independently declared Component; a component that no code realizes yet is a Spec, and the graph holds no CodeNode for it until an anchor exists.
  • The census renders role, layer, context, and references beside its structural edges, with explicit empty states, and the Design Review's binding rows show role, layer and context; these renderings narrow the shipped projections freeze, while its remaining scope stays in force.
  • Anchors are curated, never a coverage quota; an identity has one owner; a realizing unit documents its local how, never a paraphrase of the Spec's what or why.
alternatives
  • A separate architecture file declaring components, layers, and contexts was refused: it is a second place for the component to drift from the code that realizes it.
  • A closed role enum was refused: the corpus owns its architecture vocabulary, and a closed set would be the Protocol's architecture, not the adopter's.
  • A corpus-declared role vocabulary checked by a validator was refused: it is an authored registry, and the check is a content-quality check. The token grammar and the census taxonomy with its units are the whole check; a corpus that wants a list lints recipe 28 in its own gate.
  • Deriving role, layer, or context from file paths or imports was refused: it turns incidental layout into authoritative architecture and misclassifies an inferred observation as an anchored claim.
  • Adding implements was refused again: it would duplicate satisfies for contract-kind targets and make code-to-Spec realization ambiguous.
Verification

Verifier bindings

No verifier binding recorded.

Design view

Requirement drawing

  • Declared verifying examples: no declared verifying example.
  • Test or oracle bindings: no recorded binding.
Requirement drawing for spec:decisions.architectural-annotation
The diagram as text
  • spec:decisions.architectural-annotation: Architectural significance is annotated where it is realized · declared Spec
  • spec:decisions.shipped-projections-frozen: The shipped projections stay frozen · declared Spec
  • spec:model.anchors: Source anchors bind code without carrying intent · declared Spec
  • impl:protocol.anchor-model: binding-only anchor model builders · anchored code · src/model/anchors.ts:108
  • impl:protocol.census-page: renders the derived census and runtime taxonomy projection · anchored code · src/projections/census.ts:21
  • impl:protocol.structural-anchors: checks structural anchor validity and disjoint realization and reference targets · anchored code · src/validate/validators.ts:595
  • spec:decisions.architectural-annotation refines spec:decisions.shipped-projections-frozen · declared — carves out the census Roles, Layers and Contexts tables and the role, layer and context on the Design Review's code unit rows
  • spec:decisions.architectural-annotation refines spec:model.anchors · declared
  • impl:protocol.anchor-model references spec:decisions.architectural-annotation · anchored
  • impl:protocol.census-page references spec:decisions.architectural-annotation · anchored
  • impl:protocol.structural-anchors references spec:decisions.architectural-annotation · anchored
Mermaid source

Copyable source; the Studio draws static SVG.

Preferred syntax: requirementDiagram. Chosen syntax: flowchart TB because references require exact labels unavailable in requirement syntax.

Decisions

No decision record named.

Runtime

No implementation neighborhood recorded.

Runtime observation: not tracked.

Evidence

Runtime observation: not tracked.

Build attestations: not tracked.

Deployments: not tracked.

Bills of materials: not tracked.

Impact
Relations of spec:decisions.architectural-annotation
The diagram as text
  • spec:consumers.authoring-on-ramp: Authors move one Spec from intent to reviewed evidence
  • spec:consumers.census-page: Census renders the runtime taxonomy without becoming a registry
  • spec:consumers.design-review: Design Review renders graph context without becoming a gate
  • spec:consumers.design-slice: A slice reads a Pack as one design, with the architecture it touches and what each member needs next
  • spec:consumers.impact-graph.curation-assist: File-level imports show where curation is missing
  • spec:consumers.pack-design: The Pack context carries the Pack's design
  • spec:consumers.spec-studio.diagrams: A diagram is laid out from graph values into SVG with a text equivalent
  • spec:consumers.spec-studio.lenses.architecture: The architecture lens draws components by context and layer, the planned beside the built
  • spec:decisions.anchor-binding-grain: Bindings are optional, plural, and may reference a design
  • spec:decisions.architectural-annotation: Architectural significance is annotated where it is realized
  • spec:decisions.binding-not-liveness: Bindings state existence, not liveness
  • spec:decisions.shipped-projections-frozen: The shipped projections stay frozen
  • spec:model.anchors: Source anchors bind code without carrying intent
  • spec:model.planned-architecture: Components are designed ahead of their code
  • spec:model.structural-patterns: Architecturally significant units are annotated where they are realized
  • spec:protocol.role-vocabulary: The engine's architectural roles each name one pattern
  • spec:protocol.significant-units-review: The engine's accepted set covers its significant abstractions and only those
  • spec:protocol.structural-self-binding: The engine's structural self-binding covers its architecturally significant units
  • spec:validation.architecture-constraints: Declared architecture rules are checked against anchored structure
  • spec:validation.corpus-rules: Corpus-authored rules run on the one validation path
  • spec:decisions.architectural-annotation dependsOn spec:decisions.anchor-binding-grain · declared
  • spec:decisions.architectural-annotation dependsOn spec:decisions.binding-not-liveness · declared
  • spec:decisions.architectural-annotation refines spec:decisions.shipped-projections-frozen · declared — carves out the census Roles, Layers and Contexts tables and the role, layer and context on the Design Review's code unit rows
  • spec:decisions.architectural-annotation refines spec:model.anchors · declared
  • spec:consumers.authoring-on-ramp decidedBy spec:decisions.architectural-annotation · declared
  • spec:consumers.census-page decidedBy spec:decisions.architectural-annotation · declared — the census renders the structural edges and the role, layer and context attributes ruled by this decision
  • spec:consumers.design-review decidedBy spec:decisions.architectural-annotation · declared — binding rows show a unit's role and a component's layer and context
  • spec:consumers.design-slice decidedBy spec:decisions.architectural-annotation · declared — a touched component carries the layer and context its anchor states
  • spec:consumers.impact-graph.curation-assist decidedBy spec:decisions.architectural-annotation · declared
  • spec:consumers.pack-design decidedBy spec:decisions.architectural-annotation · declared — a code unit binding carries the role, layer and context its anchors state
  • spec:consumers.spec-studio.lenses.architecture decidedBy spec:decisions.architectural-annotation · declared — the lens draws only what component anchors state, membership, uses, layer, context and role
  • spec:model.anchors decidedBy spec:decisions.architectural-annotation · declared
  • spec:model.planned-architecture decidedBy spec:decisions.architectural-annotation · declared
  • spec:model.structural-patterns decidedBy spec:decisions.architectural-annotation · declared
  • spec:protocol.role-vocabulary decidedBy spec:decisions.architectural-annotation · declared
  • spec:protocol.significant-units-review decidedBy spec:decisions.architectural-annotation · declared
  • spec:protocol.structural-self-binding decidedBy spec:decisions.architectural-annotation · declared
  • spec:validation.architecture-constraints decidedBy spec:decisions.architectural-annotation · declared
  • spec:validation.corpus-rules decidedBy spec:decisions.architectural-annotation · declared — architecture checks remain the corpus's own rules
  • spec:consumers.spec-studio.diagrams dependsOn spec:decisions.architectural-annotation · declared — the architecture grid reads the layer and context a component anchor states
Mermaid source

Copyable source; the Studio draws static SVG.

Preferred syntax: flowchart. Chosen syntax: labelled flowchart, preserving exact relations, claims and folds.

Rests on

Rested on by

Distance 1

Distance 2

Distance 3

Distance 4

Distance 5

Distance 6

Distance 7

Distance 8

Distance 9

Relations

Relation and directionOther endClaimReasonExercised keys
dependsOn · outgoingBindings are optional, plural, and may reference a design
spec:decisions.anchor-binding-grain · resolves
declaredNoneNone
dependsOn · outgoingBindings state existence, not liveness
spec:decisions.binding-not-liveness · resolves
declaredNoneNone
refines · outgoingThe shipped projections stay frozen
spec:decisions.shipped-projections-frozen · resolves
declaredcarves out the census Roles, Layers and Contexts tables and the role, layer and context on the Design Review's code unit rowsNone
refines · outgoingSource anchors bind code without carrying intent
spec:model.anchors · resolves
declaredNoneNone
decidedBy · incomingAuthors move one Spec from intent to reviewed evidence
spec:consumers.authoring-on-ramp · resolves
declaredNoneNone
decidedBy · incomingCensus renders the runtime taxonomy without becoming a registry
spec:consumers.census-page · resolves
declaredthe census renders the structural edges and the role, layer and context attributes ruled by this decisionNone
decidedBy · incomingDesign Review renders graph context without becoming a gate
spec:consumers.design-review · resolves
declaredbinding rows show a unit's role and a component's layer and contextNone
decidedBy · incomingA slice reads a Pack as one design, with the architecture it touches and what each member needs next
spec:consumers.design-slice · resolves
declareda touched component carries the layer and context its anchor statesNone
decidedBy · incomingFile-level imports show where curation is missing
spec:consumers.impact-graph.curation-assist · resolves
declaredNoneNone
decidedBy · incomingThe Pack context carries the Pack's design
spec:consumers.pack-design · resolves
declareda code unit binding carries the role, layer and context its anchors stateNone
decidedBy · incomingThe architecture lens draws components by context and layer, the planned beside the built
spec:consumers.spec-studio.lenses.architecture · resolves
declaredthe lens draws only what component anchors state, membership, uses, layer, context and roleNone
decidedBy · incomingSource anchors bind code without carrying intent
spec:model.anchors · resolves
declaredNoneNone
decidedBy · incomingComponents are designed ahead of their code
spec:model.planned-architecture · resolves
declaredNoneNone
decidedBy · incomingArchitecturally significant units are annotated where they are realized
spec:model.structural-patterns · resolves
declaredNoneNone
decidedBy · incomingThe engine's architectural roles each name one pattern
spec:protocol.role-vocabulary · resolves
declaredNoneNone
decidedBy · incomingThe engine's accepted set covers its significant abstractions and only those
spec:protocol.significant-units-review · resolves
declaredNoneNone
decidedBy · incomingThe engine's structural self-binding covers its architecturally significant units
spec:protocol.structural-self-binding · resolves
declaredNoneNone
decidedBy · incomingDeclared architecture rules are checked against anchored structure
spec:validation.architecture-constraints · resolves
declaredNoneNone
decidedBy · incomingCorpus-authored rules run on the one validation path
spec:validation.corpus-rules · resolves
declaredarchitecture checks remain the corpus's own rulesNone
dependsOn · incomingA diagram is laid out from graph values into SVG with a text equivalent
spec:consumers.spec-studio.diagrams · resolves
declaredthe architecture grid reads the layer and context a component anchor statesNone

Bindings

Implementation binding: none

Design reference: present

  • impl:protocol.anchor-model · binding-only anchor model builders · src/model/anchors.ts:108 · role contract · component component:protocol.model · layer domain · context protocol
  • impl:protocol.census-page · renders the derived census and runtime taxonomy projection · src/projections/census.ts:21 · role projection · component component:protocol.projections · layer edge · context protocol
  • impl:protocol.structural-anchors · checks structural anchor validity and disjoint realization and reference targets · src/validate/validators.ts:595 · role validator · component component:protocol.validate · layer domain · context protocol

Verifier binding: none

Expected-outcome oracle: none

Runtime observation: not tracked.

Run results: not recorded in the graph.

Findings

None.

Composing (0)

Composing needs the script.