outcomeMermaid renders bounded one-hop and Pack diagrams without becoming a graph browser
spec:consumers.mermaid-viewChanged since the base graph base b5e0a8b: behavior.rules[10]; rule.portablePublication; rule.safeCleanup
Base input: schema 0.12.0, 456 Specs.
Packs: pack:self-hosting-v1
Design: no design entries · no pinned declarations · 1 decision
Findings: no errors, no warnings
specs/consumers/mermaid-view.sdp.md
No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle none.
Intent
- Give maintainers disposable, deterministic Mermaid diagrams of each Spec's one-hop neighborhood and each Pack's membership without ever projecting the whole graph or inventing a second truth store.
Behavior
ruleline 19 ·specs/consumers/mermaid-view.sdp.md:19renderMermaidis a pureReader -> pagesprojection with no filesystem or clock access; equal reader data produces byte-identical pages.ruleline 20 ·specs/consumers/mermaid-view.sdp.md:20- The page set is one page per Spec, selecting that Spec and every node one edge away, code units and test anchors included, one page per Pack selecting the Pack and its members, and one deterministic index that links them. A selected diagram is rendered or refused under the hard bounds; the projection never emits a whole-graph diagram.
ruleline 21 ·specs/consumers/mermaid-view.sdp.md:21- Machine node tokens are injective encodings of the full graph ID. Titles and other display text never become machine tokens.
ruleline 22 ·specs/consumers/mermaid-view.sdp.md:22- Visible labels are escaped for Mermaid's own syntax, apart from the Design Review's Markdown escaping, so no label can close or break a diagram.
ruleline 23 ·specs/consumers/mermaid-view.sdp.md:23- Every emitted record — pages, node declarations, edge declarations, index rows — is ordered by deterministic code-unit order independent of graph input order.
ruleline 24 ·specs/consumers/mermaid-view.sdp.md:24- An unresolved relation or edge target renders as an explicit unresolved placeholder node rather than disappearing or being invented.
ruleline 25 ·specs/consumers/mermaid-view.sdp.md:25- A cycle through the root renders as its ordinary edges; the projection computes no transitive closure and no layout.
ruleline 26 ·specs/consumers/mermaid-view.sdp.md:26- Disconnected neighborhoods and foreign edge types remain visible when they appear in the selected one-hop or Pack slice; absence of a neighbor is honest silence, not a synthetic hub.
ruleline 27 ·specs/consumers/mermaid-view.sdp.md:27- Hard bounds are exact:
maxNodesPerDiagram = 64andmaxEdgesPerDiagram = 128. A token collision or an overflow of either bound refuses the affected diagram with a deterministic refusal that names the bound, while every in-bound diagram still publishes and the command exits 0. The projection never silently truncates, shards partially, drops edges to fit, or aborts the whole page set because one diagram overflowed. ruleline 28 ·specs/consumers/mermaid-view.sdp.md:28- After the shared build, publication owns only
generated/mermaid/and uses the explicitsdp mermaidsurface. It is not a child of or an extra write inside Design Review's transaction, and it shares no publication bus or hidden side channel with other projections. ruleline 29 ·specs/consumers/mermaid-view.sdp.md:29- A Mermaid run writes its complete page set to
generated/mermaid.tmp/, removes the prior Mermaid root, and renames the temporary root into place. The shared build invalidates this root and all sibling projection roots before extraction, asspec:consumers.wholesale-view-rewrite#rule.buildInvalidatesstates, so failure leaves honest absence rather than stale output that looks current. A failed publish removes any live or temporary Mermaid root it cannot certify when its output parent remains safe. ruleline 30 ·specs/consumers/mermaid-view.sdp.md:30sdp mermaid --check-cleanrenders an independent twin, refuses divergent renders, and compares the current generated root with the new render. Missing or drifted output returns nonzero and is removed; clean output is replaced wholesale with byte-identical content.ruleline 31 ·specs/consumers/mermaid-view.sdp.md:31- When extraction succeeds but graph validation reports errors, Mermaid still publishes the labelled diagnostic projection and returns the nonzero validation exit code.
ruleline 32 ·specs/consumers/mermaid-view.sdp.md:32- The projection adds no Mermaid-specific Reader accessors, maintains no projection-owned taxonomy list, and confers nothing back into the graph.
rule.portablePublicationline 35 ·specs/consumers/mermaid-view.sdp.md:35- A case-insensitive page-path collision refuses the publisher's whole page set, names both ids and paths, removes its stale live and temporary roots when their parents are safe, and exits 1 regardless of validation's exit code. Renderers retain their page names and bytes.
no example exercises it
rule.safeCleanupline 36 ·specs/consumers/mermaid-view.sdp.md:36- Publication and failure cleanup recheck the physical output parent before each mutation; an escaping, unresolvable or linked
generated/parent is refused without cleanup through it.no example exercises it
14 unkeyed rules.
Example space
Given a graph containing Specs, Packs, one-hop relations, an unresolved target, a cycle, and a neighborhood within the stated bounds When the Mermaid projection renders and publishes through the explicit mermaid command Then each Spec page holds only that Spec's one-hop neighborhood Then each Pack page holds only that Pack and its members Then the index links every diagram deterministically Then machine tokens remain injective full-ID encodings Then hostile label characters cannot close or break Mermaid syntax Then an unresolved target renders as an explicit placeholder Then a colliding token or a diagram past maxNodesPerDiagram = 64 or maxEdgesPerDiagram = 128 is refused by name while every in-bound diagram still publishes Then generated/mermaid/ is the only current Mermaid root Then a clean independent render is byte-identical Then validation errors label the index as a diagnostic projection Then no whole-graph diagram is emitted
Verification
Verifier bindings
- test:protocol.cli-write-boundaries · anchored · test anchor binding present ·
test/cli-write-boundaries.test.ts:292External run evidence from
test/cli-write-boundaries.test.tsTest anchors:
test:protocol.cli-write-boundaries. Specs verified by those bindings: spec:consumers.design-review, spec:consumers.gherkin-view, spec:consumers.mermaid-view, spec:consumers.projections-model, spec:consumers.wholesale-view-rewrite, spec:extraction.build-pipeline.Run 1: external run evidence from vitest 4.1.10
Build: CI 433 · Branch: fix/second-review-pass · Commit: 6375b6e431a7cf885a49befec76d7876cd3e538c · Start: 2026-11-04T07:12:23.076Z · Stop: 2026-11-04T07:15:49.695Z
Name Suite Result Duration replaces a stale 'symbolic' link at 'graph.json' without touching its target build write boundaries passed 67.45 ms replaces a stale 'hard' link at 'graph.json' without touching its target build write boundaries passed 13.17 ms replaces a stale 'symbolic' link at 'imports.json' without touching its target build write boundaries passed 18.95 ms replaces a stale 'hard' link at 'imports.json' without touching its target build write boundaries passed 10.38 ms replaces a stale 'symbolic' link at 'registrars.json' without touching its target build write boundaries passed 19.24 ms replaces a stale 'hard' link at 'registrars.json' without touching its target build write boundaries passed 12.84 ms routes a successful build's ordinary removals and writes through the filesystem hooks build write boundaries passed 19.14 ms names an unresolvable output parent when generated is a dangling link build write boundaries passed 1.24 ms refuses a staging link planted after stale removal build write boundaries passed 4.94 ms build refuses an escaping generated parent before writing or cleanup build write boundaries passed 5.03 ms view refuses an escaping generated parent before writing or cleanup build write boundaries passed 4.29 ms census refuses an escaping generated parent before writing or cleanup build write boundaries passed 4.86 ms mermaid refuses an escaping generated parent before writing or cleanup build write boundaries passed 4.19 ms gherkin refuses an escaping generated parent before writing or cleanup build write boundaries passed 6.19 ms studio refuses an escaping generated parent before writing or cleanup build write boundaries passed 4.04 ms generate refuses an escaping generated parent before writing or cleanup build write boundaries passed 3.87 ms vault refuses an escaping generated parent before writing or cleanup build write boundaries passed 5.04 ms stamp refuses an escaping generated parent before writing or cleanup build write boundaries passed 11.13 ms keeps the named root in ordinary command output explicit symlinked watch root passed 5.6 ms validate starts and reruns through the named root explicit symlinked watch root passed 17.86 ms studio starts and reruns through the named root explicit symlinked watch root passed 88.19 ms vault starts and reruns through the named root explicit symlinked watch root passed 35.65 ms view refuses case-colliding pages and removes stale output portable projection publication passed 10.23 ms mermaid refuses case-colliding pages and removes stale output portable projection publication passed 7.15 ms gherkin refuses case-colliding pages and removes stale output portable projection publication passed 10.32 ms stamp replaces a symbolic link without modifying its target publication boundary regressions passed 4.1 ms stamp replaces a hard link without modifying its target publication boundary regressions passed 3.74 ms a stamp that fails after staging leaves no staging file in the page set publication boundary regressions passed 1.83 ms view recovery preserves outside output after a parent swap publication boundary regressions passed 6.23 ms census recovery preserves outside output after a parent swap publication boundary regressions passed 6.21 ms mermaid recovery preserves outside output after a parent swap publication boundary regressions passed 5.59 ms gherkin recovery preserves outside output after a parent swap publication boundary regressions passed 5.64 ms studio recovery preserves outside output after a parent swap publication boundary regressions passed 5.11 ms vault recovery preserves outside output after a parent swap publication boundary regressions passed 5 ms generate recovery preserves outside output after a parent swap publication boundary regressions passed 6.75 ms build refuses inside-link generated identity publication boundary regressions passed 2.93 ms build refuses replaced-directory generated identity publication boundary regressions passed 2.58 ms vault refuses a default vault linked outside the root but allows an explicit outside vault publication boundary regressions passed 9.03 ms generate refuses a default vault linked outside the root but allows an explicit outside vault publication boundary regressions passed 23.26 ms vault holds a default vault linked inside the root to the placement rules where it resolves publication boundary regressions passed 11.29 ms generate holds a default vault linked inside the root to the placement rules where it resolves publication boundary regressions passed 28.31 ms projection suite refuses a linked generated parent (check-clean: false) publication boundary regressions passed 65.78 ms projection suite refuses a linked generated parent (check-clean: true) publication boundary regressions passed 47.87 ms package artifacts unlink stale staging links and refuse linked recipe directories publication boundary regressions passed 1.5 ms package artifacts refuse a linked recipe directory before stale cleanup not recorded passed 0.78 ms watch leaves outside bytes unchanged after direct-empty parent swap not recorded passed 12.49 ms watch leaves outside bytes unchanged after direct-managed parent swap not recorded passed 15.69 ms watch leaves outside bytes unchanged after checkout-empty parent swap not recorded passed 77.25 ms watch leaves outside bytes unchanged after checkout-managed parent swap not recorded passed 117.05 ms watch leaves outside bytes unchanged after studio-direct parent swap not recorded passed 12.8 ms - test:protocol.mermaid-view · verifies bounded deterministic Mermaid projection and publication · anchored · test anchor binding present ·
test/mermaid-render.test.ts:20External run evidence from
test/mermaid-render.test.tsTest anchors:
test:protocol.mermaid-view. Specs verified by those bindings: spec:consumers.mermaid-view.Run 1: external run evidence from vitest 4.1.10
Build: CI 433 · Branch: fix/second-review-pass · Commit: 6375b6e431a7cf885a49befec76d7876cd3e538c · Start: 2026-11-04T07:12:23.076Z · Stop: 2026-11-04T07:15:49.695Z
Name Suite Result Duration renders every checkout-v1 Spec, Pack, and index page as the reviewed golden the bounded Mermaid projection passed 134.44 ms is byte-identical under node and edge permutation with code-unit sorted records the bounded Mermaid projection passed 2.07 ms labels the index as diagnostic when validation errors are present the bounded Mermaid projection passed 1.82 ms escapes hostile labels without changing injective full-ID machine tokens the bounded Mermaid projection passed 0.92 ms refuses a diagram whose neighbor has a duplicated id and names that neighbor the bounded Mermaid projection passed 1.29 ms names each duplicated root in its own refusal the bounded Mermaid projection passed 0.62 ms keeps one-hop cycles, disconnected Pack members, foreign edges, and dangling placeholders without emitting a whole graph the bounded Mermaid projection passed 1.05 ms withholds only the affected diagram when identities collide or a bound overflows the bounded Mermaid projection passed 3.56 ms accepts diagrams exactly at the 64-node and 128-edge bounds the bounded Mermaid projection passed 4.87 ms withholds an oversized Pack and still renders every in-bound Spec diagram the bounded Mermaid projection passed 15.43 ms
Example space
None.
Bound points
No bound example points recorded.
Oracle binding: none
Coverage
Unbound
None.
Given
a graph containing Specs, Packs, one-hop relations, an unresolved target, a cycle, and a neighborhood within the stated bounds
When
the Mermaid projection renders and publishes through the explicit mermaid command
Then
each Spec page holds only that Spec's one-hop neighborhood each Pack page holds only that Pack and its members the index links every diagram deterministically machine tokens remain injective full-ID encodings hostile label characters cannot close or break Mermaid syntax an unresolved target renders as an explicit placeholder a colliding token or a diagram past maxNodesPerDiagram = 64 or maxEdgesPerDiagram = 128 is refused by name while every in-bound diagram still publishes generated/mermaid/ is the only current Mermaid root a clean independent render is byte-identical validation errors label the index as a diagnostic projection no whole-graph diagram is emitted
Composing needs the script.
Design view
Requirement drawing
- Declared verifying examples: no declared verifying example.
The diagram as text
- spec:consumers.mermaid-view: Mermaid renders bounded one-hop and Pack diagrams without becoming a graph browser · declared Spec
- spec:consumers.projections-model: Projections fan out from one graph without becoming truth stores · declared Spec
- impl:protocol.mermaid-view: renders bounded Spec one-hop and Pack membership diagrams · anchored code ·
src/projections/mermaid.ts:14 - impl:protocol.mermaid-view-cli: publishes Mermaid through the explicit sdp mermaid surface · anchored code ·
src/cli/mermaid-command.ts:74 - test:protocol.cli-write-boundaries: test:protocol.cli-write-boundaries · anchored test binding · binding present ·
test/cli-write-boundaries.test.ts:292 - test:protocol.mermaid-view: verifies bounded deterministic Mermaid projection and publication · anchored test binding · binding present ·
test/mermaid-render.test.ts:20 - spec:consumers.mermaid-view refines spec:consumers.projections-model · declared
- impl:protocol.mermaid-view satisfies spec:consumers.mermaid-view · anchored
- impl:protocol.mermaid-view-cli satisfies spec:consumers.mermaid-view · anchored
- test:protocol.cli-write-boundaries verifies spec:consumers.mermaid-view · anchored
- test:protocol.mermaid-view verifies spec:consumers.mermaid-view · anchored
Mermaid source
Copyable source; the Studio draws static SVG.
Preferred and chosen syntax: requirementDiagram; exact refines, satisfies and verifies, with claim words in nodes and per-edge comments.
Decisions
- The shipped projections stay 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.
Runtime
component:protocol.cli· entry points, shared build and publication ·src/cli/build-command.ts:31· layer edge · context protocol Uses
component:protocol.adapters· external runtime and source adapters ·src/adapters/vitest.ts:23· layer adapter · context protocol component:protocol.codegen· contracts and registrar output ·src/codegen/contracts.ts:671· layer application · context protocol component:protocol.extract· the carrier and source pipeline ·src/extract/index.ts:197· layer application · context protocol component:protocol.graph· the one graph and its semantic decisions ·src/graph/schema.ts:34· layer domain · context protocol component:protocol.import· canonical conversion with a fidelity boundary ·src/import/import.ts:45· layer application · context protocol component:protocol.model· the authored contracts and stable ids ·src/model/anchors.ts:100· layer domain · context protocol component:protocol.projections· read-only output, layout and owned publication ·src/projections/design-review.ts:29· layer edge · context protocol component:protocol.reader· the typed graph contract and body evaluator ·src/reader/reader.ts:697· layer application · context protocol component:protocol.validate· one finding currency and ordered checks ·src/validate/validators.ts:76· layer domain · context protocol
component:protocol.projections· read-only output, layout and owned publication ·src/projections/design-review.ts:29· layer edge · context protocol Uses
component:protocol.extract· the carrier and source pipeline ·src/extract/index.ts:197· layer application · context protocol component:protocol.graph· the one graph and its semantic decisions ·src/graph/schema.ts:34· layer domain · context protocol component:protocol.model· the authored contracts and stable ids ·src/model/anchors.ts:100· layer domain · context protocol component:protocol.notation· the leaf step codec ·src/notation/slots.ts:263· layer domain · context protocol component:protocol.reader· the typed graph contract and body evaluator ·src/reader/reader.ts:697· layer application · context protocol component:protocol.validate· one finding currency and ordered checks ·src/validate/validators.ts:76· layer domain · context protocol
impl:protocol.mermaid-view· renders bounded Spec one-hop and Pack membership diagrams ·src/projections/mermaid.ts:14Component:
component:protocol.projections· read-only output, layout and owned publication ·src/projections/design-review.ts:29· layer edge · context protocol Uses
None.
impl:protocol.mermaid-view-cli· publishes Mermaid through the explicitsdp mermaidsurface ·src/cli/mermaid-command.ts:74Component:
component:protocol.cli· entry points, shared build and publication ·src/cli/build-command.ts:31· layer edge · context protocol Uses
None.
Runtime observation: not tracked.
Evidence
Runtime observation: not tracked.
Build attestations: not tracked.
Deployments: not tracked.
Bills of materials: not tracked.
Impact
The diagram as text
- spec:consumers.mermaid-view: Mermaid renders bounded one-hop and Pack diagrams without becoming a graph browser
- spec:consumers.projections-model: Projections fan out from one graph without becoming truth stores
- spec:consumers.wholesale-view-rewrite: Every view run rewrites the view wholesale
- spec:decisions.shipped-projections-frozen: The shipped projections stay frozen
- spec:consumers.mermaid-view decidedBy spec:decisions.shipped-projections-frozen · declared
- spec:consumers.mermaid-view dependsOn spec:consumers.wholesale-view-rewrite · declared — the shared build invalidates the projection roots before this publisher renders
- spec:consumers.mermaid-view refines spec:consumers.projections-model · declared
Mermaid source
Copyable source; the Studio draws static SVG.
Preferred syntax: flowchart. Chosen syntax: labelled flowchart, preserving exact relations, claims and folds.
Rests on
- refines · spec:consumers.projections-model · stated ready, floor ready
- dependsOn · spec:consumers.wholesale-view-rewrite · stated ready, floor ready
- decidedBy · spec:decisions.shipped-projections-frozen · stated ready, floor ready
Rested on by
No Spec rests on this Spec.
Relations
| Relation and direction | Other end | Claim | Reason | Exercised keys |
|---|---|---|---|---|
| decidedBy · outgoing | The shipped projections stay frozenspec:decisions.shipped-projections-frozen · resolves | declared | None | None |
| dependsOn · outgoing | Every view run rewrites the view wholesalespec:consumers.wholesale-view-rewrite · resolves | declared | the shared build invalidates the projection roots before this publisher renders | None |
| refines · outgoing | Projections fan out from one graph without becoming truth storesspec:consumers.projections-model · resolves | declared | None | None |
Bindings
Implementation binding: present
impl:protocol.mermaid-view· renders bounded Spec one-hop and Pack membership diagrams ·src/projections/mermaid.ts:14· role projection · component component:protocol.projections· layer edge · context protocolimpl:protocol.mermaid-view-cli· publishes Mermaid through the explicit `sdp mermaid` surface ·src/cli/mermaid-command.ts:74· role publisher · component component:protocol.cli· layer edge · context protocol
Design reference: none
Verifier binding: present
- test:protocol.cli-write-boundaries · anchored ·
test/cli-write-boundaries.test.ts:292· test anchor - test:protocol.mermaid-view · verifies bounded deterministic Mermaid projection and publication · anchored ·
test/mermaid-render.test.ts:20· test anchor
Expected-outcome oracle: none
Runtime observation: not tracked.
Run results: not recorded in the graph.
Findings
None.
Composing (0)
Composing needs the script.