Stated readiness by floor reachedRows: stated readiness, idea to ready. Columns: floor reached, none to ready. Each mark counts one member; above 100 members a cell is solid. Floor none is distinct from idea.
Outlined diagonal: matches. Right of diagonal: floor above statement. Left of diagonal: statement above floor.
Maturity map as text
Counts by stated readiness and floor reached. To the right the floor exceeds the statement; to the left the statement exceeds the floor.
Preferred syntax: block. Fixed categorical cells; membership appears in comments.
Framing
The Spec Studio of the original design, docs/lineage/v0-design/07-spec-studio-and-projections.md sections 1 to 3, 11 and 12, in the order a reviewer reads it: what the Studio is and why it renders HTML; the data it reads, with the recipe answers it composes and its two named inputs, and the verb that publishes and watches it; its shell, search and navigation; its four lenses, with the index that is the Packs lens and the coverage recipe the tests lens reads; the Pack page and its maturity map; the Spec page with its core and its panels; the register pages, the owner queue, and the diff, runs and glossary pages, with the run-evidence recipe the runs page reads; the composing panel and the memo it hands off; its custom elements, the decisions that shape them, and the diagrams the engine draws for them; its phone layout; the Pack export and print; how a build is stamped and shared; and the skill that teaches an agent to publish, share and read the Studio and to apply what a person composes in it. Each Spec is followed by the examples that will verify it. Recipe 27, references into a design, shows each member's code bindings and the implemented Specs it builds on.
Vocabulary: spec:consumers.projections-model
Members
1. The Spec Studio is a static HTML workbench over the one graphbehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
impl:protocol.studio-command · validates and renders the Studio with independent byte checks and diagnostic exit codes · src/cli/studio-command.ts:106 · role publisher · component component:protocol.cli · layer edge · context protocol
impl:protocol.studio-data · assembles reader contexts, Pack totals, rails and search records for static pages · src/projections/studio/data.ts:279 · role contract · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-frame · renders Studio navigation, page rails and composing controls · src/projections/studio/pages/frame.ts:6 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
1 verifier, 1 enabled · no verifying examples, 0 enabled
2. The Studio renders HTML, and the HTML stays deriveddecision · readyfloor ready · 0 open, 0 blocking questions · implementation binding none · verifier binding none
3. The Studio renders from the reader's values and embeds only what its script readscontract · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
impl:protocol.studio-recipes · evaluates shipped recipe bodies once and shares answers between Studio pages · src/projections/studio/recipes.ts:34 · role service · component component:protocol.projections · layer edge · context protocol
Design reference: present
impl:protocol.studio-register-contracts · shared recipe answer shapes for Studio registers · src/projections/studio/pages/register-answers.ts:4 · role contract · component component:protocol.projections · layer edge · context protocol
Verifier binding: present
1 verifier, 1 enabled · no verifying examples, 0 enabled
5. The Studio reads two named inputs beside the graph, a base graph and run recordscontract · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
impl:protocol.studio-base-input · reads named Studio base graphs and run inputs · src/cli/studio-inputs.ts:9 · role codec · component component:protocol.cli · layer edge · context protocol
impl:protocol.studio-command · validates and renders the Studio with independent byte checks and diagnostic exit codes · src/cli/studio-command.ts:106 · role publisher · component component:protocol.cli · layer edge · context protocol
impl:protocol.studio-inputs · named base graph and run input contract · src/projections/studio/inputs.ts:1 · role contract · component component:protocol.projections · layer edge · context protocol
1 verifier, 1 enabled · no verifying examples, 0 enabled
7. Both inputs add their pages, named, and the same inputs write the same bytesexample · readyfloor ready · 0 open, 0 blocking questions · implementation binding none · verifier binding present
impl:protocol.build-pipeline-emit · stages build outputs, checks determinism and invalidates projections · src/cli/build-command.ts:251 · role service · component component:protocol.cli · layer edge · context protocol
impl:protocol.studio-command · validates and renders the Studio with independent byte checks and diagnostic exit codes · src/cli/studio-command.ts:106 · role publisher · component component:protocol.cli · layer edge · context protocol
impl:protocol.studio-page-catalog · selects Studio pages, optional inputs and Pack exports · src/projections/studio/pages/index.ts:21 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-paths · encodes uppercase id letters for collision-free Pack and Spec page paths · src/projections/studio/paths.ts:2 · role codec · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-publish · copies local assets and replaces the Studio directory through its temporary sibling · src/projections/studio/publish.ts:24 · role publisher · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
2 verifiers, 2 enabled · no verifying examples, 0 enabled
9. sdp studio --watch rebuilds the page set on each carrier changebehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
impl:protocol.studio-watch · awaits the plain Studio publication in each coalesced carrier-watch cycle · src/cli/studio-command.ts:122 · role service · component component:protocol.cli · layer edge · context protocol
Design reference: none
Verifier binding: present
1 verifier, 1 enabled · 1 verifying example, 1 enabled
10. Each watch cycle writes the page set a plain run writesexample · readyfloor ready · 0 open, 0 blocking questions · implementation binding none · verifier binding present
impl:protocol.studio-code-spans · escapes and maps code spans across Studio text · src/projections/studio/pages/code-spans.ts:9 · role codec · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-frame · renders Studio navigation, page rails and composing controls · src/projections/studio/pages/frame.ts:6 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-html · shared Studio HTML, source and link encoding · src/projections/studio/pages/html.ts:8 · role codec · component component:protocol.projections · layer edge · context protocol
1 verifier, 1 enabled · no verifying examples, 0 enabled
12. Search finds a Spec, a Pack, an entry or a bound file by a wordbehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
impl:protocol.studio-concept-match · matches concepts deterministically across graph and browser queries · src/reader/concept-match.ts:43 · role reader · component component:protocol.reader · layer application · context protocol
impl:protocol.studio-search-page · publishes search records beside the browser results view · src/projections/studio/pages/search-page.ts:5 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-search-results · ranks and renders concept, entry and file search hits · src/studio-elements/search-results.ts:95 · role projection · component component:protocol.studio-elements · layer edge · context protocol
Design reference: none
Verifier binding: present
3 verifiers, 3 enabled · no verifying examples, 0 enabled
13. Every page of the page set is reached from the top navigation and the indexbehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
impl:protocol.studio-architecture-lens · renders recipe component rows and planned designs as architecture and member diagrams · src/projections/studio/pages/architecture-page.ts:50 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-evidence-lens · names the four evidence sources and what would bring each into the Studio · src/projections/studio/pages/evidence-page.ts:3 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-frame · renders Studio navigation, page rails and composing controls · src/projections/studio/pages/frame.ts:6 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-tests-lens · renders shared rule and example-space coverage with filters and verifier bindings · src/projections/studio/pages/tests-page.ts:34 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
1 verifier, 1 enabled · no verifying examples, 0 enabled
15. The Packs lens groups every Spec by the Packs that hold itbehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
1 verifier, 1 enabled · no verifying examples, 0 enabled
16. The index says where the corpus stands and narrows every Specbehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
23. A literal no example binds is reported uncovered, and an unbound child is namedexample · readyfloor ready · 0 open, 0 blocking questions · implementation binding none · verifier binding present
1 verifier, 1 enabled · no verifying examples, 0 enabled
24. A number slot is not enumerable and reports no uncovered valueexample · readyfloor ready · 0 open, 0 blocking questions · implementation binding none · verifier binding present
1 verifier, 1 enabled · no verifying examples, 0 enabled
25. The evidence lens names each source of runtime evidence and reads it as not trackedbehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
impl:protocol.studio-evidence-lens · names the four evidence sources and what would bring each into the Studio · src/projections/studio/pages/evidence-page.ts:3 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
1 verifier, 1 enabled · no verifying examples, 0 enabled
26. A Pack page shows the Pack's design as one card per memberbehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
2 verifiers, 2 enabled · no verifying examples, 0 enabled
27. A Pack page's maturity map places every member by its stated rung and its floorbehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
impl:protocol.studio-maturity-map · places resolved Pack members by their stated rung and floor in authored order · src/projections/studio/pages/maturity-map.ts:7 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
2 verifiers, 2 enabled · no verifying examples, 0 enabled
28. A Spec page shows one Spec in collapsible panels, in a fixed orderbehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
1 verifier, 1 enabled · no verifying examples, 0 enabled
35. The owner queue page orders the statements and questions only a person can settlebehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
1 verifier, 1 enabled · no verifying examples, 0 enabled
37. The diff page shows what changed in the design since a base graphbehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
1 verifier, 1 enabled · no verifying examples, 0 enabled
39. The runs page shows the run records the build was given, joined to test filesbehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
impl:protocol.studio-run-rows · renders recipe 45 file rows shared by the runs page and verification panel · src/projections/studio/pages/run-rows.ts:69 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-runs-page · renders readable CTRF inputs, file results, unjoined records and diagnostics · src/projections/studio/pages/runs-page.ts:6 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
1 verifier, 1 enabled · 1 verifying example, 1 enabled
40. The runs page shows a run as external evidence from a test fileexample · readyfloor ready · 0 open, 0 blocking questions · implementation binding none · verifier binding present
1 verifier, 1 enabled · no verifying examples, 0 enabled
41. CI run records are joined to verifiers in a viewbehavior · readyfloor ready · 1 open, 0 blocking questions · implementation binding present · verifier binding present
non-blocking · question.freshness · line 28 · specs/observation/run-evidence.sdp.md:28 · How does a view say a run is stale: by its commit against the commit being read, or by whether the bound files changed between the two?Decider: ownerProvisional: Display the run and source commit identifiers when they differ, as the differing-commit rule requires; whether freshness also follows changes to bound files remains open.
Implementation binding: present
impl:protocol.run-evidence-recipe · asserts realization of Run evidence in docs/agent-surface/recipes.md · test/recipes.test.ts:7277
impl:protocol.studio-runs-page · renders readable CTRF inputs, file results, unjoined records and diagnostics · src/projections/studio/pages/runs-page.ts:6 · role projection · component component:protocol.projections · layer edge · context protocol
1 verifier, 1 enabled · no verifying examples, 0 enabled
43. A test in a file with no test anchor is reported as unjoinedexample · readyfloor ready · 0 open, 0 blocking questions · implementation binding none · verifier binding present
impl:protocol.studio-glossary · renders Model terms with their entry-address links · src/projections/studio/pages/glossary-page.ts:7 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
1 verifier, 1 enabled · 1 verifying example, 1 enabled
45. A word two Specs define appears once per Spec on the glossary pageexample · readyfloor ready · 0 open, 0 blocking questions · implementation binding none · verifier binding present
impl:protocol.studio-compose · opens a native request dialog beside build-rendered scopes without changing their content · src/studio-elements/compose.ts:13 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-frame · renders Studio navigation, page rails and composing controls · src/projections/studio/pages/frame.ts:6 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-intent-panel · gathers ordered intents under the page-root storage key and partitions their hand-off · src/studio-elements/intent-panel.ts:51 · role service · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-intent-panel-element · displays gathered requests and writes copy selections or local download links · src/studio-elements/intent-panel-element.ts:14 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-scenario-editor · gathers the edited Given, When and Then as exact text scoped to its subject · src/studio-elements/scenario-editor.ts:17 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
Design reference: none
Verifier binding: present
2 verifiers, 2 enabled · 1 verifying example, 1 enabled
1 verifier, 1 enabled · no verifying examples, 0 enabled
50. The Studio's custom elements each hold one view the build renderscontract · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
component:protocol.studio-elements · optional browser behavior and proposal handoff · src/studio-elements/index.ts:13 · role interaction · layer edge · context protocol
impl:protocol.studio-compose · opens a native request dialog beside build-rendered scopes without changing their content · src/studio-elements/compose.ts:13 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-diagram-element · adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · src/studio-elements/diagram.ts:23 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-filter · filters build-rendered rows through their recorded attributes · src/studio-elements/filter.ts:25 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-intent-panel-element · displays gathered requests and writes copy selections or local download links · src/studio-elements/intent-panel-element.ts:14 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-maturity-map · places resolved Pack members by their stated rung and floor in authored order · src/projections/studio/pages/maturity-map.ts:7 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-scenario-editor · gathers the edited Given, When and Then as exact text scoped to its subject · src/studio-elements/scenario-editor.ts:17 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-search-results · ranks and renders concept, entry and file search hits · src/studio-elements/search-results.ts:95 · role projection · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-spec-structure · renders requirement and trace diagrams and the recorded structural neighborhood · src/projections/studio/pages/spec-structure.ts:44 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-verification-panels · renders rule coverage, example cards, constraint targets, verifiers and example-space coverage · src/projections/studio/pages/spec-verification.ts:74 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
1 verifier, 1 enabled · no verifying examples, 0 enabled
51. The Studio is built from custom elements, not a frameworkdecision · readyfloor ready · 0 open, 0 blocking questions · implementation binding none · verifier binding none
52. The build renders every Studio view, and an element only enhances itdecision · readyfloor ready · 0 open, 0 blocking questions · implementation binding none · verifier binding none
impl:protocol.studio-architecture-lens · renders recipe component rows and planned designs as architecture and member diagrams · src/projections/studio/pages/architecture-page.ts:50 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-diagram-element · adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · src/studio-elements/diagram.ts:23 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-diagrams · deterministic grid and band layouts with bounded folds and full text equivalents · src/projections/studio/diagrams/svg.ts:73 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-evidence-lens · names the four evidence sources and what would bring each into the Studio · src/projections/studio/pages/evidence-page.ts:3 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-recipes · evaluates shipped recipe bodies once and shares answers between Studio pages · src/projections/studio/recipes.ts:34 · role service · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-tests-lens · renders shared rule and example-space coverage with filters and verifier bindings · src/projections/studio/pages/tests-page.ts:34 · role projection · component component:protocol.projections · layer edge · context protocol
Verifier binding: none
53. The engine lays out every Studio diagram as static SVG when the page set is builtdecision · readyfloor ready · 0 open, 0 blocking questions · implementation binding none · verifier binding none
impl:protocol.studio-diagram-element · adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · src/studio-elements/diagram.ts:23 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-diagrams · deterministic grid and band layouts with bounded folds and full text equivalents · src/projections/studio/diagrams/svg.ts:73 · role projection · component component:protocol.projections · layer edge · context protocol
Verifier binding: none
54. A diagram is laid out from graph values into SVG with a text equivalentcontract · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
impl:protocol.studio-diagrams · deterministic grid and band layouts with bounded folds and full text equivalents · src/projections/studio/diagrams/svg.ts:73 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-relation-diagrams · relation and member bands and bounded relation folds · src/projections/studio/diagrams/bands.ts:10 · role projection · component component:protocol.projections · layer edge · context protocol
55. An architecture within the bound draws in one diagram, the same bytes twiceexample · readyfloor ready · 0 open, 0 blocking questions · implementation binding none · verifier binding present
1 verifier, 1 enabled · no verifying examples, 0 enabled
58. A few custom elements filter, search, open and copy on a rendered pagecontract · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
component:protocol.studio-elements · optional browser behavior and proposal handoff · src/studio-elements/index.ts:13 · role interaction · layer edge · context protocol
impl:protocol.studio-copy · copies text with selection fallback and failure feedback · src/studio-elements/copy.ts:22 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-expander · opens fragment ancestors and expands disclosures for print · src/studio-elements/expander.ts:16 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-filter · filters build-rendered rows through their recorded attributes · src/studio-elements/filter.ts:25 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-search-form · routes search forms through page-root URLs and fragments · src/studio-elements/search.ts:18 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-search-results · ranks and renders concept, entry and file search hits · src/studio-elements/search-results.ts:95 · role projection · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-stamp · resolves published stamps and source links in the browser · src/studio-elements/stamp.ts:30 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
Design reference: none
Verifier binding: present
2 verifiers, 2 enabled · no verifying examples, 0 enabled
59. The Studio reads on a phone as on a desktopbehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
impl:protocol.studio-diagram-element · adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · src/studio-elements/diagram.ts:23 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-frame · renders Studio navigation, page rails and composing controls · src/projections/studio/pages/frame.ts:6 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
1 verifier, 1 enabled · no verifying examples, 0 enabled
60. A Pack exports as one file, and every page prints as a documentbehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
1 verifier, 1 enabled · no verifying examples, 0 enabled
62. A Studio build is stamped and shared from a static hostbehavior · readyfloor ready · 0 open, 0 blocking questions · implementation binding present · verifier binding present
impl:protocol.stamp-command · writes the publishing stamp without extraction or rendering · src/cli/stamp-command.ts:8 · role publisher · component component:protocol.cli · layer edge · context protocol
impl:protocol.studio-preview-workflow · asserts the reusable Studio preview workflow and Protocol CI caller · test/studio-s4.test.ts:742
impl:protocol.studio-stamp · resolves published stamps and source links in the browser · src/studio-elements/stamp.ts:30 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
Design reference: none
Verifier binding: present
1 verifier, 1 enabled · 1 verifying example, 1 enabled
63. The stamp is written beside the page set, and a later build removes itexample · readyfloor ready · 0 open, 0 blocking questions · implementation binding none · verifier binding present
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
Intent
actor
A person in the repository who designs a capability ahead of its code and iterates on it in passes, and a pull request reviewer who holds only a link; both read far more than they change.
problem
The generated Markdown Design Review offers no built-in search or filters, and navigation is through its links, so reviewers in the first adopter open carrier files alongside it.
outcome
Give a person reviewing a design one generated HTML workbench that explores the whole graph through lenses, shows each Spec and Pack in context, and turns a wanted change into scoped intent rather than an edit.
The read-only Studio ships in the open-source package @libar-dev/software-delivery-protocol, beside the four shipped projections; hosted review, shared comments and hosted previews may later ship under @libar-ai/.
The Studio is a projection of the one graph: its page set under generated/spec-studio/ is regenerated from the graph, states no truth, and confers nothing back into the graph.
The Studio is a static page set: the index page, which is the Packs lens; a search page; a page for each other lens, each register, the owner queue, the roadmap and the glossary; one page and one slice page per Pack, one page per Spec; one export file per Pack; and, when the build is given their inputs, a diff page and a runs page; with their local assets. Its build renders each page whole, so a page needs no server, and every page but the search page reads without its script, which adds filtering, search, copying, pan and zoom, and the composing panel.
The Studio is reproducible: one graph and the same inputs render byte-identical files, and an asset whose filename embeds a hash of its content gets the same name from the same graph.
The Studio is write-careful: it writes nothing to canonical source, and a change a person wants leaves it as scoped intent for an agent, as spec:consumers.edit-model states.
The Studio never builds a second graph: every join, claim, delivery fact, derived readiness, floor failure and finding it shows is a value the reader computed when the Studio was built, and the page computes none of them again.
A page shows a catalog recipe's answer only when the Studio's design names that recipe, and the build composes the answer over the graph it derived; the page recomputes none of it.
Beside the graph the Studio reads only two optional inputs, a base graph and run records; each is named on every page that shows it, never becomes graph data, a delivery fact or a verdict, and never answers in the graph's name.
The Studio stands beside the shipped Design Review, census, Mermaid and Gherkin projections and re-specifies none of them, which spec:decisions.shipped-projections-frozen keeps as they are.
7 unkeyed rules.
Verification · manual
criteria
The Studio is accepted when a person given only a link to a build of the first adopter's corpus completes, from the page set alone, the five tasks the first adopter set over its history-view Pack (libar-platform/docs/feedback/sdp-feedback-01.md): find the history contract, locate OD-157, explain the aggregate dependency, find one declaration's type comparison down to the source line that checks it, and say whether a paused-rebuild example has native-backend evidence. Given no run records, the last task passes when the person finds that the example requires the native backend tier, reads whether a verifier is bound to it, and reports that no run result is supplied.
The same person names which statements the owner can make first, from the owner queue page.
The same person, given a build with a base graph, names what changed in the design since the base, from the diff page.
The same person names which components are designed and not yet built, from the architecture lens.
mode
manual
Verification
Verifier bindings
test:protocol.studio-publisher · anchored · test anchor binding present · test/studio-publisher.test.ts:26
Design view
Requirement drawing
Requirement drawing for spec:consumers.spec-studioThe diagram as text
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph · declared Spec
spec:consumers.spec-studio.cited-line-text: A pinned declaration shows the words of each test line that cites it · declared Spec · no satisfying binding
spec:consumers.spec-studio.components: The Studio's custom elements each hold one view the build renders · declared Spec
spec:consumers.spec-studio.data: The Studio renders from the reader's values and embeds only what its script reads · declared Spec
spec:consumers.spec-studio.diff-page: The diff page shows what changed in the design since a base graph · declared Spec
spec:consumers.spec-studio.export: A Pack exports as one file, and every page prints as a document · declared Spec
spec:consumers.spec-studio.glossary-page: The glossary page lists every term the corpus's Specs define · declared Spec
spec:consumers.spec-studio.lenses: Five lenses read the graph as Packs, capabilities, architecture, tests and evidence · declared Spec
spec:consumers.spec-studio.navigation: Every page of the page set is reached from the top navigation and the index · declared Spec
spec:consumers.spec-studio.owner-queue: The owner queue page orders the statements and questions only a person can settle · declared Spec
spec:consumers.spec-studio.pack-page: A Pack page shows the Pack's design as one card per member · declared Spec
spec:consumers.spec-studio.publisher: sdp studio publishes the Studio as one page set · declared Spec
spec:consumers.spec-studio.register-input: An outside register is a named Studio input, so a cited token links to its entry · declared Spec · no satisfying binding
spec:consumers.spec-studio.registers: The corpus's registers are pages a reviewer opens from a link · declared Spec
spec:consumers.spec-studio.responsive: The Studio reads on a phone as on a desktop · declared Spec
spec:consumers.spec-studio.roadmap-page: The roadmap page shows the upcoming work in priority order, split by what it needs · declared Spec
spec:consumers.spec-studio.runs-page: The runs page shows the run records the build was given, joined to test files · declared Spec
spec:consumers.spec-studio.sharing: A Studio build is stamped and shared from a static host · declared Spec
spec:consumers.spec-studio.shell: The Studio's shell frames every page with navigation, a rail and a canvas · declared Spec
spec:consumers.spec-studio.slice-page: A slice page shows a Pack's design as one whole · declared Spec
spec:consumers.spec-studio.spec-page: A Spec page shows one Spec in collapsible panels, in a fixed order · declared Spec
spec:decisions.studio-html-surface: The Studio renders HTML, and the HTML stays derived · declared Spec
spec:decisions.studio-web-components: The Studio is built from custom elements, not a framework · declared Spec
spec:consumers.spec-studio.diff-page.changed-entry: The diff page shows a changed entry's base and built values · declared Spec
spec:consumers.spec-studio.export.self-contained: A Pack's export opens alone and keeps its links inside it · declared Spec
spec:consumers.spec-studio.glossary-page.same-word-twice: A word two Specs define appears once per Spec on the glossary page · declared Spec
spec:consumers.spec-studio.owner-queue.dependency-first: The owner queue lists a waiting statement after the one it rests on · declared Spec
spec:consumers.spec-studio.registers.blocking-first: The questions page lists the Specs with a blocking question first · declared Spec
spec:consumers.spec-studio.runs-page.external-evidence: The runs page shows a run as external evidence from a test file · declared Spec
spec:consumers.spec-studio.sharing.stamp-written-apart: The stamp is written beside the page set, and a later build removes it · declared Spec
spec:consumers.spec-studio.spec-page.cited-declaration: A pinned declaration shows the test line that cites it · declared Spec
spec:consumers.projections-model: Projections fan out from one graph without becoming truth stores · declared Spec
spec:consumers.spec-studio.capability-map-page: The capability map page makes refinement readable by epic · declared Spec
spec:consumers.spec-studio.data.inputs: The Studio reads two named inputs beside the graph, a base graph and run records · declared Spec
spec:consumers.spec-studio.data.recipe-answers: A page takes each recipe answer from the recipe's shipped body · declared Spec
spec:consumers.spec-studio.diagrams: A diagram is laid out from graph values into SVG with a text equivalent · declared Spec
spec:consumers.spec-studio.lenses.architecture: The architecture lens draws components by context and layer, the planned beside the built · declared Spec
spec:consumers.spec-studio.lenses.evidence: The evidence lens names each source of runtime evidence and reads it as not tracked · declared Spec
spec:consumers.spec-studio.lenses.packs: The Packs lens groups every Spec by the Packs that hold it · declared Spec
spec:consumers.spec-studio.lenses.tests: The tests lens shows how far each Spec's verification reaches · declared Spec
spec:consumers.spec-studio.pack-page.maturity-map: A Pack page's maturity map places every member by its stated rung and its floor · declared Spec
spec:consumers.spec-studio.page-elements: A few custom elements filter, search, open and copy on a rendered page · declared Spec
spec:consumers.spec-studio.publisher.watch: sdp studio --watch rebuilds the page set on each carrier change · declared Spec
spec:consumers.roadmap: A roadmap orders the next bodies of work, and the graph says what each still needs · declared Spec
spec:consumers.spec-studio.search: Search finds a Spec, a Pack, an entry or a bound file by a word · 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.spec-studio.spec-page.core: A Spec page's core shows the whole Spec, with an anchor for every entry · declared Spec
spec:consumers.spec-studio.verification-panels: The panels for examples, targets, verifiers and evidence · declared Spec
spec:decisions.studio-build-renders: The build renders every Studio view, and an element only enhances it · declared Spec
spec:decisions.studio-diagram-renderer: The engine lays out every Studio diagram as static SVG when the page set is built · declared Spec
impl:protocol.stamp-command: writes the publishing stamp without extraction or rendering · anchored code · src/cli/stamp-command.ts:8
impl:protocol.studio-architecture-lens: renders recipe component rows and planned designs as architecture and member diagrams · anchored code · src/projections/studio/pages/architecture-page.ts:50
impl:protocol.studio-code-spans: escapes and maps code spans across Studio text · anchored code · src/projections/studio/pages/code-spans.ts:9
impl:protocol.studio-command: validates and renders the Studio with independent byte checks and diagnostic exit codes · anchored code · src/cli/studio-command.ts:106
impl:protocol.studio-compose: opens a native request dialog beside build-rendered scopes without changing their content · anchored code · src/studio-elements/compose.ts:13
impl:protocol.studio-data: assembles reader contexts, Pack totals, rails and search records for static pages · anchored code · src/projections/studio/data.ts:279
impl:protocol.studio-diagram-element: adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · anchored code · src/studio-elements/diagram.ts:23
impl:protocol.studio-evidence-lens: names the four evidence sources and what would bring each into the Studio · anchored code · src/projections/studio/pages/evidence-page.ts:3
impl:protocol.studio-expander: opens fragment ancestors and expands disclosures for print · anchored code · src/studio-elements/expander.ts:16
impl:protocol.studio-filter: filters build-rendered rows through their recorded attributes · anchored code · src/studio-elements/filter.ts:25
impl:protocol.studio-frame: renders Studio navigation, page rails and composing controls · anchored code · src/projections/studio/pages/frame.ts:6
impl:protocol.studio-glossary: renders Model terms with their entry-address links · anchored code · src/projections/studio/pages/glossary-page.ts:7
impl:protocol.studio-html: shared Studio HTML, source and link encoding · anchored code · src/projections/studio/pages/html.ts:8
impl:protocol.studio-intent-panel-element: displays gathered requests and writes copy selections or local download links · anchored code · src/studio-elements/intent-panel-element.ts:14
impl:protocol.studio-maturity-map: places resolved Pack members by their stated rung and floor in authored order · anchored code · src/projections/studio/pages/maturity-map.ts:7
impl:protocol.studio-pack-export: copies rendered canvas content into one inline-styled document with prefixed element references · anchored code · src/projections/studio/pages/export-page.ts:35
impl:protocol.studio-page-catalog: selects Studio pages, optional inputs and Pack exports · anchored code · src/projections/studio/pages/index.ts:21
impl:protocol.studio-paths: encodes uppercase id letters for collision-free Pack and Spec page paths · anchored code · src/projections/studio/paths.ts:2
impl:protocol.studio-preview-workflow: asserts the reusable Studio preview workflow and Protocol CI caller · anchored code · test/studio-s4.test.ts:742
impl:protocol.studio-publish: copies local assets and replaces the Studio directory through its temporary sibling · anchored code · src/projections/studio/publish.ts:24
impl:protocol.studio-requirement-view: selects Spec refiners, verifying examples and their recorded bindings · anchored code · src/projections/studio/pages/requirement-view.ts:8
impl:protocol.studio-roadmap-page: renders roadmap needs, holding parts and the shared Markdown memo · anchored code · src/projections/studio/pages/roadmap-page.ts:168
impl:protocol.studio-run-rows: renders recipe 45 file rows shared by the runs page and verification panel · anchored code · src/projections/studio/pages/run-rows.ts:69
impl:protocol.studio-runs-page: renders readable CTRF inputs, file results, unjoined records and diagnostics · anchored code · src/projections/studio/pages/runs-page.ts:6
impl:protocol.studio-scenario-editor: gathers the edited Given, When and Then as exact text scoped to its subject · anchored code · src/studio-elements/scenario-editor.ts:17
impl:protocol.studio-search-results: ranks and renders concept, entry and file search hits · anchored code · src/studio-elements/search-results.ts:95
impl:protocol.studio-slice-page: design slice summaries, member needs, architecture comparisons and boundary tables · anchored code · src/projections/studio/pages/slice-page.ts:25
impl:protocol.studio-spec-structure: renders requirement and trace diagrams and the recorded structural neighborhood · anchored code · src/projections/studio/pages/spec-structure.ts:44
impl:protocol.studio-stamp: resolves published stamps and source links in the browser · anchored code · src/studio-elements/stamp.ts:30
impl:protocol.studio-tests-lens: renders shared rule and example-space coverage with filters and verifier bindings · anchored code · src/projections/studio/pages/tests-page.ts:34
spec:consumers.spec-studio.capability-map-page refines spec:consumers.spec-studio.lenses · declared — the Capabilities page is a lens that reads refinement
spec:decisions.studio-build-renders refines spec:decisions.studio-web-components · declared — narrows where a view's values come from; the build writes them into the markup, so a host carries that markup and supplies no graph data
spec:decisions.studio-diagram-renderer refines spec:decisions.studio-web-components · declared — narrows how an element that shows a diagram renders it; the element only enhances an SVG the build drew
Preferred syntax: requirementDiagram. Chosen syntax: flowchart TB because models, folds require exact labels unavailable in requirement syntax.
Decisions
spec:decisions.shipped-projections-frozen
Re-specifying the shipped Design Review, census, Mermaid, or Gherkin projection is refused. These four projections are the ruled read surfaces over the one graph. A later decision Spec that supersedes this one replaces the ruling whole; a decision Spec that refines this one narrows it for one projection or one rendering and leaves the rest frozen. Either passes the ADR three-part test.
The build renders every Studio view into the page's markup from reader values and the recipe answers its page names, and a custom element adds only the interaction its view needs; a host page that embeds a view carries the markup the build wrote and loads the element script, and supplies no graph data.
The Studio renders generated HTML as its surface. The HTML is derived and never committed: git diffs stay over the canonical Spec source, and the Studio's files are regenerated from the graph.
impl:protocol.studio-command · validates and renders the Studio with independent byte checks and diagnostic exit codes · src/cli/studio-command.ts:106 · role publisher · component component:protocol.cli · layer edge · context protocol
impl:protocol.studio-data · assembles reader contexts, Pack totals, rails and search records for static pages · src/projections/studio/data.ts:279 · role contract · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-frame · renders Studio navigation, page rails and composing controls · src/projections/studio/pages/frame.ts:6 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
test:protocol.studio-publisher · anchored · test/studio-publisher.test.ts:26 · test anchor
Expected-outcome oracle: none
Runtime observation: not tracked.
Run results: not recorded in the graph.
Findings
None.
2. The Studio renders HTML, and the HTML stays derived
spec:decisions.studio-html-surface
The Studio renders HTML, and the HTML stays derived
spec:decisions.studio-html-surfaceDecision Record · featurereadyfloor ready
No open questions and no blocking questions; implementation binding none, verifier binding none, and expected-outcome oracle none.
Intent
outcome
Give reviewers a Studio with search, filters and collapsible views while git diffs stay over canonical Spec source.
Decision
context
When a model writes the Specs, a person's main act is review, and review reads tables, diagrams, code, comparisons and examples across many Specs. The first adopter's reviewers need search, filters, navigation and progressive disclosure across a Pack, which the generated Markdown pages do not give: the Pack page's member table is too wide for those readers, and they open the carrier files instead.
decision
The Studio renders generated HTML as its surface. The HTML is derived and never committed: git diffs stay over the canonical Spec source, and the Studio's files are regenerated from the graph.
rationale
HTML conveys more per screen: collapsible sections, wide tables that scroll in place, SVG diagrams, highlighted code and side-by-side comparisons are native to it.
HTML is shareable: a page set uploaded to any static host is a link a reviewer opens without installing anything.
HTML is interactive: search, filters and navigation run in the page over values the build wrote, which Markdown cannot do.
The Studio's code renders its HTML from the graph, so the original's argument from generation time and token cost, which priced a page a model writes, does not apply.
alternatives
Markdown renders in Markdown viewers and agents read it as text; the generated Markdown Design Review lacks the Studio's search, filters and collapsible views, so it stays beside the Studio.
consequences
The principal trade-off of HTML, diffs that are noisier in git, is sidestepped because the HTML is derived and never committed.
The Studio stands beside the Markdown Design Review. The Studio is an interactive workbench, the frozen Markdown Design Review is a generated view for agents and Markdown readers, and git review stays over canonical Spec source; neither view ranks above the other.
The case for derived HTML holds for any canonical carrier, because it rests on the HTML being derived and never committed, not on the Specs being written in TypeScript.
The richer interactions the original design lists, such as moving a target on a slider, running a scenario harness or reordering members by drag and drop, wait for later phases and their own Specs; the Studio's first build is read-only.
Verification
Verifier bindings
No verifier binding recorded.
Design view
Requirement drawing
Declared verifying examples: no declared verifying example.
Satisfying or referencing units: no recorded binding.
Test or oracle bindings: no recorded binding.
Requirement drawing for spec:decisions.studio-html-surface
Arrows: refines (declared).
The diagram as text
spec:decisions.studio-html-surface: The Studio renders HTML, and the HTML stays derived · declared Spec
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph · declared Spec
Preferred and chosen syntax: requirementDiagram; exact refines, satisfies and verifies, with claim words in nodes and per-edge comments.
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.studio-html-surfaceThe diagram as text
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph
spec:decisions.studio-html-surface: The Studio renders HTML, and the HTML stays derived
spec:extraction.regenerability: Generated artifacts are disposable projections
spec:decisions.studio-html-surface dependsOn spec:extraction.regenerability · declared — disposable HTML can be regenerated from the graph instead of committed as authored source
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The build writes each value into the page's markup, so a page reads in full as HTML. Search is the exception: a browser refuses a fetch from a page opened through file://, so the search page carries its index inside it. On the first adopter's corpus that index is too large to repeat on every page, which is why search runs on a page of its own.
Intent
outcome
Render every Studio page from the values the reader returns for the graph the agent surface reads, so a page derives nothing of its own and carries only the data its script needs.
The build renders the index from specs(), packs(), findings(), each Spec's design columns and the epic memberships recipe 52 answers, a Pack page from packContext and the Pack totals, a Spec page from specContext, and the search page from the search index; every page's rail renders the rail values. A page states no value the reader did not return or a named recipe did not answer, apart from counts the build takes of those values.
A page whose script reads data embeds it in one script element of type application/json with the id sdp-data, serialized as JSON with every < then written as the six characters \u003c, so no text can close the element. The search page embeds the search index there; every other page embeds no data, because its values are in its markup.
The Studio's data holds no context bundle or other AI slice: the context bundle is composed on each invocation and never saved, and a design pass composes one with its recipe when it needs it. A slice page renders the design slice's answer into its markup, as every page renders its values, and embeds no slice data.
{ packs: { id: string; title?: string; members: { id: string; title?: string; statedReadiness?: string; ownsExampleSpace: boolean }[] }[]; findings: { errors: number; warnings: number } }, the values every page's rail renders: each Pack in id order with its members in authored order, a member owning an example space when its Spec context carries one, and the validation report's findings counted by severity.
{ id: string; nodeType: "Primitive" | "Pack" | "Anchor" | "CodeNode"; page: string | null; title?: string; label?: string; framing?: string; narrative?: string; sections?: Record<string, unknown>; file?: string; line?: number; specKind?: string; statedReadiness?: string; floorReached?: string | null; bindings: { edge: string; specId: string }[]; entries: SearchEntry[] }: title, label, framing, narrative and sections exactly as the graph node holds them, the fields findByConcept reads; page the node's page path in the page set, null for an Anchor or a CodeNode; file and line as recorded; the kind and the two rungs on a Spec only, floorReached null when no rung derives; bindings the Specs an Anchor's or CodeNode's outgoing edges reach, with the edge type, and empty for any other node.
{ section: string; entry: string | null; key: string | null; address: string | null; line: number | null; text: string }, one per value recipe 23's walk reaches in a Spec's narrative and sections, taken with no term: each string, and each value that is not a string under a key the author coins, as its JSON text; in that walk's order, with that recipe's entry path, coined key, address and line. A term matches an entry as that recipe matches it, a string by its key or text and any other value by its key only, so the entries a term matches are the rows recipe 23 returns for it.
no citation recorded
Verification
Verifier bindings
test:protocol.studio-data · anchored · test anchor binding present · test/studio-data.test.ts:26
Design view
Requirement drawing
Requirement drawing for spec:consumers.spec-studio.dataThe diagram as text
spec:consumers.spec-studio.data: The Studio renders from the reader's values and embeds only what its script reads · declared Spec
spec:consumers.spec-studio.data.inputs: The Studio reads two named inputs beside the graph, a base graph and run records · declared Spec
spec:consumers.spec-studio.data.recipe-answers: A page takes each recipe answer from the recipe's shipped body · declared Spec
spec:consumers.spec-studio.data.inputs.both-given: Both inputs add their pages, named, and the same inputs write the same bytes · declared Spec
spec:consumers.spec-studio.data.inputs.graph-only: Without inputs the page set is the graph's alone · declared Spec
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph · declared Spec
impl:protocol.studio-base-input: reads named Studio base graphs and run inputs · anchored code · src/cli/studio-inputs.ts:9
impl:protocol.studio-command: validates and renders the Studio with independent byte checks and diagnostic exit codes · anchored code · src/cli/studio-command.ts:106
impl:protocol.studio-data: assembles reader contexts, Pack totals, rails and search records for static pages · anchored code · src/projections/studio/data.ts:279
impl:protocol.studio-inputs: named base graph and run input contract · anchored code · src/projections/studio/inputs.ts:1
impl:protocol.studio-recipes: evaluates shipped recipe bodies once and shares answers between Studio pages · anchored code · src/projections/studio/recipes.ts:34
impl:protocol.studio-register-contracts: shared recipe answer shapes for Studio registers · anchored code · src/projections/studio/pages/register-answers.ts:4
spec:consumers.spec-studio.diagrams dependsOn spec:consumers.spec-studio.data · declared — a diagram is laid out from the values and recipe answers its page renders
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The lenses, the registers, the owner queue, the slice and roadmap pages, the diff and runs pages and the panels of a Spec page show recipe answers. Each takes its answer from the recipe's shipped body, evaluated over the graph the build derived, so a page and sdp q give one answer. The two Design entries name every evaluation a build runs and which page reads each answer, so a builder and a test author read one list.
Intent
outcome
Compose every recipe answer a Studio page shows by evaluating the recipe's shipped body over the graph the build derived, so a page and sdp q give one answer.
The build composes each recipe answer a page shows by evaluating that recipe's shipped body, the one dist/recipes/ holds, over the graph, reader and validation report it derived, with the parameters the recipe evaluations name, through the body evaluation sdp q runs; it re-implements no recipe, so a page and sdp q give one answer.
a build evaluates each of these once, with no parameter unless one is named: recipes 17, 20, 24, 31, 33, 43, 44, 46, 51 and 53; recipe 52 with { detail: true }; recipe 29 with { pack: id } and recipe 54 with { pack: id, detail: true } for every Pack; recipe 55 with { pack: id } for every Pack whose manifest states order: priority; recipe 21 with { spec: id } and recipe 30 with { specs: [id] } for every Spec; recipe 34 with { spec: id } for every Spec that is not an example, Specs in no Pack included; given a base graph, recipe 35 with { base, detail: true }, and with { base, pack: id, detail: true } for every Pack; given run records, recipe 45 with { runs }.
the index renders reader values and each Spec's epicIds from recipe 52; the glossary renders reader values only; the capabilities lens renders recipe 52; the architecture lens renders recipes 17 and 43; the tests lens renders every recipe 34 answer, recipe 44, and recipe 45 given run records; a Spec page renders its recipe 21, 30 and 34 answers, its own space from recipe 44, the recipe 51 rows that cite its entries, the recipe 45 files whose specs hold its id, and its own row of recipe 35's whole-corpus answer; a Pack page renders the totals of its recipe 29 answer and, given a base graph, its own recipe 35 answer; a slice page renders its Pack's recipe 54 answer; the roadmap page renders recipe 53 and each roadmap's recipe 55 memo; the registers render recipes 20, 31, 24 beside recipe 51's rows, and 33; the owner queue renders recipe 46; the diff page renders recipe 35's whole-corpus answer; the runs page renders recipe 45; an export renders the values of the pages it holds.
Verification
Verifier bindings
test:protocol.studio-lenses · anchored · test anchor binding present · test/studio-s1.test.ts:273
Design view
Requirement drawing
Declared verifying examples: no declared verifying example.
Requirement drawing for spec:consumers.spec-studio.data.recipe-answersThe diagram as text
spec:consumers.spec-studio.data.recipe-answers: A page takes each recipe answer from the recipe's shipped body · declared Spec
spec:consumers.spec-studio.data: The Studio renders from the reader's values and embeds only what its script reads · declared Spec
impl:protocol.studio-recipes: evaluates shipped recipe bodies once and shares answers between Studio pages · anchored code · src/projections/studio/recipes.ts:34
impl:protocol.studio-register-contracts: shared recipe answer shapes for Studio registers · anchored code · src/projections/studio/pages/register-answers.ts:4
Relations of spec:consumers.spec-studio.data.recipe-answersThe diagram as text
spec:consumers.agent-surface.evaluation-sink: The evaluation sink runs one body and prints its return
spec:consumers.spec-studio.data: The Studio renders from the reader's values and embeds only what its script reads
spec:consumers.spec-studio.data.recipe-answers: A page takes each recipe answer from the recipe's shipped body
spec:consumers.spec-studio.slice-page: A slice page shows a Pack's design as one whole
spec:consumers.spec-studio.data.recipe-answers dependsOn spec:consumers.agent-surface.evaluation-sink · declared — the build composes recipe answers through the same body evaluation `sdp q` runs
spec:consumers.spec-studio.slice-page dependsOn spec:consumers.spec-studio.data.recipe-answers · declared — the build evaluates the slice recipe once for each Pack, and the page reads that answer
the build evaluates the slice recipe once for each Pack, and the page reads that answer
None
Bindings
Implementation binding: present
impl:protocol.studio-recipes · evaluates shipped recipe bodies once and shares answers between Studio pages · src/projections/studio/recipes.ts:34 · role service · component component:protocol.projections · layer edge · context protocol
Design reference: present
impl:protocol.studio-register-contracts · shared recipe answer shapes for Studio registers · src/projections/studio/pages/register-answers.ts:4 · role contract · component component:protocol.projections · layer edge · context protocol
Verifier binding: present
test:protocol.studio-lenses · anchored · test/studio-s1.test.ts:273 · test anchor
Expected-outcome oracle: none
Runtime observation: not tracked.
Run results: not recorded in the graph.
Findings
None.
5. The Studio reads two named inputs beside the graph, a base graph and run records
spec:consumers.spec-studio.data.inputs
The Studio reads two named inputs beside the graph, a base graph and run records
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
Two inputs may ride beside the graph: the graph an earlier commit wrote, so a page can show what changed since, and CI run records, so a reviewer reads what ran beside the verifier bindings. Each is named on the command line and on every page that shows it, and neither answers in the graph's name. Without them the page set is what the graph alone writes.
Intent
outcome
Let the Studio's build read a base graph and run records beside the graph, each named where it shows, while the graph alone writes the page set when neither is given.
Beside the graph the build reads at most two inputs, each named on the command line: a base graph, the graph object sdp build wrote at an earlier commit, which reaches recipe 35 as params.base; and run records, each one Common Test Report Format document, which reach recipe 45 as params.runs. The build reads neither in any other way.
The studio verb also takes --base PATH, naming the base graph, a JSON file sdp build wrote; --base-label TEXT, the words that name the base graph on its pages; and --runs PATH, naming one run record, a JSON file in the Common Test Report Format, repeatable, the records keeping the order of their flags. --base-label without --base, or --base given twice, is refused.
Before extraction or output cleanup, the command refuses an input path that the build could write or remove, including a path beneath a projection root and an alias resolving to such a path; it reports the flag and path, exits 1 and changes no file.
An input file that cannot be read or does not hold JSON refuses the run before extraction, with exit 1 and one line on stderr naming the flag and the path; a JSON value a recipe cannot read shows on its page as that recipe's diagnostics.
An input adds pages and page sections, never a data file: the base graph adds diff.html and the changed-since-base sections of the Spec and Pack pages, and run records add runs.html and the run rows of the tests lens and the verification panels.
A page that shows an input names it in words, the base graph by its label when it was given one, its schema version and its Spec count, and a run as spec:consumers.spec-studio.runs-page names it; no page holds an input's path.
An input never becomes graph data, a delivery fact, a finding, a rung or a verdict: no page counts a run toward a binding, and no difference from the base moves a rung.
Without inputs the page set is the one the graph alone writes; with them, the same graph and the same input bytes and labels write the same page set, byte for byte, and a value an input carries, such as a run's commit and times, shows only on the pages that name that input.
Given an extraction root holding a Pack and its member Specs
Given the studio command is given the base graph {base: "an earlier graph of the root"} and the run records {runs: "one CTRF report"}
When the studio command runs twice with those inputs
Then the two runs wrote byte-identical files: {byteIdentical: true}
Then the page set holds the diff page: {diffPage: true}
Then the page set holds the runs page: {runsPage: true}
Then every page that shows an input names it and holds no input path: {inputsNamed: true}
Given an extraction root holding a Pack and its member Specs
Given the studio command is given the base graph {base: "none"} and the run records {runs: "none"}
When the studio command runs twice with those inputs
Then the two runs wrote byte-identical files: {byteIdentical: true}
Then the page set holds the diff page: {diffPage: false}
Then the page set holds the runs page: {runsPage: false}
Then every page that shows an input names it and holds no input path: {inputsNamed: true}
Given an extraction root holding a Pack and its member Specs
Given the studio command is given the base graph {base:"none"|"an earlier graph of the root"} and the run records {runs:"none"|"one CTRF report"}
When the studio command runs twice with those inputs
Then the two runs wrote byte-identical files: {byteIdentical:boolean}
Then the page set holds the diff page: {diffPage:boolean}
Then the page set holds the runs page: {runsPage:boolean}
Then every page that shows an input names it and holds no input path: {inputsNamed:boolean}
{ base?: { graph: unknown; label: string | null }; runs: unknown[] }, the inputs the command hands the build: base absent without a base graph, runs the run records in the order the command names them and empty without any.
{ label: string | null; schemaVersion: string; specs: number }, how a page names the base graph: the label the command gave or null, the base graph's schemaVersion, and its count of Spec nodes.
no citation recorded
Verification
Verifier bindings
spec:consumers.spec-studio.data.inputs.both-given · Both inputs add their pages, named, and the same inputs write the same bytes · declared · example enabled · specs/consumers/spec-studio.data.inputs.both-given.sdp.md
Requirement drawing for spec:consumers.spec-studio.data.inputsThe diagram as text
spec:consumers.spec-studio.data.inputs: The Studio reads two named inputs beside the graph, a base graph and run records · declared Spec
spec:consumers.spec-studio.data.inputs.both-given: Both inputs add their pages, named, and the same inputs write the same bytes · declared Spec
spec:consumers.spec-studio.data.inputs.graph-only: Without inputs the page set is the graph's alone · declared Spec
spec:consumers.spec-studio.data: The Studio renders from the reader's values and embeds only what its script reads · declared Spec
impl:protocol.studio-base-input: reads named Studio base graphs and run inputs · anchored code · src/cli/studio-inputs.ts:9
impl:protocol.studio-command: validates and renders the Studio with independent byte checks and diagnostic exit codes · anchored code · src/cli/studio-command.ts:106
impl:protocol.studio-inputs: named base graph and run input contract · anchored code · src/projections/studio/inputs.ts:1
spec:consumers.spec-studio.diff-page dependsOn spec:consumers.spec-studio.data.inputs · declared — the base graph reaches the page as the build's named base input
spec:consumers.spec-studio.register-input dependsOn spec:consumers.spec-studio.data.inputs · declared — the register joins the base graph and the run records as a named input
spec:consumers.spec-studio.runs-page dependsOn spec:consumers.spec-studio.data.inputs · declared — the run records reach the page as the build's named runs input
spec:consumers.studio-on-ramp dependsOn spec:consumers.spec-studio.data.inputs · declared — the skill teaches the base graph and run records and where they may lie
impl:protocol.studio-base-input · reads named Studio base graphs and run inputs · src/cli/studio-inputs.ts:9 · role codec · component component:protocol.cli · layer edge · context protocol
impl:protocol.studio-command · validates and renders the Studio with independent byte checks and diagnostic exit codes · src/cli/studio-command.ts:106 · role publisher · component component:protocol.cli · layer edge · context protocol
impl:protocol.studio-inputs · named base graph and run input contract · src/projections/studio/inputs.ts:1 · role contract · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
spec:consumers.spec-studio.data.inputs.both-given · Both inputs add their pages, named, and the same inputs write the same bytes · declared · specs/consumers/spec-studio.data.inputs.both-given.sdp.md · example enabled
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the graph-only build: no input, no input page, and the same bytes twice.
assumptions
The world writes a root with one Pack of two member Specs, runs the studio command twice with no input flag, and compares the two page sets file by file; it reads every page for the words base graph and run evidence, which no page may hold without an input.
Behavior
Examples
Given an extraction root holding a Pack and its member Specs
Given the studio command is given the base graph {base: "none"} and the run records {runs: "none"}
When the studio command runs twice with those inputs
Then the two runs wrote byte-identical files: {byteIdentical: true}
Then the page set holds the diff page: {diffPage: false}
Then the page set holds the runs page: {runsPage: false}
Then every page that shows an input names it and holds no input path: {inputsNamed: true}
Verification
Verifier bindings
test:protocol.studio-graph-only · anchored · test anchor binding present · test/studio-s4.test.ts:434
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.data.inputs.graph-onlyThe diagram as text
spec:consumers.spec-studio.data.inputs.graph-only: Without inputs the page set is the graph's alone · declared Spec
spec:consumers.spec-studio.data.inputs: The Studio reads two named inputs beside the graph, a base graph and run records · declared Spec
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the two named inputs: each adds its page, each page names its input without its path, and two runs with the same inputs write the same bytes.
assumptions
The world writes a root with one Pack of two member Specs and a test anchor verifying the first, writes the root's graph with sdp build and keeps it outside the root as the base, adds a third Spec, writes one CTRF report whose one test names the anchored test file, and runs the studio command twice with both inputs and the label before. It reads the diff and runs pages for the label and the tool name, checks that no file in the page set holds either input's path, and checks that the graph the build derived holds no node or edge from either input.
Behavior
Examples
Given an extraction root holding a Pack and its member Specs
Given the studio command is given the base graph {base: "an earlier graph of the root"} and the run records {runs: "one CTRF report"}
When the studio command runs twice with those inputs
Then the two runs wrote byte-identical files: {byteIdentical: true}
Then the page set holds the diff page: {diffPage: true}
Then the page set holds the runs page: {runsPage: true}
Then every page that shows an input names it and holds no input path: {inputsNamed: true}
Verification
Verifier bindings
test:protocol.studio-inputs-both-given · anchored · test anchor binding present · test/studio-s4.test.ts:464
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.data.inputs.both-givenThe diagram as text
spec:consumers.spec-studio.data.inputs.both-given: Both inputs add their pages, named, and the same inputs write the same bytes · declared Spec
spec:consumers.spec-studio.data.inputs: The Studio reads two named inputs beside the graph, a base graph and run records · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The Studio has its own verb and root beside the four shipped publishers, and is written the way they are. Its page set opens from the file system and uploads to a static host unchanged. The run adds no stamp, commit or time, so two runs over one graph write the same bytes, and a publishing step that wants build context writes its stamp beside the page set.
Intent
outcome
Publish the Studio under its own root as one page set the graph and its named inputs alone determine, which opens through file:// and uploads to a static host unchanged.
sdp studio [root] [--exclude PATH]... [--check-clean] validates the graph and writes the Studio's page set to <root>/generated/spec-studio/; root defaults to the working directory, and each exclusion is a root-relative path prefix, as for the shipped publishers.
A run writes its page set to generated/spec-studio.tmp/, removes the prior root and renames the temporary into place, so no page of an earlier run survives a later one and no temporary survives a completed run.
Every command that enters the shared build, sdp studio among them, removes generated/spec-studio/ and its temporary sibling before extraction, beside the four roots spec:consumers.wholesale-view-rewrite names; a removal failure refuses the command before extraction.
sdp studio --check-clean renders an independent twin and refuses divergent renders, then compares the current root with the new render; missing or drifted output returns nonzero and is removed, and clean output is replaced wholesale with byte-identical content.
Findings never withhold the page set: a run over a graph with validation findings still publishes and returns the validation exit code, and each finding shows on the index, and also on its subject's page when its subject is a Spec or a Pack. A run whose extraction fails publishes nothing and returns nonzero.
The page set holds index.html, search.html, one packs/<name>.html and one slices/<name>.html per Pack, one specs/<name>.html per Spec, and assets/studio.css and assets/studio.js. <name> is the id after its namespace, with each uppercase ASCII letter written as _ and its lowercase, so no two pages collide on a file system that ignores case.
Two runs over one graph and the same inputs write byte-identical files, and no file holds a time, a commit, an absolute path or a host name of the run's own.
Every link a page writes stays inside the page set: it resolves to a page the run wrote and, with a fragment, to an element id that page carries, apart from the search page's term fragment search.html#q=<term>, which names no element. No page links a carrier or source file, an editor URI or an external address; the only link that leaves the page set is one the stamp element adds in the browser from a present stamp's source template.
no example exercises it
0 unkeyed rules.
Example space
Given an extraction root holding {corpus:"a Pack and its member Specs"|"a Spec with a validation error"|"a carrier the extractor refuses"} and a stale Studio page {stalePage:string}
When the studio command runs twice at that root, with check-clean {checkClean:boolean}
Then each run exits {exitCode:number}
Then the page set holds the entry page {entryPage:string}
Then the two runs wrote byte-identical files: {byteIdentical:boolean}
Then the stale page survives: {staleSurvives:boolean}
Then a temporary Studio sibling survives: {temporarySurvives:boolean}
Then every carrier and source file under the root stays byte-identical: {rootUntouched:boolean}
Then every link a page writes resolves inside the page set: {linksResolve:boolean}
Verification
Verifier bindings
test:protocol.studio-data · anchored · test anchor binding present · test/studio-data.test.ts:26
test:protocol.studio-publisher · anchored · test anchor binding present · test/studio-publisher.test.ts:26
Example space
corpus · "a Pack and its member Specs" | "a Spec with a validation error" | "a carrier the extractor refuses" · declared by an extraction root holding {corpus} and a stale Studio page {stalePage}
stalePage · string · declared by an extraction root holding {corpus} and a stale Studio page {stalePage}
checkClean · boolean · declared by the studio command runs twice at that root, with check-clean {checkClean}
Bound points
No bound example points recorded.
Oracle binding: none
Coverage
corpus
Declared value
Examples
"a Pack and its member Specs"
no example
"a Spec with a validation error"
no example
"a carrier the extractor refuses"
no example
stalePage: No bound values · not enumerable
checkClean: No bound values · not enumerable
Unbound
corpus: None
stalePage: None
checkClean: None
Design view
Requirement drawing
Requirement drawing for spec:consumers.spec-studio.publisherThe diagram as text
spec:consumers.spec-studio.publisher: sdp studio publishes the Studio as one page set · declared Spec
spec:consumers.spec-studio.publisher.watch: sdp studio --watch rebuilds the page set on each carrier change · declared Spec
spec:consumers.spec-studio.publisher.watch.matches-plain-run: Each watch cycle writes the page set a plain run writes · declared Spec
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph · declared Spec
impl:protocol.studio-command: validates and renders the Studio with independent byte checks and diagnostic exit codes · anchored code · src/cli/studio-command.ts:106
impl:protocol.studio-page-catalog: selects Studio pages, optional inputs and Pack exports · anchored code · src/projections/studio/pages/index.ts:21
impl:protocol.studio-paths: encodes uppercase id letters for collision-free Pack and Spec page paths · anchored code · src/projections/studio/paths.ts:2
impl:protocol.studio-publish: copies local assets and replaces the Studio directory through its temporary sibling · anchored code · src/projections/studio/publish.ts:24
impl:protocol.studio-watch: awaits the plain Studio publication in each coalesced carrier-watch cycle · anchored code · src/cli/studio-command.ts:122
Preferred syntax: requirementDiagram. Chosen syntax: flowchart TB because models, folds require exact labels unavailable in requirement syntax.
Decisions
spec:decisions.shipped-projections-frozen
Re-specifying the shipped Design Review, census, Mermaid, or Gherkin projection is refused. These four projections are the ruled read surfaces over the one graph. A later decision Spec that supersedes this one replaces the ruling whole; a decision Spec that refines this one narrows it for one projection or one rendering and leaves the rest frozen. Either passes the ADR three-part test.
impl:protocol.studio-publish · copies local assets and replaces the Studio directory through its temporary sibling · src/projections/studio/publish.ts:24
spec:consumers.spec-studio.publisher decidedBy spec:decisions.shipped-projections-frozen · declared — the Studio publishes to a root of its own beside the four frozen ones
spec:consumers.spec-studio.publisher dependsOn spec:consumers.wholesale-view-rewrite · declared — the Studio's root is written, invalidated and certified the way the shipped roots are
spec:consumers.command-line dependsOn spec:consumers.spec-studio.publisher · declared — the Studio's page set is one of the roots the verb writes
spec:consumers.spec-studio.data.inputs dependsOn spec:consumers.spec-studio.publisher · declared — each input is named by a flag of the studio verb
spec:consumers.spec-studio.export dependsOn spec:consumers.spec-studio.publisher · declared — the export files are part of the page set the publisher writes
spec:consumers.spec-studio.roadmap-page dependsOn spec:consumers.spec-studio.publisher · declared — an entry's element id carries the name the page set gives its roadmap's Pack page
spec:consumers.spec-studio.sharing dependsOn spec:consumers.spec-studio.publisher · declared — the stamp and the preview take the page set the publisher wrote
spec:consumers.studio-on-ramp dependsOn spec:consumers.spec-studio.publisher · declared — the skill teaches the verb, its watch and what each shared build removes
impl:protocol.build-pipeline-emit · stages build outputs, checks determinism and invalidates projections · src/cli/build-command.ts:251 · role service · component component:protocol.cli · layer edge · context protocol
impl:protocol.studio-command · validates and renders the Studio with independent byte checks and diagnostic exit codes · src/cli/studio-command.ts:106 · role publisher · component component:protocol.cli · layer edge · context protocol
impl:protocol.studio-page-catalog · selects Studio pages, optional inputs and Pack exports · src/projections/studio/pages/index.ts:21 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-paths · encodes uppercase id letters for collision-free Pack and Spec page paths · src/projections/studio/paths.ts:2 · role codec · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-publish · copies local assets and replaces the Studio directory through its temporary sibling · src/projections/studio/publish.ts:24 · role publisher · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
test:protocol.studio-data · anchored · test/studio-data.test.ts:26 · test anchor
test:protocol.studio-publisher · anchored · test/studio-publisher.test.ts:26 · test anchor
Expected-outcome oracle: none
Runtime observation: not tracked.
Run results: not recorded in the graph.
Findings
None.
9. sdp studio --watch rebuilds the page set on each carrier change
spec:consumers.spec-studio.publisher.watch
sdp studio --watch rebuilds the page set on each carrier change
spec:consumers.spec-studio.publisher.watchUse Case / Behavior · storyreadyfloor ready
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
While an author edits, the watch rebuilds the page set on each carrier change, and a person reloads the page to read it. Each cycle writes exactly what a plain run with the same arguments writes, so the watch adds no server, no live reload and no script of its own.
Intent
outcome
Rebuild the Studio's page set on every carrier change while an author edits, each cycle byte for byte what a plain run writes, with no server and no injected script.
sdp studio --watch installs the carrier watcher validate's watch installs, publishes once at start and again after every carrier create, change, delete or rename, each cycle writing the page set a plain sdp studio with the same arguments writes, byte for byte; it serves no page and injects no script, so a reader reloads to read the new build. Findings print each cycle and the process stays alive; a cycle whose extraction fails removes the page set; operator SIGINT exits 0; edits to source files and input files start no cycle; --watch cannot combine with --check-clean.
Given an extraction root holding a Pack and its member Specs and a stale Studio page {stalePage: "specs/probe.departed.html"}
When the studio command runs under watch at that root while one member carrier changes {changes: 2} times
Then the watch exits {exitCode: 0} on SIGINT
Then each watch cycle wrote the page set a plain run writes: {cyclesMatchPlainRun: true}
Then the page set holds a script the plain run does not write: {injectedScript: false}
Then the stale page survives: {staleSurvives: false}
Then a temporary Studio sibling survives: {temporarySurvives: false}
Given an extraction root holding a Pack and its member Specs and a stale Studio page {stalePage:string}
When the studio command runs under watch at that root while one member carrier changes {changes:number} times
Then the watch exits {exitCode:number} on SIGINT
Then each watch cycle wrote the page set a plain run writes: {cyclesMatchPlainRun:boolean}
Then the page set holds a script the plain run does not write: {injectedScript:boolean}
Then the stale page survives: {staleSurvives:boolean}
Then a temporary Studio sibling survives: {temporarySurvives:boolean}
impl:protocol.studio-watch · awaits the plain Studio publication in each coalesced carrier-watch cycle · src/cli/studio-command.ts:122 · role service · component component:protocol.cli · layer edge · context protocol
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the watch on a root whose member carrier changes, and hold each cycle's page set to a plain run's.
assumptions
The world writes a root with one Pack of two member Specs and plants the stale page, starts the watch through the command's watch hooks, changes the first member's title twice, waiting for each cycle, and after each cycle runs a plain studio command over a copy of the root as it stands and compares the two page sets file by file; it then stops the watch with SIGINT and reads the exit code.
Behavior
Examples
Given an extraction root holding a Pack and its member Specs and a stale Studio page {stalePage: "specs/probe.departed.html"}
When the studio command runs under watch at that root while one member carrier changes {changes: 2} times
Then the watch exits {exitCode: 0} on SIGINT
Then each watch cycle wrote the page set a plain run writes: {cyclesMatchPlainRun: true}
Then the page set holds a script the plain run does not write: {injectedScript: false}
Then the stale page survives: {staleSurvives: false}
Then a temporary Studio sibling survives: {temporarySurvives: false}
Verification
Verifier bindings
test:protocol.studio-watch-plain · anchored · test anchor binding present · test/studio-s5.test.ts:359
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.publisher.watch.matches-plain-runThe diagram as text
spec:consumers.spec-studio.publisher.watch.matches-plain-run: Each watch cycle writes the page set a plain run writes · declared Spec
spec:consumers.spec-studio.publisher.watch: sdp studio --watch rebuilds the page set on each carrier change · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The shell carries what every page shares, including the rules that keep a page readable: by keyboard, without color, on a phone and without its script. Recent edits stay out of it, because a page is a function of the graph alone and git holds the history.
Intent
outcome
Let a person move between the index, Packs and Specs from any page, find a Spec by what they remember of it, and read every page by keyboard, on a phone and without its script.
Served over http or https, the shell reads stamp.json beside the page set and, when it loads, shows the build context it names; a page opened through file:// requests nothing and shows no stamp.
A stated rung shows as a badge that carries the rung's word, colored from a palette of four that stays distinct under color blindness; the floor reached shows beside it as words with no color of its own, and only the divergence banner adds a warning color, beside its words.
Authored text renders as plain text with each inline code span as code, and no other Markdown is read. A mention the prose-mentions validator reads links to its target's page when the target resolves, and to the entry when the mention is an entry address.
Every page but the search page reads in full without its script: its collapsible parts are native disclosure elements, and only filtering, copying, the stamp, pan and zoom, and the composing panel need the script. The search page needs its script to match, and without it says so and links to the index.
no example exercises it
3 unkeyed rules.
UI
The parts of the shell, top to bottom and left to right.
the Studio's name linking to the index, then Packs, linking to the index's Packs section, then the search field; each lens page the page set holds adds its entry in the order spec:consumers.spec-studio.lenses gives.
on a Pack page, the Pack's members in authored order, each linked to its card on the page; on a Spec page, each Pack the Spec belongs to with its members in authored order, each linked to its Spec page and the current one marked; on any other page, every Pack; then, on a Pack or Spec page, under an Example spaces heading shown only when there is one, each member of the rail's Packs that owns an example space, linked to its Spec page, with no harness named; then the validation report's finding counts by severity, linked to the index's findings.
spec:consumers.spec-studio.shell dependsOn spec:consumers.spec-studio.lenses · declared — the top navigation opens each lens
spec:consumers.spec-studio.shell dependsOn spec:consumers.spec-studio.responsive · declared — the rail moves below the canvas under the phone breakpoint
spec:consumers.spec-studio.shell dependsOn spec:consumers.spec-studio.sharing · declared — the shell shows the stamp a publishing step writes beside the page set
spec:consumers.spec-studio.shell dependsOn spec:validation.prose-mentions · declared — a mention links where the validator resolves it
impl:protocol.studio-code-spans · escapes and maps code spans across Studio text · src/projections/studio/pages/code-spans.ts:9 · role codec · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-frame · renders Studio navigation, page rails and composing controls · src/projections/studio/pages/frame.ts:6 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-html · shared Studio HTML, source and link encoding · src/projections/studio/pages/html.ts:8 · role codec · component component:protocol.projections · layer edge · context protocol
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The first adopter asked to search entry keys, pinned declarations and file paths. A Spec's envelope holds no tags, so search reads what the graph holds: the fields concept search reads, which already include every pinned declaration, plus the keys authors coin and the files the graph records. The page matches with the reader's own code, so a term finds on the page what findByConcept finds through sdp q.
Intent
outcome
Let a person find a Spec, a Pack, a keyed entry or the code bound at a file by a word they remember of it, from any page and with no request.
Search matches with the reader's concept matching, one implementation the package exports without Node dependencies and the page script bundles, so over the fields findByConcept reads, the page returns the nodes it returns, in its order.
Search also matches the keys authors coin, Design and UI keys, open question keys and rule keys, and a node's recorded file path; a node matched only through these follows every node findByConcept matches, in id order. It indexes nothing else.
The search field on any page opens the search page with the term in its fragment, search.html#q=<term>; the search page matches as the person types and keeps the term in its fragment, so a search is a link.
Each result names its node type in words. A Spec result shows its title, id, kind, and stated rung beside the floor reached, and opens its page; a Pack result shows its title and id and opens its page, with no readiness; an Anchor or CodeNode result shows its id, label, and recorded file and line as text with a copy action, and links each Spec its edges reach, with the edge type.
A Spec with a matching entry is a result. Under a Spec result, the page lists the Spec's entries the term matches, as spec:consumers.spec-studio.data#design.searchEntry states, in the index's order, each with its section, key and recorded line, linked to the entry's element id on the Spec page when it has an entry address, and otherwise to its section's element id, or to the narrative's.
one card per node, in result order: its node type in words, title and id, the fields that matched, and the Spec's rungs or the unit's location as the result rule states; then its entry hits.
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The shell's top navigation reaches the index and each lens, and the index routes a reader by the task they came to do. The register pages, the owner queue, the glossary, and the diff and runs pages join both, so a reviewer with only a link reaches every page from any page and sees which page they are on.
Intent
outcome
Let a person reach every page of the page set from the top navigation of any page, and from the index by the task they came to do.
After the lens entries, the top navigation lists Roadmap, Queue, Questions, Decisions, Declarations, Backlog and Glossary, then Diff when the build was given a base graph and Runs when it was given run records, each linking its page; the search field follows them.
After its four routes, the index's Start here list adds See what comes next, linking the roadmap page; See what the owner can state first, linking the owner queue; See the components by context and layer, linking the architecture lens; and, given a base graph, See what changed since the base, linking the diff page.
no example exercises it
0 unkeyed rules.
Verification
Verifier bindings
test:protocol.studio-navigation · anchored · test anchor binding present · test/studio-s3.test.ts:317
test:protocol.studio-roadmap-page · anchored · test anchor binding present · test/studio-roadmap.test.ts:24
Design view
Requirement drawing
Declared verifying examples: no declared verifying example.
Requirement drawing for spec:consumers.spec-studio.navigationThe diagram as text
spec:consumers.spec-studio.navigation: Every page of the page set is reached from the top navigation and the index · declared Spec
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph · declared Spec
impl:protocol.studio-frame: renders Studio navigation, page rails and composing controls · anchored code · src/projections/studio/pages/frame.ts:6
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
Each lens is a page with a Spec of its own, so each builds on the graph it reads today: the Packs, capabilities, architecture and tests lenses read what the graph records, and the evidence lens reads not tracked until the graph records an observation. This Spec keeps what the five share.
Intent
outcome
Let a person see the graph five ways, by Pack, by capability, by architecture, by verification and by evidence, from one top navigation.
The lenses are pages of the page set, reached from the top navigation in the order Packs, capabilities, architecture, tests, evidence; the index page is the Packs lens and the default landing page.
A lens writes nothing and states nothing: it lists, groups, draws and links, and a change a person wants from it leaves through the composing panel as scoped intent.
index.html for the Packs lens, capabilities.html for the capabilities lens, architecture.html, tests.html and evidence.html, each opening with its name and one sentence saying what it reads.
Verification
Verifier bindings
test:protocol.studio-lenses · anchored · test anchor binding present · test/studio-s1.test.ts:273
Design view
Requirement drawing
Requirement drawing for spec:consumers.spec-studio.lensesThe diagram as text
spec:consumers.spec-studio.lenses: Five lenses read the graph as Packs, capabilities, architecture, tests and evidence · declared Spec
spec:consumers.spec-studio.capability-map-page: The capability map page makes refinement readable by epic · declared Spec
spec:consumers.spec-studio.lenses.architecture: The architecture lens draws components by context and layer, the planned beside the built · declared Spec
spec:consumers.spec-studio.lenses.evidence: The evidence lens names each source of runtime evidence and reads it as not tracked · declared Spec
spec:consumers.spec-studio.lenses.packs: The Packs lens groups every Spec by the Packs that hold it · declared Spec
spec:consumers.spec-studio.lenses.tests: The tests lens shows how far each Spec's verification reaches · declared Spec
spec:consumers.spec-studio.lenses.architecture.planned-apart: A component design no anchor realizes draws planned beside the built one · declared Spec
spec:consumers.spec-studio.lenses.tests.coverage-row: A Spec's row on the tests lens counts its exercised keyed rules · declared Spec
spec:consumers.capability-map: The capability map reads every epic and its refinement descendants · declared Spec
spec:consumers.spec-studio.index-page: The index says where the corpus stands and narrows every Spec · declared Spec
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph · declared Spec
spec:consumers.spec-studio.lenses.architecture.unit-register: The architecture page lists each component's significant units by role · declared Spec
impl:protocol.studio-architecture-lens: renders recipe component rows and planned designs as architecture and member diagrams · anchored code · src/projections/studio/pages/architecture-page.ts:50
impl:protocol.studio-capabilities-page: renders epic evidence, refinement and unreached Specs from the capability map · anchored code · src/projections/studio/pages/capabilities-page.ts:78
impl:protocol.studio-evidence-lens: names the four evidence sources and what would bring each into the Studio · anchored code · src/projections/studio/pages/evidence-page.ts:3
impl:protocol.studio-filter: filters build-rendered rows through their recorded attributes · anchored code · src/studio-elements/filter.ts:25
impl:protocol.studio-frame: renders Studio navigation, page rails and composing controls · anchored code · src/projections/studio/pages/frame.ts:6
spec:consumers.spec-studio.capability-map-page refines spec:consumers.capability-map · declared — the page is the capability map's reading for a person
spec:consumers.spec-studio.capability-map-page refines spec:consumers.spec-studio.lenses · declared — the Capabilities page is a lens that reads refinement
spec:consumers.spec-studio.index-page refines spec:consumers.spec-studio.lenses.packs · declared — the index is the Packs lens and where a person lands
component:protocol.reader · the typed graph contract and body evaluator · src/reader/reader.ts:671 · layer application · context protocol
component:protocol.validate · one finding currency and ordered checks · src/validate/validators.ts:72 · layer domain · context protocol
impl:protocol.studio-architecture-lens · renders recipe component rows and planned designs as architecture and member diagrams · src/projections/studio/pages/architecture-page.ts:50
impl:protocol.studio-evidence-lens · names the four evidence sources and what would bring each into the Studio · src/projections/studio/pages/evidence-page.ts:3
impl:protocol.studio-tests-lens · renders shared rule and example-space coverage with filters and verifier bindings · src/projections/studio/pages/tests-page.ts:34
spec:consumers.spec-studio.navigation dependsOn spec:consumers.spec-studio.lenses · declared — the lens entries keep the order the lenses take
spec:consumers.spec-studio.shell dependsOn spec:consumers.spec-studio.lenses · declared — the top navigation opens each lens
spec:consumers.spec-studio.capability-map-page refines spec:consumers.spec-studio.lenses · declared — the Capabilities page is a lens that reads refinement
impl:protocol.studio-architecture-lens · renders recipe component rows and planned designs as architecture and member diagrams · src/projections/studio/pages/architecture-page.ts:50 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-evidence-lens · names the four evidence sources and what would bring each into the Studio · src/projections/studio/pages/evidence-page.ts:3 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-frame · renders Studio navigation, page rails and composing controls · src/projections/studio/pages/frame.ts:6 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-tests-lens · renders shared rule and example-space coverage with filters and verifier bindings · src/projections/studio/pages/tests-page.ts:34 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
test:protocol.studio-lenses · anchored · test/studio-s1.test.ts:273 · test anchor
Expected-outcome oracle: none
Runtime observation: not tracked.
Run results: not recorded in the graph.
Findings
None.
15. The Packs lens groups every Spec by the Packs that hold it
spec:consumers.spec-studio.lenses.packs
The Packs lens groups every Spec by the Packs that hold it
spec:consumers.spec-studio.lenses.packsUse Case / Behavior · storyreadyfloor ready
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
Packs collect Specs for review, while the separate Capabilities page reads authored refinement. The index remains the landing page and keeps each Pack's members in authored order.
Intent
outcome
Let a person reach every Spec through the Packs that hold it, each Pack's members in the order its manifest gives.
The Packs lens groups Specs by Pack, each Pack's members in authored order. The separate Capabilities page reads refinement; selecting an epic narrows the index's Specs section without changing any Pack.
the index page's Packs section, one closed disclosure per Pack in id order, its summary line the Pack's title, id and member count, its body the members in authored order with their rung badges.
Verification
Verifier bindings
test:protocol.studio-lenses · anchored · test anchor binding present · test/studio-s1.test.ts:273
Design view
Requirement drawing
Declared verifying examples: no declared verifying example.
Requirement drawing for spec:consumers.spec-studio.lenses.packsThe diagram as text
spec:consumers.spec-studio.lenses.packs: The Packs lens groups every Spec by the Packs that hold it · declared Spec
spec:consumers.spec-studio.index-page: The index says where the corpus stands and narrows every Spec · declared Spec
spec:consumers.spec-studio.lenses: Five lenses read the graph as Packs, capabilities, architecture, tests and evidence · declared Spec
spec:consumers.spec-studio.index-page refines spec:consumers.spec-studio.lenses.packs · declared — the index is the Packs lens and where a person lands
Relations of spec:consumers.spec-studio.lenses.packsThe diagram as text
spec:consumers.spec-studio.index-page: The index says where the corpus stands and narrows every Spec
spec:consumers.spec-studio.lenses: Five lenses read the graph as Packs, capabilities, architecture, tests and evidence
spec:consumers.spec-studio.lenses.packs: The Packs lens groups every Spec by the Packs that hold it
spec:extraction.pack-member-order: A Pack node keeps its members in authored order
spec:consumers.spec-studio.lenses.packs dependsOn spec:extraction.pack-member-order · declared — the lens lists each Pack's members in the order its manifest gives
spec:consumers.spec-studio.index-page refines spec:consumers.spec-studio.lenses.packs · declared — the index is the Packs lens and where a person lands
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
A reader of a large design needs two ways in: by the task they came to do and by a word they remember. The index gives the first and links to search for the second, opens with a summary the build counts, and replaces one long table with a list a person narrows.
Intent
outcome
Give a person one landing page that says where the corpus stands, routes them by task, lists every Pack with its members, and narrows every Spec by the coordinates and bindings they ask about.
The page opens with a summary the build counts from reader values, each count in a sentence: the Specs and Packs; the Specs at each stated rung; the Specs stated above their floor; the open and blocking questions; the Specs with an implementation binding and with a verifier binding; and the findings by severity.
A short list then routes by task, in fixed words that quote nothing from the corpus: read a Pack's design, find a Spec, entry or file by a word, narrow the Specs, and read the findings; each route links to its place in the page set.
The Packs section lists every Pack in id order with its title and its members in authored order, each member with its stated rung beside its floor; it draws no capability tree.
The Specs section lists every Spec in id order, one row each: its title and id, kind and altitude, stated rung beside the floor reached, implementation binding and verifier binding as present or none, open and blocking questions, and its Packs.
Filters narrow the Specs section by kind, altitude, stated rung, floor reached, implementation binding, verifier binding, Pack and epic; each filter takes one value or any, the epic filter also takes no epic, the filters combine, and the section says how many of its rows it shows. Without script every row shows.
The findings section lists the validation report's findings in its order, each with its severity in words, its validator id, its subject when it has one, linked to its page when it is a Spec or a Pack and as text otherwise, its message, and its recorded file and line as text.
one closed disclosure per Pack, its summary line the Pack's title, id and member count, its body the members in authored order as links with their rung badges.
one line per Spec: the title linked to its page, the id as code, the rung badge, then as plain text the kind, altitude, floor in words, the two binding values, the question counts and the Packs; the line wraps on a narrow screen.
the Packs, Specs and findings sections carry the element ids packs, specs and findings, which the top navigation, the rail and the task routes link to.
spec:consumers.spec-studio.index-page refines spec:consumers.spec-studio.lenses.packs · declared — the index is the Packs lens and where a person lands
spec:consumers.spec-studio.index-page refines spec:consumers.spec-studio.lenses.packs · declared — the index is the Packs lens and where a person lands
spec:consumers.spec-studio.capability-map-page dependsOn spec:consumers.spec-studio.index-page · declared — the Epic filter extends the index's Specs filters
spec:consumers.spec-studio.navigation dependsOn spec:consumers.spec-studio.index-page · declared — the routes extend the index's task list
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
The original's architecture lens drew runtime layers, ports and external systems beside components. The graph holds what the architectural annotation decision admits: a component anchor's layer and bounded context, any unit's role, membership and uses, and no port or external-system node. So the lens groups components by their recorded context and layer and draws membership and uses only. A design ahead of its code states its components in component designs, which no anchor realizes yet; the lens draws them in the same grid, marked planned, so a reader sees what is designed and not built where it will sit.
Intent
outcome
Let a person see the components the code realizes and the components the design plans, grouped by bounded context and layer, with what each uses and what it holds.
The lens draws every component the anchors realize, from recipe 17's component rows and the attributes the componentRows entry adds to them, grouped by its recorded context and layer as the architecture grid of spec:consumers.spec-studio.diagrams places it, and folds above the bound as that Spec states.
The lens draws component membership, as the member count in each box, and uses, as edges between components, and nothing else: no port, external system, runtime layer or import the impact graph infers.
Beside the architecture drawing comes the component uses table, read from recipe 17's component rows and their counts of unit uses edges: one row per realized component as the user and one column per realized component as the used. A nonzero cell holds the count of anchored unit uses edges behind the pair and links to that use in the row component's detail; a zero cell between two components shows ·, with no anchored use recorded as hidden text and the legend · means no anchored use recorded, and the cell where a component meets itself stays empty. Planned uses, unresolved endpoints and uses within one component stay in their own readings and never enter the table. The table is not a drawing, and it reads in full without script and in print.
Each component design no anchor realizes, a row of recipe 43's unrealized list, draws in the same grid by its planned context and layer as a planned box, with the uses it plans drawn dashed to the components it names, and is listed again in a Designed, not built section apart from the realized components; a planned use naming a component the lens draws no box for draws no edge and stays listed in its design's row.
A realized component whose design differs from it lists each differing field, as recipe 43's differing rows give it, with its planned and realized values in its detail, and a design value recipe 43 cannot read lists in the Designed, not built section as unreadable.
Each realized component has a detail section on the lens page whose element id is its id, which its box and every link to it from another page open: its id, label, layer, context and role; its recorded file and line as text with a copy action; its members, each with its id, label, role and recorded file and line; the components it uses and is used by, each with the count of unit edges; the Specs it and its members satisfy and reference, linked, a component design its anchor satisfies among them; and its member diagram, every value read from its recipe 17 row.
A component diagram rooted at code units, the view spec:consumers.structural-mermaid asked for, is this lens's member diagram, and the shipped Mermaid root draws none.
A memberOf target the graph holds no component for, and a uses edge an end of which resolves to no component, list in an Unresolved structure section as recipe 17 reports them, never dropped.
The page opens with sentences the build counts from the two recipes' answers: the components realized and planned, the contexts and layers they state, the uses edges between components, and the designs that differ from their components.
Given component anchors that realize {realized: 1} components in the context {context: "orders"} and the layer {layer: "domain"}
Given component designs that plan {planned: 1} more components in that context and layer, which no anchor realizes
When the build renders the architecture lens
Then the context's column holds {boxes: 2} component boxes in the layer's band
Then the diagram marks {plannedBoxes: 1} boxes planned
Then the Designed, not built section lists {listed: 1} component designs
Given component anchors that realize {realized:number} components in the context {context:string} and the layer {layer:"edge"|"application"|"domain"|"adapter"|"infrastructure"}
Given component designs that plan {planned:number} more components in that context and layer, which no anchor realizes
When the build renders the architecture lens
Then the context's column holds {boxes:number} component boxes in the layer's band
Then the diagram marks {plannedBoxes:number} boxes planned
Then the Designed, not built section lists {listed:number} component designs
{ label: string | null; file: string | null; line: number | null; role: string | null; layer: string | null; context: string | null; referencedSpecs: string[]; usesCounts: { component: string; edges: number }[]; usedByCounts: { component: string; edges: number }[] }, the fields recipe 17 adds to each component row: the component's own label, file, line, role, layer and context as its CodeNode records them, each null when the node records none or no node declares the component; the Specs the component and its members reference, sorted; and, sorted by component, the count of unit uses edges behind each pair usesOut and usedBy name. Each member row gains role: string | null, and every field the recipe returns today keeps its meaning.
in order, the page title Architecture, the summary sentences, the architecture diagram or its fold with one section per context, the component uses table, the Designed, not built section, the component details in id order, and the Unresolved structure section when it has rows.
a table captioned Which components use which in a named, keyboard-focusable scroll region, one row header and one column header per realized component, both in one order: by layer from edge to infrastructure, unlayered components last, then by id; each header names the component's label with its id as code.
a table with one row per unrealized design in Spec id order: the component design's Spec, linked; the planned component's id as code; its planned context, layer and role, or not stated; the components it plans to use; and whether its component anchor exists without satisfying it; a design whose value recipe 43 cannot read adds a row naming the design, the key and the unreadable value.
a heading with the component's id as code and its label, a line with its layer, context and role in words, its source binding apart from its members, then Members grouped by recorded role, Uses with supporting unit edges at the table's fragment targets, Used by, any design differences, Satisfies and References, an empty list reading None, then the member diagram.
test:protocol.studio-architecture-maturity-requirement · anchored · test anchor binding present · test/studio-panels.test.ts:35
Example space
realized · number · declared by component anchors that realize {realized} components in the context {context} and the layer {layer}
context · string · declared by component anchors that realize {realized} components in the context {context} and the layer {layer}
layer · "edge" | "application" | "domain" | "adapter" | "infrastructure" · declared by component anchors that realize {realized} components in the context {context} and the layer {layer}
planned · number · declared by component designs that plan {planned} more components in that context and layer, which no anchor realizes
Requirement drawing for spec:consumers.spec-studio.lenses.architecture
E4: refines · declared
The diagram as text
spec:consumers.spec-studio.lenses.architecture: The architecture lens draws components by context and layer, the planned beside the built · declared Spec
spec:consumers.spec-studio.lenses.architecture.planned-apart: A component design no anchor realizes draws planned beside the built one · declared Spec
spec:consumers.spec-studio.lenses.architecture.unit-register: The architecture page lists each component's significant units by role · declared Spec
spec:consumers.spec-studio.lenses: Five lenses read the graph as Packs, capabilities, architecture, tests and evidence · declared Spec
impl:protocol.studio-architecture-lens: renders recipe component rows and planned designs as architecture and member diagrams · anchored code · src/projections/studio/pages/architecture-page.ts:50
impl:protocol.studio-unit-register: renders component source bindings and role-grouped recorded units · anchored code · src/projections/studio/pages/architecture-register.ts:7
Preferred syntax: requirementDiagram. Chosen syntax: flowchart TB because models, folds require exact labels unavailable in requirement syntax.
Decisions
spec:decisions.architectural-annotation
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.
component:protocol.reader · the typed graph contract and body evaluator · src/reader/reader.ts:671 · layer application · context protocol
component:protocol.validate · one finding currency and ordered checks · src/validate/validators.ts:72 · layer domain · context protocol
impl:protocol.studio-architecture-lens · renders recipe component rows and planned designs as architecture and member diagrams · src/projections/studio/pages/architecture-page.ts:50
Relations of spec:consumers.spec-studio.lenses.architectureThe diagram as text
spec:consumers.spec-studio.diagram-kinds.scoped-architecture: A Spec set draws the architecture it touches
spec:consumers.spec-studio.diagrams: A diagram is laid out from graph values into SVG with a text equivalent
spec:consumers.spec-studio.lenses: Five lenses read the graph as Packs, capabilities, architecture, tests and evidence
spec:consumers.spec-studio.lenses.architecture: The architecture lens draws components by context and layer, the planned beside the built
spec:consumers.spec-studio.lenses.architecture.planned-apart: A component design no anchor realizes draws planned beside the built one
spec:consumers.spec-studio.lenses.architecture.unit-register: The architecture page lists each component's significant units by role
spec:consumers.structural-mermaid: Mermaid diagrams can be rooted at code units
spec:decisions.architectural-annotation: Architectural significance is annotated where it is realized
spec:model.planned-architecture: Components are designed ahead of their code
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:consumers.spec-studio.lenses.architecture dependsOn spec:consumers.spec-studio.diagrams · declared — the lens's drawings are the architecture grid and the member diagrams
spec:consumers.spec-studio.lenses.architecture dependsOn spec:model.planned-architecture · declared — planned components come from the component designs recipe 43 reads
spec:consumers.structural-mermaid dependsOn spec:consumers.spec-studio.lenses.architecture · declared — the lens draws the component diagram rooted at code units this Spec asked for
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
A contributor about to change the engine needs the curated register of its significant units: the ports, contracts, pipeline stages and catalogs each component owns, and the designs each unit realizes or answers to. The graph already records them on the anchors. This panel reads them there, grouped by component and role, and shows what no anchor states rather than guessing it.
Intent
outcome
Let a contributor find recorded units and their design bindings through their component and role, with omitted structure visible.
The architecture page groups recorded members by role within each recorded component, and shows a component's own source binding apart from its members. A row shows the recorded id, label, file and line and its satisfies and references targets separately. The page reads graph bindings only, never an annotation review or oracle source file.
Keep a not-stated role group and a no-component section. A binding confers no review approval or execution verdict, and the page shows no inferred accepted badge.
Show each recorded role token without interpreting it through a Protocol-corpus Spec id. An adopter's unfamiliar roles remain visible and produce no finding.
Sort components by id, role groups by token and members by id in code-unit order, with not-stated roles last and the no-component section after the components.
Every row is available without script through native disclosures. The component index links to the existing component section ids, and narrow screens retain readable source paths and separate realization and reference lists.
no example exercises it
0 unkeyed rules.
Verification · reviewed
criteria
Render the self-hosted corpus and an adopter with unfamiliar roles, omitted roles and omitted membership. Check ordering, component source rows, target separation, keyboard disclosures and narrow-screen overflow, with no inferred approval badge.
mode
reviewed
Verification
Verifier bindings
test:protocol.studio-architecture-maturity-requirement · anchored · test anchor binding present · test/studio-panels.test.ts:35
Design view
Requirement drawing
Declared verifying examples: no declared verifying example.
Requirement drawing for spec:consumers.spec-studio.lenses.architecture.unit-registerThe diagram as text
spec:consumers.spec-studio.lenses.architecture.unit-register: The architecture page lists each component's significant units by role · declared Spec
spec:consumers.spec-studio.lenses.architecture: The architecture lens draws components by context and layer, the planned beside the built · declared Spec
impl:protocol.studio-unit-register: renders component source bindings and role-grouped recorded units · anchored code · src/projections/studio/pages/architecture-register.ts:7
component:protocol.reader · the typed graph contract and body evaluator · src/reader/reader.ts:671 · layer application · context protocol
component:protocol.validate · one finding currency and ordered checks · src/validate/validators.ts:72 · layer domain · context protocol
impl:protocol.studio-unit-register · renders component source bindings and role-grouped recorded units · src/projections/studio/pages/architecture-register.ts:7
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the planned component on the architecture lens: drawn in the grid where its design places it, marked planned, and listed apart.
assumptions
The world writes a root with one component anchor, component:probe.orders, that states the context orders and the layer domain, and one component design, a Spec whose Design entries name component:probe.payments in the same context and layer, which no anchor realizes; it builds the page set and reads the architecture page: the boxes in the orders lane and the domain band, the boxes carrying data-planned="true", and the rows of the Designed, not built table.
Behavior
Examples
Given component anchors that realize {realized: 1} components in the context {context: "orders"} and the layer {layer: "domain"}
Given component designs that plan {planned: 1} more components in that context and layer, which no anchor realizes
When the build renders the architecture lens
Then the context's column holds {boxes: 2} component boxes in the layer's band
Then the diagram marks {plannedBoxes: 1} boxes planned
Then the Designed, not built section lists {listed: 1} component designs
Verification
Verifier bindings
test:protocol.studio-architecture-planned-apart · anchored · test anchor binding present · test/studio-s1.test.ts:716
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.lenses.architecture.planned-apartThe diagram as text
spec:consumers.spec-studio.lenses.architecture.planned-apart: A component design no anchor realizes draws planned beside the built one · declared Spec
spec:consumers.spec-studio.lenses.architecture: The architecture lens draws components by context and layer, the planned beside the built · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
A verifier binding states that a verifier exists, and pass and fail stay in CI, so the lens shows bindings and coverage. It shows a run result only when the build was given run records, and then as evidence from a test file, never as a verdict on a Spec.
Intent
outcome
Let a person see, for every Spec, whether a verifier is bound, which keyed rules an example exercises, and which example-space values no example binds.
The lens lists one row per Spec that is not an example, in id order: its verifier binding as present or none, with its verifiers and how many are enabled; its keyed rules with how many an enabled example exercises, from recipe 34; its unkeyed rules, counted apart because the graph cannot tell which examples exercise a rule with no key; and, when it owns an example space, its uncovered values and the examples that leave a slot unbound, from recipe 44. Each row links to the verification panel of the Spec's page. A space with no enumerable slot is not measurable, whether or not it has examples; otherwise it is uncovered when any enumerable value has no example and covered when all enumerable values have examples. Non-enumerable slots do not affect a mixed space's classification.
The lens shows verifier bindings and states no run result of its own; with the run records input, a row adds how many of the results recipe 45 joins from its verifiers' test files passed, failed, were skipped, pending or other, labelled as external run evidence from those files and never as a verdict on the Spec or on one verifier.
Filters narrow the rows by verifier binding, by whether a keyed rule goes unexercised, by example-space classification (covered, uncovered, not measurable or no space), and by Pack, and the section says how many rows it shows; without script every row shows.
no example exercises it
Cited at
Test line · test/studio-s1.test.ts:434 · test:protocol.studio-tests-coverage-row
The page opens with sentences the build counts from the recipes' answers: the Specs with and without a verifier binding, the keyed rules exercised and unexercised, the unkeyed rules, the example spaces with an uncovered value, and, with run records, the inputs it names.
Given a Spec with {keyed: 2} keyed rules and {unkeyed: 1} unkeyed rules
Given an example bound to a test anchor that exercises {exercised: 1} of those keyed rules
When the build renders the tests lens
Then the Spec's row reads {coverage: "1 of 2 keyed rules exercised"}
Then the Spec's row reads its verifier binding as {binding: "present"}
Given a Spec with {keyed:number} keyed rules and {unkeyed:number} unkeyed rules
Given an example bound to a test anchor that exercises {exercised:number} of those keyed rules
When the build renders the tests lens
Then the Spec's row reads {coverage:string}
Then the Spec's row reads its verifier binding as {binding:"present"|"none"}
the Spec's title linked to its page's verification panel, its id as code, then as plain text: verifier binding present or none with <n> verifiers, <m> enabled, <e> of <k> keyed rules exercised, <u> unkeyed rules, and <v> uncovered values when its example space has an enumerable slot, or not measurable when it has a space with no enumerable slot; with run records, external run evidence: and the count of each result.
one labelled select per filter, each listing any and the values the rows hold, and a line saying how many of all rows show.
Verification
Verifier bindings
spec:consumers.spec-studio.lenses.tests.coverage-row · A Spec's row on the tests lens counts its exercised keyed rules · declared · example enabled · specs/consumers/spec-studio.lenses.tests.coverage-row.sdp.md
Example space
keyed · number · declared by a Spec with {keyed} keyed rules and {unkeyed} unkeyed rules
unkeyed · number · declared by a Spec with {keyed} keyed rules and {unkeyed} unkeyed rules
exercised · number · declared by an example bound to a test anchor that exercises {exercised} of those keyed rules
Preferred syntax: requirementDiagram. Chosen syntax: flowchart TB because models require exact labels unavailable in requirement syntax.
Decisions
spec:decisions.binding-not-liveness
Delivery facts record bindings and enabled verifier existence; coverage gaps and human readiness practice remain explicit without becoming graph facts.
component:protocol.reader · the typed graph contract and body evaluator · src/reader/reader.ts:671 · layer application · context protocol
component:protocol.validate · one finding currency and ordered checks · src/validate/validators.ts:72 · layer domain · context protocol
impl:protocol.studio-tests-lens · renders shared rule and example-space coverage with filters and verifier bindings · src/projections/studio/pages/tests-page.ts:34
spec:consumers.spec-studio.lenses.tests dependsOn spec:consumers.agent-surface.example-space-coverage · declared — a row reads its example space's uncovered values from recipe 44
spec:consumers.spec-studio.lenses.tests dependsOn spec:observation.run-evidence · declared — with run records, a row adds the results recipe 45 joins from its verifiers' files
impl:protocol.studio-tests-lens · renders shared rule and example-space coverage with filters and verifier bindings · src/projections/studio/pages/tests-page.ts:34 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
spec:consumers.spec-studio.lenses.tests.coverage-row · A Spec's row on the tests lens counts its exercised keyed rules · declared · specs/consumers/spec-studio.lenses.tests.coverage-row.sdp.md · example enabled
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute a tests-lens row: the keyed rules an enabled example exercises against those it does not, and the unkeyed rules apart.
assumptions
The world writes a root with one behavior Spec whose Behavior section holds two keyed rules and one unkeyed rule, and one example child that verifies it, exercising the first key, bound by a specTest anchor in a test file; it builds the page set and reads the Spec's row on the tests page.
Behavior
Examples
Given a Spec with {keyed: 2} keyed rules and {unkeyed: 1} unkeyed rules
Given an example bound to a test anchor that exercises {exercised: 1} of those keyed rules
When the build renders the tests lens
Then the Spec's row reads {coverage: "1 of 2 keyed rules exercised"}
Then the Spec's row reads its verifier binding as {binding: "present"}
Verification
Verifier bindings
test:protocol.studio-tests-coverage-row · anchored · test anchor binding present · test/studio-s1.test.ts:769
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.lenses.tests.coverage-rowThe diagram as text
spec:consumers.spec-studio.lenses.tests.coverage-row: A Spec's row on the tests lens counts its exercised keyed rules · declared Spec
spec:consumers.spec-studio.lenses.tests: The tests lens shows how far each Spec's verification reaches · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
The original design rendered a coverage heatmap from each example space: which combinations of its typed slots an example witnesses and which none does (docs/lineage/v0-design/04-authoring-surfaces.md §4 and §4.1, 06-extraction-and-validation.md §8). This Spec reports slot-value coverage; the glossary keeps witness for an example in an outcome class. Coverage is per slot value: no design pass has yet asked which combinations of slots no example exercises, and a combination grid grows with the product of the slots' sizes.
Intent
problem
The graph carries example spaces and bound points, but no reader value or recipe reports which literal slot values example children bind.
outcome
Report each literal slot value with the example children that bind it, and each value no child binds, before code exists.
The engine decodes each Spec's example space into its typed slots, and each example child's steps into its bound point, once, through the notation module that writes the space contracts, and the reader carries both on the Spec context; no recipe or projection parses slot notation a second time.
Slot-value coverage is a catalog recipe, recipe 44, over the decoded reader values, listing each literal-union value with the example children that bind it and each value no child binds.
The recipe enumerates slots typed as closed unions of quoted literals. It reports every other slot type, a boolean included, as not enumerable by this recipe, never as covered or as missing a value.
Coverage is reported per slot value; the recipe reports no combination of two or more slots until a design pass asks which combinations no example exercises.
Given an example space that declares the slot {slot: "quantity"} as {declared: "number"}
Given its example children bind {bound: "2; 5"}
When recipe 44 reports the space's coverage
Then the slot is enumerable: {enumerable: false}
Then the values no example binds are {uncovered: ""}
Then the examples that leave the slot unbound are {unbound: ""}
Given an example space that declares the slot {slot: "availability"} as {declared: "in stock|out of stock|backordered"}
Given its example children bind {bound: "in stock; in stock; none"}
When recipe 44 reports the space's coverage
Then the slot is enumerable: {enumerable: true}
Then the values no example binds are {uncovered: "out of stock, backordered"}
Then the examples that leave the slot unbound are {unbound: "spec:probe.parent.c3"}
Given an example space that declares the slot {slot:string} as {declared:string}
Given its example children bind {bound:string}
When recipe 44 reports the space's coverage
Then the slot is enumerable: {enumerable:boolean}
Then the values no example binds are {uncovered:string}
Then the examples that leave the slot unbound are {unbound:string}
the Spec context of a Spec that owns an example space carries exampleSpace: { slots: ExampleSlot[]; points: BoundPoint[] }, and a Spec that owns none carries no exampleSpace.
{ name: string; type: "number" | "string" | "boolean" | "enum"; values?: string[]; step: string }, one per slot the space's given and when steps declare, in the order the space contract's dimensions take, values the quoted literals in authored order when type is enum, and step the skeleton of the first step declaring the slot.
{ example: string; values: Record<string, string | number | boolean> }, one per eligible child in id order, values holding the first value the child binds for each slot, the values the space contract holds for it.
recipe 44, example-space coverage, takes params.spec or params.pack, at most one, and without either reads every Spec that owns an example space; it returns { scope, totals, spaces }, and { diagnostics: [{ parameter, problem }] } alone when the scope names no Spec or Pack, names both, or names a Spec that owns no example space.
{ name: string; type: string; step: string; enumerable: boolean; values: { value: string | number | boolean; examples: string[] }[]; unbound: string[] }: for an enumerable slot one value row per declared literal in authored order, a row with no example being an uncovered value; for any other slot one row per distinct value its examples bind, in the order they are first bound; unbound the examples that bind no value for the slot.
{ spaces: number; slots: number; enumerable: number; values: number; uncovered: number }, values counting the declared literals of the enumerable slots and uncovered those no example binds.
Requirement drawing for spec:consumers.agent-surface.example-space-coverage
E6: refines, verifies · declared
The diagram as text
spec:consumers.agent-surface.example-space-coverage: Example spaces report which values their examples cover · declared Spec
spec:consumers.agent-surface.example-space-coverage.number-not-enumerable: A number slot is not enumerable and reports no uncovered value · declared Spec
spec:consumers.agent-surface.example-space-coverage.uncovered-literal: A literal no example binds is reported uncovered, and an unbound child is named · declared Spec
spec:consumers.agent-surface.design-recipes: Design work reads its answers from catalog recipes · declared Spec
spec:consumers.spec-studio.lenses.tests dependsOn spec:consumers.agent-surface.example-space-coverage · declared — a row reads its example space's uncovered values from recipe 44
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute per-value coverage on a closed union with one covered, two uncovered values and one child that binds nothing.
assumptions
The world writes a parent Spec whose example space declares the slot as a closed union of the literals the declared value lists, separated by |, and one example child per entry of the bound value, separated by ; , each child refining and verifying the parent and binding that literal, or binding no value where the entry is none; it runs recipe 44's shipped body with the parent as spec and joins the uncovered values and the unbound children's ids with , . The parent's id ends in probe.parent, and each child's id is the parent's followed by .c1, .c2 and on, in order.
Behavior
Examples
Given an example space that declares the slot {slot: "availability"} as {declared: "in stock|out of stock|backordered"}
Given its example children bind {bound: "in stock; in stock; none"}
When recipe 44 reports the space's coverage
Then the slot is enumerable: {enumerable: true}
Then the values no example binds are {uncovered: "out of stock, backordered"}
Then the examples that leave the slot unbound are {unbound: "spec:probe.parent.c3"}
Verification
Verifier bindings
test:protocol.studio-coverage-literal · anchored · test anchor binding present · test/studio-s1.test.ts:938
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.agent-surface.example-space-coverage.uncovered-literalThe diagram as text
spec:consumers.agent-surface.example-space-coverage.uncovered-literal: A literal no example binds is reported uncovered, and an unbound child is named · declared Spec
spec:consumers.agent-surface.example-space-coverage: Example spaces report which values their examples cover · declared Spec
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the not-enumerable answer on a number slot, which reports the values bound and never a missing one.
assumptions
The world writes the parent and children as the uncovered-literal example does, with the slot declared as number and each child binding the number its entry names; it runs recipe 44's shipped body with the parent as spec, reads the slot's row, and checks that the validation report and the parent's readiness are the same before and after.
Behavior
Examples
Given an example space that declares the slot {slot: "quantity"} as {declared: "number"}
Given its example children bind {bound: "2; 5"}
When recipe 44 reports the space's coverage
Then the slot is enumerable: {enumerable: false}
Then the values no example binds are {uncovered: ""}
Then the examples that leave the slot unbound are {unbound: ""}
Verification
Verifier bindings
test:protocol.studio-coverage-number · anchored · test anchor binding present · test/studio-s1.test.ts:944
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.agent-surface.example-space-coverage.number-not-enumerableThe diagram as text
spec:consumers.agent-surface.example-space-coverage.number-not-enumerable: A number slot is not enumerable and reports no uncovered value · declared Spec
spec:consumers.agent-surface.example-space-coverage: Example spaces report which values their examples cover · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The graph derives no observation yet, and no Spec designs a source for build attestations, deployments or bills of materials, so every row of this lens reads not tracked. The lens stays in the navigation so a reader sees what is not tracked rather than assuming it is.
Intent
outcome
Let a person see which kinds of runtime evidence the Studio could show, and that none is tracked until the graph records it.
The lens lists four sources, runtime observation, build attestations, deployments and software bills of materials, and reads each as not tracked: no delivery fact records an observation, and no Spec designs a source for the other three.
one line per source, its name, then not tracked, then what would bring it in: an observation the graph records against a measurable target, or a Spec that designs the source.
Verification
Verifier bindings
test:protocol.studio-lenses · anchored · test anchor binding present · test/studio-s1.test.ts:273
Design view
Requirement drawing
Declared verifying examples: no declared verifying example.
Requirement drawing for spec:consumers.spec-studio.lenses.evidenceThe diagram as text
spec:consumers.spec-studio.lenses.evidence: The evidence lens names each source of runtime evidence and reads it as not tracked · declared Spec
spec:consumers.spec-studio.lenses: Five lenses read the graph as Packs, capabilities, architecture, tests and evidence · declared Spec
impl:protocol.studio-evidence-lens: names the four evidence sources and what would bring each into the Studio · anchored code · src/projections/studio/pages/evidence-page.ts:3
Preferred and chosen syntax: requirementDiagram; exact refines, satisfies and verifies, with claim words in nodes and per-edge comments.
Decisions
spec:decisions.binding-not-liveness
Delivery facts record bindings and enabled verifier existence; coverage gaps and human readiness practice remain explicit without becoming graph facts.
component:protocol.reader · the typed graph contract and body evaluator · src/reader/reader.ts:671 · layer application · context protocol
component:protocol.validate · one finding currency and ordered checks · src/validate/validators.ts:72 · layer domain · context protocol
impl:protocol.studio-evidence-lens · names the four evidence sources and what would bring each into the Studio · src/projections/studio/pages/evidence-page.ts:3
impl:protocol.studio-evidence-lens · names the four evidence sources and what would bring each into the Studio · src/projections/studio/pages/evidence-page.ts:3 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
test:protocol.studio-lenses · anchored · test/studio-s1.test.ts:273 · test anchor
Expected-outcome oracle: none
Runtime observation: not tracked.
Run results: not recorded in the graph.
Findings
None.
26. A Pack page shows the Pack's design as one card per member
spec:consumers.spec-studio.pack-page
A Pack page shows the Pack's design as one card per member
spec:consumers.spec-studio.pack-pageUse Case / Behavior · storyreadyfloor ready
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The Markdown Pack page renders the Pack design as one wide member table, and the first adopter's reviewers read carrier files instead. This page renders the same assembly as a summary, then a card per member that a reviewer opens where they need the detail.
Intent
outcome
Show where a Pack's design stands, member by member in reading order, on one page a reviewer scans quickly and opens where they need detail.
The page opens with the Pack's title, its id and its carrier file as text with a copy action, and a link to the Pack's slice page, then the summary; the framing follows as prose under the heading Framing, with the vocabulary references, linked.
The summary states each Pack total in one sentence that opens with its count, never as a table: the members and the unresolved ones, the members held below their stated next rung and those waiting only for their author, the design entries and pinned declarations, the open and blocking questions, the members with an implementation binding and with a design reference, and the boundary in each direction. The member sentence says in priority order when the Pack states order: priority, otherwise in authored reading order.
The summary's held sentence links each held member to its card with its count of unmet clauses, and its waiting sentence names the members whose stated next rung waits only for their author's statement unless every member does; the page never presents a rung as approved.
The members follow in authored order, one closed card each. A card's summary line shows the member's position, title and kind, its stated rung beside the floor reached, its stated next rung with nothing blocks or how many of its clauses are unmet, its open and blocking questions, and its implementation and verifier bindings as present or none.
A card lists each open question with its blocking flag in words, its address when it is keyed, linked to the question on the Spec page, its recorded line, its text, and its decider, links, provisional reading and trigger when present.
A card lists each unit that implements the member and each that references it, by id, label, and recorded file and line as text with a copy action, with its role and its component's id, layer and context.
A card states the member's verifier binding as present or none and, when it has any, counts its verifiers and verifying examples, each beside how many are enabled.
The boundary follows in four closed sections, Rests on, Rested on by, Verified by and Superseded by, each headed with its count. Each row shows the outside Spec, linked, its stated rung, its implementation binding as present or none, and the members it joins under each relation type; an empty section reads None.
Then come the members with no verifier binding, those stated ready first, under one sentence saying the graph records bindings and never runs; then the findings that name the Pack.
the title as the page heading; below it the id and the carrier file, each with a copy action, and the link Read this Pack as one design to its slice page; then the summary; then the framing under a Framing heading, and the vocabulary references.
a disclosure whose element id is the member's Spec id; its summary line reads <position>. <title>, then the kind, the rung badge, the floor in words, the next rung in words unless the member states ready, the question counts and the two binding values, all but the badge as plain text, wrapping onto further lines on a narrow screen.
the blocking flag in words; for a keyed question, question.<key> as a link to its address with a copy action for the full address; line <n> when recorded; the text; then each present field on its own labelled line.
four columns, Spec, stated rung, implementation binding and joined members, the last listing each relation type with its members.
Verification
Verifier bindings
test:protocol.roadmap-priority · checks Pack priority extraction, comparison and Studio change notes · anchored · test anchor binding present · test/roadmap-priority.test.ts:44
test:protocol.studio-pages · anchored · test anchor binding present · test/studio-pages.test.ts:18
Design view
Requirement drawing
Declared verifying examples: no declared verifying example.
Requirement drawing for spec:consumers.spec-studio.pack-pageThe diagram as text
spec:consumers.spec-studio.pack-page: A Pack page shows the Pack's design as one card per member · declared Spec
spec:consumers.spec-studio.pack-page.maturity-map: A Pack page's maturity map places every member by its stated rung and its floor · declared Spec
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph · declared Spec
impl:protocol.studio-maturity-map: places resolved Pack members by their stated rung and floor in authored order · anchored code · src/projections/studio/pages/maturity-map.ts:7
spec:consumers.spec-studio.export dependsOn spec:consumers.spec-studio.pack-page · declared — an export opens with its Pack page's content
spec:consumers.spec-studio.slice-page dependsOn spec:consumers.spec-studio.pack-page · declared — each member links to its card on the Pack page, whose element id is the member's id
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
A Pack's maturity map shows its distribution before its member lists. Equal-sized cells place each resolved member by stated readiness and floor reached. Populated cells show exact counts and member marks; faint empty cells show no number. The count table and ordered lists retain the reading in text.
Intent
outcome
Let a reviewer see at a glance where every member of a Pack stands, by the rung it states and the floor it reaches.
After the summary, show the categorical grid and full member lists defined by spec:consumers.spec-studio.diagram-kinds.maturity-picture. Every resolved member belongs to one stated-rung and floor cell; unresolved members are named apart. Populated cells link to their built lists, whose members stay in authored order.
An sdp-maturity-map holds the static SVG grid, caption and accessible count table, followed by populated cells' full member lists in disclosures that print open. Equal-sized cells have explicit axes; the legend names matches, floor above statement and statement above floor once. The diagonal has an outline, empty cells are faint, and populated cells carry exact counts and member marks, up to 100 marks and solid fill above that. Every member links to its card.
Verification
Verifier bindings
test:protocol.studio-architecture-maturity-requirement · anchored · test anchor binding present · test/studio-panels.test.ts:35
test:protocol.studio-panels · anchored · test anchor binding present · test/studio-s2.test.ts:256
Design view
Requirement drawing
Declared verifying examples: no declared verifying example.
Requirement drawing for spec:consumers.spec-studio.pack-page.maturity-mapThe diagram as text
spec:consumers.spec-studio.pack-page.maturity-map: A Pack page's maturity map places every member by its stated rung and its floor · declared Spec
spec:consumers.spec-studio.pack-page: A Pack page shows the Pack's design as one card per member · declared Spec
impl:protocol.studio-maturity-map: places resolved Pack members by their stated rung and floor in authored order · anchored code · src/projections/studio/pages/maturity-map.ts:7
component:protocol.reader · the typed graph contract and body evaluator · src/reader/reader.ts:671 · layer application · context protocol
component:protocol.validate · one finding currency and ordered checks · src/validate/validators.ts:72 · layer domain · context protocol
impl:protocol.studio-maturity-map · places resolved Pack members by their stated rung and floor in authored order · src/projections/studio/pages/maturity-map.ts:7
Relations of spec:consumers.spec-studio.pack-page.maturity-mapThe diagram as text
spec:consumers.derived-readiness-banner: Derived readiness renders beside the stated rung and warns in one direction
spec:consumers.spec-studio.diagram-kinds.maturity-picture: The maturity map is drawn as a grid of counts
spec:consumers.spec-studio.pack-page: A Pack page shows the Pack's design as one card per member
spec:consumers.spec-studio.pack-page.maturity-map: A Pack page's maturity map places every member by its stated rung and its floor
spec:consumers.spec-studio.pack-page.maturity-map dependsOn spec:consumers.derived-readiness-banner · declared — the map sets each stated rung beside the floor reached, as the banner reads them
spec:consumers.spec-studio.pack-page.maturity-map dependsOn spec:consumers.spec-studio.diagram-kinds.maturity-picture · declared — the map is drawn as the picture defines
impl:protocol.studio-maturity-map · places resolved Pack members by their stated rung and floor in authored order · src/projections/studio/pages/maturity-map.ts:7 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
test:protocol.studio-architecture-maturity-requirement · anchored · test/studio-panels.test.ts:35 · test anchor
test:protocol.studio-panels · anchored · test/studio-s2.test.ts:256 · test anchor
Expected-outcome oracle: none
Runtime observation: not tracked.
Run results: not recorded in the graph.
Findings
None.
28. A Spec page shows one Spec in collapsible panels, in a fixed order
spec:consumers.spec-studio.spec-page
A Spec page shows one Spec in collapsible panels, in a fixed order
spec:consumers.spec-studio.spec-pageUse Case / Behavior · storyreadyfloor ready
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
The original runtime panel linked Fastify routes to Effect programs, showed what Effect layers provided and required, and recorded Awilix registrations and their lifetimes, beside ports and external systems. That representation is lineage evidence in docs/lineage/v0-design/07-spec-studio-and-projections.md, section 2.3, Section F. The structural anchors record identity, component membership, uses, role, and a component's architectural layer and context, so the runtime panel shows that structural neighborhood and no more until a reader asks for more of the runtime composition.
The page shows only what the graph and the build's named inputs hold. The original header's owner, tags and last-verified time, its schema bindings and its UI / Stories section have no graph value behind them, so the page shows none of them.
Intent
outcome
Show everything the graph holds about one Spec on one page, in panels a person opens and closes one at a time.
The page's core, its header, sections, relations, bindings and findings, is the one spec:consumers.spec-studio.spec-page.core states, and the panels below add to it.
Every Spec and Pack a panel names links to its page. A code unit, component or anchor shows its id and its recorded repository-relative file and line as text, with an action that copies file:line; the page set holds no code-unit page and writes no editor URI, absolute path or assumed source URL; a recorded file and line become a link only when a stamp beside the page set names a source template, as spec:consumers.spec-studio.sharing states; a component's attributes, members and uses show in the architecture lens, which its id links to.
After the core's sections the page adds five panels, in this order, each open by default: Verification, Design view, Runtime, Evidence and Impact; a panel with nothing to show says so in one sentence and stays in its place; the core's relations, bindings and findings follow them.
Inside the core's sections the page adds a composing action beside each keyed entry that proposes new text for it, the composing actions beside each open question, the rule coverage beside each keyed rule or flow and the example cards after the rules, each constraint's target, the citations beside each cited entry, and an element id on each keyed term, as the rules below state.
Each keyed Model term in the core's Model section carries the element id term.<key>, its address after the #, and shows its key and its recorded line, as the core's entry ids do.
Beside each keyed entry an anchored source file cites, its section lists every citing file and line recipe 51 records, as text with a copy action; a pinned declaration no file cites reads no citation recorded.
The Design view panel draws the requirement drawing defined by spec:consumers.spec-studio.diagram-kinds.requirement-trace in place of realization, then lists the decision records the Spec names through decidedBy with linked titles and decision text inline. The Runtime panel retains the implementation anchors' components and uses.
The Runtime panel shows the structural neighborhood of the Spec's implementation anchors: each anchor's component with its layer and context, and the units it uses, each with its file and line; runtime observation reads not tracked.
The Impact panel draws the Spec's trace graph, one hop each way, and then lists what it rests on with each target's stated and derived rung, from recipe 21, and every Spec that rests on it to any depth, by distance, with the units, enabled verifiers and Packs each brings, from recipe 30.
Given a Spec with two pinned declarations, the first of which an anchored test file {file: "test/orders.test.ts"} cites at line {line: 12}
When the build renders the Spec's page
Then beside the first declaration the page lists {cited: "test/orders.test.ts:12"}
Then beside the second declaration the page reads {uncited: "no citation recorded"}
Given a Spec with two pinned declarations, the first of which an anchored test file {file:string} cites at line {line:number}
When the build renders the Spec's page
Then beside the first declaration the page lists {cited:string}
Then beside the second declaration the page reads {uncited:string}
beside each keyed entry, an action that composes intent proposing new text for it, with the entry's address as the change's scope and as the address it replaces.
the verifier list, with run evidence given run records, then the coverage grid when the Spec owns an example space, laid out as spec:consumers.spec-studio.verification-panels states; the panel's element id is panel.verification.
The requirement drawing, with the text equivalent naming each binding's id, source file and line under the source-text rule, then the decision records and their decision text; its element id remains panel.design-view.
the structural neighborhood of the Spec's implementation anchors, each anchor's component and the code units it uses, with file and line, then Runtime observation: not tracked; the panel's element id is panel.runtime.
the evidence fields and absence labels spec:consumers.spec-studio.verification-panels states, with no invented build, deployment, measurement or bill-of-materials data; the panel's element id is panel.evidence.
the trace graph, then Rests on and Rested on by lists, the second grouped by distance, each row with its units, enabled verifiers and Packs; the panel's element id is panel.impact.
Requirement drawing for spec:consumers.spec-studio.spec-pageThe diagram as text
spec:consumers.spec-studio.spec-page: A Spec page shows one Spec in collapsible panels, in a fixed order · declared Spec
spec:consumers.spec-studio.spec-page.cited-declaration: A pinned declaration shows the test line that cites it · declared Spec
spec:consumers.spec-studio.spec-page.core: A Spec page's core shows the whole Spec, with an anchor for every entry · declared Spec
spec:consumers.spec-studio.verification-panels: The panels for examples, targets, verifiers and evidence · declared Spec
spec:consumers.spec-studio.verification-panels.rule-coverage: Each keyed rule shows the examples that exercise it, or that none does · declared Spec
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph · declared Spec
impl:protocol.studio-requirement-view: selects Spec refiners, verifying examples and their recorded bindings · anchored code · src/projections/studio/pages/requirement-view.ts:8
impl:protocol.studio-run-rows: renders recipe 45 file rows shared by the runs page and verification panel · anchored code · src/projections/studio/pages/run-rows.ts:69
impl:protocol.studio-spec-structure: renders requirement and trace diagrams and the recorded structural neighborhood · anchored code · src/projections/studio/pages/spec-structure.ts:44
impl:protocol.studio-verification-panels: renders rule coverage, example cards, constraint targets, verifiers and example-space coverage · anchored code · src/projections/studio/pages/spec-verification.ts:74
Preferred syntax: requirementDiagram. Chosen syntax: flowchart TB because models, folds require exact labels unavailable in requirement syntax.
Decisions
spec:decisions.authored-entry-order
The Design Review renders each entry of a design or ui section as a list item in authored order, its key as inline code. A string value renders as Markdown text through the prose escaping rule; a number or boolean renders as inline code; an array or object renders as a fenced JSON block nested under its item, so a structured value the TypeScript carrier admits survives without loss. The fenced-JSON rule of the Design Review stops covering an open section as a whole and keeps covering a structured value inside one entry. The freeze on the four shipped projections stands for everything else.
component:protocol.reader · the typed graph contract and body evaluator · src/reader/reader.ts:671 · layer application · context protocol
component:protocol.validate · one finding currency and ordered checks · src/validate/validators.ts:72 · layer domain · context protocol
impl:protocol.studio-requirement-view · selects Spec refiners, verifying examples and their recorded bindings · src/projections/studio/pages/requirement-view.ts:8
impl:protocol.studio-spec-structure · renders requirement and trace diagrams and the recorded structural neighborhood · src/projections/studio/pages/spec-structure.ts:44
spec:consumers.spec-studio.spec-page dependsOn spec:consumers.spec-studio.diagram-kinds.requirement-trace · declared — the Design view reads the selected set and claims the requirement drawing defines
spec:consumers.spec-studio.spec-page dependsOn spec:consumers.spec-studio.diagrams · declared — the design view and impact panel draw requirement traceability and the one-hop trace graph
spec:consumers.spec-studio.spec-page dependsOn spec:consumers.spec-studio.diff-page · declared — given a base graph, the header's change note links the Spec's row on the diff page
spec:consumers.spec-studio.spec-page dependsOn spec:consumers.spec-studio.sharing · declared — a recorded file and line become a link only from a stamp's source template
spec:consumers.spec-studio.spec-page dependsOn spec:extraction.entry-citations · declared — the design section shows the source lines that cite each entry
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the citations beside pinned declarations: a cited declaration lists its citing file and line, and an uncited one says so.
assumptions
The world writes a root with one Spec whose Design section holds two keyed entries, each opening with a code span, and a test file that holds a specTest anchor and writes the first entry's address on its twelfth line, in the form the extractor records as a citation; it builds the page set and reads the Spec page under each declaration.
Behavior
Examples
Given a Spec with two pinned declarations, the first of which an anchored test file {file: "test/orders.test.ts"} cites at line {line: 12}
When the build renders the Spec's page
Then beside the first declaration the page lists {cited: "test/orders.test.ts:12"}
Then beside the second declaration the page reads {uncited: "no citation recorded"}
Verification
Verifier bindings
test:protocol.studio-cited-declaration · anchored · test anchor binding present · test/studio-s2.test.ts:139
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.spec-page.cited-declarationThe diagram as text
spec:consumers.spec-studio.spec-page.cited-declaration: A pinned declaration shows the test line that cites it · declared Spec
spec:consumers.spec-studio.spec-page: A Spec page shows one Spec in collapsible panels, in a fixed order · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The full Spec page adds panels to this core: diagrams, a runtime neighborhood, verification and evidence panels, impact, and actions that compose intent. The core shows what the Spec context holds, as text, so a reviewer with only a link reads the whole Spec and can cite any entry by its address.
Intent
outcome
Show everything the graph holds about one Spec on one page that reads without script: its header, its sections in order with an anchor for every addressable entry, its relations both ways, its bindings and its findings.
The header shows the title; the id with a copy action; the kind's display label and the altitude; the stated rung beside the floor reached on one line, with the divergence banner only in the dishonest direction; the stated next rung with nothing blocks or each unmet clause and its targets; the Packs the Spec belongs to, linked; its design columns; its findings by severity; and its carrier file as text with a copy action. It shows no owner, capability, tag or last-verified time: the envelope holds none, the Packs stand for a capability, and a binding never records a run.
A summary in words follows the header with what the header does not show: the open and blocking questions, and the implementation, verifier and oracle bindings as present or none. It repeats no rung the header shows.
The narrative comes next, then each section the Spec carries as a panel open by default, in the order intent, behavior, constraints, model, design, decision, verification, ui, with its entries in authored order. A section the Spec lacks is absent, and the page adds no section the graph does not hold. The narrative carries the element id narrative and each section panel section.<name>, such as section.behavior.
Every entry an entry address can name, a keyed Design or UI entry, a keyed rule or flow and a keyed open question, carries an element id equal to its address after the #, such as design.<key>, and shows its key and its recorded line.
Each open question shows its blocking flag in words, its key as code with a copy action for the full entry address when it has one, its text, its decider, its links, linked, its provisional reading and its trigger when present, and its recorded line. It shows no date: git records when a line changed.
Relations show both ways, each with its type, its direction, its claim, the other endpoint, linked when it is a Spec or a Pack, whether it resolves, and its reason and the rule keys it exercises when present.
Bindings speak binding language. The implementation binding, design reference, verifier binding and expected-outcome oracle each read present or none, and list each unit, test anchor, example or oracle by id, label, and recorded file and line as text with a copy action; a unit adds its role and component, and an example verifier says whether it is enabled. Runtime observation reads not tracked, and run results read not recorded in the graph.
the title as the page heading; below it a line with the id, kind, altitude, the rung badge with the floor in words, and the next rung; then the Packs, the design columns, the finding counts and the carrier file.
the blocking flag in words, question.<key> as code when keyed, a copy action whose text and accessible name carry the full entry address, with no second code span of that address, the text, each present field on its own labelled line, and line <n> when recorded.
Preferred and chosen syntax: requirementDiagram; exact refines, satisfies and verifies, with claim words in nodes and per-edge comments.
Decisions
spec:decisions.authored-entry-order
The Design Review renders each entry of a design or ui section as a list item in authored order, its key as inline code. A string value renders as Markdown text through the prose escaping rule; a number or boolean renders as inline code; an array or object renders as a fenced JSON block nested under its item, so a structured value the TypeScript carrier admits survives without loss. The fenced-JSON rule of the Design Review stops covering an open section as a whole and keeps covering a structured value inside one entry. The freeze on the four shipped projections stands for everything else.
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
The graph records that a verifier binding exists and never a run, and a static page runs nothing, so the panels show bindings and offer no run of an example. A run result shows only when the build was given run records, and then as evidence from a test file. No Spec designs a source for build attestations, deployments or bills of materials, so each reads not tracked. Moving a constraint target on a slider and running a scenario harness wait for designs of their own, as the HTML surface decision records; a panel action composes intent instead.
Intent
outcome
Show on a Spec page how far each example, constraint target and verifier goes, and what runtime evidence exists, without stating more than the graph records.
An example card shows the example's verifier as a binding that exists, and the example as an Executable Spec when a test anchor binds it, never as a test that passed.
A panel shows verifier bindings and states no run result of its own; with the run records input, a verifier's row adds the results recipe 45 joins from its test file, labelled as external run evidence from that file, as spec:observation.run-evidence states, and never as the verifier's verdict.
Beside each keyed rule or flow, the panel lists the examples recipe 34 reports exercising it, each linked with enabled or not enabled in words, and a keyed rule no example exercises reads no example exercises it; the unkeyed rules are counted after the list.
A Spec that owns an example space shows recipe 44's coverage: each enumerable slot with each of its declared values and the examples that bind it, a value no example binds reading no example; each other slot with the values its examples bind and the words not enumerable; and the examples that leave a slot unbound.
Given a Spec whose keyed rule {exercisedKey: "paid"} an enabled example exercises and whose keyed rule {otherKey: "refunded"} no example exercises
When the build renders the Spec's page
Then beside the first rule the panel lists the example as {enabledWords: "enabled"}
Then beside the second rule the panel reads {unexercised: "no example exercises it"}
Given a Spec whose keyed rule {exercisedKey:string} an enabled example exercises and whose keyed rule {otherKey:string} no example exercises
When the build renders the Spec's page
Then beside the first rule the panel lists the example as {enabledWords:"enabled"|"not enabled"}
Then beside the second rule the panel reads {unexercised:string}
rules and flows in authored order, each keyed entry with its rule address, recorded carrier line and the examples that exercise it, followed by the example cards; an unrecorded line stays absent.
one card per example that verifies the Spec: its title linked; its stated readiness and whether it is an Executable Spec; its given, when and then steps as preformatted text with their bound values; and actions to open the example's page and to compose intent to edit it.
each constraint with its flavor, its statement and its target as authored, and a measured value only when the graph records one, otherwise not tracked, with an action that composes intent to change the target.
each verifier with its id, its binding, and its recorded repository-relative file and line as text, as spec:consumers.spec-studio.spec-page#rule.sourceText states, no line invented for a verifier the graph does not locate; given run records, under each verifier the results joined from the test file that binds it, a test anchor's own file or, for an example, the file of the test anchor that verifies the example, each with its run, name, result in words and duration, headed External run evidence from <file>.
one table per enumerable slot, a row per declared value with the examples that bind it or no example; one line per other slot with the values bound and not enumerable; then Unbound with the examples that bind no value for a slot; and an action that composes intent proposing examples for the values no example binds.
runtime observation reads not tracked under the binding-language rule; build attestations, deployments and bills of materials show no payload and each reads not tracked until a Spec designs its source.
test:protocol.studio-panels · anchored · test anchor binding present · test/studio-s2.test.ts:256
Example space
exercisedKey · string · declared by a Spec whose keyed rule {exercisedKey} an enabled example exercises and whose keyed rule {otherKey} no example exercises
otherKey · string · declared by a Spec whose keyed rule {exercisedKey} an enabled example exercises and whose keyed rule {otherKey} no example exercises
Preferred syntax: requirementDiagram. Chosen syntax: flowchart TB because models require exact labels unavailable in requirement syntax.
Decisions
spec:decisions.binding-not-liveness
Delivery facts record bindings and enabled verifier existence; coverage gaps and human readiness practice remain explicit without becoming graph facts.
spec:consumers.spec-studio.verification-panels dependsOn spec:consumers.spec-studio.intent-panel · declared — each panel action gathers intent in the composing panel
spec:consumers.spec-studio.verification-panels dependsOn spec:observation.run-evidence · declared — with run records, a verifier's row adds the results recipe 45 joins from its test file
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute rule coverage on a Spec page: an exercised rule lists its example in words, and an unexercised rule says so.
assumptions
The world writes a root with one behavior Spec holding the rules keyed paid and refunded and one example child that verifies it, exercising paid, bound by a specTest anchor; it builds the page set and reads the Spec page beside each keyed rule.
Behavior
Examples
Given a Spec whose keyed rule {exercisedKey: "paid"} an enabled example exercises and whose keyed rule {otherKey: "refunded"} no example exercises
When the build renders the Spec's page
Then beside the first rule the panel lists the example as {enabledWords: "enabled"}
Then beside the second rule the panel reads {unexercised: "no example exercises it"}
Verification
Verifier bindings
test:protocol.studio-rule-coverage · anchored · test anchor binding present · test/studio-s2.test.ts:220
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.verification-panels.rule-coverageThe diagram as text
spec:consumers.spec-studio.verification-panels.rule-coverage: Each keyed rule shows the examples that exercise it, or that none does · declared Spec
spec:consumers.spec-studio.verification-panels: The panels for examples, targets, verifiers and evidence · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
A large design keeps registers, and each is a catalog recipe an agent runs. Four become pages, so a reviewer with only a link reads the same rows: the open questions and the decisions, which the owner works through; the pinned declarations, each with the source lines that cite it, which is where a reader finds the test that checks a declaration; and the design backlog, the Specs designed and not yet built, which a design ahead of its code is mostly made of. The key-family register stays a recipe: its rows depend on key prefixes a corpus chooses, the Studio takes no corpus configuration, and search already finds a coined key.
Intent
outcome
Let a person read every open question, decision, pinned declaration and designed-but-unbuilt Spec of the corpus on one page each, linked to the entries they name.
The page set holds four register pages, each rendering one catalog recipe's answer over the whole corpus: questions.html the open-question register, recipe 20; decisions.html the decision register, recipe 31; declarations.html the pinned declarations, recipe 24, with the entry citations of recipe 51 beside them; and backlog.html the design backlog, recipe 33.
The questions page lists the Specs with a blocking question first and then the rest, each in id order with its stated rung, and under each its questions in authored order: the blocking flag in words, the address linked to the question on the Spec page with a copy action when the question is keyed, the text, and its decider, links, provisional reading and trigger when present, a question with a trigger named a deferral.
The decisions page lists one row per decision in id order: its title linked, its id, its stated rung, the decisions it supersedes and that supersede it, the decisions it refines and that refine it with the reasons its relations state, the Specs it shapes with their count, and its keyed questions linked; a superseded decision reads superseded in words.
The declarations page lists the pinned declarations grouped by Spec in id order, each with its key linked to the entry on the Spec page, the declaration as code, and every source line recipe 51 records citing the entry's address, as file and line with a copy action, or no citation recorded.
The backlog page lists recipe 33's rows in id order: the Spec linked, its kind and altitude, its floor reached, the clauses that hold it below its stated next rung, its design columns as counts, and the units that reference it; a sentence names how many examples and decisions the recipe leaves out.
The questions page filters by blocking flag, decider, deferral and Pack, and the declarations page by whether a citation is recorded; without script every row shows.
Given a Spec {blockingSpec: "spec:probe.zeta"} with a blocking open question and a Spec {otherSpec: "spec:probe.alpha"}, before it in id order, with only a non-blocking one
When the build renders the questions page
Then the page lists {first: "spec:probe.zeta"} first
Given a Spec {blockingSpec:string} with a blocking open question and a Spec {otherSpec:string}, before it in id order, with only a non-blocking one
When the build renders the questions page
Then the page lists {first:string} first
the blocking flag in words, question.<key> as a link with a copy action for the full address when keyed, the text, then each present field on its own labelled line, deferral written beside a question with a trigger.
the title linked, the id as code, the rung badge, then labelled lines for Supersedes, Superseded by, Refines, Refined by, Shapes and Questions, each listing ids as links and an empty line reading None, and the reasons under the relations they belong to.
the title linked, the id as code, then as plain text the kind, altitude, floor in words, the unmet clauses by id, <e> entries, <d> declarations, <q> open, <b> blocking, and the referencing units by id.
Verification
Verifier bindings
spec:consumers.spec-studio.registers.blocking-first · The questions page lists the Specs with a blocking question first · declared · example enabled · specs/consumers/spec-studio.registers.blocking-first.sdp.md
Example space
blockingSpec · string · declared by a Spec {blockingSpec} with a blocking open question and a Spec {otherSpec}, before it in id order, with only a non-blocking one
otherSpec · string · declared by a Spec {blockingSpec} with a blocking open question and a Spec {otherSpec}, before it in id order, with only a non-blocking one
spec:consumers.spec-studio.registers dependsOn spec:extraction.contract-declarations · declared — the declarations page lists the pinned declarations recipe 24 reads
spec:consumers.spec-studio.registers dependsOn spec:extraction.entry-citations · declared — each declaration shows the source lines that cite its address
spec:consumers.spec-studio.cited-line-text dependsOn spec:consumers.spec-studio.registers · declared — the declarations page lists each citing line beside its declaration
spec:consumers.spec-studio.registers.blocking-first · The questions page lists the Specs with a blocking question first · declared · specs/consumers/spec-studio.registers.blocking-first.sdp.md · example enabled
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the questions page's order: a Spec with a blocking question comes before one with only non-blocking questions, whatever their id order.
assumptions
The world writes a root with the two Specs, the first holding one blocking open question and the second one non-blocking open question, builds the page set, and reads the order of the Specs on the questions page.
Behavior
Examples
Given a Spec {blockingSpec: "spec:probe.zeta"} with a blocking open question and a Spec {otherSpec: "spec:probe.alpha"}, before it in id order, with only a non-blocking one
When the build renders the questions page
Then the page lists {first: "spec:probe.zeta"} first
Verification
Verifier bindings
test:protocol.studio-registers-blocking-first · anchored · test anchor binding present · test/studio-s3.test.ts:89
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.registers.blocking-firstThe diagram as text
spec:consumers.spec-studio.registers.blocking-first: The questions page lists the Specs with a blocking question first · declared Spec
spec:consumers.spec-studio.registers: The corpus's registers are pages a reviewer opens from a link · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
A large design waits on one person: the statements its floor already allows and the questions only its owner decides. The readiness planner orders those statements, the ones they rest on first. This page shows that order to a reviewer with only a link, so the owner sees which statements can be made first and which questions hold the most. A rung stays a person's statement, so the page orders and links and states nothing.
Intent
outcome
Let the owner see, in one place, every statement the floor allows in the order that holds, and every open question only the owner settles, blocking ones first.
The first list holds every waiting statement in the queue's order, numbered by position: the Spec linked, its kind, its stated rung, the rung its floor allows, the waiting Specs it rests on, each linked to its own row, and its Packs; a statement that rests on no waiting Spec reads can be made now.
The second list holds the open questions whose decider is owner, blocking ones first, each with its address linked to the question on its Spec page, its text, its provisional reading when present, and the Specs it holds below a rung, linked. The page reads the provisional reading from the reader by the question's Spec and key, or by its position when it has no key.
The page opens with sentences the build counts from the queue's answer: the statements waiting, how many rest on no waiting Spec and can be made now, the owner's questions blocking and not blocking, and any dependency cycle the queue names.
The page orders and links: it states no rung, records no statement, and never presents a waiting statement as approved or a position as a priority the owner set.
Given a Spec {dependent: "spec:probe.alpha"} that waits for a statement its floor allows and rests on a Spec {dependency: "spec:probe.zeta"} that waits for one too
When the build renders the owner queue page
Then the queue lists {first: "spec:probe.zeta"} first
Then the row of the Spec that rests on the other links it: {linked: true}
Given a Spec {dependent:string} that waits for a statement its floor allows and rests on a Spec {dependency:string} that waits for one too
When the build renders the owner queue page
Then the queue lists {first:string} first
Then the row of the Spec that rests on the other links it: {linked:boolean}
<position>., the title linked, the id as code, then as plain text the kind, stated <rung>, floor allows <rung>, rests on and the waiting Specs as links to their rows or can be made now, and the Packs; the row's element id is the Spec's id.
blocking or non-blocking in words, the address as a link with a copy action, the text, the provisional reading on its own labelled line, then holds and the held Specs as links.
Verification
Verifier bindings
spec:consumers.spec-studio.owner-queue.dependency-first · The owner queue lists a waiting statement after the one it rests on · declared · example enabled · specs/consumers/spec-studio.owner-queue.dependency-first.sdp.md
Example space
dependent · string · declared by a Spec {dependent} that waits for a statement its floor allows and rests on a Spec {dependency} that waits for one too
dependency · string · declared by a Spec {dependent} that waits for a statement its floor allows and rests on a Spec {dependency} that waits for one too
spec:consumers.spec-studio.owner-queue.dependency-first · The owner queue lists a waiting statement after the one it rests on · declared · specs/consumers/spec-studio.owner-queue.dependency-first.sdp.md · example enabled
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the queue's order: a waiting statement that rests on another waiting statement comes after it, whatever their id order, and links it.
assumptions
The world writes a root where both Specs state scoped while their floors allow a higher rung, and the first declares dependsOn on the second; it builds the page set and reads the queue's statement rows in order.
Behavior
Examples
Given a Spec {dependent: "spec:probe.alpha"} that waits for a statement its floor allows and rests on a Spec {dependency: "spec:probe.zeta"} that waits for one too
When the build renders the owner queue page
Then the queue lists {first: "spec:probe.zeta"} first
Then the row of the Spec that rests on the other links it: {linked: true}
Verification
Verifier bindings
test:protocol.studio-queue-dependency-first · anchored · test anchor binding present · test/studio-s3.test.ts:142
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.owner-queue.dependency-firstThe diagram as text
spec:consumers.spec-studio.owner-queue.dependency-first: The owner queue lists a waiting statement after the one it rests on · declared Spec
spec:consumers.spec-studio.owner-queue: The owner queue page orders the statements and questions only a person can settle · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
Iterating on a design asks what changed since the last pass, or what a change proposal would change. Given the graph of an earlier commit, the build renders the design diff between it and the graph it built, so a reviewer reads the changed Specs, entries, relations and bindings, and each changed Spec's page says it changed.
Intent
outcome
Let a person read, from a link, what changed in the design between a base graph the build was given and the graph it built, down to each entry.
The page opens by naming its input: the base graph, its label when the build was given one, its schema version and its Spec count beside the built graph's, and a sentence that the comparison reads the two graphs only.
The page renders recipe 35's answer with detail: true over the whole corpus, in sections in this order: the totals as sentences; the Specs added, linked; the Specs removed, as their ids in text, since no page holds them; the Specs changed, each linked, with each changed part, its change in words, and for a changed value the base value and the built value as readable text blocks or lists, one above the other, never a raw JSON array; keyed changes list in the head's rule and flow order, each as one line with the entry's text rendered as on its Spec page beside its old and new address or none; the Packs whose membership, order or order meaning changed, an added Pack whose order is priority read as added as a roadmap, its added members in manifest order, a removed Pack whose order was priority read as removed as a roadmap, and a known change to priority read as now a roadmap or from priority as no longer a roadmap, stating the before and after order values for other changes of meaning; the bindings changed, kept apart and headed as derived from anchors; and the diagnostics.
Given a base graph, each changed Spec's page adds a line under its header that names the base input, counts keyed parts apart as <n> rules keyed, wording unchanged beside any other changed parts it lists, and links to its row on the diff page; each added Spec's page says it is new since the base.
Given a base graph, each Pack page adds a Changed since the base section after its maturity map, from recipe 35's answer for that Pack, listing its changed and added members, linked, and its own membership change, with the same roadmap and order-meaning wording as the diff page; a member whose only changes are keying is marked keyed only.
The page and the change notes state differences between two graphs and confer nothing: no approval, staleness or readiness, and no record that a design pass happened.
Given a base graph in which the Design entry {key: "limit"} of a Spec reads {before: "ten items"}
Given the built graph in which that entry reads {after: "twenty items"}
When the build renders the diff page
Then the Spec's row shows the base value {baseShown: "ten items"} and the built value {nowShown: "twenty items"}
Then the Spec's page carries the changed-since-base line: {changeNote: true}
Given a base graph in which the Design entry {key:string} of a Spec reads {before:string}
Given the built graph in which that entry reads {after:string}
When the build renders the diff page
Then the Spec's row shows the base value {baseShown:string} and the built value {nowShown:string}
Then the Spec's page carries the changed-since-base line: {changeNote:boolean}
Compared with the base graph <label>, schema <version>, <n> Specs; the built graph has schema <version>, <m> Specs., the label left out when none was given.
the title linked, the id as code, then one row per part: the part as code, its change in words, keyed changes in the head's rule and flow order, each as one line with the entry's text rendered as on its Spec page beside Base and Now addresses or none, and for a changed value two labelled blocks, Base and Now, holding readable text or lists without a raw JSON array; the block's element id is the Spec's id, which the Spec page's change note links to.
the Spec linked, then for implementing units, referencing units, enabled verifiers and delivery facts the ids added and removed, under the heading Bindings, derived from anchors.
Changed since the base graph <label>: followed by <n> rules keyed, wording unchanged when any parts are keyed, using rule for one, beside the other changed parts as code, linked to the Spec's row on the diff page.
Verification
Verifier bindings
spec:consumers.spec-studio.diff-page.changed-entry · The diff page shows a changed entry's base and built values · declared · example enabled · specs/consumers/spec-studio.diff-page.changed-entry.sdp.md
test:protocol.roadmap-priority · checks Pack priority extraction, comparison and Studio change notes · anchored · test anchor binding present · test/roadmap-priority.test.ts:44
Example space
key · string · declared by a base graph in which the Design entry {key} of a Spec reads {before}
before · string · declared by a base graph in which the Design entry {key} of a Spec reads {before}
after · string · declared by the built graph in which that entry reads {after}
Relations of spec:consumers.spec-studio.diff-pageThe diagram as text
spec:consumers.design-diff: Designs are compared between a base commit and the working tree at entry grain
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph
spec:consumers.spec-studio.data.inputs: The Studio reads two named inputs beside the graph, a base graph and run records
spec:consumers.spec-studio.diff-page: The diff page shows what changed in the design since a base graph
spec:consumers.spec-studio.diff-page.changed-entry: The diff page shows a changed entry's base and built values
spec:consumers.spec-studio.spec-page: A Spec page shows one Spec in collapsible panels, in a fixed order
spec:consumers.spec-studio.diff-page dependsOn spec:consumers.design-diff · declared — the page renders the design diff between the base graph and the graph built
spec:consumers.spec-studio.diff-page dependsOn spec:consumers.spec-studio.data.inputs · declared — the base graph reaches the page as the build's named base input
spec:consumers.spec-studio.spec-page dependsOn spec:consumers.spec-studio.diff-page · declared — given a base graph, the header's change note links the Spec's row on the diff page
spec:consumers.spec-studio.diff-page.changed-entry · The diff page shows a changed entry's base and built values · declared · specs/consumers/spec-studio.diff-page.changed-entry.sdp.md · example enabled
test:protocol.roadmap-priority · checks Pack priority extraction, comparison and Studio change notes · anchored · test/roadmap-priority.test.ts:44 · test anchor
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the diff page on one changed Design entry: both values side by side, and the change note on the Spec's page.
assumptions
The world writes a root with one Spec whose Design entry limit reads ten items, writes its graph with sdp build and keeps it outside the root as the base, changes the entry to twenty items, builds the page set with the base, and reads the Spec's row on the diff page and the line under the Spec page's header.
Behavior
Examples
Given a base graph in which the Design entry {key: "limit"} of a Spec reads {before: "ten items"}
Given the built graph in which that entry reads {after: "twenty items"}
When the build renders the diff page
Then the Spec's row shows the base value {baseShown: "ten items"} and the built value {nowShown: "twenty items"}
Then the Spec's page carries the changed-since-base line: {changeNote: true}
Verification
Verifier bindings
test:protocol.studio-diff-changed-entry · anchored · test anchor binding present · test/studio-s3.test.ts:210
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.diff-page.changed-entryThe diagram as text
spec:consumers.spec-studio.diff-page.changed-entry: The diff page shows a changed entry's base and built values · declared Spec
spec:consumers.spec-studio.diff-page: The diff page shows what changed in the design since a base graph · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
CI keeps the results of its test runs; the graph records only that a verifier is bound. Given run records in the Common Test Report Format, the build shows each run and the test files it joins, so a reviewer reads what ran where the verifiers are anchored. A result is evidence from a file, never the verdict of one verifier, and never a delivery fact.
Intent
outcome
Let a person read, from a link, the test runs the build was given, which anchored test files each joins, and which records join none, each labelled as external evidence.
The page names each run by its position among the inputs and its own fields: its tool and version, its build name and number, its branch, its commit, and its start and stop times as recorded, a field the record lacks reading not recorded.
Every place a run shows, on this page, in the tests lens and on a Spec page, says in words that it is external run evidence from a test file, and none says that a Spec or a verifier passed.
For each run the page shows how many of its tests passed, failed, were skipped, pending or other, in words, then each test file it joins, with the test anchors in that file, the Specs they verify, linked, and each test's name, suite, result in words and duration, then the records that join no test anchor, each with its reason, no file path or no test anchor in that file.
Each run shows its commit, and the page never says a run is fresh or stale; a stamp present beside the page set names the corpus commit the publishing step recorded, so a reader compares the two.
Given run records, the sentence over a Pack page's members with no verifier binding also says that the runs page, the tests lens and the Spec pages of the Specs their files verify show the run records as external evidence from test files; it never says that no page shows a run result.
Given one CTRF report whose tool is {tool: "vitest"} at version {version: "3.2.4"}, and whose tests in an anchored test file {passed: 2} passed and {failed: 1} failed
When the build renders the runs page
Then the run's heading reads {heading: "Run 1: external run evidence from vitest 3.2.4"}
Then the page lists {rows: 3} results under that test file
Then a page says that a Spec or a verifier passed: {verdict: false}
Given one CTRF report whose tool is {tool:string} at version {version:string}, and whose tests in an anchored test file {passed:number} passed and {failed:number} failed
When the build renders the runs page
Then the run's heading reads {heading:string}
Then the page lists {rows:number} results under that test file
Then a page says that a Spec or a verifier passed: {verdict:boolean}
Run <n>: external run evidence from <tool> <version>, <n> the input's position counting from 1 and the version left out when the record names none, then a line with the build, branch, commit and times, each labelled, a time written as an ISO 8601 UTC time from the milliseconds the record holds.
the file as text with a copy action, the anchors in it as code, the Specs they verify as links, then a table of results with columns name, suite, result and duration. A duration shows milliseconds with at most two decimals, rounded and without trailing zeroes, as 2.84 ms, 0.46 ms or 12 ms; short headers and one-word cells never break inside a word.
tool · string · declared by one CTRF report whose tool is {tool} at version {version}, and whose tests in an anchored test file {passed} passed and {failed} failed
version · string · declared by one CTRF report whose tool is {tool} at version {version}, and whose tests in an anchored test file {passed} passed and {failed} failed
passed · number · declared by one CTRF report whose tool is {tool} at version {version}, and whose tests in an anchored test file {passed} passed and {failed} failed
failed · number · declared by one CTRF report whose tool is {tool} at version {version}, and whose tests in an anchored test file {passed} passed and {failed} failed
Preferred syntax: requirementDiagram. Chosen syntax: flowchart TB because models require exact labels unavailable in requirement syntax.
Decisions
spec:decisions.binding-not-liveness
Delivery facts record bindings and enabled verifier existence; coverage gaps and human readiness practice remain explicit without becoming graph facts.
spec:consumers.spec-studio.runs-page dependsOn spec:consumers.spec-studio.data.inputs · declared — the run records reach the page as the build's named runs input
spec:consumers.spec-studio.runs-page dependsOn spec:observation.run-evidence · declared — the page renders the run evidence recipe 45 joins from the run records
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the runs page on one report: the run named by its tool, its results under the test file they join, and no page saying a Spec or a verifier passed.
assumptions
The world writes a root with one Spec and one test file holding a specTest anchor that verifies it, writes one CTRF report whose three tests name that file, two passed and one failed, builds the page set with the report as run records, and reads the runs page, then the tests lens and the Spec page for any sentence saying that the Spec or the verifier passed.
Behavior
Examples
Given one CTRF report whose tool is {tool: "vitest"} at version {version: "3.2.4"}, and whose tests in an anchored test file {passed: 2} passed and {failed: 1} failed
When the build renders the runs page
Then the run's heading reads {heading: "Run 1: external run evidence from vitest 3.2.4"}
Then the page lists {rows: 3} results under that test file
Then a page says that a Spec or a verifier passed: {verdict: false}
Verification
Verifier bindings
test:protocol.run-external · anchored · test anchor binding present · test/studio-s4.test.ts:378
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.runs-page.external-evidenceThe diagram as text
spec:consumers.spec-studio.runs-page.external-evidence: The runs page shows a run as external evidence from a test file · declared Spec
spec:consumers.spec-studio.runs-page: The runs page shows the run records the build was given, joined to test files · declared Spec
1 open question and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
The original design put test reports in the graph and used passing runs to mark verification. The Protocol keeps run verdicts in CI. A resolving verifier binding confers has-verifier; showing a recorded run beside that binding confers no delivery fact. Runtime observation against a measurable target is a separate concern carried by the runtime overlay.
An adopter that keeps CI run reports needs to read them beside verifier bindings as a separately named input. Recipe 45 reads them, and the Studio admits them as one of its two named inputs. The view identifies each run by its own fields and its commit, and distinguishes evidence from a test file from a verdict for one anchored verifier. Test reporters write a test's file as an absolute path or a path from the directory they ran in, so the join reads a path's end as well as the whole path. The freshness question records what remains unsettled about comparing a run with the source being read.
Intent
problem
A reader who wants to know whether a bound verifier passed has to leave the Protocol's views for CI, and an adopter that keeps run records has no view that shows them beside the binding without mistaking them for a delivery fact.
outcome
Show a verifier's recorded runs beside its binding in a view, labelled as external input with its commit, while the graph keeps recording only that the binding exists.
Open questions
non-blocking · question.freshnessline 28 · specs/observation/run-evidence.sdp.md:28 · How does a view say a run is stale: by its commit against the commit being read, or by whether the bound files changed between the two?Decider: ownerProvisional: Display the run and source commit identifiers when they differ, as the differing-commit rule requires; whether freshness also follows changes to bound files remains open.
Run records are an input a view reads beside the graph, named by the caller; the graph never holds them, and no node, edge or delivery fact derives from them.
A run record joins every verifier whose test anchor sits in the test file the record names, because the file is the binding grain of both anchor forms; each test name in the record shows as a row under that verifier. The join is at file grain: a result is evidence from the verifier's file, never the result of that verifier, because a file may hold several suites and a filtered run may exercise only one.
The Protocol reads run records in the Common Test Report Format, CTRF, an open JSON schema with reporters for the common test runners, passed to a view as a recipe parameter. A record joins only when its reporter fills CTRF's optional filePath field, and an adopter with records of another shape maps them into CTRF itself.
A record's file path joins a test anchor's file when, with each backslash written as a slash and a leading ./ removed, it equals that file or ends with a slash followed by that file; when several anchored files match, the longest joins.
A record that names no file path, or a file that holds no test anchor, is reported as unjoined with its reason, never dropped, and an input that is not a CTRF report is reported with its problem while the other inputs still join.
A run's commit is CTRF's results.environment.commit, and a run without one reads not recorded; given the commit being read, the recipe says for each run whether its commit is that commit, and never says the run is fresh or stale.
A view shows each run beside the verifiers anchored in its file, with its result, its commit and the input it came from, labelled as external run evidence from that file and never as has-verifier, implemented or a pass verdict for one verifier.
The Design Review stays a function of the graph alone and shows no run; run evidence appears only in a view that explicitly admits records as external input: recipe 45, and the Studio built with run records, which shows them on its runs page, in its tests lens and on the Spec pages of the Specs their files verify.
Given a CTRF report whose test {testName: "renders the page"} names the file {filePath: "/home/runner/work/repo/repo/test/page.test.ts"} and reports the result {status: "passed"}
Given the graph holds a test anchor in the file {anchorFile: "test/page.test.ts"} that verifies {specId: "spec:probe.page"}
When recipe 45 reads the report
Then the test joins the file {joinedFile: "test/page.test.ts"}
Then the test is unjoined for the reason {reason: "none"}
Then the delivery facts of the verified Spec are unchanged: {factsUnchanged: true}
Given a CTRF report whose test {testName: "counts the rows"} names the file {filePath: "test/other.test.ts"} and reports the result {status: "failed"}
Given the graph holds a test anchor in the file {anchorFile: "test/page.test.ts"} that verifies {specId: "spec:probe.page"}
When recipe 45 reads the report
Then the test joins the file {joinedFile: ""}
Then the test is unjoined for the reason {reason: "noTestAnchor"}
Then the delivery facts of the verified Spec are unchanged: {factsUnchanged: true}
Given a CTRF report whose test {testName:string} names the file {filePath:string} and reports the result {status:"passed"|"failed"|"skipped"}
Given the graph holds a test anchor in the file {anchorFile:string} that verifies {specId:string}
When recipe 45 reads the report
Then the test joins the file {joinedFile:string}
Then the test is unjoined for the reason {reason:"none"|"noFilePath"|"noTestAnchor"}
Then the delivery facts of the verified Spec are unchanged: {factsUnchanged:boolean}
recipe 45, run evidence, takes params.runs, one CTRF report or a list of them in input order, required; params.commit, the commit being read, optional; and params.spec, a Spec id, optional, which keeps only the files whose test anchors verify that Spec directly or through an enabled example. It returns { inputs, diagnostics, totals, files, unjoined }, and { diagnostics } alone when params.runs is missing or holds no report it can read.
the recipe reads reportFormat and specVersion; results.tool.name and version; results.summary with tests, passed, failed, skipped, pending, other, start and stop; results.environment with commit, branchName, buildName and buildNumber; and per test name, status, duration, filePath and suite; it reads no other field. A readable CTRF report has reportFormat: "CTRF" and a specVersion, as the CTRF schema requires; a report missing either produces a run diagnostic and contributes no run rows.
{ index: number; tool: string | null; toolVersion: string | null; specVersion: string; commit: string | null; branch: string | null; build: string | null; start: number | null; stop: number | null; summary: { tests: number; passed: number; failed: number; skipped: number; pending: number; other: number }; sameCommit: boolean | null }, one per readable report, index its position from 0, build the build name and number joined by a space, and sameCommit null without params.commit or without a run commit.
{ file: string; anchors: { id: string; verifies: string[] }[]; specs: string[]; results: { input: number; name: string; suite: string | null; status: string; duration: number | null }[] }, one per anchored test file a record joins, sorted by file, specs the Specs its anchors verify directly or through an enabled example, sorted, and results in input order and then record order, suite the record's suite path joined by > , and duration the recorded milliseconds without rounding; a view formats that number for display.
{ input: number | null; problem: string }, for a missing params.runs, with input null, or for an input that is not an object, has no results.tests list, lacks reportFormat or specVersion, or names a reportFormat other than CTRF.
{ inputs: number; tests: number; joined: number; unjoined: number; files: number; specs: number }, counting the readable reports, every test they hold, the tests joined and unjoined, the files joined, and the distinct Specs those files verify.
no citation recorded
Verification
Verifier bindings
spec:observation.run-evidence.absolute-path-joins · A test whose reporter wrote an absolute path joins its anchored file · declared · example enabled · specs/observation/run-evidence.absolute-path-joins.sdp.md
Preferred syntax: requirementDiagram. Chosen syntax: flowchart TB because models require exact labels unavailable in requirement syntax.
Decisions
spec:decisions.binding-not-liveness
Delivery facts record bindings and enabled verifier existence; coverage gaps and human readiness practice remain explicit without becoming graph facts.
spec:observation.run-evidence dependsOn spec:consumers.agent-surface.recipe-parameters · declared — the caller passes run records to the recipe as data
spec:observation.run-evidence dependsOn spec:extraction.delivery-facts · declared — the view reads verifier bindings while leaving their delivery facts unchanged
spec:observation.run-evidence refines spec:consumers.projections-model · declared — run records inform a view without becoming graph facts
spec:consumers.spec-studio.data.inputs dependsOn spec:observation.run-evidence · declared — the run records input is read only as run evidence
spec:consumers.spec-studio.lenses.tests dependsOn spec:observation.run-evidence · declared — with run records, a row adds the results recipe 45 joins from its verifiers' files
spec:consumers.spec-studio.runs-page dependsOn spec:observation.run-evidence · declared — the page renders the run evidence recipe 45 joins from the run records
spec:consumers.spec-studio.verification-panels dependsOn spec:observation.run-evidence · declared — with run records, a verifier's row adds the results recipe 45 joins from its test file
spec:protocol.roadmap-replaces-plans dependsOn spec:observation.run-evidence · declared — an arc's acceptance reads run records as evidence from test files at their recorded commit
impl:protocol.run-evidence-recipe · asserts realization of Run evidence in docs/agent-surface/recipes.md · test/recipes.test.ts:7277
impl:protocol.studio-runs-page · renders readable CTRF inputs, file results, unjoined records and diagnostics · src/projections/studio/pages/runs-page.ts:6 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
spec:observation.run-evidence.absolute-path-joins · A test whose reporter wrote an absolute path joins its anchored file · declared · specs/observation/run-evidence.absolute-path-joins.sdp.md · example enabled
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the file-grain join through path normalization, and hold the graph untouched by it.
assumptions
The world writes a root with one Spec and one test file holding a specTest anchor that verifies it, derives the graph, keeps the Spec's delivery facts, runs recipe 45's shipped body with one CTRF report holding the one test, and compares the Spec's delivery facts in a graph derived again afterwards.
Behavior
Examples
Given a CTRF report whose test {testName: "renders the page"} names the file {filePath: "/home/runner/work/repo/repo/test/page.test.ts"} and reports the result {status: "passed"}
Given the graph holds a test anchor in the file {anchorFile: "test/page.test.ts"} that verifies {specId: "spec:probe.page"}
When recipe 45 reads the report
Then the test joins the file {joinedFile: "test/page.test.ts"}
Then the test is unjoined for the reason {reason: "none"}
Then the delivery facts of the verified Spec are unchanged: {factsUnchanged: true}
Verification
Verifier bindings
test:protocol.run-absolute · anchored · test anchor binding present · test/studio-s4.test.ts:346
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:observation.run-evidence.absolute-path-joinsThe diagram as text
spec:observation.run-evidence.absolute-path-joins: A test whose reporter wrote an absolute path joins its anchored file · declared Spec
spec:observation.run-evidence: CI run records are joined to verifiers in a view · declared Spec
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the unjoined report for a record whose file holds no test anchor.
assumptions
The world writes a root with one Spec and one test file holding a specTest anchor that verifies it, and a CTRF report whose one test names another file; it runs recipe 45's shipped body and reads the joined files and the unjoined rows, and compares the Spec's delivery facts before and after.
Behavior
Examples
Given a CTRF report whose test {testName: "counts the rows"} names the file {filePath: "test/other.test.ts"} and reports the result {status: "failed"}
Given the graph holds a test anchor in the file {anchorFile: "test/page.test.ts"} that verifies {specId: "spec:probe.page"}
When recipe 45 reads the report
Then the test joins the file {joinedFile: ""}
Then the test is unjoined for the reason {reason: "noTestAnchor"}
Then the delivery facts of the verified Spec are unchanged: {factsUnchanged: true}
Verification
Verifier bindings
test:protocol.run-unjoined · anchored · test anchor binding present · test/studio-s4.test.ts:353
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:observation.run-evidence.unanchored-file-unjoinedThe diagram as text
spec:observation.run-evidence.unanchored-file-unjoined: A test in a file with no test anchor is reported as unjoined · declared Spec
spec:observation.run-evidence: CI run records are joined to verifiers in a view · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
A Spec's Model section defines terms, and a term may carry a key that gives it an address. The glossary page gathers every defined term on one page so a reviewer finds a word and the Spec that defines it. A corpus's ratified glossary stays the document it is; the page lists what the Specs define, so two definitions of one word read side by side.
Intent
outcome
Let a person find any term a Spec defines, read its definition, and open the Spec and the entry that define it.
The page set holds glossary.html, which lists every term a Spec's Model section defines, sorted by the term's lowercase form in code-unit order and then by Spec id, each with its definition as text, its Spec linked, and, when the term carries a key, its address spec:<id>#term.<key> with a copy action, linked to the term on the Spec page; the term and its definition split as spec:carrier.markdown-body-grammar states.
The page opens with the count of terms and of defining Specs in one sentence and the letters its terms start with, each linked to the heading over its terms.
Given two Specs whose Model sections define the term {term: "order"}, the first with the key {key: "order"}
When the build renders the glossary page
Then the page lists the term {rows: 2} times
Then the keyed row shows the address {address: "spec:probe.alpha#term.order"}
Given two Specs whose Model sections define the term {term:string}, the first with the key {key:string}
When the build renders the glossary page
Then the page lists the term {rows:number} times
Then the keyed row shows the address {address:string}
one heading per first letter, lowercased, with the element id letter.<letter>, over the terms that start with it; a term that starts with no letter sits under the heading # with the element id letter.other.
the term in bold, its definition as text with inline code spans as code, then the Spec's title linked and, when keyed, term.<key> as a link with a copy action for the full address.
Relations of spec:consumers.spec-studio.glossary-pageThe diagram as text
spec:carrier.markdown-body-grammar: The Markdown body accepts one closed form per section
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.glossary-page: The glossary page lists every term the corpus's Specs define
spec:consumers.spec-studio.glossary-page.same-word-twice: A word two Specs define appears once per Spec on the glossary page
spec:model.term-addresses: A Model term may carry a key that addresses it
spec:consumers.spec-studio.glossary-page dependsOn spec:carrier.markdown-body-grammar · declared — the page splits a Model entry into its term and definition as the body grammar reads it
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the glossary on one word two Specs define: both definitions listed, and the keyed one with its address.
assumptions
The world writes a root with two Specs under the probe namespace, alpha and beta, each defining order in its Model section, the first with an authored key; it builds the page set and reads the glossary page's rows for the term.
Behavior
Examples
Given two Specs whose Model sections define the term {term: "order"}, the first with the key {key: "order"}
When the build renders the glossary page
Then the page lists the term {rows: 2} times
Then the keyed row shows the address {address: "spec:probe.alpha#term.order"}
Verification
Verifier bindings
test:protocol.studio-glossary-same-word-twice · anchored · test anchor binding present · test/studio-s3.test.ts:278
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.glossary-page.same-word-twiceThe diagram as text
spec:consumers.spec-studio.glossary-page.same-word-twice: A word two Specs define appears once per Spec on the glossary page · declared Spec
spec:consumers.spec-studio.glossary-page: The glossary page lists every term the corpus's Specs define · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
The change-proposal contract requires the commit whose graph the person read, and a generated page set carries no commit, so a proposal's base comes from the build stamp when one is present and from the person otherwise. The panel hands off the same Markdown memo an agent gets from recipe 49 for the same proposal, so a person, a reviewer and an agent read one text. A static page holds no credentials, so the panel opens no pull request and writes nothing but its own gathered intents in the browser.
Intent
outcome
Let a person gather the changes they want while they read, each bounded by a Spec, its neighbors, a Pack or one open question, and hand them to an agent that edits source.
The composing panel is on every page, after the canvas, closed by default with its heading and the count of gathered intents; without script it says that composing needs the script.
Gathered intents persist in the browser's local storage under the page set's own key, so refreshing a tab on a phone loses none, and two page sets served from one host never share intents.
A composed intent names its scope by id or entry address, so the agent that receives it reads the same Spec, Pack, entry or question through the graph.
The panel hands its gathered intents off as one change proposal, on the change-proposal contract, and as the memo recipe 49 renders for it: the person copies the memo or the proposal as text, or saves either as a file. The page opens no pull request, because a static page holds no credentials; any pull request comes from the agent's ordinary source edit.
A proposal's base is the commit a present build stamp names, otherwise one the person supplies, and the person gives one reason for the whole proposal; without a base and a reason the panel exports its intents as scoped-intent text, and the agent that receives them writes the proposal against a commit it knows.
A request scoped to a Pack records the members this page set renders for that Pack, and expands to them at hand-off only when the proposal's base is the commit the page set's stamp names; otherwise it stays scoped-intent text for an agent to resolve against the base. A request that changes a Pack's membership or framing, names an empty Pack or names a Pack with an unresolved member, stays scoped-intent text too, so the change-proposal contract keeps its Spec and entry scopes.
The proposal holds only the intents its contract can carry; every intent that stays scoped-intent text is listed apart under Not in the proposal, and Copy scoped intent copies those intents, so the panel drops none. The copied text names each intent's action and recorded scope: the member Spec ids for a member change, with the Pack id as context, or the Pack id for a membership or framing change.
no example exercises it
Cited at
Test line · test/studio-s5.test.ts:1038 · test:protocol.studio-intent-handoff · test:protocol.studio-intents-refresh
Given the composing panel holds {gathered: 3} gathered intents
When the person refreshes the tab
Then the composing panel holds {kept: 3} gathered intents
Given the composing panel holds {gathered:number} gathered intents
When the person refreshes the tab
Then the composing panel holds {kept:number} gathered intents
sdp-studio:intents:<root path>, where the root path is the URL path of the page set's root as the page's page-root attribute resolves it, so a page set at /preview/12/ and one at /preview/13/ keep apart.
{ scope: string[]; request: string; text?: string; replaces?: string; follows?: string; pack?: string; packMembersComplete?: boolean; action: string } per gathered intent, in gathering order, where action names the composing action that gathered it, such as edit-example, and pack keeps the Pack a Pack-scoped request named, with scope holding the resolved members this page set renders for it and packMembersComplete recording whether every manifest member resolved when the request was gathered.
the intents gathered so far, headed Composing with their count, each on one line naming its scope and the change it asks for, such as adding an example or changing a constraint's target, with a button that discards it.
Copy memo, Copy proposal, Save memo, Save proposal and Discard all, the copy and save actions shown only when a base and a reason are present; and Copy scoped intent whenever an intent stays scoped-intent text, every intent without a base and a reason, and otherwise those the proposal cannot hold.
the actions on other panels that compose intent: propose new text for a keyed entry, resolve an open question or promote it to a decision record, propose or edit an example, propose or change a constraint target, and propose examples for values no example binds.
a native dialog with a labelled text area for the request, a second for the exact entry text when the action proposes one, and Gather and Cancel buttons.
Requirement drawing for spec:consumers.spec-studio.intent-panelThe diagram as text
spec:consumers.spec-studio.intent-panel: A composing panel on every page gathers scoped intent for an agent · declared Spec
spec:consumers.spec-studio.intent-panel.refresh-keeps-intents: Refreshing a tab keeps every gathered intent · declared Spec
spec:consumers.intent-composition: Composed intent hands off on one proposal shape · declared Spec
impl:protocol.studio-compose: opens a native request dialog beside build-rendered scopes without changing their content · anchored code · src/studio-elements/compose.ts:13
impl:protocol.studio-frame: renders Studio navigation, page rails and composing controls · anchored code · src/projections/studio/pages/frame.ts:6
impl:protocol.studio-intent-panel: gathers ordered intents under the page-root storage key and partitions their hand-off · anchored code · src/studio-elements/intent-panel.ts:51
impl:protocol.studio-intent-panel-element: displays gathered requests and writes copy selections or local download links · anchored code · src/studio-elements/intent-panel-element.ts:14
impl:protocol.studio-scenario-editor: gathers the edited Given, When and Then as exact text scoped to its subject · anchored code · src/studio-elements/scenario-editor.ts:17
impl:protocol.studio-intent-panel · gathers ordered intents under the page-root storage key and partitions their hand-off · src/studio-elements/intent-panel.ts:51
impl:protocol.studio-intent-panel-element · displays gathered requests and writes copy selections or local download links · src/studio-elements/intent-panel-element.ts:14
impl:protocol.studio-scenario-editor · gathers the edited Given, When and Then as exact text scoped to its subject · src/studio-elements/scenario-editor.ts:17
spec:consumers.spec-studio.components dependsOn spec:consumers.spec-studio.intent-panel · declared — the panel element renders the gathered intents that Spec designs
spec:consumers.spec-studio.verification-panels dependsOn spec:consumers.spec-studio.intent-panel · declared — each panel action gathers intent in the composing panel
spec:consumers.studio-on-ramp dependsOn spec:consumers.spec-studio.intent-panel · declared — the skill teaches what the composing panel hands off and what stays scoped-intent text
impl:protocol.studio-compose · opens a native request dialog beside build-rendered scopes without changing their content · src/studio-elements/compose.ts:13 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-frame · renders Studio navigation, page rails and composing controls · src/projections/studio/pages/frame.ts:6 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-intent-panel · gathers ordered intents under the page-root storage key and partitions their hand-off · src/studio-elements/intent-panel.ts:51 · role service · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-intent-panel-element · displays gathered requests and writes copy selections or local download links · src/studio-elements/intent-panel-element.ts:14 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-scenario-editor · gathers the edited Given, When and Then as exact text scoped to its subject · src/studio-elements/scenario-editor.ts:17 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the panel's persistence across a refresh of the tab.
assumptions
The world runs the composing panel's element module under Node with a storage object standing in for the browser's local storage, gathers the intents through the panel's own gather call, then creates a fresh panel over the same storage and page root, as a refreshed tab would, and counts the intents it shows.
Behavior
Examples
Given the composing panel holds {gathered: 3} gathered intents
When the person refreshes the tab
Then the composing panel holds {kept: 3} gathered intents
Verification
Verifier bindings
test:protocol.studio-intents-refresh · anchored · test anchor binding present · test/studio-s5.test.ts:249
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.intent-panel.refresh-keeps-intentsThe diagram as text
spec:consumers.spec-studio.intent-panel.refresh-keeps-intents: Refreshing a tab keeps every gathered intent · declared Spec
spec:consumers.spec-studio.intent-panel: A composing panel on every page gathers scoped intent for an agent · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
A person reviews a proposed change as text, not as JSON beside the proposal check's rows. The memo is a rendering of the proposal document and never a second source of it: it ends with the document itself, so one paste hands an agent everything the person reviewed. Recipe 49 renders it, and the Studio's composing panel writes the same bytes, so a person, a reviewer and an agent read one text.
Intent
outcome
Render a change proposal as one Markdown memo, the same bytes from the recipe and from the Studio's composing panel, that a person reviews and hands to an agent whole.
Recipe 49 renders a proposal as the Markdown memo a person reviews and hands off, ending with the document itself, and the Studio's composing panel, spec:consumers.spec-studio.intent-panel, writes the same bytes for the same document, so a person, a reviewer and an agent read one text.
Given a change proposal with {changes: 2} changes, one whose exact text holds a run of {ticks: 3} backticks
When recipe 49 renders its memo and the composing panel renders its memo
Then the two memos are byte-identical: {identical: true}
Then the memo ends with the proposal as JSON in a fenced block: {carriesDocument: true}
Then the fence around that exact text is {fence: 4} backticks long
Given a change proposal with {changes:number} changes, one whose exact text holds a run of {ticks:number} backticks
When recipe 49 renders its memo and the composing panel renders its memo
Then the two memos are byte-identical: {identical:boolean}
Then the memo ends with the proposal as JSON in a fenced block: {carriesDocument:boolean}
Then the fence around that exact text is {fence:number} backticks long
recipe 49, the proposal memo, takes params.proposal and returns { schemaProblems: [{ path, problem }], memo }: the schema problems recipe 38 reports for the same document and, when there are none, the memo as one string, otherwise memo: null; it reads no graph value, so one document renders one memo in any corpus.
the memo opens with the line # Change proposal, a blank line, the line Base: followed by the base as a code span, the line Reason: followed by the reason as a code span, and a blank line.
Cited at
Test line · test/studio-s5.test.ts:1137 · test:protocol.studio-memo-shared
each change follows in document order as the line ## Change <n>, counting from 1, and a blank line, then each on its own line: Scope: followed by the scope items as code spans joined by , ; Request: followed by a blank line and the request in a fenced block whose info string is text; when present, Replaces: or Follows: followed by the address as a code span; Relation: followed by the action, the source as a code span, the relation type and the target as a code span, separated by single spaces; and Reason: followed by the change's reason as a code span; then, when the change carries exact text, a blank line and the text in a fenced block with no info string; then a blank line.
Cited at
Test line · test/studio-s5.test.ts:1138 · test:protocol.studio-memo-shared
the memo ends with the line ## The proposal, a blank line, and the document in a fenced block whose info string is json, written as JSON.stringify writes it with two-space indentation and the keys in the order the document holds them.
Cited at
Test line · test/studio-s5.test.ts:1139 · test:protocol.studio-memo-shared
a code span uses a backtick run one longer than the longest run its content holds, padded with a space on each side when the content starts or ends with a backtick; a fence is a backtick run one longer than the longest run its content holds and at least three long; each request and each change's exact text is enclosed in a fence longer than any backtick run it holds, each reason is enclosed in a code span whose backtick run is longer than any run it holds, so no field of the memo can open HTML, add a heading or close its enclosing span or fence; every value is written verbatim; every line ends with a line feed and the memo with one.
Verification
Verifier bindings
spec:consumers.intent-composition.proposal.memo.shared · Recipe 49 and the composing panel write one memo for one proposal · declared · example enabled · specs/consumers/intent-composition.proposal.memo.shared.sdp.md
Example space
changes · number · declared by a change proposal with {changes} changes, one whose exact text holds a run of {ticks} backticks
ticks · number · declared by a change proposal with {changes} changes, one whose exact text holds a run of {ticks} backticks
spec:consumers.roadmap.memo dependsOn spec:consumers.intent-composition.proposal.memo · declared — the memo writes its code spans by the proposal memo's markup rules
spec:consumers.spec-studio.intent-panel dependsOn spec:consumers.intent-composition.proposal.memo · declared — the panel writes the memo recipe 49 renders, byte for byte
spec:protocol.roadmap-replaces-plans dependsOn spec:consumers.intent-composition.proposal.memo · declared — the pull request carries a review's proposal as its memo
impl:protocol.proposal-memo-recipe · realizes the catalog proposal memo through its verbatim body check · test/recipes.test.ts:7298
impl:protocol.studio-proposal-memo · renders proposal fields verbatim with fences that outgrow their content · src/studio-elements/memo.ts:13 · role projection · component component:protocol.studio-elements · layer edge · context protocol
Design reference: none
Verifier binding: present
spec:consumers.intent-composition.proposal.memo.shared · Recipe 49 and the composing panel write one memo for one proposal · declared · specs/consumers/intent-composition.proposal.memo.shared.sdp.md · example enabled
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the shared memo: the recipe and the panel render the same bytes, the memo carries the document, and a fence outgrows the backticks it holds.
assumptions
The world writes a proposal document with a base, a reason and the stated number of changes, the first scoped to one entry address with exact text that holds the stated run of backticks, and the second declaring a relation; it runs recipe 49's shipped body with the document as proposal, calls the composing panel's memo function on the same document, compares the two strings, parses the last fenced block's content as JSON and compares it with the document, and measures the fence around the first change's text.
Behavior
Examples
Given a change proposal with {changes: 2} changes, one whose exact text holds a run of {ticks: 3} backticks
When recipe 49 renders its memo and the composing panel renders its memo
Then the two memos are byte-identical: {identical: true}
Then the memo ends with the proposal as JSON in a fenced block: {carriesDocument: true}
Then the fence around that exact text is {fence: 4} backticks long
Verification
Verifier bindings
test:protocol.studio-memo-shared · anchored · test anchor binding present · test/studio-s5.test.ts:272
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.intent-composition.proposal.memo.sharedThe diagram as text
spec:consumers.intent-composition.proposal.memo.shared: Recipe 49 and the composing panel write one memo for one proposal · declared Spec
spec:consumers.intent-composition.proposal.memo: Recipe 49 renders a change proposal as the Markdown memo a person reviews · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The original's harness element has no subject in the graph, which holds example spaces, bound points and oracle bindings but no harness node, so its successor takes the Spec that owns an example space. The build renders every view into the page's markup and an element adds only the interaction its view needs, as spec:decisions.studio-build-renders rules, so a trace graph draws one hop, a maturity map places members by stated rung and floor, a card always shows its rung, and the attributes the original used to choose another setting are gone.
Intent
outcome
Give the Studio a small set of custom elements that each hold one view of the graph, rendered by the build, in a Studio page or in any HTML page that holds that markup and loads the element script.
Each element is self-contained and light on dependencies, and works in any HTML page that holds the markup the build wrote for it and loads the Studio's script.
The build renders every element's view into its markup, from reader values and the recipe answers the page names, so the view reads without script; the element adds only interaction, and an element whose view needs none is defined with no behavior.
An element with a graph subject takes that subject's graph id in the attribute its Design entry names; an element over gathered intents has no single graph subject.
sdp-spec-card with spec-id and variant: one Spec as a card; full is a Pack page's member card, short one line with the title linked, the id, the rung badge and the floor in words; no behavior.
sdp-trace-graph with spec-id: the Spec's relations one hop each way, drawn in relation bands inside an sdp-diagram, then its text equivalent; no behavior of its own.
sdp-maturity-map with pack-id: the Pack's members placed by stated rung and floor reached, drawn as a static SVG grid of counts, then its count table and each populated cell's member list; no behavior.
sdp-example-space with spec-id, naming the Spec that owns the example space: the space's slots with their types and the step that declares each, its children's bound points as a table with one row per example and one column per slot, an unbound slot written unbound, its expected-outcome oracle binding as present or none, and recipe 44's coverage; its coverage is a report, never a verifier run or a delivery fact; no behavior beyond the composing actions inside it.
sdp-scenario-editor with spec-id and mode: in edit mode a form holding the example's given, when and then steps, in propose mode the parent's step vocabulary as a starting point; submitting gathers an intent scoped to the example or to the parent, with the steps as its exact text; without script it shows the steps as text and says that composing needs the script.
sdp-intent-panel with page-root and no graph-subject attribute, rendering the gathered intents across their scopes as spec:consumers.spec-studio.intent-panel states.
sdp-compose with scope and action: a button labelled with what it composes that opens the compose dialog and gathers the intent in the composing panel; scope is a Spec id, entry address or Pack id, with a Pack's space-separated resolved member ids in members, members-complete set to true only when every manifest member resolves, and a Change applies to choice between member Specs and Pack membership or framing; action is one of resolve-question, promote-question, edit-example, propose-example, change-target, propose-target, propose-values and change-entry; hidden without script.
impl:protocol.studio-architecture-diagrams: architecture grids and bounded context and layer folds · anchored code · src/projections/studio/diagrams/architecture.ts:4
impl:protocol.studio-compose: opens a native request dialog beside build-rendered scopes without changing their content · anchored code · src/studio-elements/compose.ts:13
impl:protocol.studio-copy: copies text with selection fallback and failure feedback · anchored code · src/studio-elements/copy.ts:22
impl:protocol.studio-diagram-element: adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · anchored code · src/studio-elements/diagram.ts:23
impl:protocol.studio-diagrams: deterministic grid and band layouts with bounded folds and full text equivalents · anchored code · src/projections/studio/diagrams/svg.ts:73
impl:protocol.studio-expander: opens fragment ancestors and expands disclosures for print · anchored code · src/studio-elements/expander.ts:16
impl:protocol.studio-filter: filters build-rendered rows through their recorded attributes · anchored code · src/studio-elements/filter.ts:25
impl:protocol.studio-intent-panel-element: displays gathered requests and writes copy selections or local download links · anchored code · src/studio-elements/intent-panel-element.ts:14
impl:protocol.studio-maturity-map: places resolved Pack members by their stated rung and floor in authored order · anchored code · src/projections/studio/pages/maturity-map.ts:7
impl:protocol.studio-relation-diagrams: relation and member bands and bounded relation folds · anchored code · src/projections/studio/diagrams/bands.ts:10
impl:protocol.studio-scenario-editor: gathers the edited Given, When and Then as exact text scoped to its subject · anchored code · src/studio-elements/scenario-editor.ts:17
impl:protocol.studio-search-form: routes search forms through page-root URLs and fragments · anchored code · src/studio-elements/search.ts:18
impl:protocol.studio-search-results: ranks and renders concept, entry and file search hits · anchored code · src/studio-elements/search-results.ts:95
impl:protocol.studio-spec-structure: renders requirement and trace diagrams and the recorded structural neighborhood · anchored code · src/projections/studio/pages/spec-structure.ts:44
impl:protocol.studio-stamp: resolves published stamps and source links in the browser · anchored code · src/studio-elements/stamp.ts:30
impl:protocol.studio-verification-panels: renders rule coverage, example cards, constraint targets, verifiers and example-space coverage · anchored code · src/projections/studio/pages/spec-verification.ts:74
The build renders every Studio view into the page's markup from reader values and the recipe answers its page names, and a custom element adds only the interaction its view needs; a host page that embeds a view carries the markup the build wrote and loads the element script, and supplies no graph data.
The engine lays out every Studio diagram at build time with its own deterministic layered layout and writes it into the page as inline SVG followed by a text equivalent. The custom element that holds a diagram adds only pan, zoom and pinch, by changing the SVG's view box. One diagram draws at most the bound spec:consumers.spec-studio.diagrams#design.bound names, and above it the diagram folds, by context and then by layer, as that Spec states.
impl:protocol.studio-diagram-element · adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · src/studio-elements/diagram.ts:23
impl:protocol.studio-intent-panel-element · displays gathered requests and writes copy selections or local download links · src/studio-elements/intent-panel-element.ts:14
impl:protocol.studio-maturity-map · places resolved Pack members by their stated rung and floor in authored order · src/projections/studio/pages/maturity-map.ts:7
impl:protocol.studio-scenario-editor · gathers the edited Given, When and Then as exact text scoped to its subject · src/studio-elements/scenario-editor.ts:17
impl:protocol.studio-spec-structure · renders requirement and trace diagrams and the recorded structural neighborhood · src/projections/studio/pages/spec-structure.ts:44
spec:consumers.spec-studio.components dependsOn spec:consumers.spec-studio.intent-panel · declared — the panel element renders the gathered intents that Spec designs
component:protocol.studio-elements · optional browser behavior and proposal handoff · src/studio-elements/index.ts:13 · role interaction · layer edge · context protocol
impl:protocol.studio-compose · opens a native request dialog beside build-rendered scopes without changing their content · src/studio-elements/compose.ts:13 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-diagram-element · adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · src/studio-elements/diagram.ts:23 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-filter · filters build-rendered rows through their recorded attributes · src/studio-elements/filter.ts:25 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-intent-panel-element · displays gathered requests and writes copy selections or local download links · src/studio-elements/intent-panel-element.ts:14 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-maturity-map · places resolved Pack members by their stated rung and floor in authored order · src/projections/studio/pages/maturity-map.ts:7 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-scenario-editor · gathers the edited Given, When and Then as exact text scoped to its subject · src/studio-elements/scenario-editor.ts:17 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-search-results · ranks and renders concept, entry and file search hits · src/studio-elements/search-results.ts:95 · role projection · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-spec-structure · renders requirement and trace diagrams and the recorded structural neighborhood · src/projections/studio/pages/spec-structure.ts:44 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-verification-panels · renders rule coverage, example cards, constraint targets, verifiers and example-space coverage · src/projections/studio/pages/spec-verification.ts:74 · role projection · component component:protocol.projections · layer edge · context protocol
Design reference: none
Verifier binding: present
test:protocol.studio-intent-handoff · anchored · test/studio-s5.test.ts:407 · test anchor
Expected-outcome oracle: none
Runtime observation: not tracked.
Run results: not recorded in the graph.
Findings
None.
51. The Studio is built from custom elements, not a framework
spec:decisions.studio-web-components
The Studio is built from custom elements, not a framework
spec:decisions.studio-web-componentsDecision Record · featurereadyfloor ready
No open questions and no blocking questions; implementation binding none, verifier binding none, and expected-outcome oracle none.
Intent
outcome
Let each Studio view work in an HTML page that can load its element script and supply graph data without imposing a framework on that page.
Decision
context
The Studio's views must work inside the Studio and in HTML pages that can load the element script and supply its graph data, such as an exported report, and its assets should stay small and cache well.
decision
The Studio is built from Web Components, custom elements written without React, Vue, Svelte or another framework.
rationale
Custom elements avoid a matching framework runtime in every embedding page; the host loads the Studio's element script and supplies the graph data.
Element names and attributes are a public embedding contract that is costly to replace; in exchange for framework-independent embedding, the Studio supplies rendering and state handling within its elements.
alternatives
Components of React, Vue or Svelte would impose that framework on every page that embeds one of them.
consequences
The few elements that need richer state, the harness and the scenario editor, may use a small reactive primitive inside themselves, such as @lit/reactive-element or a signals-style atom, without imposing a framework on the page that embeds them.
A host that strips scripts, such as a pull request description, shows a static link to a Studio page, never an element.
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.studio-web-components
Scroll horizontally to read the whole drawing.
The diagram as text
spec:decisions.studio-web-components: The Studio is built from custom elements, not a framework · declared Spec
spec:decisions.studio-build-renders: The build renders every Studio view, and an element only enhances it · declared Spec
spec:decisions.studio-diagram-renderer: The engine lays out every Studio diagram as static SVG when the page set is built · declared Spec
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph · declared Spec
impl:protocol.studio-architecture-lens: renders recipe component rows and planned designs as architecture and member diagrams · anchored code · src/projections/studio/pages/architecture-page.ts:50
impl:protocol.studio-diagram-element: adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · anchored code · src/studio-elements/diagram.ts:23
impl:protocol.studio-diagrams: deterministic grid and band layouts with bounded folds and full text equivalents · anchored code · src/projections/studio/diagrams/svg.ts:73
impl:protocol.studio-evidence-lens: names the four evidence sources and what would bring each into the Studio · anchored code · src/projections/studio/pages/evidence-page.ts:3
impl:protocol.studio-recipes: evaluates shipped recipe bodies once and shares answers between Studio pages · anchored code · src/projections/studio/recipes.ts:34
impl:protocol.studio-tests-lens: renders shared rule and example-space coverage with filters and verifier bindings · anchored code · src/projections/studio/pages/tests-page.ts:34
spec:decisions.studio-build-renders refines spec:decisions.studio-web-components · declared — narrows where a view's values come from; the build writes them into the markup, so a host carries that markup and supplies no graph data
spec:decisions.studio-diagram-renderer refines spec:decisions.studio-web-components · declared — narrows how an element that shows a diagram renders it; the element only enhances an SVG the build drew
spec:decisions.studio-build-renders refines spec:decisions.studio-web-components · declared — narrows where a view's values come from; the build writes them into the markup, so a host carries that markup and supplies no graph data
spec:decisions.studio-diagram-renderer refines spec:decisions.studio-web-components · declared — narrows how an element that shows a diagram renders it; the element only enhances an SVG the build drew
No open questions and no blocking questions; implementation binding none, verifier binding none, and expected-outcome oracle none.
Intent
outcome
Let every Studio view read in full without script, print, and travel inside a Pack export, while its custom element adds only the interaction the view needs.
Decision
context
The custom-elements decision frames an element as a view that renders from graph data its host page supplies. The Studio's pages read in full without script and open from file://, a Pack export carries no script, two builds of one graph write the same bytes, and the page computes no join, claim, fact or floor; the page elements the Studio ships already add behavior to markup the build wrote.
decision
The build renders every Studio view into the page's markup from reader values and the recipe answers its page names, and a custom element adds only the interaction its view needs; a host page that embeds a view carries the markup the build wrote and loads the element script, and supplies no graph data.
rationale
A view rendered at build time reads without script, prints, survives the Pack export, and keeps one graph to one set of bytes.
An element that holds no graph data cannot compute a join, claim, fact or floor in the browser, which the Studio refuses.
alternatives
Elements that render their views from graph data a host supplies, as the custom-elements decision first framed them, show nothing without script and put a second rendering path in the browser.
consequences
An element's attributes name its subject and its interaction, never a setting the build did not render, so the original's readiness-pill, depth, highlight and group-by attributes are gone.
The custom-elements decision still rules how the elements are written: as custom elements without a framework.
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.studio-build-renders
Scroll horizontally to read the whole drawing.
The diagram as text
spec:decisions.studio-build-renders: The build renders every Studio view, and an element only enhances it · declared Spec
spec:decisions.studio-web-components: The Studio is built from custom elements, not a framework · declared Spec
impl:protocol.studio-architecture-lens: renders recipe component rows and planned designs as architecture and member diagrams · anchored code · src/projections/studio/pages/architecture-page.ts:50
impl:protocol.studio-diagram-element: adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · anchored code · src/studio-elements/diagram.ts:23
impl:protocol.studio-diagrams: deterministic grid and band layouts with bounded folds and full text equivalents · anchored code · src/projections/studio/diagrams/svg.ts:73
impl:protocol.studio-evidence-lens: names the four evidence sources and what would bring each into the Studio · anchored code · src/projections/studio/pages/evidence-page.ts:3
impl:protocol.studio-recipes: evaluates shipped recipe bodies once and shares answers between Studio pages · anchored code · src/projections/studio/recipes.ts:34
impl:protocol.studio-tests-lens: renders shared rule and example-space coverage with filters and verifier bindings · anchored code · src/projections/studio/pages/tests-page.ts:34
spec:decisions.studio-build-renders refines spec:decisions.studio-web-components · declared — narrows where a view's values come from; the build writes them into the markup, so a host carries that markup and supplies no graph data
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.studio-build-rendersThe diagram as text
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph
spec:consumers.spec-studio.components: The Studio's custom elements each hold one view the build renders
spec:decisions.studio-build-renders: The build renders every Studio view, and an element only enhances it
spec:decisions.studio-web-components: The Studio is built from custom elements, not a framework
spec:decisions.studio-build-renders refines spec:decisions.studio-web-components · declared — narrows where a view's values come from; the build writes them into the markup, so a host carries that markup and supplies no graph data
impl:protocol.studio-architecture-lens · renders recipe component rows and planned designs as architecture and member diagrams · src/projections/studio/pages/architecture-page.ts:50 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-diagram-element · adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · src/studio-elements/diagram.ts:23 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-diagrams · deterministic grid and band layouts with bounded folds and full text equivalents · src/projections/studio/diagrams/svg.ts:73 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-evidence-lens · names the four evidence sources and what would bring each into the Studio · src/projections/studio/pages/evidence-page.ts:3 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-recipes · evaluates shipped recipe bodies once and shares answers between Studio pages · src/projections/studio/recipes.ts:34 · role service · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-tests-lens · renders shared rule and example-space coverage with filters and verifier bindings · src/projections/studio/pages/tests-page.ts:34 · role projection · component component:protocol.projections · layer edge · context protocol
Verifier binding: none
Expected-outcome oracle: none
Runtime observation: not tracked.
Run results: not recorded in the graph.
Findings
None.
53. The engine lays out every Studio diagram as static SVG when the page set is built
spec:decisions.studio-diagram-renderer
The engine lays out every Studio diagram as static SVG when the page set is built
spec:decisions.studio-diagram-rendererDecision Record · storyreadyfloor ready
No open questions and no blocking questions; implementation binding none, verifier binding none, and expected-outcome oracle none.
Intent
outcome
Give the Studio diagrams that a reader with only a link reads without script, that two builds of one graph draw byte for byte, and that need no layout code in the page.
Decision
context
The Studio's pages read in full without script and open from file://, two builds of one graph write the same bytes, and the custom-elements decision admits a framework runtime only through a decision that refines it. The architecture lens, a component's members, a Spec's relations and the code that realizes a Spec all need a drawing. A prototype over the Protocol's own components and the first adopter's, read through sdp q, measured how large those drawings are (reviews/assets/plan46-prototypes/studio-diagrams/).
decision
The engine lays out every Studio diagram at build time with its own deterministic layered layout and writes it into the page as inline SVG followed by a text equivalent. The custom element that holds a diagram adds only pan, zoom and pinch, by changing the SVG's view box. One diagram draws at most the bound spec:consumers.spec-studio.diagrams#design.bound names, and above it the diagram folds, by context and then by layer, as that Spec states.
rationale
Inline SVG reads without script, prints, survives the Pack export and opens from file://, so the page carries no layout code and the element stays small.
A layout computed from graph values, with no font, clock or random value, draws the same bytes from the same graph, which the Studio's reproducibility rule and --check-clean need.
The bound sits between what the two corpora need and what a page reads well: in the prototype the largest real drawing is the Protocol's thirty-five-box member diagram, and a synthetic sixty-two-component drawing spanned about two and a half screen widths unfolded; nothing between forty and sixty-two boxes was measured, and the edge bound is headroom over the thirty-nine edges the largest real diagram draws.
alternatives
Mermaid rendered in the page needs its script and a runtime of several hundred kilobytes, lays out differently per browser, and shows nothing without script; the shipped Mermaid projection stays frozen for its own readers.
A layout library such as ELK or Dagre run at build time adds a dependency whose version moves the bytes, while the Studio's diagrams need only labelled bands and a grid.
Drawing on a canvas from embedded data puts the diagram out of reach of a screen reader, of print and of a reader without script.
consequences
The engine owns a small layout module and its tests; the layout's look is judged in review, and its determinism and fold by test.
The text equivalent states every box and edge, so a diagram is never the only way to read what it shows.
A change to the layout moves the Studio's bytes like any other rendering change, and --check-clean catches one nobody intended.
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.studio-diagram-rendererThe diagram as text
spec:decisions.studio-diagram-renderer: The engine lays out every Studio diagram as static SVG when the page set is built · declared Spec
spec:decisions.studio-web-components: The Studio is built from custom elements, not a framework · declared Spec
impl:protocol.studio-diagram-element: adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · anchored code · src/studio-elements/diagram.ts:23
impl:protocol.studio-diagrams: deterministic grid and band layouts with bounded folds and full text equivalents · anchored code · src/projections/studio/diagrams/svg.ts:73
spec:decisions.studio-diagram-renderer refines spec:decisions.studio-web-components · declared — narrows how an element that shows a diagram renders it; the element only enhances an SVG the build drew
spec:decisions.studio-diagram-renderer dependsOn spec:extraction.determinism · declared — a diagram laid out from graph values alone keeps one graph to one set of bytes
spec:decisions.studio-diagram-renderer refines spec:decisions.studio-web-components · declared — narrows how an element that shows a diagram renders it; the element only enhances an SVG the build drew
spec:consumers.spec-studio.diagram-kinds decidedBy spec:decisions.studio-diagram-renderer · declared — every new kind is laid out by the engine at build time as the renderer decision rules
impl:protocol.studio-diagram-element · adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · src/studio-elements/diagram.ts:23 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-diagrams · deterministic grid and band layouts with bounded folds and full text equivalents · src/projections/studio/diagrams/svg.ts:73 · role projection · component component:protocol.projections · layer edge · context protocol
Verifier binding: none
Expected-outcome oracle: none
Runtime observation: not tracked.
Run results: not recorded in the graph.
Findings
None.
54. A diagram is laid out from graph values into SVG with a text equivalent
spec:consumers.spec-studio.diagrams
A diagram is laid out from graph values into SVG with a text equivalent
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
Every Studio diagram is laid out in the engine when the page set is built, so a page draws it with no script and the same inputs draw the same bytes. The architecture grid, component members and one-hop trace retain their readings; the Spec page's requirement drawing replaces realization, and other pages name their supplied drawing answers. Words carry every reading the picture shows, and its text equivalent states every box and edge.
Intent
outcome
Draw the Studio's diagrams as inline SVG that reads without script, prints, and stays the same bytes for the same graph, with every box and edge also stated in words.
The build lays out each diagram and writes it into its page as inline SVG; no diagram is laid out in the browser, and a page draws every diagram with no script.
A layout reads only the boxes, each with its id, words and supplied grouping, and edges, each with its two ends, exact kind and claim, optional reason and aggregation count, taken from the reader values and recipe answers its page names; it reads no font, file, clock or random value, measures text by character count and writes whole-pixel coordinates. Depth, reach and component resolution belong to those answers, never layout.
The architecture diagram places each component in the column of its recorded context, contexts in code-unit order and then a column for components that state none, and in the band of its layer, in the order edge, application, domain, adapter, infrastructure, then a band for components that state none; a cell holds its components in id order.
An architecture edge joins two components and carries the count of unit uses edges between them, as the component rows of spec:consumers.spec-studio.lenses.architecture#design.componentRows count them: each end of a unit uses edge resolves to its component, directly or through memberOf, and a use within one component draws nothing.
A trace graph draws the Spec in a band of its own, the Specs its declared relations name above it in one band per relation type, in the order refines, dependsOn, constrainedBy, decidedBy, verifies, supersedes, and the Specs whose declared relations name it below in bands of the same order; a Spec related more than one way sits in the band of its first relation, and each relation is its own edge.
A member diagram draws a component's members in bands by how deep uses among members reaches, a member that uses another sitting above it, and the units and components outside the component that members use in a last band of their own.
An architecture diagram over the bound with more than one context draws one box per context, with the uses between contexts aggregated and counted, and then each context's own diagram in a section of its own, where every other context it uses or is used by is one folded box in a band of its own.
A drawing still over the bound after these folds, the context overview, one context's diagram or one layer's, writes no SVG; its text equivalent lists every box and edge the drawing would hold and then says the drawing was omitted because it exceeds the bound.
A trace graph over the bound folds its largest relation group first, ties broken by direction and then by relation type, into one box that names the count and the relation and links to the Spec page's relations, until the drawing fits.
A member diagram over the bound writes no SVG; its text equivalent lists every member and every use edge, and then says the drawing was omitted because it exceeds the bound.
Every reading a fill, outline or line style marks is also in words: bands and columns carry labels, a planned component reads planned, a folded box reads folded, and an aggregated edge's count is in its text equivalent. A drawing whose edges all have one relation names it once in its legend and draws no edge label; solid uses and dashed plans to use share the use relation, with the planned wording also in the legend. A drawing with several relations keeps its labelled bands and edge labels.
Each diagram is followed by its text equivalent, which states every box with its words and every edge as a sentence naming its two ends and its kind, and the SVG names it as its description.
The diagram element adds only pan, zoom and pinch by changing the SVG's view box; it never moves a box or edge. At viewport widths of at least 720 CSS pixels the SVG starts at natural size inside a keyboard-accessible scroll region, with overflow inside the figure. Below that width the responsive contract fits the same drawing to the screen. Reset restores the initial view and scroll position. Without script the drawing, scrolling, links and text equivalent remain usable. Print fits the drawing to paper and exposes its text equivalent.
Given an architecture of {components: 45} components spread over {contexts: 3} contexts and {layers: 5} layers, with {edges: 0} uses edges between components
When the build lays the architecture diagram out twice
Then the two drawings are byte-identical: {identical: true}
Then the diagram folds by {fold: "context"}
Then the first drawing holds {drawn: 3} boxes
Then its text equivalent names {named: 3} boxes and edges
Given an architecture of {components: 50} components spread over {contexts: 1} contexts and {layers: 5} layers, with {edges: 0} uses edges between components
When the build lays the architecture diagram out twice
Then the two drawings are byte-identical: {identical: true}
Then the diagram folds by {fold: "layer"}
Then the first drawing holds {drawn: 5} boxes
Then its text equivalent names {named: 5} boxes and edges
Given an architecture of {components: 12} components spread over {contexts: 3} contexts and {layers: 4} layers, with {edges: 20} uses edges between components
When the build lays the architecture diagram out twice
Then the two drawings are byte-identical: {identical: true}
Then the diagram folds by {fold: "nothing"}
Then the first drawing holds {drawn: 12} boxes
Then its text equivalent names {named: 32} boxes and edges
Given an architecture of {components:number} components spread over {contexts:number} contexts and {layers:number} layers, with {edges:number} uses edges between components
When the build lays the architecture diagram out twice
Then the two drawings are byte-identical: {identical:boolean}
Then the diagram folds by {fold:"nothing"|"context"|"layer"}
Then the first drawing holds {drawn:number} boxes
Then its text equivalent names {named:number} boxes and edges
For requirement, trace, capability and dependency drawings, trigger the existing folds before the hard bound when deterministic layout height exceeds 2000 logical pixels. Measure height from the box and lane layout before routing, using the same label metrics and width budget as the drawing. A fold triggered by these limits must strictly lower that height and hold at least two boxes, keeping the same scope, claims and complete text equivalent. If no lawful fold fits the height budget, omit the SVG and open the text equivalent.
A title or recorded label leads at fourteen pixels, followed by the displayed id at twelve pixels and remaining words such as a component's member count. Title lines hold at most 28 characters and id lines 30, with an eight-pixel character advance. Wrap at spaces or id punctuation, then by code point, and calculate box height from every line.
Wrap a cell's boxes within the fixed logical width budget instead of a fixed box count; retain context columns with local scrolling when they exceed it. Layout reads no browser or font measurement.
880 logical pixels for a band or grid, band labels included above their band; 264 per context cell when several contexts share a grid, the full band budget when only one context is shown, and 24 between boxes. Routing gutters may widen the SVG to preserve distinct lanes. A drawing wider than 880 scrolls inside its figure and receives the build-written instruction Scroll horizontally to read the whole drawing.
Drop the namespace and leading dotted segments every id in the figure shares, marking elision with …; keep more segments on collisions. A displayed id carries a namespace only when shown in full. Full ids remain in link titles, the text equivalent and source.
Reserve boxes and labels as obstacles, route orthogonally with distinct ports and lanes eight pixels apart, and never share a collinear segment or overlap labels. Crossings are permitted only at free points. Keep exact relations and claims through the words-beside-style rule. A deterministic finite routing failure omits the SVG, opens its text equivalent and explains the failure; the build owns search mechanics.
uses for a realized use, drawn solid; plans to use for a use a component design states, drawn dashed; on a trace graph the relation's type; an arrow points from the unit or Spec that uses or declares to the one it names.
the svg carries role="img", a title, aria-describedby naming its text equivalent and a viewBox of its own size; a box is a g with class node and data-id, plus data-planned="true" or data-folded="true" when it is planned or folded, holding a link to the box's target; an edge is a g with class edge, data-from, data-to and data-kind; a band is a g with class band and data-label, a column a g with class lane and data-label, each also drawing its label as text. An edge also carries data-claim and a stable data-edge-key when its label uses a legend key; route and label coordinates are presentation values and mint no graph edge.
a component's box links to its detail on the architecture lens, a planned component's to its component design's Spec page, a context's or layer's folded box to its section on the same page, a Spec's to its page, and a folded relation group's to the Spec page's relations.
a details element closed by default, summary The diagram as text, holding one li per box, <id>: <words>, followed by · folded members: <ids> when folded identities are present, and then one li per edge, <from> <kind> <to>, followed by · <claim> when present, (<n> unit edges) when the edge aggregates more than one, and — <reason> when present.
sdp-diagram with subject, the rooted Spec, Pack, component or context id, or architecture, wraps one figure containing its caption and legend, any build-written scroll instruction, a keyboard-focusable named .diagram-scroll region containing the SVG, its text equivalent and, when offered, its closed Mermaid-source disclosure with labelled read-only textarea and sdp-copy. Caption, legend and source stay outside the scroll region. On upgrade it adds Zoom in, Zoom out and Reset buttons and handles drag, a wheel with Control or Command held, and pinch; it adds no layout or copy behavior.
a diagram's text equivalent has the id diagram.<subject>.text and its arrow has the id diagram.<subject>.arrow. A page that draws a second view of one subject inserts that view's name before text or arrow, so the Spec page's realization drawing uses diagram.<subject>.realization.text and diagram.<subject>.realization.arrow; its trace graph keeps the unqualified ids. Every id is unique on its page.
A drawing over the bound keeps its figure and caption, writes Shown as text: this drawing exceeds the bound of <b> boxes and <e> edges., and opens its text equivalent. A routing failure instead writes Shown as text: a distinct route or label could not be placed within the routing budget. and opens the same complete box-and-edge reading. A drawing still above the height budget after lawful folds instead writes Shown as text: this drawing exceeds the height budget of <h> pixels after folding. and opens its text equivalent. No omission offers partial Mermaid source.
spec:consumers.spec-studio.diagrams.within-bound · An architecture within the bound draws in one diagram, the same bytes twice · declared · example enabled · specs/consumers/spec-studio.diagrams.within-bound.sdp.md
test:protocol.studio-diagram-core · anchored · test anchor binding present · test/studio-diagram-core.test.ts:37
Example space
components · number · declared by an architecture of {components} components spread over {contexts} contexts and {layers} layers, with {edges} uses edges between components
contexts · number · declared by an architecture of {components} components spread over {contexts} contexts and {layers} layers, with {edges} uses edges between components
layers · number · declared by an architecture of {components} components spread over {contexts} contexts and {layers} layers, with {edges} uses edges between components
edges · number · declared by an architecture of {components} components spread over {contexts} contexts and {layers} layers, with {edges} uses edges between components
Requirement drawing for spec:consumers.spec-studio.diagrams
E8: refines, verifies · declared (3 per relation)
The diagram as text
spec:consumers.spec-studio.diagrams: A diagram is laid out from graph values into SVG with a text equivalent · declared Spec
spec:consumers.spec-studio.diagram-kinds: The Studio chooses diagram kinds from graph values · declared Spec
spec:consumers.spec-studio.diagram-kinds.edge-routing: Edges route around boxes with deterministic orthogonal paths · declared Spec
spec:consumers.spec-studio.diagram-kinds.legibility: A diagram preserves readable labels before zoom · declared Spec
spec:consumers.spec-studio.diagrams.folds-by-context: An architecture over the bound folds by context · declared Spec
spec:consumers.spec-studio.diagrams.folds-by-layer: One context over the bound folds by layer · declared Spec
spec:consumers.spec-studio.diagrams.within-bound: An architecture within the bound draws in one diagram, the same bytes twice · declared Spec
spec:consumers.spec-studio.diagram-kinds.capability-tree: A refinement drawing follows the capability map · declared Spec
spec:consumers.spec-studio.diagram-kinds.dependency: A dependency drawing shows the declared footing of a Spec set · declared Spec
spec:consumers.spec-studio.diagram-kinds.maturity-picture: The maturity map is drawn as a grid of counts · declared Spec
spec:consumers.spec-studio.diagram-kinds.mermaid-source: A diagram offers Mermaid source as copyable text · declared Spec
spec:consumers.spec-studio.diagram-kinds.requirement-trace: A requirement drawing separates intent from realization and verification · declared Spec
spec:consumers.spec-studio.diagram-kinds.scoped-architecture: A Spec set draws the architecture it touches · declared Spec
spec:consumers.spec-studio.components: The Studio's custom elements each hold one view the build renders · declared Spec
impl:protocol.studio-architecture-diagrams: architecture grids and bounded context and layer folds · anchored code · src/projections/studio/diagrams/architecture.ts:4
impl:protocol.studio-architecture-lens: renders recipe component rows and planned designs as architecture and member diagrams · anchored code · src/projections/studio/pages/architecture-page.ts:50
impl:protocol.studio-capability-diagrams: places refinement occurrences and bounded branches from the capability map · anchored code · src/projections/studio/diagrams/capability.ts:101
impl:protocol.studio-diagram-element: adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · anchored code · src/studio-elements/diagram.ts:23
impl:protocol.studio-diagram-layout: title-first box placement, wrapping and band sizing for desktop and phone · anchored code · src/projections/studio/diagrams/layout.ts:140
impl:protocol.studio-diagram-routing: port, channel and overflow-rail edge routes around boxes and labels · anchored code · src/projections/studio/diagrams/routing.ts:38
impl:protocol.studio-diagram-source: escaped Mermaid flowchart and mindmap source in placed box order · anchored code · src/projections/studio/diagrams/mermaid.ts:13
impl:protocol.studio-diagrams: deterministic grid and band layouts with bounded folds and full text equivalents · anchored code · src/projections/studio/diagrams/svg.ts:73
impl:protocol.studio-maturity-map: places resolved Pack members by their stated rung and floor in authored order · anchored code · src/projections/studio/pages/maturity-map.ts:7
impl:protocol.studio-relation-diagrams: relation and member bands and bounded relation folds · anchored code · src/projections/studio/diagrams/bands.ts:10
impl:protocol.studio-requirement-diagram: folds requirement bindings by relation direction and claim and serializes exact relations · anchored code · src/projections/studio/diagrams/requirement.ts:12
impl:protocol.studio-slice-architecture: selected component grid with distinct planned identities and complete unit edges · anchored code · src/projections/studio/diagrams/slice.ts:219
impl:protocol.studio-slice-dependencies: supplied depth bands with protected boundary boxes and lossless text · anchored code · src/projections/studio/diagrams/slice.ts:10
spec:consumers.spec-studio.diagram-kinds.edge-routing refines spec:consumers.spec-studio.diagram-kinds · declared — arrows that cover no label serve the readable drawings the diagram kinds state
spec:consumers.spec-studio.diagram-kinds.legibility refines spec:consumers.spec-studio.diagram-kinds · declared — readable labels are part of the outcome the diagram kinds state
The engine lays out every Studio diagram at build time with its own deterministic layered layout and writes it into the page as inline SVG followed by a text equivalent. The custom element that holds a diagram adds only pan, zoom and pinch, by changing the SVG's view box. One diagram draws at most the bound spec:consumers.spec-studio.diagrams#design.bound names, and above it the diagram folds, by context and then by layer, as that Spec states.
impl:protocol.studio-diagram-element · adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · src/studio-elements/diagram.ts:23
impl:protocol.studio-diagrams · deterministic grid and band layouts with bounded folds and full text equivalents · src/projections/studio/diagrams/svg.ts:73
spec:consumers.spec-studio.diagrams dependsOn spec:consumers.spec-studio.data · declared — a diagram is laid out from the values and recipe answers its page renders
spec:consumers.spec-studio.diagrams dependsOn spec:decisions.architectural-annotation · declared — the architecture grid reads the layer and context a component anchor states
spec:consumers.spec-studio.lenses.architecture dependsOn spec:consumers.spec-studio.diagrams · declared — the lens's drawings are the architecture grid and the member diagrams
spec:consumers.spec-studio.slice-page dependsOn spec:consumers.spec-studio.diagrams · declared — both drawings keep the diagram contract, bound and text equivalent included
spec:consumers.spec-studio.spec-page dependsOn spec:consumers.spec-studio.diagrams · declared — the design view and impact panel draw requirement traceability and the one-hop trace graph
impl:protocol.studio-diagrams · deterministic grid and band layouts with bounded folds and full text equivalents · src/projections/studio/diagrams/svg.ts:73 · role projection · component component:protocol.projections · layer edge · context protocol
impl:protocol.studio-relation-diagrams · relation and member bands and bounded relation folds · src/projections/studio/diagrams/bands.ts:10 · role projection · component component:protocol.projections · layer edge · context protocol
spec:consumers.spec-studio.diagrams.within-bound · An architecture within the bound draws in one diagram, the same bytes twice · declared · specs/consumers/spec-studio.diagrams.within-bound.sdp.md · example enabled
test:protocol.studio-diagram-core · anchored · test/studio-diagram-core.test.ts:37 · test anchor
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the grid, the text equivalent and determinism on an architecture that fits one drawing.
assumptions
The world builds the layout's input directly: the components are named component:probe.c01 and on, assigned in turn to the first contexts in code-unit order and the first layers in the closed order, and the uses edges join distinct component pairs taken in id order until the count is reached. It lays the input out twice through the engine's layout and compares the two SVG strings.
Behavior
Examples
Given an architecture of {components: 12} components spread over {contexts: 3} contexts and {layers: 4} layers, with {edges: 20} uses edges between components
When the build lays the architecture diagram out twice
Then the two drawings are byte-identical: {identical: true}
Then the diagram folds by {fold: "nothing"}
Then the first drawing holds {drawn: 12} boxes
Then its text equivalent names {named: 32} boxes and edges
Verification
Verifier bindings
test:protocol.studio-diagram-within-bound · anchored · test anchor binding present · test/studio-s1.test.ts:669
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.diagrams.within-boundThe diagram as text
spec:consumers.spec-studio.diagrams.within-bound: An architecture within the bound draws in one diagram, the same bytes twice · declared Spec
spec:consumers.spec-studio.diagrams: A diagram is laid out from graph values into SVG with a text equivalent · declared Spec
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the fold by context on an architecture too large for one drawing whose contexts each fit.
assumptions
The world builds the layout's input as the within-bound example does, with no uses edge, so each of the three contexts holds fifteen components and draws in a section of its own within the bound.
Behavior
Examples
Given an architecture of {components: 45} components spread over {contexts: 3} contexts and {layers: 5} layers, with {edges: 0} uses edges between components
When the build lays the architecture diagram out twice
Then the two drawings are byte-identical: {identical: true}
Then the diagram folds by {fold: "context"}
Then the first drawing holds {drawn: 3} boxes
Then its text equivalent names {named: 3} boxes and edges
Verification
Verifier bindings
test:protocol.studio-diagram-folds-context · anchored · test anchor binding present · test/studio-s1.test.ts:675
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.diagrams.folds-by-contextThe diagram as text
spec:consumers.spec-studio.diagrams.folds-by-context: An architecture over the bound folds by context · declared Spec
spec:consumers.spec-studio.diagrams: A diagram is laid out from graph values into SVG with a text equivalent · declared Spec
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the fold by layer on an architecture whose one context is too large for one drawing.
assumptions
The world builds the layout's input as the within-bound example does, with every component in one context and no uses edge, so each of the five layers holds ten components and draws in a section of its own within the bound.
Behavior
Examples
Given an architecture of {components: 50} components spread over {contexts: 1} contexts and {layers: 5} layers, with {edges: 0} uses edges between components
When the build lays the architecture diagram out twice
Then the two drawings are byte-identical: {identical: true}
Then the diagram folds by {fold: "layer"}
Then the first drawing holds {drawn: 5} boxes
Then its text equivalent names {named: 5} boxes and edges
Verification
Verifier bindings
test:protocol.studio-diagram-folds-layer · anchored · test anchor binding present · test/studio-s1.test.ts:681
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.diagrams.folds-by-layerThe diagram as text
spec:consumers.spec-studio.diagrams.folds-by-layer: One context over the bound folds by layer · declared Spec
spec:consumers.spec-studio.diagrams: A diagram is laid out from graph values into SVG with a text equivalent · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The build renders every page whole, so these elements add behavior to markup that is already there rather than rendering views of their own. A browser refuses a module script on a page opened through file://, so they ship as one classic script.
Intent
outcome
Give the Studio's pages their few interactions through custom elements that enhance markup the build wrote, so a page with its script filters, searches and copies, and every page but the search page still reads in full without it.
The elements ship in one classic script, assets/studio.js, with no module syntax and nothing loaded at run time; the build bundles it from the package's source, with the concept matcher.
Each element enhances markup the build wrote and renders no graph value of its own, except that the search results element renders values from the search index its page embeds.
sdp-search with page-root, the relative path from its page to the page-set root: wraps the search field's form and, on submit, opens <page-root>search.html#q=<term> with the term percent-encoded.
sdp-search-results: on the search page, reads the index from the sdp-data element, matches the fragment's term and each term the person types, writes the results spec:consumers.spec-studio.search designs, and keeps the term in the fragment.
sdp-filter: wraps a hidden form of labelled select elements, each with data-filter="<name>" and an any option, and the rows marked data-row. On upgrade it shows the form, hides each row whose data-<name> differs from a chosen value, and writes <shown> of <total> shown in its output element; a row whose attribute holds several space-separated values, such as its Packs, matches when one of them equals the choice. When a followed link or a fragment change targets an element inside a row it hides, it returns every control to any, adds to its output that the filter was cleared to show that target, and scrolls the target into view.
sdp-expander: adds Open all and Close all buttons for the details elements inside it, and on load and on each fragment change opens every details that holds the fragment's target and scrolls the target into view.
sdp-copy with text, or with for naming a text area on its page: a Copy button whose accessible name includes the text or the text area's label; it copies that text and says Copied, and where the clipboard is unavailable it selects the text so the person can copy it.
sdp-stamp with page-root: served over http or https, it requests <page-root>stamp.json and, when it loads, shows its corpus commit, engine and build time as text; otherwise it shows nothing.
no citation recorded
Verification
Verifier bindings
test:protocol.studio-copy-source · anchored · test anchor binding present · test/studio-diagram-core.test.ts:191
test:protocol.studio-page-elements · anchored · test anchor binding present · test/studio-elements.test.ts:26
Design view
Requirement drawing
Declared verifying examples: no declared verifying example.
Requirement drawing for spec:consumers.spec-studio.page-elementsThe diagram as text
spec:consumers.spec-studio.page-elements: A few custom elements filter, search, open and copy on a rendered page · declared Spec
spec:consumers.spec-studio.components: The Studio's custom elements each hold one view the build renders · declared Spec
component:protocol.studio-elements · optional browser behavior and proposal handoff · src/studio-elements/index.ts:13 · role interaction · layer edge · context protocol
impl:protocol.studio-copy · copies text with selection fallback and failure feedback · src/studio-elements/copy.ts:22 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-expander · opens fragment ancestors and expands disclosures for print · src/studio-elements/expander.ts:16 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-filter · filters build-rendered rows through their recorded attributes · src/studio-elements/filter.ts:25 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-search-form · routes search forms through page-root URLs and fragments · src/studio-elements/search.ts:18 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-search-results · ranks and renders concept, entry and file search hits · src/studio-elements/search-results.ts:95 · role projection · component component:protocol.studio-elements · layer edge · context protocol
impl:protocol.studio-stamp · resolves published stamps and source links in the browser · src/studio-elements/stamp.ts:30 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
Design reference: none
Verifier binding: present
test:protocol.studio-copy-source · anchored · test/studio-diagram-core.test.ts:191 · test anchor
test:protocol.studio-page-elements · anchored · test/studio-elements.test.ts:26 · test anchor
Expected-outcome oracle: none
Runtime observation: not tracked.
Run results: not recorded in the graph.
Findings
None.
59. The Studio reads on a phone as on a desktop
spec:consumers.spec-studio.responsive
The Studio reads on a phone as on a desktop
spec:consumers.spec-studio.responsiveUse Case / Behavior · storyreadyfloor ready
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The curated graph's edges carry no confidence, and the impact graph's inferred imports stay outside it, so a diagram never drops an edge for a low score; a trace graph draws one hop at every width, and a narrow screen scales the drawing rather than cutting it.
Intent
actor
A person reviewing a design on a phone, including a pull request reviewer who holds only a link.
outcome
Let a design be reviewed on a phone through the same pages a desktop shows.
Every page of the Studio is responsive, so the same pages serve a desktop and a phone.
1 unkeyed rule.
Example space
Given a Studio page whose layout holds {wideColumns:number} columns
When the page is shown {width:number} pixels wide
Then the layout holds {columns:number} columns
every layout collapses to one column below 720 CSS pixels of viewport width; at 390 CSS pixels no page exceeds the viewport. The top navigation and stamp line wrap, and a table wider than its column scrolls inside its own container, including maturity maps, run results and coverage tables; queue rows wrap within their column.
below the same width a diagram opens scaled to the screen's width, with its zoom controls above it and its text equivalent below it, and draws the same boxes and edges a desktop draws.
Verification
Verifier bindings
test:protocol.studio-intent-handoff · anchored · test anchor binding present · test/studio-s5.test.ts:407
Example space
wideColumns · number · declared by a Studio page whose layout holds {wideColumns} columns
width · number · declared by the page is shown {width} pixels wide
Bound points
No bound example points recorded.
Oracle binding: none
Coverage
wideColumns: No bound values · not enumerable
width: No bound values · not enumerable
Unbound
wideColumns: None
width: None
Design view
Requirement drawing
Declared verifying examples: no declared verifying example.
Requirement drawing for spec:consumers.spec-studio.responsiveThe diagram as text
spec:consumers.spec-studio.responsive: The Studio reads on a phone as on a desktop · declared Spec
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph · declared Spec
impl:protocol.studio-diagram-element: adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · anchored code · src/studio-elements/diagram.ts:23
impl:protocol.studio-frame: renders Studio navigation, page rails and composing controls · anchored code · src/projections/studio/pages/frame.ts:6
component:protocol.reader · the typed graph contract and body evaluator · src/reader/reader.ts:671 · layer application · context protocol
impl:protocol.studio-diagram-element · adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · src/studio-elements/diagram.ts:23
spec:consumers.spec-studio.shell dependsOn spec:consumers.spec-studio.responsive · declared — the rail moves below the canvas under the phone breakpoint
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
A design is sent and archived as well as browsed: attached to a message, handed to someone outside the repository, printed for a review meeting. Every build writes each Pack as one self-contained HTML file inside the page set, so a reader with only a link downloads it from the Pack page, and the file opens anywhere with nothing beside it. Every page also prints as a document.
Intent
outcome
Let a person take a Pack's whole design away as one file that opens anywhere, and print any page as a readable document.
An export is one HTML file that loads nothing: its style is inline, it carries no script, and every diagram in it is inline SVG, so it opens from any folder or as an attachment with no other file.
An export holds the Pack page's content and then each member's Spec page content in authored order, every disclosure written open; it leaves out the navigation, the rail, the search field, the stamp line, the composing panel and every control that needs the script.
Inside an export, a link to the Pack or to a member points at its section in the file, a link to an element of the Pack page or of a member's page points at that element in the file, and a link to anything else becomes its id as text, so no link leaves the file.
Within an export, every element id copied from the Pack page takes the prefix pack/ and every id copied from a member's page the prefix <Spec id>/, while each member's section keeps its Spec id as its own id; every fragment link and every attribute that names an element id, such as aria-describedby or a label's for, is rewritten to the prefixed id, so no two elements in the file share an id.
Every page prints as a document: the print style hides the navigation, the rail, the search field, the composing panel and every control, gives the canvas the page's width, prints a diagram whole at that width, and prints every disclosure open except Mermaid source, which prints only when the reader opened it, the expander opening each before printing and restoring it after.
Given a Pack of {members: 3} member Specs, one of which names a Spec outside the Pack
When the build writes the Pack's export file
Then the export loads {loads: 0} other files
Then the export holds {scripts: 0} script elements
Then every link in the export points inside it or is text: {linksInside: true}
Then no two elements in the export share an id: {idsUnique: true}
Then the export holds {sections: 3} member sections
Given a Pack of {members:number} member Specs, one of which names a Spec outside the Pack
When the build writes the Pack's export file
Then the export loads {loads:number} other files
Then the export holds {scripts:number} script elements
Then every link in the export points inside it or is text: {linksInside:boolean}
Then no two elements in the export share an id: {idsUnique:boolean}
Then the export holds {sections:number} member sections
a copied id is written pack/<id> for the Pack page and <Spec id>/<id> for a member's page, so a member's section.behavior becomes its Spec id, a slash and section.behavior; the slash appears in no graph id, so a prefixed id never equals a member's section id or another prefixed id.
sdp-expander, before the page prints, opens every details inside it except a drawing's or the maturity map's Mermaid source, which keeps the state the reader left, and after printing restores each one's state.
each member's section has its Spec id as its element id and opens with the member's position, title and id.
Verification
Verifier bindings
spec:consumers.spec-studio.export.self-contained · A Pack's export opens alone and keeps its links inside it · declared · example enabled · specs/consumers/spec-studio.export.self-contained.sdp.md
test:protocol.studio-intent-handoff · anchored · test anchor binding present · test/studio-s5.test.ts:407
Example space
members · number · declared by a Pack of {members} member Specs, one of which names a Spec outside the Pack
Requirement drawing for spec:consumers.spec-studio.exportThe diagram as text
spec:consumers.spec-studio.export: A Pack exports as one file, and every page prints as a document · declared Spec
spec:consumers.spec-studio.export.self-contained: A Pack's export opens alone and keeps its links inside it · declared Spec
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph · declared Spec
impl:protocol.studio-diagram-element: adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · anchored code · src/studio-elements/diagram.ts:23
impl:protocol.studio-expander: opens fragment ancestors and expands disclosures for print · anchored code · src/studio-elements/expander.ts:16
impl:protocol.studio-pack-export: copies rendered canvas content into one inline-styled document with prefixed element references · anchored code · src/projections/studio/pages/export-page.ts:35
component:protocol.reader · the typed graph contract and body evaluator · src/reader/reader.ts:671 · layer application · context protocol
impl:protocol.studio-diagram-element · adds view-box pan, zoom and pinch to build-rendered SVG without changing its layout · src/studio-elements/diagram.ts:23
impl:protocol.studio-pack-export · copies rendered canvas content into one inline-styled document with prefixed element references · src/projections/studio/pages/export-page.ts:35
spec:consumers.spec-studio.export dependsOn spec:consumers.spec-studio.pack-page · declared — an export opens with its Pack page's content
spec:consumers.spec-studio.export dependsOn spec:consumers.spec-studio.publisher · declared — the export files are part of the page set the publisher writes
spec:consumers.spec-studio.export dependsOn spec:consumers.spec-studio.spec-page · declared — an export holds each member's Spec page content
spec:consumers.spec-studio.export.self-contained · A Pack's export opens alone and keeps its links inside it · declared · specs/consumers/spec-studio.export.self-contained.sdp.md · example enabled
test:protocol.studio-intent-handoff · anchored · test/studio-s5.test.ts:407 · test anchor
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the export's self-containment on a Pack whose member names a Spec outside it.
assumptions
The world writes a root with one Pack of three member Specs and one further Spec outside the Pack that the first member names through dependsOn, builds the page set, and reads the one export file: it counts the link, img, iframe and script elements with a src or href reaching another file, the script elements of any kind, and the member sections, checks that every a element's href is a fragment the file holds, and collects every element id in the file to check that none repeats.
Behavior
Examples
Given a Pack of {members: 3} member Specs, one of which names a Spec outside the Pack
When the build writes the Pack's export file
Then the export loads {loads: 0} other files
Then the export holds {scripts: 0} script elements
Then every link in the export points inside it or is text: {linksInside: true}
Then no two elements in the export share an id: {idsUnique: true}
Then the export holds {sections: 3} member sections
Verification
Verifier bindings
test:protocol.studio-export-contained · anchored · test anchor binding present · test/studio-s5.test.ts:312
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.export.self-containedThe diagram as text
spec:consumers.spec-studio.export.self-contained: A Pack's export opens alone and keeps its links inside it · declared Spec
spec:consumers.spec-studio.export: A Pack exports as one file, and every page prints as a document · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
A page set is a function of the graph and its named inputs, so it carries no commit or time. A reviewer opening a preview still needs to know which commit and which engine built it, so a publishing step that runs after the build writes one stamp file at the page set's root, and the shell shows it where the set is served over http or https. The same stamp may name where the repository's source is served, so a recorded file and line become a link in a preview and stay text everywhere else. A reusable workflow does the build, the stamp and the upload for every pull request, and deploys a preview only where the repository has chosen a host. Checks and previews use GitHub's default pull-request merge checkout, so the gate proves the merge result and the run evidence, page set and stamp name that same commit.
A stakeholder opens the link, navigates the Studio and composes intent, and the pull request's author hands that intent to an agent that edits the source.
Intent
outcome
Let a stakeholder open the Studio of a pull request from a link, and let its author know which graph and which build the stakeholder read.
The Studio's build writes no stamp, so every page and data file it writes stays a function of the graph and its named inputs; the stamp is written apart, after the build.
sdp stamp [root] [--commit SHA] [--source TEMPLATE] writes stamp.json into <root>/generated/spec-studio/ and touches no other file: it derives no graph, renders no page, and refuses with exit 1 when the root holds no page set; a stamp without --commit names the commit unknown.
Publishing a preview and writing its stamp are a step the adopter's CI runs, never the Studio's build; the shell reads the stamp as spec:consumers.spec-studio.shell#rule.stamp states.
The package's repository ships a reusable GitHub Actions workflow that, on a pull request, installs the caller's dependencies, runs sdp studio with the caller's root, exclusions and inputs, runs sdp stamp with the checked-out merge commit and the repository's source template, and uploads the page set as a CI artifact; it opens no pull request, writes no comment and holds no credential beyond the run's own token.
The workflow deploys the stamped page set under /preview/<pr-number>/ only when the caller asks for it and the repository serves a host from the branch the workflow writes to; a pull request from a fork never deploys.
A deploy that pushes a preview succeeds only once the host has built the commit it pushed; a host build that errors, or does not finish within the wait, fails the job, so a green deploy means the preview is live.
Every recorded file and line a page shows as text carries its file and line as data on its element, and when a loaded stamp names a source template the stamp element links each to the template with the file and line filled in; without such a stamp, or through file://, each stays text.
Given a page set the studio command wrote at an extraction root
When the stamp command runs with the commit {commit: "0123abc"} and the source template {source: "https://example.test/blob/0123abc/{file}#L{line}"}
Then the stamp names the corpus commit {corpusCommit: "0123abc"}
Then every page file stays byte-identical: {pagesUntouched: true}
Then a later studio run keeps the stamp: {stampSurvives: false}
Given a page set the studio command wrote at an extraction root
When the stamp command runs with the commit {commit:string} and the source template {source:string}
Then the stamp names the corpus commit {corpusCommit:string}
Then every page file stays byte-identical: {pagesUntouched:boolean}
Then a later studio run keeps the stamp: {stampSurvives:boolean}
{ schemaVersion: string; corpusCommit: string; engine: string; builtAt: string; source?: string } in stamp.json at the page set's root, written by sdp stamp and never by the Studio's build: the graph schema version of the stamping engine, the commit --commit names or unknown, the engine sdp --version names, the time the step ran as an ISO 8601 UTC timestamp to the second, and the source template --source names, when given.
a URL holding {file} and optionally {line}, such as https://github.com/<owner>/<repo>/blob/<commit>/{file}#L{line}, into which the shell writes a recorded root-relative file and its line; sdp stamp refuses a template without {file}.
.github/workflows/studio-preview.yml, triggered by workflow_call and called as uses: libar-dev/software-delivery-protocol/.github/workflows/studio-preview.yml@<ref>.
root (default .), exclude (root-relative prefixes, one per line), node-version (default 20), install (the install command, default npm ci), sdp (the command that runs the installed sdp, default npx sdp), runs-artifact (the name of an artifact an earlier job uploaded holding CTRF reports, each passed as --runs), diff (a boolean: write the graph of the pull request's base commit in a separate worktree, with that commit's own install and engine, and pass it as --base labelled base <short commit>), and deploy (a boolean, default false).
the workflow stamps with the checked-out merge commit and the source template <server>/<repository>/blob/<merge commit>/<root>/{file}#L{line}, the root and its slash left out when the root is ..
a pull request's preview is served at <host>/preview/<pr-number>/, which the workflow writes as the folder preview/<pr-number>/ of the gh-pages branch, the branch GitHub Pages serves when a repository enables Pages from it.
the page element sdp-stamp, once its stamp loads, also sets data-corpus-commit on itself and, when the stamp names a source template, wraps each code element carrying data-source-file and data-source-line in a link to the template with {file} and {line} filled in, the file percent-encoded by path segment; without a template it links nothing.
a recorded file and line written as <file>:<line> in a code element carrying data-source-file and data-source-line, beside its copy action.
Verification
Verifier bindings
spec:consumers.spec-studio.sharing.stamp-written-apart · The stamp is written beside the page set, and a later build removes it · declared · example enabled · specs/consumers/spec-studio.sharing.stamp-written-apart.sdp.md
Example space
commit · string · declared by the stamp command runs with the commit {commit} and the source template {source}
source · string · declared by the stamp command runs with the commit {commit} and the source template {source}
Requirement drawing for spec:consumers.spec-studio.sharingThe diagram as text
spec:consumers.spec-studio.sharing: A Studio build is stamped and shared from a static host · declared Spec
spec:consumers.spec-studio.sharing.stamp-written-apart: The stamp is written beside the page set, and a later build removes it · declared Spec
spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph · declared Spec
impl:protocol.stamp-command: writes the publishing stamp without extraction or rendering · anchored code · src/cli/stamp-command.ts:8
impl:protocol.studio-preview-workflow: asserts the reusable Studio preview workflow and Protocol CI caller · anchored code · test/studio-s4.test.ts:742
impl:protocol.studio-stamp: resolves published stamps and source links in the browser · anchored code · src/studio-elements/stamp.ts:30
spec:consumers.spec-studio.sharing dependsOn spec:consumers.spec-studio.publisher · declared — the stamp and the preview take the page set the publisher wrote
spec:consumers.spec-studio.shell dependsOn spec:consumers.spec-studio.sharing · declared — the shell shows the stamp a publishing step writes beside the page set
spec:consumers.spec-studio.spec-page dependsOn spec:consumers.spec-studio.sharing · declared — a recorded file and line become a link only from a stamp's source template
spec:consumers.studio-on-ramp dependsOn spec:consumers.spec-studio.sharing · declared — the skill teaches the stamp, its lifetime and the pull-request preview workflow
impl:protocol.stamp-command · writes the publishing stamp without extraction or rendering · src/cli/stamp-command.ts:8 · role publisher · component component:protocol.cli · layer edge · context protocol
impl:protocol.studio-preview-workflow · asserts the reusable Studio preview workflow and Protocol CI caller · test/studio-s4.test.ts:742
impl:protocol.studio-stamp · resolves published stamps and source links in the browser · src/studio-elements/stamp.ts:30 · role interaction · component component:protocol.studio-elements · layer edge · context protocol
Design reference: none
Verifier binding: present
spec:consumers.spec-studio.sharing.stamp-written-apart · The stamp is written beside the page set, and a later build removes it · declared · specs/consumers/spec-studio.sharing.stamp-written-apart.sdp.md · example enabled
No open questions and no blocking questions; implementation binding none, verifier binding present, and expected-outcome oracle none.
Intent
outcome
Execute the stamp step apart from the build: it touches no page, and no stamp outlives its build.
assumptions
The world writes a root with one Pack of two member Specs, runs the studio command, keeps the bytes of every page file, runs the stamp command, reads stamp.json and compares the page files with the kept bytes, then runs the studio command again and checks whether stamp.json exists.
Behavior
Examples
Given a page set the studio command wrote at an extraction root
When the stamp command runs with the commit {commit: "0123abc"} and the source template {source: "https://example.test/blob/0123abc/{file}#L{line}"}
Then the stamp names the corpus commit {corpusCommit: "0123abc"}
Then every page file stays byte-identical: {pagesUntouched: true}
Then a later studio run keeps the stamp: {stampSurvives: false}
Verification
Verifier bindings
test:protocol.studio-stamp-apart · anchored · test anchor binding present · test/studio-s4.test.ts:555
Design view
Requirement drawing
Satisfying or referencing units: no recorded binding.
Requirement drawing for spec:consumers.spec-studio.sharing.stamp-written-apartThe diagram as text
spec:consumers.spec-studio.sharing.stamp-written-apart: The stamp is written beside the page set, and a later build removes it · declared Spec
spec:consumers.spec-studio.sharing: A Studio build is stamped and shared from a static host · declared Spec
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
The Studio's work reaches an agent in three forms: a person or an agent holding only a link, a coding agent that publishes pages or receives intent a person composed in them, and a developer who sets up previews in CI. Each needs steps that most graph questions never use, so the Studio has its own skill and the reading skill points to it.
Intent
outcome
Give an agent a shipped on-ramp that publishes and shares the Spec Studio, reads it by task from a repository or a link, and turns intent composed in it into checked carrier edits.
The skill starts from what the agent holds: a repository to publish from, a page set or a link to read, composed intent to apply, or a CI workflow to set up; a reader holding only a link reads the pages without building a graph.
The skill teaches sdp studio for a page set with a base graph or run records and sdp generate for every root without them; that every command entering the shared build removes the page set; that supplied inputs lie outside every path the build writes or removes; and that the watch rebuilds on carrier edits with no server.
The skill teaches stamping after the final build with the commit the build read, that a later build removes the stamp, that source links need a stamp served over http or https, and the reusable preview workflow's inputs, permissions, artifact, deployment and fork behavior.
The skill maps a reviewer's task to the page that answers it, and states what a page does not: it shows values the build computed, its order sets no priority, a run row is no verdict, and a Pack export carries no stamp or composing panel.
The skill teaches receiving the composing panel's hand-off: the proposal and its memo, and the scoped-intent text the proposal cannot carry. The agent writes the graph at the proposal's base, runs the proposal check, sends a moved or uncheckable change to a person, applies the rest through the authoring skill, and writes scoped-intent text into a proposal against a known base before checking it.
The skill cites the Studio's Specs for law and each verb's --help for its flags, and restates neither.
no example exercises it
0 unkeyed rules.
Verification
Verifier bindings
test:protocol.studio-on-ramp · skill-asset checks verify the Studio on-ramp against the verbs, workflow and pages · anchored · test anchor binding present · test/skills.test.ts:1700
Design view
Requirement drawing
Declared verifying examples: no declared verifying example.
Requirement drawing for spec:consumers.studio-on-rampThe diagram as text
spec:consumers.studio-on-ramp: The Studio skill teaches agents to publish, share and read the Spec Studio · declared Spec
spec:consumers.reading-on-ramp: The reading skill teaches agents to query the graph · declared Spec
impl:protocol.studio-on-ramp: asserts realization of the shipped Studio skill document · anchored code · test/skills.test.ts:1693
test:protocol.studio-on-ramp: skill-asset checks verify the Studio on-ramp against the verbs, workflow and pages · anchored test binding · binding present · test/skills.test.ts:1700
spec:consumers.studio-on-ramp refines spec:consumers.reading-on-ramp · declared — a Studio page is a person's reading of the one graph, and the skill sends an agent from a page to the graph behind it
Preferred and chosen syntax: requirementDiagram; exact refines, satisfies and verifies, with claim words in nodes and per-edge comments.
Decisions
No decision record named.
Runtime
impl:protocol.studio-on-ramp · asserts realization of the shipped Studio skill document · test/skills.test.ts:1693
Uses
None.
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.studio-on-rampThe diagram as text
spec:consumers.intent-composition: Composed intent hands off on one proposal shape
spec:consumers.reading-on-ramp: The reading skill teaches agents to query the graph
spec:consumers.spec-studio.data.inputs: The Studio reads two named inputs beside the graph, a base graph and run records
spec:consumers.spec-studio.export: A Pack exports as one file, and every page prints as a document
spec:consumers.spec-studio.intent-panel: A composing panel on every page gathers scoped intent for an agent
spec:consumers.spec-studio.publisher: sdp studio publishes the Studio as one page set
spec:consumers.spec-studio.sharing: A Studio build is stamped and shared from a static host
spec:consumers.studio-on-ramp: The Studio skill teaches agents to publish, share and read the Spec Studio
spec:consumers.studio-on-ramp dependsOn spec:consumers.intent-composition · declared — a received proposal is checked and applied as the hand-off law states
spec:consumers.studio-on-ramp dependsOn spec:consumers.spec-studio.data.inputs · declared — the skill teaches the base graph and run records and where they may lie
spec:consumers.studio-on-ramp dependsOn spec:consumers.spec-studio.export · declared — the skill teaches the Pack export and what it leaves out
spec:consumers.studio-on-ramp dependsOn spec:consumers.spec-studio.intent-panel · declared — the skill teaches what the composing panel hands off and what stays scoped-intent text
spec:consumers.studio-on-ramp dependsOn spec:consumers.spec-studio.publisher · declared — the skill teaches the verb, its watch and what each shared build removes
spec:consumers.studio-on-ramp dependsOn spec:consumers.spec-studio.sharing · declared — the skill teaches the stamp, its lifetime and the pull-request preview workflow
spec:consumers.studio-on-ramp refines spec:consumers.reading-on-ramp · declared — a Studio page is a person's reading of the one graph, and the skill sends an agent from a page to the graph behind it
a Studio page is a person's reading of the one graph, and the skill sends an agent from a page to the graph behind it
None
Bindings
Implementation binding: present
impl:protocol.studio-on-ramp · asserts realization of the shipped Studio skill document · test/skills.test.ts:1693
Design reference: none
Verifier binding: present
test:protocol.studio-on-ramp · skill-asset checks verify the Studio on-ramp against the verbs, workflow and pages · anchored · test/skills.test.ts:1700 · test anchor