Spec Studio

A change proposal is addressed, based and checked before it lands

spec:consumers.intent-composition.proposalContract · storyready floor ready

Packs: pack:design-iteration-v1, pack:design-management-v1, pack:self-hosting-v1

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

Findings: no errors, no warnings

specs/consumers/intent-composition.proposal.sdp.md

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

The original design's patch loop made every change from a view reviewable and checked before it touched source. A patch named its target, the graph hash it was made against, a rationale, its operations and who proposed it; a CLI checked its schema and its base, applied it to a copy of the graph, ran the validators and only then rewrote the Spec files (docs/lineage/v0-design/02-system-architecture.md §2; 07-spec-studio-and-projections.md §6). The Protocol refused the patch and the codemod. A view composes scoped intent, an agent edits source as a person would, git records the edit and the same checks evaluate it. That edit model drops two things the patch loop gave: a proposed change a person can review before an agent applies it, and a guard against a proposal made against an older design.

The first adopter's agents already write proposals in that shape. A design pass returns findings that each name an entry address or a Spec section, state the gap, and propose exact text for a Spec with the entry it replaces or follows (libar-platform/design/advisors/task-pass.md), and its register tool applies a JSON patch only after checking all of it (libar-platform/design/advisors/register.md). This Spec states the reviewable half of the patch loop without the codemod. A proposal is a request that an agent applies as an ordinary edit, checked by sdp validate on a worktree before it merges. It also gives the Spec Studio's composing panel a shape to hand off.

Intent
problem
A proposed design change travels as free prose, so a reviewer cannot tell what it touches, which version of the design it read, or whether it still applies once the design has moved.
outcome
Give a proposed design change a reviewable shape: what it touches by Spec id or entry address, the commit it was read at, the change requested and why, checked on a worktree before merge.
Contract
rule line 25 · specs/consumers/intent-composition.proposal.sdp.md:25
A proposal is one JSON document on one schema, which a recipe takes as a parameter; a Markdown memo is a rendering of that document and never a second source of it.
rule line 26 · specs/consumers/intent-composition.proposal.sdp.md:26
A proposal names its scope as one or more Spec ids or entry addresses, each resolved before anything is applied: a Spec id through the reader's Spec context, an entry address through address resolution.
rule line 27 · specs/consumers/intent-composition.proposal.sdp.md:27
A proposal names the commit whose graph it was read against.
rule line 28 · specs/consumers/intent-composition.proposal.sdp.md:28
A proposal states the requested change in words an agent can apply, such as the exact text for an entry with the address it replaces or follows, a new open question with its flag, or a relation to declare or remove.
rule line 29 · specs/consumers/intent-composition.proposal.sdp.md:29
A proposal states its reason in one line.
rule line 30 · specs/consumers/intent-composition.proposal.sdp.md:30
The proposal check compares each change's scope between the proposal's base commit and the working tree through the design diff, entry by entry, and reports each change on its own row, so one changed scope never hides the state of another change; the check applies nothing and routes nothing.
rule line 31 · specs/consumers/intent-composition.proposal.sdp.md:31
Applying a proposal is an ordinary source edit by an agent or a person; no tool rewrites a carrier from it, and nothing is applied to a copy of the graph first.
rule line 32 · specs/consumers/intent-composition.proposal.sdp.md:32
A proposal carries no status, approval or verdict, and the graph records none; whether it was accepted is git history and the adopter's own record.
rule line 33 · specs/consumers/intent-composition.proposal.sdp.md:33
A proposal carries no proposer. Whoever hands it over is its author until it is applied, and then git authorship and co-author trailers are the record; the schema refuses the field.

9 unkeyed rules.

Design
proposalDocument line 37 · specs/consumers/intent-composition.proposal.sdp.md:37
{ "schema": "sdp-proposal/1", "base": "<commit>", "reason": "<one line>", "changes": [change] }, with schema, base, reason and a non-empty changes required and no other field.

no citation recorded

proposalChange line 38 · specs/consumers/intent-composition.proposal.sdp.md:38
{ "scope": ["<spec id or entry address>"], "request": "<words an agent can apply>", "text": "<exact entry text>", "replaces": "<entry address>", "follows": "<entry address>", "relation": { "action": "declare", "from": "<spec id>", "type": "dependsOn", "target": "<spec id>" }, "reason": "<one line>" }, with scope non-empty and request required, replaces and follows exclusive, action either declare or remove, from naming the relation's source Spec, and no other field.

no citation recorded

proposalSchemaFile line 39 · specs/consumers/intent-composition.proposal.sdp.md:39
the package ships the document's JSON Schema as schemas/sdp-proposal-1.schema.json, so an agent can use it as a structured-output schema; the check recipe validates the same shape itself, and a test holds the two to the same accepted and refused samples.
checkRecipe line 40 · specs/consumers/intent-composition.proposal.sdp.md:40
recipe 38, the proposal check, takes params.proposal and params.base, the base graph, and returns { schemaProblems: [{ path, problem }], base, diagnostics, totals: { changes, moved, unresolved }, changes }, with the design diff's diagnostics for the Specs it compares; when the document breaks the schema or the base graph is missing it returns the problems and no change rows.
checkedScope line 41 · specs/consumers/intent-composition.proposal.sdp.md:41
the check resolves and compares the deduplicated union of scope, replaces, follows and relation.from, and a change row's scope reports that union, so an entry a change replaces or follows cannot move unseen.
checkRows line 42 · specs/consumers/intent-composition.proposal.sdp.md:42
each change row is { index, scope: [{ ref, resolvesAtHead, resolvesAtBase, moved }], moved, relationTarget }; an item's moved is true when its Spec is added or removed between the two graphs, and otherwise, for an entry address, when the entry's value is added, removed or changed, an order-only move leaving it false, or, for a whole Spec, when any of its parts changed or moved in order; the row's moved is true when any item's is; relationTarget is { ref, resolvesAtHead } for a declared relation and null otherwise.
incomparableScope line 43 · specs/consumers/intent-composition.proposal.sdp.md:43
an item outside the common schema, or an otherwise unmoved whole-Spec item whose order across rules and flows one graph does not keep, carries comparable: false and a reason in place of moved; its row carries comparable: false and a null moved unless another item moved.
Verification

Verifier bindings

  • test:protocol.proposal-schema-and-recipe · anchored · test anchor binding present · test/iteration-recipes.test.ts:1517

    External run evidence from test/iteration-recipes.test.ts

    Test anchors: test:protocol.context-bundle-recipe, test:protocol.design-diff-recipe, test:protocol.perspective-filter-recipe, test:protocol.proposal-schema-and-recipe. Specs verified by those bindings: spec:consumers.context-bundle, spec:consumers.design-diff, spec:consumers.intent-composition.proposal, spec:consumers.review-perspectives.

    Run 1: external run evidence from vitest 4.1.10

    Build: CI 391 · Branch: cursor/media-plan-and-articles-09b1 · Commit: 076cd4f1f85640d8236e5cca1bffffa68ab79a33 · Start: 2026-10-31T15:32:20.471Z · Stop: 2026-10-31T15:34:02.073Z

    NameSuiteResultDuration
    compares keyed values, keyed order and unkeyed sections while keeping bindings apartiteration loop: design diffpassed83.58 ms
    compares question fields by key, whole unkeyed questions, envelope fields and other sectionsiteration loop: design diffpassed24.03 ms
    reports added and removed Specs and Packs, filters the union of membership, and ignores source linesiteration loop: design diffpassed39.49 ms
    diagnoses required input and schema differences and compares common contentiteration loop: design diffpassed10.49 ms
    runs the documented base-worktree procedure, preserves constant anchors, and compares HEADiteration loop: design diffpassed23367.74 ms
    compares a keyed rule that becomes a flow at the same addressiteration loop: design diffpassed31.53 ms
    compares new Design entries across schema versions when the base corpus has noneiteration loop: design diffpassed26.78 ms
    diagnoses uncertain optional fields at base 0.9.0 and head 0.9.0iteration loop: design diffpassed14.73 ms
    diagnoses uncertain optional fields at base 0.9.0 and head 0.10.0iteration loop: design diffpassed18.9 ms
    diagnoses uncertain optional fields at base 0.10.0 and head 0.9.0iteration loop: design diffpassed28.09 ms
    normalizes legacy rule markers in graphs with comparable rule-key capabilityiteration loop: design diffpassed17.53 ms
    invents no order across rules and flows from a legacy baseiteration loop: design diffpassed26.36 ms
    compares a legacy base's keyed entries by order within each listiteration loop: design diffpassed21.05 ms
    reports proposal scopes outside the common schema as incomparableiteration loop: design diffpassed7.3 ms
    lists all authored reasons into and out of the planning subject in type/from/to orderrelation reasons in planning recipespassed18.61 ms
    keeps dependency reasons in context-bundle footingrelation reasons in planning recipespassed8.94 ms
    matches every declared selector, combines requirements, and keeps authored order unless prioritizediteration loop: perspective filterpassed69.31 ms
    matches layers and contexts only through named bindings and keeps anchored matches apartiteration loop: perspective filterpassed27.79 ms
    reports malformed and unsupported selectors while applying understood onesiteration loop: perspective filterpassed26.17 ms
    keeps term addresses, term lines and key maps through the section cutiteration loop: context bundlepassed29.65 ms
    keeps questions and declarations in one place and member-example steps only in their member rowiteration loop: context bundlepassed30.4 ms
    takes the declaration cut last only with addresses and keeps compact pointers and linksiteration loop: context bundlepassed91.81 ms
    cuts a pinned dotted key to its line when it has no entry addressiteration loop: context bundlepassed20.04 ms
    composes both scopes, dependency footing, declarations, example bindings and a perspective subsetiteration loop: context bundlepassed38.24 ms
    takes all six whole-mode cuts in fixed order and counts the complete returned value including Unicodeiteration loop: context bundlepassed70.24 ms
    keeps a pinned declaration whole through the sixth cut when its key contains a dotiteration loop: context bundlepassed21.59 ms
    reports invalid, missing, doubled and unknown scopes without a partial bundleiteration loop: context bundlepassed34.89 ms
    accepts term scopes and detects changed definitions through their authored keysiteration loop: proposal schema and checkpassed39.18 ms
    holds the schema and recipe to the same accepted and refused documentsiteration loop: proposal schema and checkpassed126.52 ms
    checks the complete scope union, resolves both graphs, and reports each change independentlyiteration loop: proposal schema and checkpassed15.33 ms
    agrees with recipe 35 on added, removed and changed entry values and on whole-Spec changesiteration loop: proposal schema and checkpassed13.3 ms
    excludes anchor-only changes and requires the caller's base graphiteration loop: proposal schema and checkpassed14.83 ms
    compares interleaved keyed rules and flows in their authored order and reports verifier changes apartiteration loop: comparison and budget edgespassed21.4 ms
    cuts example text once and preserves compact pointers after the sixth cutiteration loop: comparison and budget edgespassed60.02 ms
    reads the base graph and proposal from named JSON files through the real parameter seamiteration loop: comparison and budget edgespassed8.13 ms
    requires a test bound directly to an example before the bundle names it enablediteration loop: example enablementpassed17.83 ms
    compares rule order by text and other anonymous collections as a wholeiteration loop: anonymous collection orderpassed16.78 ms
    keeps addresses in each place when narrative, example, question and section text are cutiteration loop: protected entry addressespassed47.69 ms
Design view

Requirement drawing

Requirement drawing for spec:consumers.intent-composition.proposal
The diagram as text
  • spec:consumers.intent-composition.proposal: A change proposal is addressed, based and checked before it lands · declared Spec
  • spec:consumers.intent-composition.proposal.memo: Recipe 49 renders a change proposal as the Markdown memo a person reviews · declared Spec
  • 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: Composed intent hands off on one proposal shape · declared Spec
  • impl:protocol.proposal-memo-recipe: realizes the catalog proposal memo through its verbatim body check · anchored code · test/recipes.test.ts:7298
  • impl:protocol.proposal-schema-and-recipe: realizes the shipped proposal schema and proposal check in the recipe catalog · anchored code · test/iteration-recipes.test.ts:1510
  • impl:protocol.studio-proposal-contract: browser proposal shape and schema checks · anchored code · src/studio-elements/proposal.ts:1
  • impl:protocol.studio-proposal-memo: renders proposal fields verbatim with fences that outgrow their content · anchored code · src/studio-elements/memo.ts:13
  • oracle:protocol.studio-memo: oracle:protocol.studio-memo · anchored oracle binding · test/studio-s5.test.ts:262
  • test:protocol.proposal-schema-and-recipe: test:protocol.proposal-schema-and-recipe · anchored test binding · binding present · test/iteration-recipes.test.ts:1517
  • test:protocol.studio-memo-shared: test:protocol.studio-memo-shared · anchored test binding · binding present · test/studio-s5.test.ts:272
  • spec:consumers.intent-composition.proposal refines spec:consumers.intent-composition · declared
  • spec:consumers.intent-composition.proposal.memo refines spec:consumers.intent-composition.proposal · declared
  • spec:consumers.intent-composition.proposal.memo.shared refines spec:consumers.intent-composition.proposal.memo · declared
  • spec:consumers.intent-composition.proposal.memo.shared verifies spec:consumers.intent-composition.proposal.memo · declared
  • impl:protocol.proposal-memo-recipe satisfies spec:consumers.intent-composition.proposal.memo · anchored
  • impl:protocol.proposal-schema-and-recipe satisfies spec:consumers.intent-composition.proposal · anchored
  • impl:protocol.studio-proposal-contract satisfies spec:consumers.intent-composition.proposal · anchored
  • impl:protocol.studio-proposal-memo satisfies spec:consumers.intent-composition.proposal.memo · anchored
  • oracle:protocol.studio-memo models spec:consumers.intent-composition.proposal.memo · anchored
  • test:protocol.proposal-schema-and-recipe verifies spec:consumers.intent-composition.proposal · anchored
  • test:protocol.studio-memo-shared verifies spec:consumers.intent-composition.proposal.memo.shared · anchored
Mermaid source

Copyable source; the Studio draws static SVG.

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

Decisions

No decision record named.

Runtime
  • component:protocol.studio-elements · optional browser behavior and proposal handoff · src/studio-elements/index.ts:13 · layer edge · context protocol

    Uses

    • 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:671 · layer application · context protocol
  • impl:protocol.proposal-schema-and-recipe · realizes the shipped proposal schema and proposal check in the recipe catalog · test/iteration-recipes.test.ts:1510

    Uses

    None.

  • impl:protocol.studio-proposal-contract · browser proposal shape and schema checks · src/studio-elements/proposal.ts:1

    Component: component:protocol.studio-elements · optional browser behavior and proposal handoff · src/studio-elements/index.ts:13 · 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
Relations of spec:consumers.intent-composition.proposal
The diagram as text
  • spec:consumers.agent-surface.address-and-cycle-recipes: Address resolution and dependency cycles stay executable graph recipes
  • spec:consumers.delivery-session-on-ramp: Delivery sessions route work from current graph state
  • spec:consumers.design-diff: Designs are compared between a base commit and the working tree at entry grain
  • spec:consumers.edit-model: Views compose scoped intent instead of patching canonical source
  • spec:consumers.intent-composition: Composed intent hands off on one proposal shape
  • spec:consumers.intent-composition.proposal: A change proposal is addressed, based and checked before it lands
  • spec:consumers.intent-composition.proposal.memo: Recipe 49 renders a change proposal as the Markdown memo a person reviews
  • spec:consumers.obsidian-vault.iteration: A design pass is followed and answered from the vault
  • spec:consumers.spec-studio.intent-panel: A composing panel on every page gathers scoped intent for an agent
  • spec:consumers.upgrade-kit.rule-key-proposal: The rule-key proposal keys every unkeyed rule as a change proposal
  • spec:protocol.roadmap-replaces-plans: The Protocol reads its next work from its roadmap and keeps its delivery record in git and its pull requests
  • spec:consumers.intent-composition.proposal dependsOn spec:consumers.agent-surface.address-and-cycle-recipes · declared — the check resolves entry-address scopes through address resolution
  • spec:consumers.intent-composition.proposal dependsOn spec:consumers.design-diff · declared
  • spec:consumers.intent-composition.proposal dependsOn spec:consumers.edit-model · declared
  • spec:consumers.intent-composition.proposal refines spec:consumers.intent-composition · declared
  • spec:consumers.delivery-session-on-ramp dependsOn spec:consumers.intent-composition.proposal · declared — the design loop hands its findings back as a change proposal checked against its base
  • spec:consumers.obsidian-vault.iteration dependsOn spec:consumers.intent-composition.proposal · declared — intent composed in the vault hands off on the one proposal contract
  • spec:consumers.spec-studio.intent-panel dependsOn spec:consumers.intent-composition.proposal · declared — the panel hands off a change proposal
  • spec:consumers.upgrade-kit.rule-key-proposal dependsOn spec:consumers.intent-composition.proposal · declared — the recipe writes a change proposal in the shape the proposal check reads
  • spec:protocol.roadmap-replaces-plans dependsOn spec:consumers.intent-composition.proposal · declared — a review's findings against Specs travel as a checked change proposal
  • spec:consumers.intent-composition.proposal.memo refines spec:consumers.intent-composition.proposal · declared
Mermaid source

Copyable source; the Studio draws static SVG.

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

Rests on

Rested on by

Distance 1

Distance 2

Distance 3

Distance 4

Distance 5

Distance 6

Relations

Relation and directionOther endClaimReasonExercised keys
dependsOn · outgoingAddress resolution and dependency cycles stay executable graph recipes
spec:consumers.agent-surface.address-and-cycle-recipes · resolves
declaredthe check resolves entry-address scopes through address resolutionNone
dependsOn · outgoingDesigns are compared between a base commit and the working tree at entry grain
spec:consumers.design-diff · resolves
declaredNoneNone
dependsOn · outgoingViews compose scoped intent instead of patching canonical source
spec:consumers.edit-model · resolves
declaredNoneNone
refines · outgoingComposed intent hands off on one proposal shape
spec:consumers.intent-composition · resolves
declaredNoneNone
dependsOn · incomingDelivery sessions route work from current graph state
spec:consumers.delivery-session-on-ramp · resolves
declaredthe design loop hands its findings back as a change proposal checked against its baseNone
dependsOn · incomingA design pass is followed and answered from the vault
spec:consumers.obsidian-vault.iteration · resolves
declaredintent composed in the vault hands off on the one proposal contractNone
dependsOn · incomingA composing panel on every page gathers scoped intent for an agent
spec:consumers.spec-studio.intent-panel · resolves
declaredthe panel hands off a change proposalNone
dependsOn · incomingThe rule-key proposal keys every unkeyed rule as a change proposal
spec:consumers.upgrade-kit.rule-key-proposal · resolves
declaredthe recipe writes a change proposal in the shape the proposal check readsNone
dependsOn · incomingThe Protocol reads its next work from its roadmap and keeps its delivery record in git and its pull requests
spec:protocol.roadmap-replaces-plans · resolves
declareda review's findings against Specs travel as a checked change proposalNone
refines · incomingRecipe 49 renders a change proposal as the Markdown memo a person reviews
spec:consumers.intent-composition.proposal.memo · resolves
declaredNoneNone

Bindings

Implementation binding: present

  • impl:protocol.proposal-schema-and-recipe · realizes the shipped proposal schema and proposal check in the recipe catalog · test/iteration-recipes.test.ts:1510 · role contract
  • impl:protocol.studio-proposal-contract · browser proposal shape and schema checks · src/studio-elements/proposal.ts:1 · role contract · component component:protocol.studio-elements · layer edge · context protocol

Design reference: none

Verifier binding: present

  • test:protocol.proposal-schema-and-recipe · anchored · test/iteration-recipes.test.ts:1517 · 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.