Spec Studio

A Studio build is stamped and shared from a static host

spec:consumers.spec-studio.sharingUse Case / Behavior · storyready floor ready

Packs: pack:self-hosting-v1, pack:spec-studio-v1

Design: 9 design entries · 3 pinned declarations · no decisions

Findings: no errors, no warnings

specs/consumers/spec-studio.sharing.sdp.md

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

A page set is a function of the graph and its named inputs, so it carries no commit or time. A reviewer opening a preview still needs to know which commit and which engine built it, so a publishing step that runs after the build writes one stamp file at the page set's root, and the shell shows it where the set is served over http or https. The same stamp may name where the repository's source is served, so a recorded file and line become a link in a preview and stay text everywhere else. A reusable workflow does the build, the stamp and the upload for every pull request, and deploys a preview only where the repository has chosen a host. Checks and previews use GitHub's default pull-request merge checkout, so the gate proves the merge result and the run evidence, page set and stamp name that same commit.

A stakeholder opens the link, navigates the Studio and composes intent, and the pull request's author hands that intent to an agent that edits the source.

Intent
outcome
Let a stakeholder open the Studio of a pull request from a link, and let its author know which graph and which build the stakeholder read.
Behavior
rule line 25 · specs/consumers/spec-studio.sharing.sdp.md:25
A build is shared by uploading its page set to a static host, such as S3, Vercel or GitHub Pages.
rule.buildWritesNoStamp line 26 · specs/consumers/spec-studio.sharing.sdp.md:26
The Studio's build writes no stamp, so every page and data file it writes stays a function of the graph and its named inputs; the stamp is written apart, after the build.

spec:consumers.spec-studio.sharing.stamp-written-apart · enabled

rule.stampVerb line 27 · specs/consumers/spec-studio.sharing.sdp.md:27
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.

spec:consumers.spec-studio.sharing.stamp-written-apart · enabled

rule.stampLifetime line 28 · specs/consumers/spec-studio.sharing.sdp.md:28
A later build removes the page set and its stamp together, so no stamp outlives the build it names.

spec:consumers.spec-studio.sharing.stamp-written-apart · enabled

Cited at

  • test/skills.test.ts:1797
rule.publishingStep line 29 · specs/consumers/spec-studio.sharing.sdp.md:29
Publishing a preview and writing its stamp are a step the adopter's CI runs, never the Studio's build; the shell reads the stamp as spec:consumers.spec-studio.shell#rule.stamp states.

no example exercises it

rule.previewWorkflow line 30 · specs/consumers/spec-studio.sharing.sdp.md:30
The package's repository ships a reusable GitHub Actions workflow that, on a pull request, installs the caller's dependencies, runs sdp studio with the caller's root, exclusions and inputs, runs sdp stamp with the checked-out merge commit and the repository's source template, and uploads the page set as a CI artifact; it opens no pull request, writes no comment and holds no credential beyond the run's own token.

no example exercises it

rule.previewDeploy line 31 · specs/consumers/spec-studio.sharing.sdp.md:31
The workflow deploys the stamped page set under /preview/<pr-number>/ only when the caller asks for it and the repository serves a host from the branch the workflow writes to; a pull request from a fork never deploys.

no example exercises it

rule.previewPublished line 32 · specs/consumers/spec-studio.sharing.sdp.md:32
A deploy that pushes a preview succeeds only once the host has built the commit it pushed; a host build that errors, or does not finish within the wait, fails the job, so a green deploy means the preview is live.

no example exercises it

rule.sourceLinks line 33 · specs/consumers/spec-studio.sharing.sdp.md:33
Every recorded file and line a page shows as text carries its file and line as data on its element, and when a loaded stamp names a source template the stamp element links each to the template with the file and line filled in; without such a stamp, or through file://, each stays text.

no example exercises it

1 unkeyed rule.

Verifying examples

The stamp is written beside the page set, and a later build removes it · spec:consumers.spec-studio.sharing.stamp-written-apart · ready floor ready

Executable Spec

Given a page set the studio command wrote at an extraction root
When the stamp command runs with the commit {commit: "0123abc"} and the source template {source: "https://example.test/blob/0123abc/{file}#L{line}"}
Then the stamp names the corpus commit {corpusCommit: "0123abc"}
Then every page file stays byte-identical: {pagesUntouched: true}
Then a later studio run keeps the stamp: {stampSurvives: false}

Open example

Example space

Given a page set the studio command wrote at an extraction root
When the stamp command runs with the commit {commit:string} and the source template {source:string}
Then the stamp names the corpus commit {corpusCommit:string}
Then every page file stays byte-identical: {pagesUntouched:boolean}
Then a later studio run keeps the stamp: {stampSurvives:boolean}
Design
buildStamp line 36 · specs/consumers/spec-studio.sharing.sdp.md:36
{ schemaVersion: string; corpusCommit: string; engine: string; builtAt: string; source?: string } in stamp.json at the page set's root, written by sdp stamp and never by the Studio's build: the graph schema version of the stamping engine, the commit --commit names or unknown, the engine sdp --version names, the time the step ran as an ISO 8601 UTC timestamp to the second, and the source template --source names, when given.

no citation recorded

sourceTemplate line 37 · specs/consumers/spec-studio.sharing.sdp.md:37
a URL holding {file} and optionally {line}, such as https://github.com/<owner>/<repo>/blob/<commit>/{file}#L{line}, into which the shell writes a recorded root-relative file and its line; sdp stamp refuses a template without {file}.
previewWorkflow line 38 · specs/consumers/spec-studio.sharing.sdp.md:38
.github/workflows/studio-preview.yml, triggered by workflow_call and called as uses: libar-dev/software-delivery-protocol/.github/workflows/studio-preview.yml@<ref>.

no citation recorded

workflowInputs line 39 · specs/consumers/spec-studio.sharing.sdp.md:39
root (default .), exclude (root-relative prefixes, one per line), node-version (default 20), install (the install command, default npm ci), sdp (the command that runs the installed sdp, default npx sdp), runs-artifact (the name of an artifact an earlier job uploaded holding CTRF reports, each passed as --runs), diff (a boolean: write the graph of the pull request's base commit in a separate worktree, with that commit's own install and engine, and pass it as --base labelled base <short commit>), and deploy (a boolean, default false).

no citation recorded

previewArtifact line 40 · specs/consumers/spec-studio.sharing.sdp.md:40
the artifact spec-studio-pr-<pr-number>, holding the stamped page set.
workflowSource line 41 · specs/consumers/spec-studio.sharing.sdp.md:41
the workflow stamps with the checked-out merge commit and the source template <server>/<repository>/blob/<merge commit>/<root>/{file}#L{line}, the root and its slash left out when the root is ..
previewPath line 42 · specs/consumers/spec-studio.sharing.sdp.md:42
a pull request's preview is served at <host>/preview/<pr-number>/, which the workflow writes as the folder preview/<pr-number>/ of the gh-pages branch, the branch GitHub Pages serves when a repository enables Pages from it.
stampElement line 43 · specs/consumers/spec-studio.sharing.sdp.md:43
the page element sdp-stamp, once its stamp loads, also sets data-corpus-commit on itself and, when the stamp names a source template, wraps each code element carrying data-source-file and data-source-line in a link to the template with {file} and {line} filled in, the file percent-encoded by path segment; without a template it links nothing.
UI
sourceMark line 46 · specs/consumers/spec-studio.sharing.sdp.md:46
a recorded file and line written as <file>:<line> in a code element carrying data-source-file and data-source-line, beside its copy action.
Verification

Verifier bindings

  • spec:consumers.spec-studio.sharing.stamp-written-apart · The stamp is written beside the page set, and a later build removes it · declared · example enabled · specs/consumers/spec-studio.sharing.stamp-written-apart.sdp.md

    External run evidence from test/studio-s4.test.ts

    Test anchors: test:protocol.run-absolute, test:protocol.run-external, test:protocol.run-unjoined, test:protocol.studio-graph-only, test:protocol.studio-inputs-both-given, test:protocol.studio-stamp-apart. Specs verified by those bindings: spec:consumers.spec-studio.data.inputs, spec:consumers.spec-studio.data.inputs.both-given, spec:consumers.spec-studio.data.inputs.graph-only, spec:consumers.spec-studio.runs-page, spec:consumers.spec-studio.runs-page.external-evidence, spec:consumers.spec-studio.sharing, spec:consumers.spec-studio.sharing.stamp-written-apart, spec:observation.run-evidence, spec:observation.run-evidence.absolute-path-joins, spec:observation.run-evidence.unanchored-file-unjoined.

    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
    recipe 45 joins normalized paths, preserves records and graph facts, and diagnoses other inputsnot recordedpassed32.43 ms
    renders external run evidence with result rows, metadata, diagnostics and conditional navigationnot recordedpassed64.35 ms
    reads repeated --runs before extraction and leaves input bytes untouchednot recordedpassed65.17 ms
    stamps apart, touches no page, refuses bad sources and removes the stamp on rebuildnot recordedpassed33.53 ms
    executes the bound example against a fresh worldA test whose reporter wrote an absolute path joins its anchored file (spec:observation.run-evidence.absolute-path-joins)passed6.06 ms
    executes the bound example against a fresh worldA test in a file with no test anchor is reported as unjoined (spec:observation.run-evidence.unanchored-file-unjoined)passed7.32 ms
    executes the bound example against a fresh worldThe runs page shows a run as external evidence from a test file (spec:consumers.spec-studio.runs-page.external-evidence)passed10.49 ms
    executes the bound example against a fresh worldWithout inputs the page set is the graph's alone (spec:consumers.spec-studio.data.inputs.graph-only)passed26.8 ms
    executes the bound example against a fresh worldBoth inputs add their pages, named, and the same inputs write the same bytes (spec:consumers.spec-studio.data.inputs.both-given)passed76.23 ms
    executes the bound example against a fresh worldThe stamp is written beside the page set, and a later build removes it (spec:consumers.spec-studio.sharing.stamp-written-apart)passed31.42 ms
    the stamp links source locations only after an HTTP stamp loads, encoding path segmentsnot recordedpassed4.11 ms
    recipe 45 picks the longest suffix and scopes through enabled examples at file grainnot recordedpassed8.33 ms
    ships a reusable preview, disabled by default, and deploys its own pull requests with runs and diffnot recordedpassed8.77 ms
    the tests lens counts file results once per Spec and names every run inputnot recordedpassed22.51 ms
    the Pack sentence keeps the graph's binding limit and positively names external evidencenot recordedpassed19.64 ms
    run metadata labels build and branch, and absent fields read not recordednot recordedpassed0.51 ms
    unjoined records escape outside names and explain both reason codes in wordsnot recordedpassed8.74 ms
    run files show the file alone, bindings and Suite, with one header per runnot recordedpassed8.99 ms
    recipe 45 does not join a suffix inside a path segmentnot recordedpassed3.02 ms
    stamp defaults to unknown and a stamped page set passes check-cleannot recordedpassed30.07 ms
    every reusable preview job's permissions fit the CI caller's grantnot recordedpassed15.2 ms
    PR checks and preview stamps name the same default merge checkoutnot recordedpassed7.86 ms
    preview download is optional and cancelled or skipped checks do not call itnot recordedpassed7.96 ms
    deploy checks the enabled Pages source before writing: gh-pagesnot recordedpassed28.99 ms
    deploy checks the enabled Pages source before writing: mainnot recordedpassed34.99 ms
    deploy checks the enabled Pages source before writing: disablednot recordedpassed11.65 ms
    deploy succeeds only once Pages publishes the pushed commit: an unrelated errored build is newestnot recordedpassed127.2 ms
    deploy succeeds only once Pages publishes the pushed commit: a retried build follows an errored onenot recordedpassed62.59 ms
    deploy succeeds only once Pages publishes the pushed commit: the build errorsnot recordedpassed40.96 ms
    deploy succeeds only once Pages publishes the pushed commit: the commit is never builtnot recordedpassed902.58 ms
    deploy succeeds only once Pages publishes the pushed commit: the answer arrives after the waitnot recordedpassed1531.29 ms
    preview still stamps and uploads rendered pages when evidence is absent and validation failsnot recordedpassed92.59 ms
    places external file rows under their verifier and renders shared files oncenot recordedpassed41.84 ms
    accepts the preview workflow's base and run flags togethernot recordedpassed22.06 ms
    formats external run durations to at most two decimals on every pagenot recordedpassed21.61 ms

Example space

  • commit · string · declared by the stamp command runs with the commit {commit} and the source template {source}
  • source · string · declared by the stamp command runs with the commit {commit} and the source template {source}

Bound points

Examplecommitsource
spec:consumers.spec-studio.sharing.stamp-written-apart"0123abc""https://example.test/blob/0123abc/{file}#L{line}"

Oracle binding: present · oracle:protocol.studio-sharing · test/studio-s4.test.ts:538

Coverage

commit: "0123abc" · spec:consumers.spec-studio.sharing.stamp-written-apart · not enumerable

source: "https://example.test/blob/0123abc/{file}#L{line}" · spec:consumers.spec-studio.sharing.stamp-written-apart · not enumerable

Unbound

  • commit: None
  • source: None
Design view

Requirement drawing

Requirement drawing for spec:consumers.spec-studio.sharing
The diagram as text
  • spec:consumers.spec-studio.sharing: A Studio build is stamped and shared from a static host · declared Spec
  • spec:consumers.spec-studio.sharing.stamp-written-apart: The stamp is written beside the page set, and a later build removes it · declared Spec
  • spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph · declared Spec
  • impl:protocol.stamp-command: writes the publishing stamp without extraction or rendering · anchored code · src/cli/stamp-command.ts:8
  • impl:protocol.studio-preview-workflow: asserts the reusable Studio preview workflow and Protocol CI caller · anchored code · test/studio-s4.test.ts:742
  • impl:protocol.studio-stamp: resolves published stamps and source links in the browser · anchored code · src/studio-elements/stamp.ts:30
  • oracle:protocol.studio-sharing: oracle:protocol.studio-sharing · anchored oracle binding · test/studio-s4.test.ts:538
  • test:protocol.studio-stamp-apart: test:protocol.studio-stamp-apart · anchored test binding · binding present · test/studio-s4.test.ts:555
  • spec:consumers.spec-studio.sharing refines spec:consumers.spec-studio · declared
  • spec:consumers.spec-studio.sharing.stamp-written-apart refines spec:consumers.spec-studio.sharing · declared
  • spec:consumers.spec-studio.sharing.stamp-written-apart verifies spec:consumers.spec-studio.sharing · declared
  • impl:protocol.stamp-command satisfies spec:consumers.spec-studio.sharing · anchored
  • impl:protocol.studio-preview-workflow satisfies spec:consumers.spec-studio.sharing · anchored
  • impl:protocol.studio-stamp satisfies spec:consumers.spec-studio.sharing · anchored
  • oracle:protocol.studio-sharing models spec:consumers.spec-studio.sharing · anchored
  • test:protocol.studio-stamp-apart verifies spec:consumers.spec-studio.sharing.stamp-written-apart · anchored
Mermaid source

Copyable source; the Studio draws static SVG.

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

Decisions

No decision record named.

Runtime
  • component:protocol.cli · entry points, shared build and publication · src/cli/build-command.ts:32 · 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:633 · layer application · context protocol
    • component:protocol.extract · the carrier and source pipeline · src/extract/index.ts:192 · 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:671 · layer application · context protocol
    • component:protocol.validate · one finding currency and ordered checks · src/validate/validators.ts:72 · layer domain · context protocol
  • 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.stamp-command · writes the publishing stamp without extraction or rendering · src/cli/stamp-command.ts:8

    Component: component:protocol.cli · entry points, shared build and publication · src/cli/build-command.ts:32 · layer edge · context protocol

    Uses

    • impl:protocol.schema-version · versioned graph nodes, claims, edges and located evidence · src/graph/schema.ts:9
  • impl:protocol.studio-preview-workflow · asserts the reusable Studio preview workflow and Protocol CI caller · test/studio-s4.test.ts:742

    Uses

    None.

  • impl:protocol.studio-stamp · resolves published stamps and source links in the browser · src/studio-elements/stamp.ts:30

    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.spec-studio.sharing
The diagram as text
  • spec:consumers.engine-provenance: The CLI names the engine that produced a result
  • spec:consumers.spec-studio: The Spec Studio is a static HTML workbench over the one graph
  • spec:consumers.spec-studio.publisher: sdp studio publishes the Studio as one page set
  • spec:consumers.spec-studio.sharing: A Studio build is stamped and shared from a static host
  • spec:consumers.spec-studio.sharing.stamp-written-apart: The stamp is written beside the page set, and a later build removes it
  • spec:consumers.spec-studio.shell: The Studio's shell frames every page with navigation, a rail and a canvas
  • spec:consumers.spec-studio.spec-page: A Spec page shows one Spec in collapsible panels, in a fixed order
  • spec:consumers.studio-on-ramp: The Studio skill teaches agents to publish, share and read the Spec Studio
  • spec:extraction.determinism: Committed source derives byte-identical output
  • spec:extraction.schema-versioning: The graph declares its schema version
  • spec:consumers.spec-studio.sharing constrainedBy spec:extraction.determinism · declared
  • spec:consumers.spec-studio.sharing dependsOn spec:consumers.engine-provenance · declared
  • spec:consumers.spec-studio.sharing dependsOn spec:consumers.spec-studio.publisher · declared — the stamp and the preview take the page set the publisher wrote
  • spec:consumers.spec-studio.sharing dependsOn spec:extraction.schema-versioning · declared
  • spec:consumers.spec-studio.sharing refines spec:consumers.spec-studio · declared
  • spec:consumers.spec-studio.shell dependsOn spec:consumers.spec-studio.sharing · declared — the shell shows the stamp a publishing step writes beside the page set
  • spec:consumers.spec-studio.spec-page dependsOn spec:consumers.spec-studio.sharing · declared — a recorded file and line become a link only from a stamp's source template
  • spec:consumers.studio-on-ramp dependsOn spec:consumers.spec-studio.sharing · declared — the skill teaches the stamp, its lifetime and the pull-request preview workflow
  • spec:consumers.spec-studio.sharing.stamp-written-apart refines spec:consumers.spec-studio.sharing · declared
  • spec:consumers.spec-studio.sharing.stamp-written-apart verifies spec:consumers.spec-studio.sharing · 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

Relations

Relation and directionOther endClaimReasonExercised keys
constrainedBy · outgoingCommitted source derives byte-identical output
spec:extraction.determinism · resolves
declaredNoneNone
dependsOn · outgoingThe CLI names the engine that produced a result
spec:consumers.engine-provenance · resolves
declaredNoneNone
dependsOn · outgoingsdp studio publishes the Studio as one page set
spec:consumers.spec-studio.publisher · resolves
declaredthe stamp and the preview take the page set the publisher wroteNone
dependsOn · outgoingThe graph declares its schema version
spec:extraction.schema-versioning · resolves
declaredNoneNone
refines · outgoingThe Spec Studio is a static HTML workbench over the one graph
spec:consumers.spec-studio · resolves
declaredNoneNone
dependsOn · incomingThe Studio's shell frames every page with navigation, a rail and a canvas
spec:consumers.spec-studio.shell · resolves
declaredthe shell shows the stamp a publishing step writes beside the page setNone
dependsOn · incomingA Spec page shows one Spec in collapsible panels, in a fixed order
spec:consumers.spec-studio.spec-page · resolves
declareda recorded file and line become a link only from a stamp's source templateNone
dependsOn · incomingThe Studio skill teaches agents to publish, share and read the Spec Studio
spec:consumers.studio-on-ramp · resolves
declaredthe skill teaches the stamp, its lifetime and the pull-request preview workflowNone
refines · incomingThe stamp is written beside the page set, and a later build removes it
spec:consumers.spec-studio.sharing.stamp-written-apart · resolves
declaredNoneNone
verifies · incomingThe stamp is written beside the page set, and a later build removes it
spec:consumers.spec-studio.sharing.stamp-written-apart · resolves
declaredNonebuildWritesNoStamp, stampVerb, stampLifetime

Bindings

Implementation binding: present

  • impl:protocol.stamp-command · writes the publishing stamp without extraction or rendering · src/cli/stamp-command.ts:8 · role publisher · component component:protocol.cli · layer edge · context protocol
  • impl:protocol.studio-preview-workflow · asserts the reusable Studio preview workflow and Protocol CI caller · test/studio-s4.test.ts:742
  • impl:protocol.studio-stamp · resolves published stamps and source links in the browser · src/studio-elements/stamp.ts:30 · role interaction · component component:protocol.studio-elements · layer edge · context protocol

Design reference: none

Verifier binding: present

Expected-outcome oracle: present

  • oracle:protocol.studio-sharing · test/studio-s4.test.ts:538

Runtime observation: not tracked.

Run results: not recorded in the graph.

Findings

None.

Composing (0)

Composing needs the script.