Spec Studio

The CLI names the engine that produced a result

spec:consumers.engine-provenanceUse Case / Behavior · storyready floor ready

Changed since the base graph base da4b141: relation.refines:spec:consumers.command-line

Base input: schema 0.11.0, 405 Specs.

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

Design: 1 design entry · 1 pinned declaration · no decisions

Findings: no errors, no warnings

specs/consumers/engine-provenance.sdp.md

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

Intent
problem
An adopter pinned to a build of the Protocol needs to name that build: the package version alone does not change between commits, so when a check changes with no Spec changed, nothing tells the engine moving from the corpus moving.
outcome
Let sdp --version name the package version and the commit the build came from, without putting either into the graph.
Behavior
rule line 22 · specs/consumers/engine-provenance.sdp.md:22
sdp --version prints one line, sdp <version> (<commit>), and exits 0. The version is the package's own version; the commit is the full hash the build was made from, or unknown when the build could not read one; a build from a checkout with uncommitted changes names the commit checked out when it ran.
rule line 23 · specs/consumers/engine-provenance.sdp.md:23
The build records the commit in a file beside the compiled CLI, and the CLI reads that file; it never runs git at run time.
rule line 24 · specs/consumers/engine-provenance.sdp.md:24
The build reads the commit from git first. When git gives no full commit, it reads the archive's substituted commit file; a full commit there names the archived revision, and an absent, unsubstituted or malformed file leaves the commit unknown.
rule line 25 · specs/consumers/engine-provenance.sdp.md:25
Neither the version nor the commit enters the graph, a projection or a generated contract, so a derived artifact stays a function of the corpus alone.

4 unkeyed rules.

Design
archiveCommit line 28 · specs/consumers/engine-provenance.sdp.md:28
.git-archive-commit contains $Format:%H$ in a checkout and is marked export-subst in .gitattributes, so git archives carry their full commit. The build reads the trimmed file only as a full Git object name, never as a command or an abbreviated hash.

no citation recorded

Verification

Verifier bindings

  • test:protocol.engine-provenance · version checks verify the engine provenance line and the build's commit record · anchored · test anchor binding present · test/cli.test.ts:2371

    External run evidence from test/cli.test.ts

    Test anchors: test:protocol.engine-provenance, test:protocol.extraction-determinism, test:protocol.projections-model.publication, test:protocol.regenerability, test:protocol.validate-watch. Specs verified by those bindings: spec:consumers.engine-provenance, spec:consumers.projections-model, spec:consumers.validate-watch, spec:extraction.determinism, spec:extraction.regenerability.

    Run 2: external run evidence from vitest 4.1.10

    Build: CI 380 · Branch: feature/roadmap-and-slices-v0 · Commit: 34909918bf0be0e849959644401797191cae379f · Start: 2026-10-22T17:42:16.533Z · Stop: 2026-10-22T17:42:27.785Z

    NameSuiteResultDuration
    prints the exact help text for no argssdp clipassed1.39 ms
    points operators to the shipped on-ramps and Protocol corpussdp clipassed1.4 ms
    describes both anchor forms and non-failing warnings in helpsdp clipassed0.33 ms
    prints the exact help text for --helpsdp clipassed0.14 ms
    builds the checkout-v1 example: writes graph, contracts, and registrar manifest atomicallysdp clipassed92.85 ms
    invalidates an existing Design Review when build replaces its source graphsdp clipassed51.1 ms
    views the self-hosting corpus from the default repository rootsdp clipassed8406.8 ms
    renders contracts warnings through the one formatter and counts them in the summarysdp clipassed6.91 ms
    withholds case-colliding contract paths with a warning: graph kept, nothing gatessdp clipassed3.45 ms
    passes --check-clean on the example (determinism self-check through the CLI)sdp clipassed28.36 ms
    end-to-end determinism self-check: delete generated/, rebuild, byte-identicalsdp clipassed106.14 ms
    fails clean on a root that is not a directory: one line, exit 1, never a stack tracesdp clipassed0.32 ms
    rejects an unknown option: one line, exit 1, nothing runssdp clipassed0.1 ms
    accepts repeatable --exclude paths for buildsdp clipassed3.25 ms
    accepts repeatable --exclude paths for validatesdp clipassed3.57 ms
    accepts repeatable --exclude paths for viewsdp clipassed4.61 ms
    uses the identical normalized exclusions in both --check-clean extractionssdp clipassed4.99 ms
    refuses invalid --exclude path "" before build writessdp clipassed0.75 ms
    refuses invalid --exclude path "." before build writessdp clipassed0.21 ms
    refuses invalid --exclude path "./explorations" before build writessdp clipassed0.27 ms
    refuses invalid --exclude path "explorations/" before build writessdp clipassed0.16 ms
    refuses invalid --exclude path "/explorations" before build writessdp clipassed0.19 ms
    refuses invalid --exclude path "../x" before build writessdp clipassed0.18 ms
    refuses invalid --exclude path "a/../b" before build writessdp clipassed0.13 ms
    refuses invalid --exclude path "a//b" before build writessdp clipassed0.12 ms
    refuses invalid --exclude path "a\\b" before build writessdp clipassed0.21 ms
    refuses a missing --exclude operand before build writessdp clipassed0.28 ms
    names a flag supplied as an --exclude operand before build writessdp clipassed0.19 ms
    documents repeatable --exclude paths in helpsdp clipassed0.06 ms
    rejects a second root argument: one line, exit 1, nothing runssdp clipassed0.16 ms
    notes an empty authored model: zero spec files still builds and exits 0, but says where it lookedsdp clipassed0.59 ms
    renders a finding's location exactly once, from the structured fields: file:line — [severity]sdp clipassed2.19 ms
    renders a Gherkin parser failure through the public CLIsdp clipassed1.24 ms
    exits 1, writes nothing, and removes a stale graph.json on a hard-error corpussdp clipassed1.87 ms
    fails build on an integer-like design key holding a static valuesdp clipassed1.25 ms
    fails build on an integer-like design key holding a non-static valuesdp clipassed1.05 ms
    fails build on an integer-like design key holding a methodsdp clipassed1.09 ms
    fails build on an integer-like design key holding an accessorsdp clipassed1.22 ms
    fails --check-clean on a diverging second extraction: exit 1, the stale graph.json removedsdp clipassed7.21 ms
    fails --check-clean on a diverging second contract generation: exit 1, no artifact survivessdp clipassed18.15 ms
    owns the contracts tree wholesale: with nothing to generate, a stale contracts dir is removedsdp clipassed2.71 ms
    reconciles a registrar sibling that a later generation no longer owessdp clipassed19.57 ms
    fails --check-clean on registrar-byte drift and removes the uncertified known setsdp clipassed26.76 ms
    passes --check-clean without a prior manifest when no registrars are owedsdp clipassed3.91 ms
    fails --check-clean on registrar manifest whitespace driftsdp clipassed26 ms
    fails --check-clean on registrar manifest ignored property driftsdp clipassed26.54 ms
    removes graph, contracts, manifest, and registrar siblings after a staged write failuresdp clipassed19.02 ms
    fails clean when extraction throws past discovery: one line, exit 1, the stale graph.json removedsdp clipassed0.6 ms
    fails clean when generated exists as a file: one line each for build and view, never a stack tracesdp clipassed5.38 ms
    names the survivor when a recovery-path removal is denied: a stale artifact never silently reads as currentsdp clipassed0.56 ms
    stops a build when an existing Design Review cannot be invalidatedsdp clipassed1.62 ms
    fails clean when the checks throw: one line, exit 1, the built graph.json stayssdp clipassed2.52 ms
    suppresses the empty-model note when spec files were found but none reified — a failed file is not an absent onesdp clipassed1.52 ms
    treats a root of only ordinary .feature files as an empty authored model, not a missing-identity errorsdp clipassed0.65 ms
    suppresses the empty-model note when a failed .sdp.gherkin finding.file matches the carrier suffix predicatesdp clipassed1.01 ms
    builds a mixed root with one .sdp.gherkin carrier and ignores the ordinary .feature siblingsdp clipassed0.88 ms
    removes the temp twin on a failed build and a failed view — no partial .tmp artifact survivessdp clipassed8.95 ms
    recognizes the published-bin path: a .bin-style symlink resolves to the entry modulesdp clipassed0.43 ms
    exits 0 quietly on a stdout EPIPE and stays fatal for any other stream errorsdp clipassed0.53 ms
    validates the example: exit 0, the artifact written, and no warningsdp clipassed28.78 ms
    gates on the checks, not the build: a clean-building broken link validates to exit 1 with the artifact keptsdp clipassed2.67 ms
    short-circuits the checks on extraction hard errors: validate keeps build semanticssdp clipassed1.64 ms
    prints help plus an unknown-command errorsdp clipassed0.13 ms
    views the example: validate + the Design Review written, with no warningsdp clipassed33.87 ms
    owns the view directory wholesale: a stale page does not survive a re-rendersdp clipassed15.8 ms
    regenerates the view byte-identically: delete generated/, re-view, same bytessdp clipassed24.79 ms
    writes the view even when checks fail: findings render in it, the exit code is validate'ssdp clipassed2.06 ms
    keeps build semantics on extraction hard errors: no graph, no view, stale view removedsdp clipassed1.87 ms
    fails view --check-clean on a diverging second render: exit 1, the stale view removedsdp clipassed6.53 ms
    fails clean when the render throws: one line on stderr, exit 1, the stale view removedsdp clipassed2.71 ms
    closes the compiled watch process with exit 0 after operator SIGINTsdp validate --watchpassed299.82 ms
    documents --watch as a validate-only authoring loopsdp validate --watchpassed0.19 ms
    rejects --watch on build with a named error and no watchersdp validate --watchpassed0.18 ms
    rejects --watch on view with a named error and no watchersdp validate --watchpassed0.06 ms
    rejects --watch on census with a named error and no watchersdp validate --watchpassed0.05 ms
    rejects --watch on mermaid with a named error and no watchersdp validate --watchpassed0.05 ms
    rejects --watch on gherkin with a named error and no watchersdp validate --watchpassed0.04 ms
    rejects --watch on import with a named error and no watchersdp validate --watchpassed0.17 ms
    rejects --watch on new with a named error and no watchersdp validate --watchpassed0.2 ms
    rejects --watch on q with a named error and no watchersdp validate --watchpassed0.18 ms
    rejects --watch --check-clean with a named error and no watchersdp validate --watchpassed0.12 ms
    installs the watcher before the first validation cyclesdp validate --watchpassed4.45 ms
    catches an edit during the first cycle with exactly one coalesced rerunsdp validate --watchpassed5.23 ms
    coalesces a burst during an active cycle into exactly one rerunsdp validate --watchpassed4.92 ms
    prints validation findings and keeps watching until abort exits 0sdp validate --watchpassed2.68 ms
    ignores generated, dist, node_modules, coverage, dot directories, and configured excludessdp validate --watchpassed5.24 ms
    coalesces production-shaped events from later turns into one pending rerunsdp validate --watchpassed7.83 ms
    does not natively subscribe to excluded or generated subtreessdp validate --watchpassed69.25 ms
    routes a native watcher error through a typed channel and closes oncesdp validate --watchpassed3.1 ms
    clean-repo determinism: the full pipeline at a different absolute path is byte-identicalnot recordedpassed67.67 ms
    prints one line naming the package version and the recorded commit, and exits 0sdp --versionpassed0.49 ms
    names the commit unknown when the build recorded none or recorded something elsesdp --versionpassed0.33 ms
    reads the version from the package manifest two directories above the CLI modulesdp --versionpassed0.38 ms
    documents --version and --params in the usage textsdp --versionpassed0.14 ms
    records the checked-out commit at build time, or unknown when git cannot name onesdp --versionpassed11.15 ms
    publishes the commit the build step reads from git beside the CLIsdp --versionpassed0.9 ms
    builds commit metadata from a substituted git archive extracted without .gitsdp --versionpassed64.59 ms
    uses only a full archive commit when git gives none, keeping git firstsdp --versionpassed0.68 ms
    answers from the compiled CLI with the commit its build recorded beside itsdp --versionpassed327.1 ms
    runs recipe 4 as shipped, its changed files passed with --params @PATHa shipped recipe file through the compiled CLIpassed363.4 ms
Design view

Requirement drawing

  • Declared verifying examples: no declared verifying example.
Requirement drawing for spec:consumers.engine-provenance
The diagram as text
  • spec:consumers.engine-provenance: The CLI names the engine that produced a result · declared Spec
  • spec:consumers.command-line: Every verb answers --help, and one verb writes every projection root · declared Spec
  • impl:protocol.build-artifacts: the build step that writes each catalog recipe to dist/recipes and records the build commit beside the CLI · anchored code · src/cli/build-artifacts.ts:182
  • impl:protocol.engine-provenance-cli: prints sdp version and the commit parsed from the build-info file beside the compiled CLI · anchored code · src/cli/sdp.ts:102
  • test:protocol.engine-provenance: version checks verify the engine provenance line and the build's commit record · anchored test binding · binding present · test/cli.test.ts:2371
  • spec:consumers.engine-provenance refines spec:consumers.command-line · declared — the version flag is one more answer the command line gives an adopter
  • impl:protocol.build-artifacts satisfies spec:consumers.engine-provenance · anchored
  • impl:protocol.engine-provenance-cli satisfies spec:consumers.engine-provenance · anchored
  • test:protocol.engine-provenance verifies spec:consumers.engine-provenance · anchored
Mermaid source

Copyable source; the Studio draws static SVG.

Preferred and chosen syntax: requirementDiagram; exact refines, satisfies and verifies, with claim words in nodes and per-edge comments.

Decisions

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
  • impl:protocol.build-artifacts · the build step that writes each catalog recipe to dist/recipes and records the build commit beside the CLI · src/cli/build-artifacts.ts:182

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

    Uses

    None.

  • impl:protocol.engine-provenance-cli · prints sdp version and the commit parsed from the build-info file beside the compiled CLI · src/cli/sdp.ts:102

    Component: component:protocol.cli · entry points, shared build and publication · src/cli/build-command.ts:32 · 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.engine-provenance
  • E3: constrainedBy · declared
The diagram as text
  • spec:consumers.adopter-on-ramp: An adopter learns graph homes, carrier grammar and shipped paths from the on-ramps
  • spec:consumers.command-line: Every verb answers --help, and one verb writes every projection root
  • spec:consumers.engine-provenance: The CLI names the engine that produced a result
  • spec:consumers.spec-studio.sharing: A Studio build is stamped and shared from a static host
  • spec:extraction.determinism: Committed source derives byte-identical output
  • spec:consumers.engine-provenance constrainedBy spec:extraction.determinism · declared
  • spec:consumers.engine-provenance dependsOn spec:consumers.adopter-on-ramp · declared — an adopter pinned to a build asks the CLI the adopter on-ramp points it to which build it runs
  • spec:consumers.engine-provenance refines spec:consumers.command-line · declared — the version flag is one more answer the command line gives an adopter
  • spec:consumers.spec-studio.sharing dependsOn spec:consumers.engine-provenance · 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

Relations

Relation and directionOther endClaimReasonExercised keys
constrainedBy · outgoingCommitted source derives byte-identical output
spec:extraction.determinism · resolves
declaredNoneNone
dependsOn · outgoingAn adopter learns graph homes, carrier grammar and shipped paths from the on-ramps
spec:consumers.adopter-on-ramp · resolves
declaredan adopter pinned to a build asks the CLI the adopter on-ramp points it to which build it runsNone
refines · outgoingEvery verb answers --help, and one verb writes every projection root
spec:consumers.command-line · resolves
declaredthe version flag is one more answer the command line gives an adopterNone
dependsOn · incomingA Studio build is stamped and shared from a static host
spec:consumers.spec-studio.sharing · resolves
declaredNoneNone

Bindings

Implementation binding: present

  • impl:protocol.build-artifacts · the build step that writes each catalog recipe to dist/recipes and records the build commit beside the CLI · src/cli/build-artifacts.ts:182 · role publisher · component component:protocol.cli · layer edge · context protocol
  • impl:protocol.engine-provenance-cli · prints sdp version and the commit parsed from the build-info file beside the compiled CLI · src/cli/sdp.ts:102 · role projection · component component:protocol.cli · layer edge · context protocol

Design reference: none

Verifier binding: present

  • test:protocol.engine-provenance · version checks verify the engine provenance line and the build's commit record · anchored · test/cli.test.ts:2371 · 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.