specification · diff
git:20260914.08516ab to git:20260919.cdf15ac
45 added, 94 removed. Audit A to A.
---
name: specification
- description: Use when transcribing an intent document into the requirements ledger, deriving the design boundary, architecture and timing constraints from it, or updating them from rework feedback; not for RTL implementation or verification.
+ description: Establish requirements, design decisions, interfaces, clocks and constraints from the delivered intent, or revise them after evidence-based clarification; not for implementing RTL or verification.
---
- # Requirements and Specification Freeze
-
- Your sole responsibility: turn the delivered `<intent>/brainstorm.md` into a frozen design
- source of truth. You dispatch and hold no document body: the intent document, the ledger and
- `design.md` are read and written only inside sub-Task contexts.
-
- What this stage freezes is the **boundary** — the rows, the clocks, the ports, the obligations the
- design is held to at that boundary, and the timing scenarios. **Which RTL modules exist is not
- yours to fix.** `design.md` argues for a structure, and the engineer's rows constrain it, but the
- module split is decided by whoever writes the RTL against the boundary you froze.
-
- ## Iron Rule
-
- Write only under `{workdir}`; never another module's artifacts. Reading templates and upstream inputs outside it is fine.
-
- ## Artifacts
-
- `<skill>` is this skill's own base directory, named on the first line of this file.
-
- Read `{workdir}/dispatch.json` for this round's inputs: its `inputs` table maps each upstream key to a location, so `<key>/<subpath>` is how you address one. The only input is the intent tree, the container `<intent>/`: `brainstorm.md`, in whatever shape the engineer wrote it, plus whatever the engineer delivered with it and the document names as authoritative. Frozen for the run. The document is read whole only by the transcriber and the reviewers; another file in the container is read by whoever a row pointing at it concerns.
-
- Everything below is produced under `{workdir}`. Each JSON sidecar's shape is `references/<name>.schema.json`.
-
- | Path | What it is |
- |---|---|
- | `requirements.json` | The ledger: one row per proposition the intent document states, in the engineer's words, with `judge` naming who establishes it. Every downstream rule binds it |
- | `manifest.json` | `module` — the top RTL module's name, and the only thing here. Six readers resolve `<TOP>` from it |
- | `design.md` | The decisions made around the ledger: the architecture it proposes, the boundary narrative, the obligations more than one part must jointly keep, and the timing scenarios (template: `references/design-template.md`) |
- | `clocks.json`, `top-io.json` | The boundary: clocks and their arrival budgets, top-level ports |
- | `check-hints.json` | How simulation observes each ledger row it judges |
- | `constraints/<TOP>.sdc`, `constraints/<TOP>.sgdc` | Generated by `derive-constraints` |
- | `spec-review/decisions.md` | The user's rulings, in their words. It accumulates across rounds — a ruling this round did not revisit still stands, so it is carried forward and appended to, never rewritten |
- | `spec-review/findings/` | The two reviews. This round's record: it does not carry into the next round, so a review on disk is always about what is on disk now |
- | `result.json` | The status envelope |
-
- ## Fan-out
-
- - **Dispatch-and-wait:** after dispatching, send a brief status and end the turn; a wave's gate begins once every sub-Task in it has reported.
- - **Sub-Task `STATUS: BLOCKED`:** a crash, not a `fail` verdict. Finalize with a `--fail-reason` naming what failed — it lands in the envelope's `stage_specific.fail_reason` — and leave re-dispatch to a repair round.
-
- ## Workflow
-
- ### Which round is this
-
- Read `{workdir}/dispatch.json` first. The kernel writes `scope` / `caused_by` / `reasons` **only when they carry something**, so their presence is what tells you:
-
- - **`caused_by` present — failures downstream are waiting on this stage.** Each entry is one failing run's own `result.json`, and a round scheduled for some other reason carries them too: answer them in this round. Scope is the union of `dispatch.json`'s `scope` and what the `caused_by` envelopes attribute; Read each envelope once. Dispatch one repair sub-Task over the boundary and `design.md`, then pick up at **`check-crossrefs`** and run through to finalize: the authoring dispatches are skipped, but the join and the constraints must re-verify against what changed, and the delivery review re-runs so the promoted review is never stale. The ledger is not re-transcribed: the intent document is frozen, and a row changes only by a human's ruling.
- - **`caused_by` absent — a first delivery.** Run every step below.
+ # Specification
- Either way your previous round, if any, is already in `{workdir}`: edit it in place, touching only what this round requires. Rewriting an artifact this round did not change still changes its bytes, and every stage downstream declares these files as inputs, so a cosmetic rewrite invalidates their proofs and buys a rebuild of everything transitively below for no change in content. Row ids never change and are never renumbered; a row added in a repair takes a fresh id.
+ Establish the task's requirements and implementation boundary from the original intent. Read
+ `{workdir}/dispatch.json`; `intent` names the delivered material and its referenced authorities.
+ Read the evidence needed to resolve a question. Write this stage's artifacts under `{workdir}`.
+ Author directly or delegate focused work, retaining responsibility for the resulting decisions.
- A `{workdir}` already holding part of a round means the session was compacted or interrupted: that work is yours to continue or redo, and artifacts on disk are not a gate you already passed.
+ ## Establish or revise the definition
- ### Transcribe
+ Continue from existing artifacts. Use changed inputs, failure records and actual user decisions
+ to scope work; absence of `caused_by` does not imply a first delivery. Preserve unaffected content
+ and stable requirement IDs. Read an upstream request's evidence before accepting its attribution.
- Dispatch one Level-1 sub-Task per `references/ledger-task-contract.md`. In its own context it reads `<intent>/brainstorm.md` and writes `requirements.json`.
+ Produce the requirements ledger using [ledger-task-contract.md](references/ledger-task-contract.md)
+ and the boundary using [decompose-task-contract.md](references/decompose-task-contract.md).
+ `design.md` records design choices and joint obligations; the RTL author decides the module split.
+ The boundary sidecars are `manifest.json`, `clocks.json` and `top-io.json`; their formats are in the
+ corresponding reference schemas.
- **Gate, script.**
+ Check the ledger:
```bash
python3 <skill>/scripts/spec/__main__.py check-ledger --workdir {workdir}
```
- A non-zero exit names every shape or content defect on stderr (an unknown judge, a duplicate id, an `unassignable` row with no reason); re-dispatch the transcriber. On success stdout is the gate view: the count per judge, and verbatim the rows judged `unassignable`, `outside` and `human`, and the rows carrying a `target`. Keep it; the human gate below hands it over.
-
- ### Decompose
-
- Dispatch one Level-1 sub-Task per `references/decompose-task-contract.md`. It reads `requirements.json`, not the intent document, and writes `manifest.json`, `design.md`, `clocks.json` and `top-io.json`. The author holds the rows and their ids and nothing else, so the design cites requirements rather than restating them.
-
- ### Review
-
- Dispatch one Level-1 reviewer per `references/review-task-contract.md`, naming its output `requirements.md`. It reads the intent document and everything on disk so far, and reports where any two of them disagree.
-
- **Gate, human — the ledger and boundary gate.** Path-handoff, echoing no body, with four exceptions the gate view already holds verbatim: the `unassignable` rows with their `note`, the `outside` rows, the `human` rows, and the rows carrying a `target`. Add the `spec-review/findings/requirements.md` and `design.md` paths.
-
- What the user decides here: every `unassignable` row (how it is measured, who judges it, or that it is not a requirement, in which case it becomes `none` with the reason in `note`); each `human` row, which they judge now from the documents in front of them; and the boundary, which the hints and the constraints derive from next, so this is the last cheap moment to change it. Write each ruling to `spec-review/decisions.md` in **their words, not yours**, then dispatch a repair sub-Task that edits what it names — nothing outside a sub-Task edits an artifact. After any edit to the ledger, re-run `check-ledger` and this review. A reported omission re-enters at transcribe, a boundary change at decompose.
+ `<skill>` is this skill's directory. The output shows unresolved/unassignable, outside-scope and
+ rows requiring decisions, plus numerical targets. Resolve these according to the task and actual
+ authorization. Explain choices requiring a human decision before seeking it; act within an existing
+ delegation when permitted. Record material decisions and their basis in `spec-review/decisions.md`,
+ identifying who decided and under what authorization. An agent decision is not a user quotation.
- ### Check hints
+ Distinguish a mistaken transcription or design assumption from a proposed change to acceptance.
+ Correct the former from source evidence. A genuine acceptance change needs authorization and a
+ clear account of what is no longer being claimed. Neither an approval nor a decision record proves
+ reachability, physical feasibility or successful verification. Investigate factual questions or
+ return them to the responsible stage rather than redefining a requirement to make a result pass.
- Dispatch one Level-1 sub-Task per `references/check-hints-task-contract.md`, writing `check-hints.json`. It runs here rather than beside decompose because a row the human just ruled on can have become one simulation judges.
+ ## Complete and review
- **Gate, script.** Run `check-crossrefs` to check references between the current ledger, boundary and hints. It reports invalid or missing requirement references, duplicate check IDs and undeclared clock domains. Finalize repeats this check against the files being delivered.
+ Use [check-hints-task-contract.md](references/check-hints-task-contract.md) to describe the
+ observations used by simulation. Check the ledger/boundary/hint references and derive constraints:
```bash
python3 <skill>/scripts/spec/__main__.py check-crossrefs --workdir {workdir}
- ```
-
- The verdict is structured on stdout: exit 0 clean, exit 1 the join found something. Exit 1 with **nothing** on stdout is a file it could not read, named on stderr — route that to whoever authors it. **Fix nothing yourself.** Each disagreement names both sides, and which of the two is wrong is a judgment: the hint may name the wrong row, or the row may name the wrong judge. Decide that, then route the rework to whoever authored that file.
-
- On a clean gate, immediately derive the constraints:
-
- ```bash
python3 <skill>/scripts/spec/__main__.py derive-constraints --workdir {workdir}
```
- It generates `constraints/<TOP>.{sdc,sgdc}` from `clocks.json` + `top-io.json`. Running it here surfaces defects no cross-file join can see (the exactly-one-`primary` rule, clock-name collisions) while a rework is still cheap. It reads only the boundary sidecars, so a defect it reports on stderr routes to decompose.
-
- ### Delivery review
-
- Dispatch one Level-1 reviewer per `references/review-task-contract.md`, naming its output `delivery.md`. Same contract as the first one, and everything the round delivers is now on disk — the ledger the human ruled on, the boundary, the hints, the constraints — so this is the pass where a hint's rule and a `specification`-judged row's realization can be checked at all.
-
- **Handoff, not a gate.** Give the user the paths, echoing no body: `design.md`, the `check-crossrefs` verdict, and both `spec-review/findings/` paths, so they can read the reviews themselves.
+ These checks identify inconsistent references and invalid tool inputs; they do not establish the
+ truth of an engineering assumption. Repair the side that is wrong based on evidence.
- Read the findings and dispatch sub-Tasks to assess and repair defects in this stage. A boundary change re-enters at decompose; a row change at transcribe. Re-run the affected checks and reviews after repair. Ask the user when resolution requires a decision about intent. Record any finding the user explicitly accepts as-is in `spec-review/decisions.md` in their words. If a blocking defect remains unresolved, close the round with `--fail-reason` naming it.
+ Have the complete delivery independently reviewed using
+ [review-task-contract.md](references/review-task-contract.md). Assess findings against their sources,
+ repair defects, and recheck affected artifacts. Have substantive changes reassessed. Retain the
+ review and material decisions; assess acceptance impact independently of a finding's label.
+ Present `design.md`, review paths and any unresolved decision to the user as needed.
- ### Finalize
+ ## Close
- Every run ends here, an unresolvable failure included:
+ Finalize when this stage's work is complete or an unresolved issue must return to the caller:
```bash
- python3 <skill>/scripts/spec/__main__.py finalize --workdir {workdir} [--fail-reason "<one-line reason>"]
+ python3 <skill>/scripts/spec/__main__.py finalize --workdir {workdir} \
+ [--fail-reason "<unresolved cause and evidence>"]
```
- The status is derived, so you assert nothing about the outcome: a reason names what stopped the round, and its absence means the stage delivered what it owes. On the delivering path finalize re-runs `check-crossrefs` and `derive-constraints` in-process, then re-validates `requirements.json` and refuses one that still carries an `unassignable` row — the first two were clean at the cross-reference gate, so a failure there means an artifact was edited after that gate, which is BLOCKED rather than a routable fail. Exit 0 = `result.json` written. A non-zero exit is a program exception: BLOCKED, reason on stderr, never a `status=fail`.
-
- ## Return Contract
-
- Control returns to the caller, which decides what runs next from `result.json`.
+ Finalize checks current references, derives constraints, validates the ledger and rejects unresolved
+ `unassignable` rows. It does not adjudicate review prose. Supply `--fail-reason` for an unresolved
+ blocking issue or incomplete review; `stage_specific.fail_reason` carries that cause.
- Your sole completion signal is `{workdir}/result.json` present with `status=pass`.
+ Exit 0 means `result.json` was written, pass or fail; return `STATUS: DONE` and let the caller route
+ it. A nonzero exit means closure failed; resolve the cause or return `STATUS: BLOCKED <cause>`.