Spec-Producer Governance — the default authoring procedure
The procedure the conductor follows when it runs the spec-producer role from the SDD default — i.e. no plugin covers the domain and no model-tuned producer agent is named for the slot, so the conductor loads this governance and authors inline in its own warm context (recorded produced-by.spec-producer: sdd:automaton). The grader is separate — a cold spec-judge (sdd:sdd-spec-judge or the plugin's judge) always reviews the output; this governance never judges its own work.
Load alongside this governance: sdd:spec-format-governance (the required ## Use Cases section and the spec.md enrichment / human-readability rule), sdd:suite-format-governance (the .feature format bar and scenario-ordering convention), and the resolved oracle, builder, and architect actor bars — forward face — to self-align before writing (scope and kill-or-ship, testability/coverage, structural fit). These are exactly the bars the spec-judge grades backward at the spec gate, so the producer self-aligns to the same lens set it will be graded against. Load sdd:ownership-governance for the write-ownership matrix — which fields the spec-producer may write and which belong to the conductor or the gate skill.
Track every governance you load. The spec-judge cannot otherwise tell a skipped pre-flight from a correctly run one — both look like the same output gap. Keep a running list of each governance name as you load it (this governance plus every bar named above) and declare the full list as governances_loaded in your structured output — a required field, listed even when empty, and never written into spec.md or the .feature.
Inputs (folded in by the conductor)
DOMAIN, DOMAIN_PATH, SPEC_PATH
COMMAND_SURFACE: <command syntax / signatures / events — or null>
DESIGN_DECISIONS: <known choices — or null>
USER_INPUT: <What / Why / command surface for a new feature — or null>
BACKFILL: <true if implementation already exists>
JUDGE_FEEDBACK: <spec-judge SCENARIOS_FAILING / BLOCKER from a prior pass — or null>
USER_ANSWERS: <answers to previously returned QUESTIONS — or null>
Procedure
Gather intent, grilling breadth-first and depth one-at-a-time. First scan the request holistically and summarize every issue; then drive the single most important to resolution before the next — one deep thread, not many shallow. For
BACKFILL, read source, tests, and history and infer What / Why / decisions / surface; otherwise useUSER_INPUT. A required input that is missing and cannot be inferred becomes aCONTENT_GAP(an<!-- open: -->marker), never an invention. Revision pass (JUDGE_FEEDBACKnon-null): fix only the failing scenarios / sections; fold inUSER_ANSWERS. Settle the prose before touching the suite — scenarios authored against unsettled prose chase a moving target.Reconcile contradictions toward the correct answer, not the popular one. When grilling surfaces a conflict — between the
spec.mdbody and the.feature, between either and the design rules or the implementation, or between two rules — do not guess, and do not just count which reading more files repeat. Zoom out and reason about which is actually right given the design's intent and the whole model; weigh the evidence (the canonical definition, what the implementation does, which decision is most recent and authoritative) to find the coherent answer. Edit the side that is wrong; never reword a rule merely because more files echo it. If the correct answer cannot be established, return aCONTENT_GAPrather than picking a direction.Write the
spec.mdbody persdd:spec-format-governance. That bar owns the required structure — the## Use Casessection (subject, non-goals, and per use case its actor / goal, entry point, and extensions, plus the surface-element trace) and the enrichment rules; follow it rather than re-listing sections here (a hardcoded list drifts from the bar).Find the use cases before you name them. A use case is discovered from the situation the change serves, not derived from the interface you already have in mind — deriving it from the surface reproduces the surface and calls it a requirement. Enumerate by actor, never by entry point (
sdd:spec-format-governanceowns the ordering): walking the interface returns only the use cases it already implies and is blind to the one nobody built. List the actors first — every person in a role, sibling capability, scheduler, or operator that reaches this capability, plus whoever is affected by its outcome without invoking it (the reviewer, the on-call, the next agent). Then per actor name the goals they arrive with — their result, not the call they make; where the answer restates the mechanism ("the caller wants to call it"), you have renamed the function, not found the use case, and the honest move is aCONTENT_GAP, never a plausible actor you invented. Then map goals to entry points, and report both mismatches: a goal with no entry point is a way in the capability lacks or a goal another node owns, and an entry point serving no listed goal is surface nobody asked for. OnBACKFILLthe source yields only the served use cases by construction — recover the unserved ones from the request history, the issue tracker, and recurring workarounds, and record where each came from rather than presenting an inferred set as complete. Then enumerate the extensions — walk each use case for any path from its trigger that does not reach its success outcome. That criterion decides membership; the recurring kinds (the refusal, the error, the boundary, the partial result, the contended or absent input) are a prompt to search, not a closed set (sdd:spec-format-governanceowns the criterion — a divergence matching none of them still belongs, and a kind that cannot arise is not owed a row). Where nothing can diverge, writeextensions: none — <why>, so the claim is visible and contestable rather than absent. Then trace the surface — take each element the capability exposes (flag, option, parameter, prop, event) and name the use case that needs it and the elements it may not be combined with. An element you cannot attribute to a use case is the finding, not an oversight to fill in: raise it, because the Oracle bar's verdict on it is cut-or-justify.Then check the extensions against the CFG — the producer-side mirror of the Architect bar. Where the node carries a
## Control Flowgraph, every extension you just enumerated is a path that graph must actually contain, and every forbidden combination is a decision it must actually refuse. Walk them both ways: an edge with no extension is the ordinary uncovered-edge case, and an extension with no edge is a divergence the prose claims and the drawn graph cannot take (sdd:architect-spec-governancegrades exactly this backward). Fix whichever side is wrong — add the missing edge where the extension is real, drop the extension where the graph is right — and never reportSTATUS: completewith a stated extension no edge reaches. Where the graph already reaches every stated extension, amend neither side: the check has found nothing, and rewriting a graph or an extension it cleared manufactures churn the Architect lens never asked for. This is a self-alignment duty, not a judge's: settling it here spends no cold round on a contradiction the Architect lens will find every time. On a node with no CFG the check is vacuous and fires nothing. Author the body content — What, Why, design decisions, and the command / API surface where one exists — and enrich for human review (headings, tables, short paragraphs, a diagram where it carries the idea). Never leave placeholders (TBD,TODO, empty sections). Do not write the control frontmatter (status,project-path,approval,produced-by) — those belong to the conductor and the gate skill. Every referenced engine, skill, or artifact path you name must be real — a reference that resolves to nothing is caught mechanically at step 5 below, but naming a real path the first time spends no round on it. OnBACKFILLthe four sections are still mandatory — draw the## Control FlowCFG and its## Scenario mapfrom the code, never stop at## Use Cases(sdd:spec-format-governance;check-spec-structure'sincomplete-nodeflags a leaf that skips them).Write
<DOMAIN_PATH>/<DOMAIN>.feature— pure boolean Gherkin persdd:suite-format-governance. For a fold (aggregation) node whose rule combines two or more interacting sub-conditions, state that rule in closed form — and re-derive its soundness against the real data model — before you derive any scenario (sdd:suite-format-governance). The order is load-bearing: scenarios are drawn from the rule, so deriving them first is the retrofit-after-the-fact shape that diverged (github-192, by example) where stating the rule first converged (github-224). A single-condition fold may be specified by example, and demanding a closed form of it is over-firing — the failure mode of this rule. Closed form is not soundness (R''shipped a proof and still deadlocked until re-derived against the real graph,R'''), and it buys convergence, not coverage — pair the rule with a mutation sweep (each interacting condition's mutation breaks a distinct scenario) and a safety dual (a liveness scenario passes an over-permissive fold green; assert the case it cannot observe). A matrix / per-cell claim is the same rule applied — draw every independent cell as its own scenario, exclude the degenerate cells, and confirm the cells distinct by the sweep. Cover every use case from the## Use Casessection with one-or-more scenarios (happy path, negative mirror, boundary) — a use case with no scenario is unverified intent; a scenario with no use case is an orphan. A stated extension earns its scenario by being a path in the CFG, never by being drawn from the prose — the graph is the single source scenarios derive from, and a suite drawn from a stated list is 1:1 with that list by construction and can no longer surface a hole (sdd:builder-spec-governance). So route a divergence covered nowhere back through the graph: add the missing path, and the standing 1:1 edge coverage supplies the scenario. A forbidden combination is the same rule in guard form — the CFG carries the decision that refuses it, and the refusal scenario comes from that guard's edge. OnBACKFILL, re-derive the scenario set from the CFG's edges rather than patching the standing suite; the retired corpus is reference only, a claim to verify against the current code (sdd:suite-format-governance). EachThenis an observable boolean — name the artifact a verifier reads to settle it; an act is assertable only when it leaves a trace, and where it records nothing, add the record rather than dropping the act. Never internal state, function names, "sometimes", or how the artifact was authored. Order scenarios by lifecycle stage (the step-down convention). Keep the.featureplain; rubric form is legal only inside an@rubric-tagged scenario.A
Givenis a test vector, not specification (sdd:suite-format-governancecarries the canonical bar and the swap test). Author eachGiven's apparatus — its domain, entities, names, framing — from a domain the artifact does not illustrate. On a revise CR the apparatus never reuses the artifact's existing worked examples; onBACKFILLit never reuses the illustrations you read out of source. Read those examples in full at step 1 — they are evidence of the behavior you are specifying; exclude them only from the apparatus you author into aGiven.Self-check the
.featureform before returning. Run the deterministic form check — thecheck-suiteengine (scripts/check-suite.mtsin thespec-gateskill), the executable form ofsdd:suite-format-governance— scoped to what you just authored:node "<spec-gate skill>/scripts/check-suite.mts" --files <the authored .feature path(s)>Exit
0= form clean; exit1prints each✗ <file>: <reason>. Fix every violation (a non-boolean/hedgedThen, leaked rubric lingo in an untagged scenario, a missingFeature/Then, or missing section comments over the sectioning threshold) and re-run until clean before reportingSTATUS: complete. Settling this mechanical bar here spends no cold-judge round on a defect a linter catches every time; the same engine runs fail-closed at the gate (../spec-gate/), so an unfixed violation would block there anyway. Ifnodeis unavailable, self-review against the suite-format bar by hand.A clean form check does not clear an entangled
Given. The engine reads form, not apparatus — it reports no violation on aGivenwhose apparatus reuses the artifact's worked examples. Re-read each authoredGivenagainst the test-vector bar by hand and rewrite the apparatus before returningSTATUS: complete.A clean form check does not clear a scenario that cannot fail. The engine reads form, not discrimination — a well-formed
Then, and a well-formed@rubricblock, are both reported clean when no subject can ever fail them. Apply the miss test (sdd:suite-format-governance) to every scenario and every@rubricdimension you authored: name a plausible wrong subject — a memorizer, a copier, a procedure-follower, a single-brancher — and check that it loses. Name none and the scenario is inert; rewrite it. The wrong subject must be plausible — an empty artifact fails everything and clears nothing. Rewrite any dimension grading presence (a line is emitted), restatement (the doctrine's own words), or procedure (the steps, not the judgment). Rewrite the toothless finding — aThenasserting a signal or finding is raised but not its binding consequence (it withholds the pass, blocks the gate, changes the outcome): name the wrong subject that raises the finding and acts on nothing, then rewrite theThento assert the consequence. Rewrite the process-Then— aThenasserting how the artifact was produced ("co-developed with the code", "written test-first", "refactored before completing", authoring order) rather than its observable behavior or end-state; nothing in the artifact or a run reveals the authoring sequence, so it can never be aThen— rewrite it to assert the observable behavior instead (sdd:suite-format-governance). Before writing any criterion as a dimension, run the substitutability test (sdd:suite-format-governance): a criterion belongs in a@rubriconly if you accept that strength elsewhere may pay for weakness here — otherwise it is not in the sum at all, it is a booleanThen. Write the trade down for each dimension you author or revise, in the same record that carries the cut's reason, naming it and what pays for it — an unrecorded trade is an unowned selection nobody can disagree with. The duty is yours alone: no judge reports a missing record, so nothing catches you skipping it. For a@rubric, sum what each named wrong subject banks (never zero a dimension to make a point): that sum sits strictly under the threshold — a tie passes, since the collapsingThenpasses a score at least the threshold. How far under is not a constant: it is your judge's noise at the cut (cSEM), measured by scoring the subject more than once, never decreed here. Ground a dimension or its cut on non-author evidence (cold-instrument doctrine). When you justify a@rubricdimension or its cut with a measurement — an ablation Δ, a discrimination count over N runs — it is admissible only if it is not solely your own: it meets the non-author evidence standard the doctrine Strategist states canonically (sdd:doctrine-loop), never re-listed here. Your own instrument silently assumes the property under test, so a cut grounded on your own measurement alone is not grounded — record that it needs non-author or fresh-adversarial evidence. A measurement grounding no dimension or cut is unconstrained; this governs the evidence, not the cut value (that is the miss-test arithmetic above).In
revisemode, run the substitutability test over the standing@rubricdimensions your CR touches, not only the ones you author. A dimension already in the sum that fails the test is a correction, and a correction is not a deletion: removing it changes the attainable maximum, so the cut it leaves behind is un-re-derived whether or not its number still needs to change. Re-derive that cut as a fresh policy call in the same edit and record its reason against the new attainable maximum; raise one clearance per corrected scenario and never let one blanket approval stand in for each scenario's own cut decision. Route it on the removal — never on whether the diff calls the editmixed, which the in-scenario shape is not. The full procedure is Correcting a standing rubric (sdd:suite-format-governance). A green form check does not clear this:check-suite.mtsreports only the vacuoussum(max) < thresholdrubric, and a cut nobody re-derived clears that check every time.Read your authored scenarios against each other. No two scenarios sharing a
Whenmay demand opposite verdicts on one constructible snapshot (sdd:suite-format-governance); narrow oneGivento exclude the overlap before returning. OverlappingGivens whoseThens agree, and scenarios whoseWhens name different operations, are not contradictions — the bar is the contradiction, never the overlap. Specialization is not contradiction: a general scenario and a specific sibling whose narrowerGivencarves out an exception do not contradict, even when the generalGivendoes not literally exclude it — a contradiction is a pair with no intended winner. When you are authoring the generalGivenfresh, state the exclusion anyway; it is clearer. Never retrofit it into a frozen scenario — that is a narrowing that fires Clearance.Check coverage and mirroring before returning. Every outcome and carve-out the node's
## Use Cases/ README states — including an exception named only in prose — must have at least one scenario; do not reportSTATUS: completewhile a stated outcome or carve-out has none — add the missing scenario. A duty specified on one node of a mirrored pair (producer/judge, sender/receiver) must be mirrored on the counterpart node; do not report complete while only one side carries the duty — specify it on the counterpart too (sdd:suite-format-governance).Also self-run referenced-artifact-exists —
check-spec-state.mtsinscripts/, scoped to thespec.md/README.mdyou just authored or touched:node "<spec-gate skill>/scripts/check-spec-state.mts" --files <the authored spec.md/README.md path(s)>Exit
0= every referenced path resolves; exit1prints each✗ <file>: references nonexistent artifact .... Fix every violation the same way — a broken reference to a skill/engine/artifact that never existed is a content gap, not a typo to shrug at.
Responding to a change verdict
Load sdd:remediation-governance — the findings are evidence, not a work order. It carries the
four rules (substantiate before acting · state the rule and sweep, scope-aware · re-derive against the
rule governing the artifact · account for provenance, where a regression stops the loop) and the
REMEDIATION trace this role returns in its Output below.
Output (the conductor collects)
REMEDIATION: <per finding answered: verdict, rule, swept, ruled-out, provenance — `sdd:remediation-governance`; omit when no verdict was answered>
STATUS: complete | needs-input | blocked
SCENARIOS_WRITTEN: <count>
NOTES: <what was written / revised>
GOVERNANCES_LOADED: [ every governance name loaded before writing — required, [] when none, never written into spec.md or the .feature ]
QUESTIONS: [ batched, when needs-input ]
CONTENT_GAPS: [ { artifact, location, gap } ] # become <!-- open: --> markers
OBSERVATIONS: [ { owner: architect | strategist, note, evidence } ]