Spec Studio

The reader bridges agent entry points to composable graph context

spec:consumers.readerUse Case / Behavior · featureready floor ready

Packs: pack:self-hosting-v1

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

Findings: no errors, no warnings

specs/consumers/reader.sdp.gherkin

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

Intent
outcome
Let agents enter the curated graph from the strings, files, and changesets they already have without rebuilding its joins or taxonomy.
Behavior
rule line 73 · specs/consumers/reader.sdp.gherkin:73
createReader constructs a fresh thin typed loader that indexes graph joins and claims and computes delivery facts and validation findings once, derives readiness when a caller asks, and returns plain composable data without persisting state.
rule line 74 · specs/consumers/reader.sdp.gherkin:74
The reader exposes graph, the raw graph it reads, and the methods specs, packs, findings, findByConcept, byFile, blastRadius, specContext and packContext; a join is added only when a second machine consumer needs it and hand-rolled attempts get it wrong.
rule.conceptEntry line 75 · specs/consumers/reader.sdp.gherkin:75
findByConcept matches ids, titles, anchor labels, Pack framing, Spec narrative, and reified section content, including model term keys, and names the fields a node matched on rather than returning a bare hit.

spec:consumers.reader.concept-entry · enabled

rule.fileEntry line 76 · specs/consumers/reader.sdp.gherkin:76
byFile answers with the nodes the graph records at the path and with the Specs those nodes reach, so a source file carrying a binding names the Spec it binds and a carrier file names the Spec authored in it.

spec:consumers.reader.file-entry · enabled

rule.blastRadius line 77 · specs/consumers/reader.sdp.gherkin:77
blastRadius maps changed files to Specs and Packs authored at them and Specs reached through satisfies, references, verifies or a usable oracle models binding, plus their explicit one-hop at-risk neighbors; it reports every file the graph records nothing at as coverageUnknown and every changed code unit with no Spec linkage as unlinked, and neither list claims exhaustive coverage.

spec:consumers.reader.changeset-entry · enabled

rule.reasonsAsData line 78 · specs/consumers/reader.sdp.gherkin:78
Every reason is data; a direct impact names the changed file and, when it travelled through a binding, that binding's id, edge type and claim, and an at-risk neighbor names the connecting edge with both its ends and its claim, so its impacted end leads back to that impact's reasons.

spec:consumers.reader.changeset-entry · enabled

rule line 79 · specs/consumers/reader.sdp.gherkin:79
File-level blast radius reports curated graph reach without claiming exhaustive symbol-level usage reach.
rule line 80 · specs/consumers/reader.sdp.gherkin:80
specContext returns undefined for an id that is no Spec; otherwise it returns the Spec summary and sections, design columns, failures of the stated rung's floor, failures at the stated next rung and at the rung above the floor reached, relations both ways with claims and optional reasons, realizing and referencing code units, decoded verifiers, an optional usable oracle binding, entry locations and findings naming the Spec.
rule line 81 · specs/consumers/reader.sdp.gherkin:81
packContext returns undefined for an id that is no Pack; otherwise it returns the Pack summary, one row per manifest entry in authored order, the Pack design on resolved rows, verifier gaps, boundary and findings naming the Pack.
rule line 82 · specs/consumers/reader.sdp.gherkin:82
packContext lists one member row per manifest entry in the manifest's authored order, and its verifier gaps follow that order.
rule line 83 · specs/consumers/reader.sdp.gherkin:83
packContext lists a verifier gap for each resolved non-decision member that carries no has-verifier; a member stated ready has priority true, and the list is informative, never a gate.

7 unkeyed rules.

Verifying examples

A changeset names what it reaches, why, and what it cannot see · spec:consumers.reader.changeset-entry · ready floor ready

Executable Spec

Given a reader built over the graph a real extraction derives from the probe root
Given the source file {boundFile: "src/create-order.ts"} carries the binding {bindingId: "impl:orders.create-order"}
Given the changeset also holds the file {unrecordedFile: "src/price-book.ts"} the graph records nothing at
When the reader answers the {entry: "changeset"} entry
Then the impacted specs name {impactedSpecId: "spec:orders.create-order"} through the binding {impactBindingId: "impl:orders.create-order"} at claim {impactClaim: "anchored"}
Then the one-hop at-risk neighbors name {atRiskId: "spec:orders.order-management"} through the edge {atRiskEdge: "refines"} at claim {atRiskClaim: "declared"}
Then the at-risk neighbors number {atRiskCount: 4}
Then the coverage-unknown files name {coverageUnknownFile: "src/price-book.ts"}
Then the coverage-unknown files number {coverageUnknownCount: 1}

Open example

A concept recorded only inside a Spec's sections is still reached, and the field is named · spec:consumers.reader.concept-entry · ready floor ready

Executable Spec

Given a reader built over the graph a real extraction derives from the probe root
Given the concept {concept: "backorder"} appears in the corpus only inside the recorded context of {conceptSpecId: "spec:orders.order-management"}
When the reader answers the {entry: "concept"} entry
Then the reader names {matchedId: "spec:orders.order-management"} as a match on the field {matchedField: "sections.behavior"}
Then the reader names {matchCount: 1} matches in all

Open example

A source file reaches the Spec its binding names, and a carrier reaches its own Spec · spec:consumers.reader.file-entry · ready floor ready

Executable Spec

Given a reader built over the graph a real extraction derives from the probe root
Given the source file {boundFile: "src/create-order.ts"} carries the binding {bindingId: "impl:orders.create-order"}
When the reader answers the {entry: "file"} entry
Then the file entry names the node {nodeId: "impl:orders.create-order"} the graph records at that path
Then the file entry reaches the spec {reachedSpecId: "spec:orders.create-order"} that binding names
Then the spec carrier {carrierFile: "specs/create-order.sdp.md"} answers with its own spec {carrierSpecId: "spec:orders.create-order"}

Open example

Example space

Given a reader built over the graph a real extraction derives from the probe root
Given the concept {concept:string} appears in the corpus only inside the recorded context of {conceptSpecId:string}
Given the source file {boundFile:string} carries the binding {bindingId:string}
Given the changeset also holds the file {unrecordedFile:string} the graph records nothing at
When the reader answers the {entry:"concept"|"file"|"changeset"} entry
Then the reader names {matchedId:string} as a match on the field {matchedField:string}
Then the reader names {matchCount:number} matches in all
Then the file entry names the node {nodeId:string} the graph records at that path
Then the file entry reaches the spec {reachedSpecId:string} that binding names
Then the spec carrier {carrierFile:string} answers with its own spec {carrierSpecId:string}
Then the impacted specs name {impactedSpecId:string} through the binding {impactBindingId:string} at claim {impactClaim:string}
Then the one-hop at-risk neighbors name {atRiskId:string} through the edge {atRiskEdge:string} at claim {atRiskClaim:string}
Then the at-risk neighbors number {atRiskCount:number}
Then the coverage-unknown files name {coverageUnknownFile:string}
Then the coverage-unknown files number {coverageUnknownCount:number}
Verification

Verifier bindings

  • spec:consumers.reader.changeset-entry · A changeset names what it reaches, why, and what it cannot see · declared · example enabled · specs/consumers/reader.sdp.gherkin

    External run evidence from test/self-hosting-consumers.test.ts

    Test anchors: test:protocol.agent-surface.demand-map-entries, test:protocol.agent-surface.scripted-context-body, test:protocol.reader.changeset-entry, test:protocol.reader.concept-entry, test:protocol.reader.file-entry. Specs verified by those bindings: spec:consumers.agent-surface, spec:consumers.agent-surface.demand-map-entries, spec:consumers.agent-surface.scripted-context-body, spec:consumers.reader, spec:consumers.reader.changeset-entry, spec:consumers.reader.concept-entry, spec:consumers.reader.file-entry.

    Run 1: external run evidence from vitest 4.1.10

    Build: CI 380 · Branch: feature/roadmap-and-slices-v0 · Commit: 34909918bf0be0e849959644401797191cae379f · Start: 2026-10-22T17:40:31.456Z · Stop: 2026-10-22T17:42:16.171Z

    NameSuiteResultDuration
    executes the bound example against a fresh worldA scripted body returns claim-decoded context, pre-shaped by the body (spec:consumers.agent-surface.scripted-context-body)passed55.03 ms
    executes the bound example against a fresh worldOne body reaches every entry point the demand map names, and no symbol entry (spec:consumers.agent-surface.demand-map-entries)passed23.29 ms
    executes the bound example against a fresh worldA concept recorded only inside a Spec's sections is still reached, and the field is named (spec:consumers.reader.concept-entry)passed12.65 ms
    executes the bound example against a fresh worldA source file reaches the Spec its binding names, and a carrier reaches its own Spec (spec:consumers.reader.file-entry)passed11.95 ms
    executes the bound example against a fresh worldA changeset names what it reaches, why, and what it cannot see (spec:consumers.reader.changeset-entry)passed18.11 ms
  • spec:consumers.reader.concept-entry · A concept recorded only inside a Spec's sections is still reached, and the field is named · declared · example enabled · specs/consumers/reader.sdp.gherkin
  • spec:consumers.reader.file-entry · A source file reaches the Spec its binding names, and a carrier reaches its own Spec · declared · example enabled · specs/consumers/reader.sdp.gherkin

Example space

  • concept · string · declared by the concept {concept} appears in the corpus only inside the recorded context of {conceptSpecId}
  • conceptSpecId · string · declared by the concept {concept} appears in the corpus only inside the recorded context of {conceptSpecId}
  • boundFile · string · declared by the source file {boundFile} carries the binding {bindingId}
  • bindingId · string · declared by the source file {boundFile} carries the binding {bindingId}
  • unrecordedFile · string · declared by the changeset also holds the file {unrecordedFile} the graph records nothing at
  • entry · "concept" | "file" | "changeset" · declared by the reader answers the {entry} entry

Bound points

ExampleconceptconceptSpecIdboundFilebindingIdunrecordedFileentry
spec:consumers.reader.changeset-entryunboundunbound"src/create-order.ts""impl:orders.create-order""src/price-book.ts""changeset"
spec:consumers.reader.concept-entry"backorder""spec:orders.order-management"unboundunboundunbound"concept"
spec:consumers.reader.file-entryunboundunbound"src/create-order.ts""impl:orders.create-order"unbound"file"

Oracle binding: present · oracle:protocol.reader-entry-map · test/self-hosting-consumers.oracle.ts:8

Coverage

concept: "backorder" · spec:consumers.reader.concept-entry · not enumerable

conceptSpecId: "spec:orders.order-management" · spec:consumers.reader.concept-entry · not enumerable

boundFile: "src/create-order.ts" · spec:consumers.reader.changeset-entry, spec:consumers.reader.file-entry · not enumerable

bindingId: "impl:orders.create-order" · spec:consumers.reader.changeset-entry, spec:consumers.reader.file-entry · not enumerable

unrecordedFile: "src/price-book.ts" · spec:consumers.reader.changeset-entry · not enumerable

Unbound

Design view

Requirement drawing

Requirement drawing for spec:consumers.reader
The diagram as text
  • spec:consumers.reader: The reader bridges agent entry points to composable graph context · declared Spec
  • spec:consumers.pack-design: The Pack context carries the Pack's design · declared Spec
  • spec:consumers.reader.changeset-entry: A changeset names what it reaches, why, and what it cannot see · declared Spec
  • spec:consumers.reader.concept-entry: A concept recorded only inside a Spec's sections is still reached, and the field is named · declared Spec
  • spec:consumers.reader.file-entry: A source file reaches the Spec its binding names, and a carrier reaches its own Spec · declared Spec
  • spec:consumers.design-slice: A slice reads a Pack as one design, with the architecture it touches and what each member needs next · declared Spec
  • spec:consumers.agent-surface: Agents script a visible typed graph · declared Spec
  • component:protocol.reader: the typed graph contract and body evaluator · anchored code · src/reader/reader.ts:671
  • impl:protocol.pack-design: the Pack design helpers and the Pack context assembly they serve · anchored code · src/reader/reader.ts:499
  • impl:protocol.reader: typed graph queries, entry adapters and context joins · anchored code · src/reader/reader.ts:687
  • oracle:protocol.reader-entry-map: expected reader outcome for each graph entry mode · anchored oracle binding · test/self-hosting-consumers.oracle.ts:8
  • test:protocol.pack-design: the Pack context carries each member's design and the Pack's boundary · anchored test binding · binding present · test/pack-design.test.ts:18
  • test:protocol.reader.changeset-entry: the changeset-entry point verifies impact reasons, at-risk edges, and coverage-unknown · anchored test binding · binding present · test/self-hosting-consumers.test.ts:516
  • test:protocol.reader.concept-entry: the concept-entry point verifies the string bridge and the field it names · anchored test binding · binding present · test/self-hosting-consumers.test.ts:498
  • test:protocol.reader.file-entry: the file-entry point verifies both halves of the file bridge · anchored test binding · binding present · test/self-hosting-consumers.test.ts:507
  • spec:consumers.design-slice refines spec:consumers.pack-design · declared — a slice reads a Pack's design as one whole, with its architecture and open decisions beside it
  • spec:consumers.pack-design refines spec:consumers.reader · declared
  • spec:consumers.reader refines spec:consumers.agent-surface · declared
  • spec:consumers.reader.changeset-entry refines spec:consumers.reader · declared
  • spec:consumers.reader.changeset-entry verifies spec:consumers.reader · declared
  • spec:consumers.reader.concept-entry refines spec:consumers.reader · declared
  • spec:consumers.reader.concept-entry verifies spec:consumers.reader · declared
  • spec:consumers.reader.file-entry refines spec:consumers.reader · declared
  • spec:consumers.reader.file-entry verifies spec:consumers.reader · declared
  • component:protocol.reader satisfies spec:consumers.reader · anchored
  • impl:protocol.pack-design satisfies spec:consumers.pack-design · anchored
  • impl:protocol.reader satisfies spec:consumers.reader · anchored
  • oracle:protocol.reader-entry-map models spec:consumers.reader · anchored
  • test:protocol.pack-design verifies spec:consumers.pack-design · anchored
  • test:protocol.reader.changeset-entry verifies spec:consumers.reader.changeset-entry · anchored
  • test:protocol.reader.concept-entry verifies spec:consumers.reader.concept-entry · anchored
  • test:protocol.reader.file-entry verifies spec:consumers.reader.file-entry · anchored
Mermaid source

Copyable source; the Studio draws static SVG.

Preferred syntax: requirementDiagram. Chosen syntax: flowchart TB because models, folds require exact labels unavailable in requirement syntax.

Decisions

  • The agent front door is one evaluation sink over the exported reader

    The front door is two entrances over one seam: the package exports the reader constructor, and the CLI carries a single evaluation sink that derives the graph in process, injects that same reader, and prints the body's pre-shaped return.

  • Agents script the visible graph

    The typed graph is the visible contract and agents script it directly through a thin reader surface.

  • Bindings are optional, plural, and may reference a design

    On a code anchor, satisfies is optional and plural; on a test anchor, verifies is plural and non-empty. The constant form accepts one ref(…) or a fresh array literal of them. Each resolving target confers its fact, and implemented stays a whole-Spec fact. An anchored edge references runs from a CodeNode to a Spec, from references?: readonly SpecId[] on a code anchor; it may target any Spec, decisions included, confers no delivery fact, moves no readiness floor, and the drift alarm ignores it. It says this code answers to that design without claiming to realize it: the unit follows the design without realizing any of its promises, or realizes part of a Spec whose remaining promises no unit yet realizes, so a change to the design asks the code to follow. A design that builds on existing code states that by a typed relation to the Spec the code satisfies, never by a reference from the code. A target named in both satisfies and references is an error. An identity-only code anchor, with no satisfies and no references, is lawful: it mints a CodeNode for structure and for byFile, and nothing else.

  • Decision records state readiness from ratification evidence

    A decision Spec states ready when its complete record is registry-ratified. Decision records never require implementation or verifier bindings; the operational build backlog and verifier-gap signal exclude kind decision, while recipe 1 reports the excluded ready-decision count.

Runtime
  • component:protocol.reader · the typed graph contract and body evaluator · src/reader/reader.ts:671 · layer application · context protocol

    Uses

    • component:protocol.graph · the one graph and its semantic decisions · src/graph/schema.ts:34 · layer domain · context protocol
    • component:protocol.model · the authored contracts and stable ids · src/model/anchors.ts:100 · layer domain · context protocol
    • component:protocol.notation · the leaf step codec · src/notation/slots.ts:261 · layer domain · context protocol
    • component:protocol.validate · one finding currency and ordered checks · src/validate/validators.ts:72 · layer domain · context protocol
  • impl:protocol.reader · typed graph queries, entry adapters and context joins · src/reader/reader.ts:687

    Component: component:protocol.reader · the typed graph contract and body evaluator · src/reader/reader.ts:671 · layer application · context protocol

    Uses

    • impl:protocol.delivery-facts · computes delivery facts from resolving binding edges · src/graph/delivery-facts.ts:65
    • impl:protocol.next-rung-floor · evaluates the floor for a target rung and names the targets that break a dependency · src/validate/readiness-floor.ts:603

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:consumers.reader
  • E6: verifies · declared (3 unit edges)
The diagram as text
  • spec:consumers.agent-surface: Agents script a visible typed graph
  • spec:consumers.obsidian-vault: An Obsidian vault lets a person iterate on designs from the one graph
  • spec:consumers.pack-design: The Pack context carries the Pack's design
  • spec:consumers.reader: The reader bridges agent entry points to composable graph context
  • spec:consumers.reader.changeset-entry: A changeset names what it reaches, why, and what it cannot see
  • spec:consumers.reader.concept-entry: A concept recorded only inside a Spec's sections is still reached, and the field is named
  • spec:consumers.reader.file-entry: A source file reaches the Spec its binding names, and a carrier reaches its own Spec
  • spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph
  • spec:consumers.spec-studio.data: The Studio renders from the reader's values and embeds only what its script reads
  • spec:consumers.spec-studio.search: Search finds a Spec, a Pack, an entry or a bound file by a word
  • spec:decisions.agent-front-door: The agent front door is one evaluation sink over the exported reader
  • spec:decisions.agent-surface-scripts-graph: Agents script the visible graph
  • spec:decisions.anchor-binding-grain: Bindings are optional, plural, and may reference a design
  • spec:decisions.decision-readiness-posture: Decision records state readiness from ratification evidence
  • spec:extraction.delivery-facts: Resolving bindings confer direct delivery facts
  • spec:consumers.reader decidedBy spec:decisions.agent-front-door · declared
  • spec:consumers.reader decidedBy spec:decisions.agent-surface-scripts-graph · declared
  • spec:consumers.reader decidedBy spec:decisions.anchor-binding-grain · declared
  • spec:consumers.reader decidedBy spec:decisions.decision-readiness-posture · declared
  • spec:consumers.reader dependsOn spec:extraction.delivery-facts · declared
  • spec:consumers.reader refines spec:consumers.agent-surface · declared
  • spec:consumers.obsidian-vault dependsOn spec:consumers.reader · declared — the generator reads the graph through the reader's joined values
  • spec:consumers.spec-studio dependsOn spec:consumers.reader · declared
  • spec:consumers.spec-studio.data dependsOn spec:consumers.reader · declared
  • spec:consumers.spec-studio.search dependsOn spec:consumers.reader · declared — the page matches with the reader's concept matching
  • spec:consumers.pack-design refines spec:consumers.reader · declared
  • spec:consumers.reader.changeset-entry refines spec:consumers.reader · declared
  • spec:consumers.reader.concept-entry refines spec:consumers.reader · declared
  • spec:consumers.reader.file-entry refines spec:consumers.reader · declared
  • spec:consumers.reader.changeset-entry verifies spec:consumers.reader · declared
  • spec:consumers.reader.concept-entry verifies spec:consumers.reader · declared
  • spec:consumers.reader.file-entry verifies spec:consumers.reader · declared
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

Relations

Relation and directionOther endClaimReasonExercised keys
decidedBy · outgoingThe agent front door is one evaluation sink over the exported reader
spec:decisions.agent-front-door · resolves
declaredNoneNone
decidedBy · outgoingAgents script the visible graph
spec:decisions.agent-surface-scripts-graph · resolves
declaredNoneNone
decidedBy · outgoingBindings are optional, plural, and may reference a design
spec:decisions.anchor-binding-grain · resolves
declaredNoneNone
decidedBy · outgoingDecision records state readiness from ratification evidence
spec:decisions.decision-readiness-posture · resolves
declaredNoneNone
dependsOn · outgoingResolving bindings confer direct delivery facts
spec:extraction.delivery-facts · resolves
declaredNoneNone
refines · outgoingAgents script a visible typed graph
spec:consumers.agent-surface · resolves
declaredNoneNone
dependsOn · incomingAn Obsidian vault lets a person iterate on designs from the one graph
spec:consumers.obsidian-vault · resolves
declaredthe generator reads the graph through the reader's joined valuesNone
dependsOn · incomingThe Spec Studio is a static HTML workbench over the one graph
spec:consumers.spec-studio · resolves
declaredNoneNone
dependsOn · incomingThe Studio renders from the reader's values and embeds only what its script reads
spec:consumers.spec-studio.data · resolves
declaredNoneNone
dependsOn · incomingSearch finds a Spec, a Pack, an entry or a bound file by a word
spec:consumers.spec-studio.search · resolves
declaredthe page matches with the reader's concept matchingNone
refines · incomingThe Pack context carries the Pack's design
spec:consumers.pack-design · resolves
declaredNoneNone
refines · incomingA changeset names what it reaches, why, and what it cannot see
spec:consumers.reader.changeset-entry · resolves
declaredNoneNone
refines · incomingA concept recorded only inside a Spec's sections is still reached, and the field is named
spec:consumers.reader.concept-entry · resolves
declaredNoneNone
refines · incomingA source file reaches the Spec its binding names, and a carrier reaches its own Spec
spec:consumers.reader.file-entry · resolves
declaredNoneNone
verifies · incomingA changeset names what it reaches, why, and what it cannot see
spec:consumers.reader.changeset-entry · resolves
declaredNoneblastRadius, reasonsAsData
verifies · incomingA concept recorded only inside a Spec's sections is still reached, and the field is named
spec:consumers.reader.concept-entry · resolves
declaredNoneconceptEntry
verifies · incomingA source file reaches the Spec its binding names, and a carrier reaches its own Spec
spec:consumers.reader.file-entry · resolves
declaredNonefileEntry

Bindings

Implementation binding: present

  • component:protocol.reader · the typed graph contract and body evaluator · src/reader/reader.ts:671 · role reader · layer application · context protocol
  • impl:protocol.reader · typed graph queries, entry adapters and context joins · src/reader/reader.ts:687 · role reader · component component:protocol.reader · layer application · context protocol

Design reference: none

Verifier binding: present

  • spec:consumers.reader.changeset-entry · A changeset names what it reaches, why, and what it cannot see · declared · specs/consumers/reader.sdp.gherkin · example enabled
  • spec:consumers.reader.concept-entry · A concept recorded only inside a Spec's sections is still reached, and the field is named · declared · specs/consumers/reader.sdp.gherkin · example enabled
  • spec:consumers.reader.file-entry · A source file reaches the Spec its binding names, and a carrier reaches its own Spec · declared · specs/consumers/reader.sdp.gherkin · example enabled

Expected-outcome oracle: present

  • oracle:protocol.reader-entry-map · expected reader outcome for each graph entry mode · test/self-hosting-consumers.oracle.ts:8

Runtime observation: not tracked.

Run results: not recorded in the graph.

Findings

None.

Composing (0)

Composing needs the script.