Spec Studio

Design diff

Compared with the base graph base b5e0a8b, schema 0.12.0, 456 Specs; the built graph has schema 0.12.0, 459 Specs.

The comparison reads the two graphs only. Recipe 35 with detail enabled.

  • 3 Specs added.
  • 0 Specs removed.
  • 43 Specs changed.
  • 1 Pack with membership, member order or order meaning changes.
  • 9 Specs with binding changes.

Specs added

Specs removed

None.

Specs changed

The Markdown envelope is explicit and bounded

spec:carrier.envelope-contract

behavior.rules[7] · changed

Base

The frontmatter opens at byte zero with an exact `---` line and closes at the next exact `---` line; a byte-order mark, a `...` line in the frontmatter, a further exact `---` line in the body, a lone CR, or mixed LF and CRLF newlines refuses the carrier.

Rule

Now

The frontmatter opens at byte zero with an exact `---` line and closes at the next exact `---` line; a byte-order mark, a `...` line in the frontmatter, a further exact `---` line in the body, or mixed LF and CRLF newlines refuses the carrier. A lone CR, U+2028 or U+2029 anywhere in the carrier refuses it at that physical line, under `spec:carrier.markdown-authoring#rule.lineEndings`.

Rule

rule.reservedProperties · changed

Base

A derived name is never authorable in the envelope: a delivery-fact or graph-field key (`implemented`, `has-verifier`, `hasVerifier`, `observed`, `claim`, `deliveryFacts`, `nodeType`, `specKind`, `satisfies`, `verifies`, `belongsTo` or `models`) is refused as `extract/reserved-property`, because delivery facts are derived and never authored; `title` is refused as `extract/invalid-frontmatter`, and any other unknown envelope key as `extract/unrecognized-property`.

Rule

Now

A derived name is never authorable in the envelope: a delivery-fact or graph-field key (`implemented`, `has-verifier`, `hasVerifier`, `observed`, `claim`, `deliveryFacts`, `nodeType`, `specKind`, `satisfies`, `verifies`, `belongsTo` or `models`) is refused as `extract/reserved-property`, because delivery facts are derived and never authored; `title` is refused as `extract/invalid-frontmatter`, and any other unknown envelope key as `extract/unrecognized-property`. Delivery-fact names and `deliveryFacts` are compared case-insensitively; underscore forms are not delivery-fact names.

Rule

Gherkin authoring enters the one graph

spec:carrier.gherkin-authoring

rule.authoredFacts · changed

Base

A tag whose head, compared case-insensitively, is `implemented`, `has-verifier`, `hasVerifier`, `observed`, `claim`, `status`, `lifecycle`, `workflow` or `architect`, followed by the end of the tag, `.` or `-`, is refused, so the carrier authors no delivery fact, claim, lifecycle state or workflow status.

Rule

Now

A tag whose head, compared case-insensitively, is `implemented`, `has-verifier`, `hasVerifier`, `observed`, `deliveryFacts`, `claim`, `status`, `lifecycle`, `workflow` or `architect`, followed by the end of the tag, `.` or `-`, is refused, so the carrier authors no delivery fact, claim, lifecycle state or workflow status.

Rule

rule.physicalLines · changed

Base

An unknown description key or a heading-shaped description line is refused at its physical source line, despite blanks and comments; remaining non-heading prose is narrative, lawful only as free prose on the typed prose owners named by the prose-ownership decision, `spec:decisions.prose-ownership`, and never a new field or a parser within a parser.

Rule

Now

Feature, Scenario, Example and Rule title lines, tag lines, ordinary and example-space step lines, and description lines holding a lone CR, U+2028 or U+2029 are refused at their physical source lines; LF and CRLF remain lawful line endings. An unknown description key or a heading-shaped description line is also refused at its physical source line, despite blanks and comments; remaining non-heading prose is narrative, lawful only as free prose on the typed prose owners named by the prose-ownership decision, `spec:decisions.prose-ownership`, and never a new field or a parser within a parser.

Rule

Markdown authoring enters the one graph

spec:carrier.markdown-authoring

rule.lineEndings · added

Now

Whichever carrier writes them, the title, prose, entries and steps of a Spec or Pack hold no lone CR, U+2028 or U+2029, because a renderer that breaks a line there would show a line the carrier does not state; LF and CRLF are the only line endings. A Markdown carrier holding one anywhere is refused whole at that line, as `spec:carrier.envelope-contract` states, a Gherkin carrier as `spec:carrier.gherkin-authoring#rule.physicalLines` states, and a TypeScript Spec or Pack whose title, narrative, framing or section string holds one is not extracted.

Rule

The Markdown body accepts one closed form per section

spec:carrier.markdown-body-grammar

rule.blockShapes · changed

Base

The refused block shapes are read line by line in narrative, section prose, and list text: a line that opens with a pipe, a block-quote opener, whitespace, a star or plus bullet, an ordered-list prefix, or a `<`, and a line that is only a thematic break or a setext underline. A table without outer pipes is prose to the parser.

Rule

Now

The refused block shapes are read line by line in narrative, section prose, and list text. A line is refused when it opens with a pipe, a block-quote opener, whitespace, a `<`, or a hyphen and a tab; with a star, a plus sign, or an ordered-list prefix (digits and then `.` or `)`), each followed by whitespace or the end of the line; with an ATX heading (one to six hashes followed by whitespace or the end of the line); or with a backtick or tilde fence opener. A line that is only a thematic break or a setext underline, including a single `=` or `-`, is refused too. A table without outer pipes is prose to the parser.

Rule

rule.keyedEntryShape · changed

Base

A keyed entry is one ASCII word, a colon, and a space before its value. Where a section takes plain bullets, a bullet of that shape is read as a key and refused unless the section names that key, so a plain bullet never opens with a single word and a colon.

Rule

Now

A keyed entry is a key, one ASCII letter followed by zero or more ASCII letters or digits, then a colon and a space before its nonempty value, so a single letter such as `a:` is a key. A hyphenated delivery-fact name, compared case-insensitively, is also read as a key; other hyphenated or underscored words stay plain text. Where a section takes plain bullets, a bullet of the keyed shape is read as a key and refused unless the section names that key, with reserved properties refused there too.

Rule

rule.reservedProperties · changed

Base

The keys `implemented`, `hasVerifier`, `observed`, `claim`, `deliveryFacts`, `nodeType`, `specKind`, `satisfies`, `verifies`, `belongsTo`, and `models` are refused in every keyed section, under `spec:validation.authored-honesty`. In Design and UI, an otherwise lawful lower-camel key outside this set is ordinary content, including `dependsOn`, `references`, `uses` and `memberOf`; it creates no edge. Every closed section still admits only its own fields.

Rule

Now

The keys `implemented`, `has-verifier`, `hasVerifier`, `observed`, `claim`, `deliveryFacts`, `nodeType`, `specKind`, `satisfies`, `verifies`, `belongsTo`, and `models` are refused in every keyed entry, including one in a plain-bullet section, under `spec:validation.authored-honesty`. In Design and UI, an otherwise lawful lower-camel key outside this set is ordinary content, including `dependsOn`, `references`, `uses` and `memberOf`; it creates no edge. Every closed section still admits only its own fields. Delivery-fact names and `deliveryFacts` are compared case-insensitively; underscore forms are not delivery-fact names.

Rule

Slot notation declares, binds, and refuses to guess

spec:carrier.slot-notation

rule.reservedThenSlot · added

Now

The slot name `kind` is reserved in every Then step, both in an example-space vocabulary and in a structured example. Graph validation reports `conformance/reserved-then-slot` at error severity, naming the reserved word. Given and When slots may still be named `kind`.

Rule

Recipe answers fit an agent's context and explain their misses

spec:consumers.agent-surface.answer-shapes

design.wrapIdiom · changed

Base
to filter a shipped answer, the caller wraps the shipped body in an async arrow function that takes `params`, inside its own body, `const answer = await (async (params) => { <shipped body> })({ <the recipe's own parameters> });`, and returns a filtered value, so the caller's own parameters never reach the recipe as names it does not take; the catalog shows the shell form and states that the caller's part must hold no shell expansion.
Now
to filter a shipped answer, the caller calls the recipe through the `recipes` binding with only the recipe's own parameters, `const answer = await recipes(<number>, { <the recipe's own parameters> });`, inside its own body, and returns a filtered value, so the caller's own parameters never reach the recipe as names it does not take and the shipped body is never inlined into the caller's; the catalog shows the shell form and states that the caller's part must hold no shell expansion.

rule.floorNotEvaluated · added

Now

A recipe that reports a Spec's floor reached reports `not evaluated`, never `none`, for a Spec over whose unratified kind or altitude the reader evaluates no floor, with no stated next rung and no unmet clause; readiness divergence leaves such a Spec out, and a count by floor reached counts it under a `not evaluated` key, present only when such a Spec is counted.

Rule

Authoring questions stay executable graph recipes

spec:consumers.agent-surface.authoring-recipes

behavior.rules[0] · changed

Base

Promotion preflight reports the Spec's stated rung, floor reached, current floor failures, and both next rungs as `aboveStated` and `aboveFloor`, each with `rung`, `failures` and `firstUnmetClause`; `rung` is null at `ready`, and a typed-dependency failure carries its targets.

Rule

Now

Promotion preflight reports the Spec's stated rung, floor reached, current floor failures, and both next rungs as `aboveStated` and `aboveFloor`, each with `rung`, `failures` and `firstUnmetClause`; `rung` is null at `ready`, and a typed-dependency failure carries its targets. A Spec whose floor is not evaluated reports its floor reached as `not evaluated` and null for both next rungs and its current floor failures.

Rule

behavior.rules[2] · changed

Base

The lower ladder groups non-ready Specs by family and reports stated readiness, floor reached, stated next rung and its first unmet clause; null means nothing blocks that rung, never automatic promotion.

Rule

Now

The lower ladder groups non-ready Specs by family and reports stated readiness, floor reached, stated next rung and its first unmet clause; beside a named next rung, a null clause means nothing blocks that rung, never automatic promotion. A Spec whose floor is not evaluated reports its floor reached as `not evaluated` with no next rung and no clause.

Rule

Example spaces report which values their examples cover

spec:consumers.agent-surface.example-space-coverage

rule.perSlotOnly · changed

Base

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.

Rule

Now

Coverage is reported per slot value; the recipe reports no combination of two or more slots.

Rule

Authors move one Spec from intent to reviewed evidence

spec:consumers.authoring-on-ramp

rule.scaffoldWriteBoundary · added

Now

`sdp new spec` uses the original working directory as the boundary for parent creation and the scaffold write. It refuses an escaping or unresolvable parent with exit 1, before creating anything through a statically planted escaping link. It creates parents and the scaffold through held directories, rechecks containment before each creation and after entering each parent, and rechecks the scaffold's location before reporting success; a detected relocation removes the scaffold and refuses. This defends against planted links and detects intervening changes; Node has no openat-style operations, so re-verification does not provide race-free confinement against a concurrent writer inside the working directory.

Rule

The capability map reads every epic and its refinement descendants

spec:consumers.capability-map

design.countShape · changed

Base
totals and each rollup carry `{ specs, byStatedReadiness, byFloorReached, byKind, byAltitude, withImplementationBinding, withVerifierBinding, openQuestions, blockingQuestions }`; every descriptor value has a key including zero, floor counts add `none`, and totals additionally carry `{ epics, reached, unreached }`. Reached and unreached partition selected nodes, using their full-corpus epic membership. The epic's own evidence stays on its node row, outside its rollup.
Now
totals and each rollup carry `{ specs, byStatedReadiness, byFloorReached, byKind, byAltitude, withImplementationBinding, withVerifierBinding, openQuestions, blockingQuestions }`; every ratified descriptor value has a key including zero and floor counts add `none`; any other value, such as an unratified kind or altitude or the floor `not evaluated`, has a key only when a counted Spec carries it; totals additionally carry `{ epics, reached, unreached }`. Reached and unreached partition selected nodes, using their full-corpus epic membership. The epic's own evidence stays on its node row, outside its rollup.

rule.nodeEvidence · changed

Base

Each Spec carries its own stated readiness, structural floor reached, delivery facts, and open questions with their blocking flags. A missing floor reads `none`. No value propagates from a child to its parent.

Rule

Now

Each Spec carries its own stated readiness, structural floor reached, delivery facts, and open questions with their blocking flags. A missing floor reads `none`, and a floor not evaluated over an unratified kind or altitude reads `not evaluated`. No value propagates from a child to its parent.

Rule

Census renders the runtime taxonomy without becoming a registry

spec:consumers.census-page

behavior.rules[3] · changed

Base

Stated readiness and structurally derived readiness render as separate dimensions, including a count for Specs that have not structurally reached the first derived rung; the census never resolves or confers readiness.

Rule

Now

Stated readiness and structurally derived readiness render as separate dimensions, including a count for Specs that have not structurally reached the first derived rung. A Spec whose kind or altitude is unratified has no floor evaluated, so it stays out of that count and counts on a `floor not evaluated (unratified descriptor)` row, present only when such a Spec exists. The census never resolves or confers readiness.

Rule

Derived readiness renders beside the stated rung and warns in one direction

spec:consumers.derived-readiness-banner

behavior.rules[5] · added

Now

When no floor is evaluated over a Spec because its kind or altitude is unratified, the floor reached renders as `floor not evaluated (unratified descriptor)` on its page, in the index and in the Pack member table, and no banner is raised, because no clause was evaluated to be unmet.

Rule

Design Review renders graph context without becoming a gate

spec:consumers.design-review

rule.portablePublication · added

Now

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.

Rule

rule.safeCleanup · added

Now

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.

Rule

Gherkin view renders any Spec as a disposable read shape

spec:consumers.gherkin-view

behavior.rules[4] · changed

Base

Every emitted record is ordered by deterministic code-unit order independent of graph input order. Hostile characters are escaped so they cannot close a fence or invent a DocString.

Rule

Now

Every emitted record is ordered by deterministic code-unit order independent of graph input order. Hostile characters are escaped so they cannot close a fence or invent a DocString, and every line terminator, CR, LF, U+2028 or U+2029, folds to one space, so a page never shows a line the graph does not state.

Rule

behavior.rules[6] · changed

Base

A Gherkin-view run writes its complete page set to `generated/gherkin.tmp/`, removes the prior Gherkin-view root, and renames the temporary root into place. The shared build invalidates this root and all sibling projection roots before extraction, as `spec:consumers.wholesale-view-rewrite#rule.buildInvalidates` states, so failure leaves honest absence rather than stale output that looks current. A failed publish removes any live or temporary Gherkin-view root it cannot certify.

Rule

Now

A Gherkin-view run writes its complete page set to `generated/gherkin.tmp/`, removes the prior Gherkin-view root, and renames the temporary root into place. The shared build invalidates this root and all sibling projection roots before extraction, as `spec:consumers.wholesale-view-rewrite#rule.buildInvalidates` states, so failure leaves honest absence rather than stale output that looks current. A failed publish removes any live or temporary Gherkin-view root it cannot certify when its output parent remains safe.

Rule

rule.portablePublication · added

Now

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.

Rule

rule.safeCleanup · added

Now

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.

Rule

Mermaid renders bounded one-hop and Pack diagrams without becoming a graph browser

spec:consumers.mermaid-view

behavior.rules[10] · changed

Base

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, as `spec:consumers.wholesale-view-rewrite#rule.buildInvalidates` states, 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.

Rule

Now

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, as `spec:consumers.wholesale-view-rewrite#rule.buildInvalidates` states, 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.

Rule

rule.portablePublication · added

Now

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.

Rule

rule.safeCleanup · added

Now

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.

Rule

An Obsidian vault lets a person iterate on designs from the one graph

spec:consumers.obsidian-vault

design.buildOwnedMessage · moved

Now
`sdp vault: the vault <out> overlaps <path>, which every build rewrites or removes; choose another directory, such as generated/obsidian-vault/`, with `<path>` the first overlapping path in the order `spec:consumers.obsidian-vault#design.buildOwnedPaths` lists them.

design.defaultVaultMessage · added

Now
`sdp vault: the default vault <out> does not resolve inside the root; choose a vault directory explicitly to place it elsewhere`.

design.exitCodes · moved

Now
0 when the vault is synchronized over a graph with no validation error; the validation exit code when it is synchronized over one with errors; 1 on a refused option, a refused vault directory, a guard refusal, a case collision, a failed extraction or a write that fails.

design.failedIndex · moved

Now
after a failed extraction, `sdp/index.md` opens with `> [!warning] The last regeneration failed, and the notes show the graph of the last one that succeeded.` followed by one line per extraction error, its root-relative file and its message.

design.findingLine · moved

Now
`- <severity> · <validator id> · <file>:<line> · <message>`, leaving out the file and line when the finding names none and the line when it names only a file, with the message escaped as `spec:consumers.obsidian-vault.notes#rule.textEscaped` states.

design.indexNote · moved

Now
`sdp/index.md` opens with `` > [!info] Generated by `sdp vault` from the graph. Every file under `sdp/` is regenerated, except a `.base` file you changed: write your own notes outside it, and intent notes in `intent/`. ``, then `# Spec graph`, the finding counts by severity, `## Findings without a note` with one line per finding whose subject has no Spec or Pack note, in report order, the corpus Base embedded, and a link to each Pack note in id order.

design.summaryLine · moved

Now
on stdout after a synchronization, `Wrote <out>/sdp (<n> files: <w> written, <u> unchanged, <r> removed)`.

rule.defaultInsideRoot · added

Now

When a run names no vault directory, the default `generated/obsidian-vault/` must resolve inside the root, following any symbolic link at or above it. A run checks this before the build and before each synchronization, and a watch checks it again before its closing cleanup: a default that resolves outside the root, or is a link that resolves nowhere, refuses the run or skips that cleanup, writing and removing nothing in the vault. A default that resolves inside the root, through a link or not, is held to `spec:consumers.obsidian-vault#rule.outsideExtraction` and `spec:consumers.obsidian-vault#rule.apartFromBuild` where it resolves; a vault outside the root is one the run names.

Rule

Every Spec, Pack, code unit and keyed term is a note, and every relation is a link

spec:consumers.obsidian-vault.notes

design.headLine · changed

Base
under a Spec note's title, `` `<id>` · <kind display label> · <altitude> · stated <rung> · floor <rung or none> ``, then ` · <stated next rung>: <failing clause ids, or nothing blocks>` when the Spec states less than `ready`.
Now
under a Spec note's title, `` `<id>` · <kind display label> · <altitude> · stated <rung> · floor <rung or none> ``, with `floor not evaluated (unratified descriptor)` in place of the floor when the Spec's kind or altitude is unratified, then ` · <stated next rung>: <failing clause ids, or nothing blocks>` when the reader names a stated next rung, which it does for a Spec stating less than `ready` with its floor evaluated.

design.packNoteBody · changed

Base
the banner, `# <title>`, the framing, `## Members, filterable` with the Pack's Base embedded, `## Members, in advisory priority order` when `order` is `"priority"`, otherwise `## Members, in reading order`, as a numbered list in manifest order, each a link with its stated rung, floor and stated next rung or `nothing blocks`, then `## Boundary` with the reader's four boundary lists and `## Findings`. A roadmap states `Priority confers no permission or sequencing requirement.` before its ordered list heading.
Now
the banner, `# <title>`, the framing, `## Members, filterable` with the Pack's Base embedded, `## Members, in advisory priority order` when `order` is `"priority"`, otherwise `## Members, in reading order`, as a numbered list in manifest order, each a link with its stated rung, its floor as the head line writes it, and its stated next rung with its failing clause ids or `nothing blocks` when the reader names one, then `## Boundary` with the reader's four boundary lists and `## Findings`. A roadmap states `Priority confers no permission or sequencing requirement.` before its ordered list heading.

design.specProperties · changed

Base
`aliases` (the id, then the title), `title`, `specKind`, `altitude`, `statedReadiness`, `derivedReadiness` (`none` when no rung derives), `statedNextRung` (left out when the Spec states `ready`), `statedNextRungFailures` (the failing clause ids), `implementationBinding`, `verifierBinding`, `designEntries`, `declarations`, `openQuestions` (a count), `blockingQuestions`, `decisions` (links to the notes of the resolving decisions the design columns name), `packs` (links to the Pack notes), `carrier` (the root-relative carrier path).
Now
`aliases` (the id, then the title), `title`, `specKind`, `altitude`, `statedReadiness`, `derivedReadiness` (`none` when no rung derives, and `not evaluated` when the Spec's kind or altitude is unratified, so no floor is evaluated), `statedNextRung` (left out when the Spec states `ready`), `statedNextRungFailures` (the failing clause ids), `implementationBinding`, `verifierBinding`, `designEntries`, `declarations`, `openQuestions` (a count), `blockingQuestions`, `decisions` (links to the notes of the resolving decisions the design columns name), `packs` (links to the Pack notes), `carrier` (the root-relative carrier path).

The Pack context carries the Pack's design

spec:consumers.pack-design

behavior.rules[1] · changed

Base

A member's stated next rung is the rung above its stated rung, none when it states `ready`. Its unmet clauses come from the one floor evaluator with that rung as the target, each failure with its targets when it has them. The list is empty when the floor already holds the stated next rung, so the rung waits for its author's statement, never a promotion. The floor reached and the failures at the rung above it are separate readings.

Rule

Now

A member's stated next rung is the rung above its stated rung, none when it states `ready` or no floor is evaluated over it. Its unmet clauses come from the one floor evaluator with that rung as the target, each failure with its targets when it has them. The list is empty when the floor already holds the stated next rung, so the rung waits for its author's statement, never a promotion. The floor reached and the failures at the rung above it are separate readings.

Rule

Projections fan out from one graph without becoming truth stores

spec:consumers.projections-model

term.diagnostic publication posture · changed

Base
After extraction succeeds, a projection publishes its honestly labelled graph view even when validation reports errors, and returns the validation exit code so findings remain both visible and nonzero.
Now
After extraction succeeds, a projection publishes its honestly labelled graph view even when validation reports errors, and returns the validation exit code so findings remain both visible and nonzero. Publication failures remain separate: an unsafe output parent refuses writes and cleanup through it; Design Review, Mermaid and Gherkin publishers refuse their whole page set on a case-insensitive page-path collision, name both ids and paths, remove stale roots only through safe parents, and exit 1. Renderers retain their page names and bytes.

The reader bridges agent entry points to composable graph context

spec:consumers.reader

behavior.rules[1] · changed

Base

The reader exposes `graph`, the raw graph it reads, and the methods `specs`, `packs`, `findings`, `findByConcept`, `byFile`, `blastRadius`, `specContext` and `packContext`; a join is added only when a second machine consumer needs it and hand-rolled attempts get it wrong.

Rule

Now

The reader exposes `graph`, the raw graph it reads, and the methods `specs`, `packs`, `findings`, `findByConcept`, `byFile`, `blastRadius`, `resolveEntryAddress`, `specContext` and `packContext`; a join is added only when a second machine consumer needs it and hand-rolled attempts get it wrong.

Rule

rule.entryAddressResolution · added

Now

`resolveEntryAddress` resolves one entry address with the grammar and entry rules that prose validation and entry citations use, and returns `{ entry, resolves, reason }`: `entry` names the resolved entry, such as `rule[2]`, `question[0]` or `design.wrapIdiom`, or is null; `reason` is null when the address resolves and otherwise `malformed`, `spec`, `section` or `entry`; recipe 51 and the vault projection are its machine consumers.

Rule

A roadmap orders the next bodies of work, and the graph says what each still needs

spec:consumers.roadmap

design.entryRow · changed

Base
`{ place, id, title, specKind, altitude, need, statedReadiness, floorReached, statedNextRung, holdsNextRung, work, workRows, buildNow, blockingQuestions, decisions, restsOn, restedOnBy, earlierStatements, packs, sharesScopeWith }` in place order, where `statedNextRung` is null at `ready`, `holdsNextRung` lists the holding rows that keep the floor from the stated next rung, `work` is `{ specs, toDesign, toState, toBuild, built, drift }` counted over the entry's work, `buildNow` lists the ids of its work to build, `packs` lists the entry's Packs other than the roadmap, and `sharesScopeWith` lists places.
Now
`{ place, id, title, specKind, altitude, need, statedReadiness, floorReached, statedNextRung, holdsNextRung, work, workRows, buildNow, blockingQuestions, decisions, restsOn, restedOnBy, earlierStatements, packs, sharesScopeWith }` in place order, where `floorReached` is null when no rung derives and `not evaluated` when no floor is evaluated, `statedNextRung` is null at `ready` and when no floor is evaluated, `holdsNextRung` lists the holding rows that keep the floor from the stated next rung, `work` is `{ specs, toDesign, toState, toBuild, built, drift }` counted over the entry's work, `buildNow` lists the ids of its work to build, `packs` lists the entry's Packs other than the roadmap, and `sharesScopeWith` lists places.

A roadmap renders as the forward section of a pull request description

spec:consumers.roadmap.memo

design.memoDesign · changed

Base
the section `### To design` holds a table with the columns `Place`, `Entry`, `Next` and `Purpose and reach`; `Next` reads, for at most three of the work rows with the entry's need, the entry's own first and the rest in Spec-id order, the row's id as a code span or `itself` for the entry's own, its stated rung and stated next rung as code spans joined by ` → `, then `held by` and each clause id followed by its targets as code spans in parentheses, or `nothing holds it`; then `and <n> more parts to design` when rows are left out; then `blocked by` and each blocking question's address as a code span, or its Spec id when unkeyed; then `decided by` and each decision below `ready` as a code span with its stated rung; the parts joined by `; `.
Now
the section `### To design` holds a table with the columns `Place`, `Entry`, `Next` and `Purpose and reach`; `Next` reads, for at most three of the work rows with the entry's need, the entry's own first and the rest in Spec-id order, the row's id as a code span or `itself` for the entry's own, its stated rung and stated next rung as code spans joined by ` → `, then `held by` and each clause id followed by its targets as code spans in parentheses, or `nothing holds it`, or for a row whose floor is not evaluated its stated rung as a code span followed by `, floor not evaluated`; then `and <n> more parts to design` when rows are left out; then `blocked by` and each blocking question's address as a code span, or its Spec id when unkeyed; then `decided by` and each decision below `ready` as a code span with its stated rung; the parts joined by `; `.

rule.holds · changed

Base

An entry to design names the parts that set its need, its own first, each with its stated next rung and the clauses and dependency targets that hold it, then its blocking questions and its decisions below `ready`; an entry to state names the waiting statements the statement queue puts before its own, inside the entry, elsewhere on the roadmap and outside it, as advice on the order of statements and never as a readiness requirement; an entry to build names each Spec it rests on that is not built.

Rule

Now

An entry to design names the parts that set its need, its own first, each with its stated next rung and the clauses and dependency targets that hold it, or with `floor not evaluated` when no floor is evaluated over the part, then its blocking questions and its decisions below `ready`; an entry to state names the waiting statements the statement queue puts before its own, inside the entry, elsewhere on the roadmap and outside it, as advice on the order of statements and never as a readiness requirement; an entry to build names each Spec it rests on that is not built.

Rule

A pinned declaration shows the words of each test line that cites it

spec:consumers.spec-studio.cited-line-text

design.lineBound · added

Now
a recorded line holds at most a few hundred code units; a longer line is cut at a word boundary and marked as cut, and the whole line stays one source link away

narrative · changed

Base
A reader checking a pinned declaration reaches the test line that cites it and then follows a source link to read the assertion. The words of that line would close the task on the page. The graph records where a line cites an entry and never what the line says, and the Studio reads only the graph and its named inputs, so one of them has to hold the words. The extractor already reads the line when it records the citation, which makes the citation row the cheapest honest home; the choice is the owner's, because it puts source text in the graph for the first time.
Now
A reader checking a pinned declaration reaches the test line that cites it and then follows a source link to read the assertion. The words of that line would close the task on the page. The graph records where a line cites an entry and never what the line says, and the Studio reads only the graph and its named inputs, so one of them has to hold the words. The extractor already reads the line when it records the citation, which makes the citation row the cheapest honest home; the owner chose it, though it puts source text in the graph for the first time.

question.lineBound · removed

Base
question
How long may a recorded line be, and how does a page show a line that was cut?
blocking
false
key
lineBound
decider
delegated
provisional
a bound of a few hundred code units, cut at a word boundary and marked as cut, the whole line one source link away

question.lineText · removed

Base
question
May the Studio show source text the graph does not hold, and if so is it recorded in the graph beside the citation or read as a named input?
blocking
true
key
lineText
decider
owner
provisional
the extractor records the citing line's text, trimmed and bounded, on the citation row it already writes, as inferred data that confers nothing, and the Studio reads no source

rule.lineRecorded · added

Now

The extractor records the citing line's text, trimmed and bounded, on the citation row it already writes, as inferred data that confers nothing; the Studio reads no source to show it.

Rule

The Studio renders from the reader's values and embeds only what its script reads

spec:consumers.spec-studio.data

design.searchRecord · changed

Base
`{ 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.
Now
`{ 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 and `not evaluated` when no floor is evaluated; `bindings` the Specs an Anchor's or CodeNode's outgoing edges reach, with the edge type, and empty for any other node.

The maturity map is drawn as a grid of counts

spec:consumers.spec-studio.diagram-kinds.maturity-picture

rule.discreteCells · changed

Base

Draw one equal-sized cell per stated-rung and floor pair. A populated cell shows its exact count and one mark per member, up to `100` marks, beyond which it is filled solid, and links to that cell's full ordered member list; an empty cell is a faint outline with no number. `matches`, `floor above statement` and `statement above floor` are named once each in the legend, and the diagonal carries an outline. Floor none is distinct from idea, and unresolved members are listed apart.

Rule

Now

Draw one equal-sized cell per stated-rung and floor pair. A populated cell shows its exact count and one mark per member, up to `100` marks, beyond which it is filled solid, and links to that cell's full ordered member list; an empty cell is a faint outline with no number. `matches`, `floor above statement` and `statement above floor` are named once each in the legend, and the diagonal carries an outline. Floor none is distinct from idea, and unresolved members and members whose floor is not evaluated are listed apart.

Rule

rule.fullMembership · changed

Base

Every resolved member appears in exactly one cell list in authored order. The picture holds cell counts, not per-member cards. Without script every populated cell links to its already-built list and every member links to its card.

Rule

Now

Every resolved member whose floor is evaluated appears in exactly one cell list in authored order. The picture holds cell counts, not per-member cards. Without script every populated cell links to its already-built list and every member links to its card.

Rule

A composing panel on every page gathers scoped intent for an agent

spec:consumers.spec-studio.intent-panel

rule.memoPreview · added

Now

Whenever the panel offers the memo, it shows a closed, read-only preview of the same text `Copy memo` copies and `Save memo` saves, so the person can read the hand-off before it leaves.

Rule

ui.composeDialog · moved

Now
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.

ui.composingActions · moved

Now
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.

ui.memoPreview · added

Now
a closed disclosure headed `Preview memo`, before the copy and save actions and shown with them, holding the memo as preformatted text that the person reads and cannot edit.

A Pack page's maturity map places every member by its stated rung and its floor

spec:consumers.spec-studio.pack-page.maturity-map

rule.maturityMap · changed

Base

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.

Rule

Now

After the summary, show the categorical grid and full member lists defined by spec:consumers.spec-studio.diagram-kinds.maturity-picture. Every resolved member whose floor is evaluated belongs to one stated-rung and floor cell; unresolved members and members whose floor is not evaluated are named apart. Populated cells link to their built lists, whose members stay in authored order.

Rule

A Studio build is stamped and shared from a static host

spec:consumers.spec-studio.sharing

rule.stampVerb · changed

Base

`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`.

Rule

Now

`sdp stamp [root] [--commit SHA] [--source TEMPLATE]` writes `stamp.json` into `<root>/generated/spec-studio/` and touches no other file but its staging file `stamp.json.tmp` beside it: it removes a leftover staging file, writes the stamp there and renames it into place, and removes it again when the stamp fails after writing it. It derives no graph, renders no page, and refuses with exit 1 when the root holds no page set or when `generated/` or the page set is a symbolic link; a stamp without `--commit` names the commit `unknown`.

Rule

The Studio's shell frames every page with navigation, a rail and a canvas

spec:consumers.spec-studio.shell

rule.rungBadge · changed

Base

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.

Rule

Now

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. A Spec whose floor is not evaluated shows `floor not evaluated`, and no page raises a divergence banner for it, counts it as stated above its floor or shows its stated next rung.

Rule

A slice page shows a Pack's design as one whole

spec:consumers.spec-studio.slice-page

question.exportCarriesSlice · removed

Base
question
Does a Pack export also carry the Pack's slice page?
blocking
false
key
exportCarriesSlice
decider
delegated
provisional
no; the export keeps the Pack page and its members, and the slice page stays one link away in the page set

rule.exportOmitsSlice · added

Now

A Pack export carries the Pack page and its members' pages and not the slice page, which stays one link from the Pack page in the page set.

Rule

Validation re-runs while an author edits carriers

spec:consumers.validate-watch

behavior.rules[1] · changed

Base

A carrier ends in `.sdp.md`, `.sdp.gherkin` or `.sdp.ts`. The watcher ignores the directories discovery skips, the configured exclusion prefixes and every non-carrier path other than the rules files and parameter files `--rules` names, which it watches wherever they live, as `spec:validation.corpus-rules#rule.watchReruns` and `spec:validation.corpus-rules#rule.watchedParams` state; a removed watched directory and an event with no filename each schedule a run because their affected carriers cannot be named.

Rule

Now

A carrier ends in `.sdp.md`, `.sdp.gherkin` or `.sdp.ts`. The watcher ignores the directories discovery skips, the configured exclusion prefixes and every non-carrier path other than the rules files and parameter files `--rules` names, which it watches wherever they live, as `spec:validation.corpus-rules#rule.watchReruns` and `spec:validation.corpus-rules#rule.watchedParams` state, and the symbolic links discovery warns about, as `spec:extraction.excludes#rule.canonicalDiscovery` states, because creating, removing or replacing one changes the warning list. The watcher never follows a link. A watched directory removed or replaced by a link, a file or another directory, and an event with no filename, each schedule a run because their affected carriers cannot be named. So does a watched directory's own watch reporting a change to the directory itself, because a directory deleted and recreated can keep its identity while that watch has died; on a platform that reports a change to the directory's attributes the same way, that change schedules a run too. An event for an entry that has the directory's own name can look the same and then schedules a run too, as where the filesystem reports no birth time for the directory. A directory that replaces a watched one, the root included, is watched in its place, and a root that no longer resolves to a directory ends the watch with exit 1.

Rule

Every view run rewrites the view wholesale

spec:consumers.wholesale-view-rewrite

behavior.rules[2] · changed

Base

A run that cannot produce a current view removes the stale one instead of leaving it readable as current: an absent view is honest, a stale view is not.

Rule

Now

A run that cannot produce a current view removes the stale one when its output parent remains safe instead of leaving it readable as current: an absent view is honest, a stale view is not.

Rule

behavior.rules[5] · changed

Base

Findings never withhold the view. A run whose checks report findings still writes the current view and returns the checks' own exit code, because the view is where those findings are read in context.

Rule

Now

Validation findings never withhold the view; publication refusals remain separate. A run whose checks report findings still writes the current view and returns the checks' own exit code, because the view is where those findings are read in context.

Rule

rule.portablePublication · added

Now

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.

Rule

rule.safeCleanup · added

Now

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.

Rule

The build pipeline has one ordered flow

spec:extraction.build-pipeline

behavior.flows[2] · changed

Base

Each projection verb runs validation, then renders its root from that same graph and publishes it whatever the findings, keeping validation's exit code.

Flow

Now

Each projection verb runs validation, then renders its root from that same graph and publishes it whatever the findings, keeping validation's exit code unless publication is refused by the write boundary or a case-insensitive page-path collision.

Flow

rule.exclusiveStaging · added

Now

A staged file is created exclusively after removing its stale temporary entry; publication replaces the destination entry rather than truncating through a symbolic or hard link.

Rule

rule.failedPublication · changed

Base

On failure, `sdp build` removes its graph, contracts, manifest, temporary outputs and the confined registrar siblings known from the previous and new manifests. It removes imports only when that invocation requested them. A failed removal names the surviving path and says it must not be read as current; an untrusted registrar path is outside generated ownership.

Rule

Now

On failure, when output parents remain safe, `sdp build` removes its graph, contracts, manifest, temporary outputs and the confined registrar siblings known from the previous and new manifests. It removes imports only when that invocation requested them. A failed removal names the surviving path and says it must not be read as current; an untrusted registrar path is outside generated ownership.

Rule

rule.writeBoundary · added

Now

Before each filesystem mutation, including failure cleanup, the build and publishers recheck that the output parent resolves inside the extraction root. An escaping or unresolvable parent refuses the operation with exit 1 and no cleanup through that parent. A linked `generated/` is refused even when its target is inside the root. The build records the directory identity of `generated/`, checks it between mutations and after publication, and refuses if it changes. This defends against planted links and detects intervening changes; Node has no openat-style operations, so these path checks do not provide race-free confinement against a concurrent writer inside the root.

Rule

A bound example runs its contract steps against a fresh world

spec:extraction.example-runner

rule.handlerDispatch · changed

Base

A missing or stale step handler is a compile-time refusal rather than a silent skip: the bindings type covers every step and only the steps, so spec-side drift fails the typecheck instead of the run.

Rule

Now

The bindings type covers every step and only the steps, so missing or stale handlers fail typechecking. At execution, dispatch looks up the contract key on the bindings and then their prototype chain, calling the first function found with the bindings as `this` and the world, parameters and contract step as arguments. An inherited owner is excluded, and traversal stops before it, when its prototype is null or when it is callable and its prototype's prototype is null; these boundaries exclude Object.prototype and Function.prototype from any realm while preserving inherited instance and static class methods. Own handlers remain eligible even on null-prototype or callable bindings. Methods of built-in parent classes such as Map, Array and Promise remain eligible before those boundaries. An inherited `constructor`, a missing handler or a first value that is not a function fails at execution with `no handler bound for step key "<key>"`; dispatch never skips that value to find a later function.

Rule

Extraction exclusions are strict consumer input

spec:extraction.excludes

rule.canonicalDiscovery · changed

Base

Discovery reads Spec and Pack carriers by the suffixes `.sdp.md`, `.sdp.gherkin` and `.sdp.ts`. Other `.ts` and `.tsx` files are anchor candidates, except `.d.ts` files. Discovery never descends into `node_modules`, `dist`, `generated`, `coverage` or a dot-directory, and configured exclusions apply to both lists.

Rule

Now

Discovery reads Spec and Pack carriers by the suffixes `.sdp.md`, `.sdp.gherkin` and `.sdp.ts`. Other `.ts` and `.tsx` files are anchor candidates, except `.d.ts` files. Discovery never descends into `node_modules`, `dist`, `generated`, `coverage` or a dot-directory, and configured exclusions apply to both lists. Discovery never follows a symbolic link below the root, and a root named explicitly is resolved to its real directory first. A link that discovery reaches outside the configured exclusions gets one warning naming it when the entry it stands for would be read: a link to a directory warns unless discovery skips a directory of that name, and any other link, one with a missing target included, warns only when its name is a carrier or anchor-candidate filename, even one that starts with a dot.

Rule

The build derives step and space contracts from graph examples

spec:extraction.executable-contracts

design.findingIds · changed

Base
`contracts/undeclared-slot` · `contracts/off-dimension-value` · `contracts/conflicting-binding` · `contracts/conflicting-dimension` · `contracts/untyped-vocabulary-slot` · `contracts/multi-entry-example` · `contracts/unmatched-vocabulary-step` · `contracts/case-colliding-path` · `contracts/multiple-registrar-paths` · `contracts/conflicting-step-key` · `contracts/duplicate-step-key`, each at warning severity.
Now
`contracts/undeclared-slot` · `contracts/off-dimension-value` · `contracts/conflicting-binding` · `contracts/conflicting-dimension` · `contracts/untyped-vocabulary-slot` · `contracts/multi-entry-example` · `contracts/unmatched-vocabulary-step` · `contracts/case-colliding-path` · `contracts/multiple-registrar-paths` · `contracts/conflicting-step-key` · `contracts/duplicate-step-key` · `contracts/reserved-then-slot` · `contracts/reserved-then-key`, each at warning severity.

design.planDispatch · changed

Base
the runner's `planExample` runs each step through `bindings[step.key]`, carries `key` on each planned step beside `text` and `label`, and renders the label from `text` and `params`, so a red keyed step still names itself in the Spec's own words.
Now
the runner's `planExample` dispatches each contract key to an own or inherited handler with the bindings as `this`, following the realm-independent prototype boundaries and refusals in `spec:extraction.example-runner#rule.handlerDispatch`. Built-in parent-class methods remain eligible before those boundaries; an inherited `constructor`, missing handler or non-function fails with `no handler bound for step key "<key>"`. Each planned step carries `key` beside `text` and `label`, and the label renders from `text` and `params`, so a red keyed step still names itself in the Spec's own words.

rule.reservedThenKey · added

Now

The contract key `unspecified` is reserved for the coverage-gap outcome, whether written as a step key or as unkeyed Then text. A Then using it is a `conformance/reserved-then-key` error. Generation withholds its space contract when declared in a vocabulary, or its step contract when carried by an example, with `contracts/reserved-then-key` naming the reserved key; a withheld space contract also withholds its children's registrars. Given and When keys remain unrestricted.

Rule

rule.reservedThenSlot · added

Now

A Then slot named `kind` withholds its space contract when declared in a vocabulary, or its step contract when carried by an example, with `contracts/reserved-then-slot` naming the reserved word; a withheld space contract also withholds its children's registrars. Outcome variants keep their flat shape, with `kind` as the discriminant and the other slots as sibling fields.

Rule

Derived runnable modules freeze the registrar interface

spec:extraction.runnable-modules

behavior.rules[10] · changed

Base

Failure rendering reuses the contract's matching Then step plus the existing `renderContractStep` path. When the oracle selected no authored Then, emit a scenario-level diagnostic quoting Spec ID, oracle kind, and the contract keys of the available Then steps; preserve the original assertion as `cause`.

Rule

Now

Failure rendering reuses the contract's matching Then step plus the existing `renderContractStep` path. When a specified oracle outcome selected no authored Then, emit a scenario-level diagnostic quoting Spec ID, oracle kind, and the contract keys of the available Then steps; preserve the original assertion as `cause`.

Rule

design.unspecifiedCoverageGap · added

Now
`scenario <spec>: oracle selected "unspecified"; coverage gap cannot witness a bound example` is the diagnostic for an unspecified oracle outcome, with `oracle outcome "unspecified" names a coverage gap` as its cause.

rule.reservedThenKey · changed

Base

Bound unspecified outcome — `unspecified` names a coverage gap in the example space, but a bound executable example selecting it reddens because no authored Then may silently witness that gap.

Rule

Now

The Then contract key `unspecified` is reserved under spec:extraction.executable-contracts#rule.reservedThenKey. An oracle returning `unspecified` names a coverage gap; a bound executable example selecting it reddens with a distinct coverage-gap diagnostic because no authored Then may witness that gap.

Rule

Source anchors bind code without carrying intent

spec:model.anchors

term.Protocol builder binding · changed

Base
A builder import from the public Protocol package or its anchors subpath, or a relative import whose importer-relative resolution, including the TypeScript `.js`-to-`.ts` convention, canonicalizes to this package's `ids`, `anchors` or `model/code-anchor` module; consumer-local lookalike modules confer no binding authority. On the CommonJS package surface the trusted relative-module set is empty (`import.meta.url` is rewritten away), so relative bindings mint no anchors there while package imports stay trusted. The comment form needs no builder binding.
Now
A builder import from the public Protocol package or its anchors subpath, or a relative import whose importer-relative resolution, including the TypeScript `.js`-to-`.ts` convention, canonicalizes to a trusted source module. The trusted modules are `src/ids.ts`, `src/anchors.ts` and `src/model/code-anchor.ts` in the running engine's package and, when the extraction root's own `package.json` names `@libar-dev/software-delivery-protocol`, in that root too. Consumer-local lookalike modules confer no binding authority. The CommonJS package surface cannot locate the engine's own source modules, but still trusts the identified extraction root's modules and package imports. The comment form needs no builder binding.

CI run records are joined to verifiers in a view

spec:observation.run-evidence

narrative · changed

Base
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.
Now
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. Whether changes to bound files also make a run stale waits on the bound-file freshness capture, `spec:observation.run-evidence.bound-file-freshness`.

question.freshness · removed

Base
question
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?
blocking
false
key
freshness
decider
owner
provisional
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.

The Protocol removes its frozen plans, review reports and superseded concept material

spec:protocol.delivery-record-cleanup

question.durableContent · changed

Base
question
Which content in `plans/`, `reviews/` and the concept documents does no Spec, test, decision or recipe carry yet, and where does each piece belong?
blocking
true
key
durableContent
decider
owner
provisional
a measured inventory by the arc that removes them, reviewed before anything is deleted
Now
question
Which content in `plans/`, `reviews/` and the concept documents does no Spec, test, decision or recipe carry yet, and where does each piece belong?
blocking
true
key
durableContent
decider
owner
provisional
the owner accepted the whole-repository review's measured inventory, with its row rulings, as the answer; the question leaves the Spec when the cleanup arc lands that inventory in its first commit

rule.inventoryFirst · added

Now

The arc that removes them opens with a measured inventory, in its first commit, of what `plans/`, `reviews/` and the concept documents still carry that no Spec, test, decision or recipe carries, each piece with its home; a review by another model family checks the inventory before anything is deleted.

Rule

Machine truth is never authored

spec:validation.authored-honesty

rule.reservedProperties · changed

Base

Specs and Packs author no derived edge or delivery fact.

Rule

Now

Specs and Packs author no derived edge or delivery fact. Spec and Pack envelope properties, top-level properties of each section record and each entry in a section array, and keyed Markdown entries reserve `implemented`, `has-verifier`, `hasVerifier`, `observed` and `deliveryFacts`, compared case-insensitively, and `claim`, `nodeType`, `specKind`, `satisfies`, `verifies`, `belongsTo` and `models`. Underscore forms are not delivery-fact names. Gherkin tags refuse delivery-fact names and authored claim or lifecycle lookalikes. Nested content, such as a Model term named `implemented` or a key inside a Design value, may name these concepts without authoring graph truth.

Rule

The floor names what blocks the floor's next rung

spec:validation.next-rung-floor

behavior.rules[0] · changed

Base

The evaluator takes an optional rung to evaluate. Given one, it evaluates the cumulative clauses of every rung up to and including it; without one, it evaluates up to the stated rung. A Spec of an unratified kind, or an evaluation with no ratified rung to reach, yields no failure, and the descriptor conformance error owns that case.

Rule

Now

The evaluator takes an optional rung to evaluate. Given one, it evaluates the cumulative clauses of every rung up to and including it; without one, it evaluates up to the stated rung. A Spec of an unratified kind or altitude, or an evaluation with no ratified rung to reach, yields no failure, and the descriptor conformance error owns that case.

Rule

behavior.rules[1] · changed

Base

The floor's next rung is the rung above derived readiness: `idea` when no rung derives, and none when derived readiness is `ready`. Because derived readiness is the highest rung whose cumulative clauses all pass, the failures at the floor's next rung are that rung's own clauses, and there is at least one whenever that rung exists for a Spec of a ratified kind.

Rule

Now

The floor's next rung is the rung above derived readiness: `idea` when no rung derives, and none when derived readiness is `ready` or no floor is evaluated. Because derived readiness is the highest rung whose cumulative clauses all pass, the failures at the floor's next rung are that rung's own clauses, and there is at least one whenever that rung exists.

Rule

rule.notEvaluated · added

Now

No floor is evaluated over a Spec whose kind or altitude is unratified. The reader marks such a Spec with `floorNotEvaluated`, naming those descriptors with the kind first, and gives it no derived readiness, no floor's next rung and no stated next rung; its failure lists are empty because nothing was evaluated, so a consumer can read it as not evaluated rather than as below `idea` or as a rung nothing blocks.

Rule

Stated readiness must clear its floor

spec:validation.readiness-floor

behavior.rules[11] · changed

Base

Given a Primitive node and a valid graph index over plain value data, evidence predicates tolerate section containers of the wrong shape and treat missing expected containers as absent evidence. An unratified kind derives no rung; an evaluation with an unratified kind or rung returns no failures, and descriptor conformance reports the invalid descriptor.

Rule

Now

Given a Primitive node and a valid graph index over plain value data, evidence predicates tolerate section containers of the wrong shape and treat missing expected containers as absent evidence. An unratified kind or altitude derives no rung; an evaluation with an unratified kind, altitude or rung returns no failures, and descriptor conformance reports the invalid descriptor.

Rule

Packs with membership, member order or order meaning changes

changed · pack:self-hosting-v1

Members added: spec:consumers.ai-assisted-reading, spec:consumers.agent-surface.combination-coverage, spec:observation.run-evidence.bound-file-freshness

Members removed: None

Member order unchanged.

Bindings, derived from anchors

The Markdown body accepts one closed form per section

Implementing units

Added: None

Removed: None

Referencing units

Added: None

Removed: None

Enabled verifiers

Added: test:protocol.markdown-body-grammar-regressions

Removed: None

Delivery facts

Added: None

Removed: None

Authors move one Spec from intent to reviewed evidence

Implementing units

Added: None

Removed: None

Referencing units

Added: None

Removed: None

Enabled verifiers

Added: test:protocol.spec-scaffolder

Removed: None

Delivery facts

Added: None

Removed: None

Design Review renders graph context without becoming a gate

Implementing units

Added: None

Removed: None

Referencing units

Added: None

Removed: None

Enabled verifiers

Added: test:protocol.cli-write-boundaries

Removed: None

Delivery facts

Added: None

Removed: None

Gherkin view renders any Spec as a disposable read shape

Implementing units

Added: None

Removed: None

Referencing units

Added: None

Removed: None

Enabled verifiers

Added: test:protocol.cli-write-boundaries

Removed: None

Delivery facts

Added: None

Removed: None

Mermaid renders bounded one-hop and Pack diagrams without becoming a graph browser

Implementing units

Added: None

Removed: None

Referencing units

Added: None

Removed: None

Enabled verifiers

Added: test:protocol.cli-write-boundaries

Removed: None

Delivery facts

Added: None

Removed: None

Projections fan out from one graph without becoming truth stores

Implementing units

Added: None

Removed: None

Referencing units

Added: None

Removed: None

Enabled verifiers

Added: test:protocol.cli-write-boundaries

Removed: None

Delivery facts

Added: None

Removed: None

Every view run rewrites the view wholesale

Implementing units

Added: None

Removed: None

Referencing units

Added: None

Removed: None

Enabled verifiers

Added: test:protocol.cli-write-boundaries

Removed: None

Delivery facts

Added: None

Removed: None

The build pipeline has one ordered flow

Implementing units

Added: None

Removed: None

Referencing units

Added: None

Removed: None

Enabled verifiers

Added: test:protocol.cli-write-boundaries

Removed: None

Delivery facts

Added: None

Removed: None

Source anchors bind code without carrying intent

Implementing units

Added: None

Removed: None

Referencing units

Added: None

Removed: None

Enabled verifiers

Added: test:protocol.structural-anchor-regressions

Removed: None

Delivery facts

Added: None

Removed: None

Diagnostics

None.

Composing (0)

Composing needs the script.