cyber-sdd 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.plugin/pins.json +1 -1
- package/package.json +1 -1
- package/skills/architect-spec-governance/README.md +1 -0
- package/skills/architect-spec-governance/SKILL.md +12 -1
- package/skills/builder-spec-governance/README.md +1 -0
- package/skills/builder-spec-governance/SKILL.md +19 -3
- package/skills/oracle-spec-governance/README.md +7 -2
- package/skills/oracle-spec-governance/SKILL.md +21 -4
- package/skills/spec-format-governance/README.md +1 -1
- package/skills/spec-format-governance/SKILL.md +71 -8
- package/skills/spec-producer-governance/README.md +1 -1
- package/skills/spec-producer-governance/SKILL.md +6 -2
- package/skills/start-mission/README.md +1 -1
- package/skills/start-mission/SKILL.md +5 -5
package/.plugin/pins.json
CHANGED
package/package.json
CHANGED
|
@@ -22,6 +22,7 @@ asked of the implementation instead of the spec.
|
|
|
22
22
|
| **Placement matches the declared layout** | The project declares its layout strategy in its root `spec.md` placement map; placement is judged *within* that declaration, not against a preferred one. Under the screaming-architecture default a capability lives in a folder named for its intent; a project that declared `mirror-source` is correctly placed when it mirrors its source. |
|
|
23
23
|
| **…and the layout preserves the partition** | The declaration is not a licence. Layouts are ranked by whether they keep node ↔ capability one-to-one, because the mission scheduler cuts one mission per node and a scattered capability degrades the schedule toward serial (ADR-0025). **One capability per node, never smeared across nodes** holds under every strategy, and a layered / framework-first top level stays discouraged however it is declared. |
|
|
24
24
|
| **A well-formed CFG** | The capability's control-flow graph connects — every decision reachable, no dangling branch — and the suite's sections mirror it. |
|
|
25
|
+
| **The CFG reaches every stated extension** | A use case's **extensions** are its divergence paths (`spec-format-governance`), so each is an edge the graph must actually contain. An extension named in `## Use Cases` with no path to it in `## Control Flow` is a **dangling branch read from the other side** — the prose claims a divergence the drawn graph cannot take. A **forbidden combination** is the same defect in guard form: the graph carries the decision that refuses the pair, or the constraint is unenforceable and the prose is decoration. Judge it **both ways** — an edge with no extension is the ordinary uncovered-edge case; an extension with no edge is this one. |
|
|
25
26
|
| **An orthogonal axis** | Structural fit judges a property the builder was not optimizing — a real independent check even from the same hand. |
|
|
26
27
|
| **Structural concerns are deferred** | A structural problem in *another* capability is an observation that spawns a new spec — never a marker in the one being built. |
|
|
27
28
|
|
|
@@ -37,6 +37,15 @@ unbound.
|
|
|
37
37
|
level stays discouraged however it is declared.
|
|
38
38
|
- **A well-formed CFG.** Its control-flow graph connects — every decision reachable, no
|
|
39
39
|
dangling branch — and the suite's sections mirror it.
|
|
40
|
+
- **The CFG reaches every stated extension.** A use case's **extensions** are its divergence paths
|
|
41
|
+
(`sdd:spec-format-governance`), so each is an edge the graph must actually contain. An extension
|
|
42
|
+
named in `## Use Cases` with no path to it in `## Control Flow` is a **dangling branch read from
|
|
43
|
+
the other side** — the prose claims a divergence the drawn graph cannot take. A **forbidden
|
|
44
|
+
combination** of surface elements is the same defect in guard form: if two elements may not be
|
|
45
|
+
combined, the graph carries the decision that refuses them, or the constraint is unenforceable and
|
|
46
|
+
the prose is decoration. Judge the graph against the stated extensions in **both** directions —
|
|
47
|
+
an edge with no extension is the ordinary uncovered-edge case; an extension with no edge is this
|
|
48
|
+
one.
|
|
40
49
|
- **An orthogonal axis.** Structural fit judges a property the builder was not optimizing — a real
|
|
41
50
|
independent check even from the same hand.
|
|
42
51
|
- **Structural concerns are deferred.** A structural problem in another capability is an observation
|
|
@@ -55,5 +64,7 @@ from `spec.md` + the suite only — the solution is out of view (grader independ
|
|
|
55
64
|
boundaries.
|
|
56
65
|
2. **Placement matches the *declared* layout** (`sdd:spec-structure-governance`), not a preferred
|
|
57
66
|
one; one capability per node either way, never smeared across nodes.
|
|
58
|
-
3. **A well-formed CFG** the suite's sections mirror
|
|
67
|
+
3. **A well-formed CFG** the suite's sections mirror — and it reaches every stated extension;
|
|
68
|
+
an extension with no edge is a dangling branch read from the prose side, a forbidden combination
|
|
69
|
+
with no guard is unenforceable.
|
|
59
70
|
4. **Structural concerns in another capability are deferred** — an observation that spawns a new spec.
|
|
@@ -19,6 +19,7 @@ contract?" at the impl gate.
|
|
|
19
19
|
| Requirement | What it means |
|
|
20
20
|
| --- | --- |
|
|
21
21
|
| **Every branch is covered** | Each edge of the capability's CFG has its scenario, and every guard/negative edge is paired with a positive companion. The scenario map is 1:1 in both directions — no orphan scenario, no uncovered edge. |
|
|
22
|
+
| **Every stated extension is a path in the CFG** | A use case's **extensions** are its divergences (`spec-format-governance`), and the CFG is the **single source** scenarios derive from — so an extension earns its scenario by being a path in the graph, never as a second rule beside the edge coverage above. An extension with no path is a hole in the *graph*: fix it there, and the 1:1 edge coverage supplies the scenario. Never derive a scenario from the prose directly — a suite drawn from a stated list is 1:1 with that list by construction and can no longer surface a hole. `extensions: none` is a claim to judge; a forbidden combination is the same rule in guard form. |
|
|
22
23
|
| **Every scenario is testable** | Each scenario asserts an observable outcome a check can confirm — a boolean, no "sometimes". A behavior the capability cannot expose cannot be specced. |
|
|
23
24
|
| **A graded subject is still a boolean** | A non-deterministic capability (one whose output varies run to run) still reaches a per-scenario boolean, through a rubric plus a threshold over N runs. The rubric form stays out of the boolean `.feature`, carried as a judge-only `@rubric` scenario. |
|
|
24
25
|
|
|
@@ -24,6 +24,17 @@ plugin may bind its own, and this loads when the registry leaves `builder`/`spec
|
|
|
24
24
|
stated in **closed form** (single-condition folds may be by example — demanding closed form of one
|
|
25
25
|
is over-firing), and its coverage is backed by a **mutation sweep** and a **safety dual**
|
|
26
26
|
(`sdd:suite-format-governance`).
|
|
27
|
+
- **Every stated extension is a path in the CFG.** A use case's **extensions** are its divergences
|
|
28
|
+
(`sdd:spec-format-governance`), and the CFG is the **single source** the scenarios derive from —
|
|
29
|
+
so an extension earns its scenario **by being a path in the graph**, never as a second rule
|
|
30
|
+
alongside the edge coverage above. The check is therefore: does the CFG contain a path to each
|
|
31
|
+
stated extension? An extension with no path is a hole in the **graph** — fix it there, and the
|
|
32
|
+
standing 1:1 edge coverage supplies the scenario. **Never derive a scenario from the prose
|
|
33
|
+
directly**: a suite drawn from a stated list is 1:1 with that list by construction and can no
|
|
34
|
+
longer surface a hole, which is the retrofit shape that has diverged in this corpus before. A use
|
|
35
|
+
case declaring `extensions: none` asserts nothing can diverge — judge that claim against the
|
|
36
|
+
graph. A **forbidden combination** is the same rule in guard form: it is a decision the CFG must
|
|
37
|
+
carry, and its refusal scenario comes from that guard's edge.
|
|
27
38
|
- **Every scenario is testable.** Each asserts an observable outcome a check can confirm — a boolean,
|
|
28
39
|
no "sometimes". A behavior the capability cannot expose cannot be specced.
|
|
29
40
|
- **A graded subject is still a boolean.** For a non-deterministic capability the contract reaches a
|
|
@@ -40,9 +51,14 @@ plugin may bind its own, and this loads when the registry leaves `builder`/`spec
|
|
|
40
51
|
|
|
41
52
|
1. **Every branch of the capability is covered** — every edge has its scenario, guards paired with
|
|
42
53
|
positives, the scenario map 1:1.
|
|
43
|
-
2. **Every
|
|
54
|
+
2. **Every stated extension is a path in the CFG** — the graph is the single source scenarios derive
|
|
55
|
+
from, so an extension earns its scenario by being a path, never as a second rule alongside edge
|
|
56
|
+
coverage; a divergence with no path is a hole in the *graph*. Never derive a scenario from the
|
|
57
|
+
prose directly. `extensions: none` is a claim to judge; a forbidden combination is a guard the
|
|
58
|
+
graph carries.
|
|
59
|
+
3. **Every scenario is testable** — an observable boolean outcome; behavior the capability cannot
|
|
44
60
|
expose cannot be specced.
|
|
45
|
-
|
|
61
|
+
4. **A graded subject still reaches a per-scenario boolean** via rubric + threshold; the rubric stays
|
|
46
62
|
out of the `.feature`.
|
|
47
|
-
|
|
63
|
+
5. **A dimension or cut is grounded on non-author evidence** — a measurement justifying it must be not
|
|
48
64
|
solely the author's own (canonical standard: `sdd:doctrine-loop`); the cold-instrument doctrine.
|
|
@@ -4,7 +4,10 @@ This is an internal SDD governance about scope and the kill-or-ship call at the
|
|
|
4
4
|
|
|
5
5
|
Before a capability's spec is approved, someone has to ask the uncomfortable questions: is this one
|
|
6
6
|
thing or two things glued together? Is it worth building at all? Does every scenario in its suite
|
|
7
|
-
actually belong to it?
|
|
7
|
+
actually belong to it? Are the **actors enumerated**, and does that enumeration close both ways — no
|
|
8
|
+
actor without a use case, no use case without a listed actor? Is every element the capability
|
|
9
|
+
**exposes** bought by a use case, or unbought scope to cut? This governance is that question list —
|
|
10
|
+
the **Oracle** bar. It judges the
|
|
8
11
|
**capability itself**, read from its spec and suite together — not how the document is written,
|
|
9
12
|
which is a different bar (`spec-format-governance`).
|
|
10
13
|
|
|
@@ -16,7 +19,9 @@ which is a different bar (`spec-format-governance`).
|
|
|
16
19
|
| **Bounded, stated scope** | What is out of scope is named. A capability that keeps absorbing adjacent problems is scope creep — cut it back. |
|
|
17
20
|
| **The node owns its decisions** | Every scenario tests a decision the node owns. A property co-owned across a seam — activation/routing, a sibling's behavior, harness wiring — is out of scope: relocate it to the node that owns it, or kill it. |
|
|
18
21
|
| **Strict — non-decisions are killed** | An invariant that always holds is not acceptance and does not enter the suite. The one exception is a user `@pinned` scenario, kept whatever strict prunes. |
|
|
19
|
-
| **
|
|
22
|
+
| **Every surface element is paid for by a use case** | An element the capability exposes — a flag, an option, a parameter, a prop, an event — that **no use case needs** is unbought scope: cut it, or name the use case. This is the same kill-or-ship judgment one level down — the capability answers for its cost, and so does each thing it exposes. |
|
|
23
|
+
| **The actors are enumerated, and the enumeration closes** | The Why names a real problem and **who feels it**, so the use cases are derived from a stated set of actors rather than from the interface. Graded **both ways**: an actor carrying no use case, and a use case whose actor is absent from the list, are each a hole. A goal that restates the mechanism is an unanswered Why, not a filled-in field. On a backfill, an enumeration drawn only from source covers the *served* use cases by construction. |
|
|
24
|
+
| **Worth shipping, or kill** | If the value does not clear the cost of building, the verdict is kill. |
|
|
20
25
|
| **Kill-or-revert** | A capability that passes every check but proves fatal goes back to Draft — surface the deal-breaker. |
|
|
21
26
|
| **No premature commitment** | A decision that need not be made yet is deferred to the last responsible moment. |
|
|
22
27
|
|
|
@@ -23,13 +23,25 @@ writing, the cold spec-judge judges kill-or-ship. Oracle has no impl face. The S
|
|
|
23
23
|
capabilities** — split them, each into its own node. Test: can you name the outcome without "and"?
|
|
24
24
|
- **Scope is bounded and stated.** What is out of scope is named. A capability that keeps absorbing
|
|
25
25
|
adjacent problems is scope creep — cut it back.
|
|
26
|
+
- **Every surface element is paid for by a use case.** An element the capability exposes — a flag,
|
|
27
|
+
an option, a parameter, a prop, an event — that **no use case needs** is unbought scope: the
|
|
28
|
+
verdict is cut it or name the use case, never ship it and see (`sdd:spec-format-governance`).
|
|
29
|
+
This is the same kill-or-ship judgment one level down: the capability answers for its cost, and so
|
|
30
|
+
does each thing it exposes. An actor or goal that restates the mechanism has not identified who
|
|
31
|
+
wants this — treat it as an unanswered Why, not as a filled-in field.
|
|
26
32
|
- **The suite's decisions are the node's to hold.** Every scenario tests a **decision the node owns**.
|
|
27
33
|
A property **co-owned** across a seam — activation/routing, a sibling's behavior, harness wiring —
|
|
28
34
|
is out of scope: relocate it to the node that owns it, or kill it.
|
|
29
35
|
- **Strict — a non-decision is killed.** An **invariant** that always holds is not acceptance and does
|
|
30
36
|
not enter the suite. The one exception is a user **`@pinned`** scenario, kept whatever strict prunes.
|
|
31
|
-
- **
|
|
32
|
-
the
|
|
37
|
+
- **The actors are enumerated, and the enumeration closes.** The Why names a real problem and **who
|
|
38
|
+
feels it** — so the use cases are derived from a stated set of actors, not from the interface
|
|
39
|
+
(`sdd:spec-format-governance`). Grade it **both ways**: an actor carrying no use case, and a use
|
|
40
|
+
case whose actor is absent from the list, are each a hole. A goal that restates the mechanism has
|
|
41
|
+
renamed the function rather than found the use case — an unanswered Why, not a filled-in field.
|
|
42
|
+
On a backfill, an enumeration drawn only from source is **served** use cases by construction:
|
|
43
|
+
judge whether the unserved ones were sought, not merely whether the list is tidy.
|
|
44
|
+
- **Worth shipping, or kill.** If value does not clear the cost of building, the verdict is **kill**.
|
|
33
45
|
- **Kill-or-revert is allowed.** A capability that passes every check but proves fatal goes back to
|
|
34
46
|
Draft — surface the deal-breaker.
|
|
35
47
|
- **No premature commitment.** Defer a decision that need not be made yet to the last responsible
|
|
@@ -37,9 +49,14 @@ writing, the cold spec-judge judges kill-or-ship. Oracle has no impl face. The S
|
|
|
37
49
|
|
|
38
50
|
## Key points (read-check)
|
|
39
51
|
|
|
40
|
-
1. **One coherent intent** — two concerns are two capabilities; bounded and stated scope.
|
|
52
|
+
1. **One coherent intent** — two concerns are two capabilities; bounded and stated scope. **Every
|
|
53
|
+
surface element is paid for by a use case** — an orphan element is unbought scope (cut or
|
|
54
|
+
justify); an actor/goal restating the mechanism is an unanswered Why.
|
|
41
55
|
2. **Every scenario tests a decision the node owns** — a co-owned seam property is out of scope
|
|
42
56
|
(relocate or kill).
|
|
43
57
|
3. **Strict** — an invariant / non-decision does not enter the suite; only a user `@pinned` scenario
|
|
44
58
|
escapes.
|
|
45
|
-
4. **
|
|
59
|
+
4. **The actors are enumerated and the enumeration closes** — graded both ways (an actor with no use
|
|
60
|
+
case, a use case with no listed actor); a goal restating the mechanism is an unanswered Why; a
|
|
61
|
+
backfill list drawn only from source covers the served cases by construction.
|
|
62
|
+
5. **Worth shipping or kill** — value must clear the build cost; a fatal proof reverts to Draft.
|
|
@@ -44,7 +44,7 @@ A `spec.md` has **four sections, in this order**:
|
|
|
44
44
|
| Section | What goes in it |
|
|
45
45
|
| --- | --- |
|
|
46
46
|
| `## What` | What the capability is, the problem it solves, who has that problem, and what it deliberately does not do (non-goals). |
|
|
47
|
-
| `## Use Cases` | Every distinct way the capability is invoked
|
|
47
|
+
| `## Use Cases` | Every distinct way the capability is invoked, each named after the thing you actually call (a CLI verb, a function, an endpoint) and carrying four parts: the **actor and their goal**, the **entry point** (trigger / inputs / outcome), and its **extensions** — what else can happen, each divergence with its cause and outcome. Plus a trace of every element the capability exposes (flag, option, parameter, prop, event) to the use case that needs it and the elements it may not combine with. An element no use case needs is an orphan: cut it or justify it. |
|
|
48
48
|
| `## Control Flow` | The decisions the capability makes once invoked, taken as one **control-flow graph (CFG)** and **drawn** as a diagram rather than described in prose. Use cases feed into one CFG; several usually share it. |
|
|
49
49
|
| `## Scenario map` | A table pairing each branch in that diagram with the one test scenario covering it, grouped by use case. One-to-one, both directions — so a gap in coverage is visible instead of buried in prose. |
|
|
50
50
|
|
|
@@ -20,12 +20,73 @@ deliberately excludes). One or two short paragraphs; add a **Key terms** glossar
|
|
|
20
20
|
jargon. Legible to a non-engineer.
|
|
21
21
|
|
|
22
22
|
### `## Use Cases`
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
**trigger / inputs / outcome
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
One entry per distinct way the capability is invoked, each **named to its implementation surface**
|
|
24
|
+
(a CLI verb, a public function, an endpoint) and carrying four parts: **actor / goal**, the
|
|
25
|
+
**entry point** (trigger / inputs / outcome), and its **extensions**. Naming the impl surface keeps
|
|
26
|
+
the spec, the suite, and the code on **one screaming structure**: the builder gives each use case
|
|
27
|
+
its own module, so each change stays local.
|
|
28
|
+
|
|
29
|
+
A use case answers *"who is trying to do what, how do they invoke it, and what else can happen?"* —
|
|
30
|
+
never *"given this state, does it do that?"* (that is a scenario).
|
|
31
|
+
|
|
32
|
+
**Enumerate by actor, never by entry point.** Walking the interface and asking who calls each entry
|
|
33
|
+
point can only return use cases the interface already implies — it reproduces the surface and calls
|
|
34
|
+
it a requirement, and it is structurally blind to the use case nobody has built yet. So the section
|
|
35
|
+
is derived the other way round:
|
|
36
|
+
|
|
37
|
+
1. **List the actors** — every person in a role, sibling capability, scheduler, or operator that
|
|
38
|
+
reaches this capability, **plus** whoever is affected by its outcome without invoking it (the
|
|
39
|
+
reviewer, the on-call, the next agent in a chain). The second group are stakeholders rather than
|
|
40
|
+
actors and are where a missed use case usually hides.
|
|
41
|
+
2. **Per actor, name the goals** they come to this capability with — their result, not the call they
|
|
42
|
+
make.
|
|
43
|
+
3. **Then map goals to entry points.** A goal with **no** entry point is the finding this ordering
|
|
44
|
+
exists to surface: either the capability is missing a way in, or the goal belongs to another
|
|
45
|
+
node. An entry point serving **no** listed actor's goal is the mirror finding — it is surface
|
|
46
|
+
nobody asked for.
|
|
47
|
+
|
|
48
|
+
The enumeration is checkable both ways: an actor carrying no use case, and a use case whose actor
|
|
49
|
+
is absent from the list, are each a hole. On **backfill** the source yields only the *served* use
|
|
50
|
+
cases by construction — recover the unserved ones from the request history, the issue tracker, and
|
|
51
|
+
recurring workarounds, and record where each came from.
|
|
52
|
+
|
|
53
|
+
- **Actor and goal — one line each, not a persona.** Name who invokes it (a person in a role,
|
|
54
|
+
another capability, a scheduler) and the outcome **they** want, stated as their result rather
|
|
55
|
+
than the mechanism ("recover the work after a crash", not "calls `resume()`"). An actor may be
|
|
56
|
+
an agent or a sibling capability; that is normal, not a degenerate case. Where the goal restates
|
|
57
|
+
the function name, the use case has not been found yet — it has been renamed.
|
|
58
|
+
- **Entry point** — the trigger, its inputs, and the success outcome. A table is the usual form.
|
|
59
|
+
- **Extensions — what else can happen, and the instrument that finds it.** An extension is **any
|
|
60
|
+
path from this use case's trigger that does not reach its success outcome**; state each with its
|
|
61
|
+
cause and its outcome. That criterion decides membership — the recurring kinds (an error, a
|
|
62
|
+
refusal, a boundary, a partial result, a contended or absent input) are a **prompt to search, not
|
|
63
|
+
a closed set**, so a divergence matching none of them still belongs and a kind that cannot arise
|
|
64
|
+
here is not owed a row. **A use case with no extensions is a claim that nothing can go wrong** —
|
|
65
|
+
state that claim explicitly (`extensions: none — <why>`) rather than leaving the field off, so a
|
|
66
|
+
reviewer can disagree with it.
|
|
67
|
+
|
|
68
|
+
Extensions are a **discovery instrument, not a second specification.** They exist to make the
|
|
69
|
+
**CFG complete**: a graph drawn from an implementation reproduces what the code already does and
|
|
70
|
+
can never tell you a branch is *missing*, whereas asking what can go wrong **for this actor**
|
|
71
|
+
finds it. So every extension you find belongs in `## Control Flow` as a path, and the scenarios
|
|
72
|
+
still derive from **the CFG alone** (`## Scenario map`, 1:1 on the **(path class, edge)** pair).
|
|
73
|
+
Never draw a scenario from the stated list directly: a suite derived from prose is 1:1 with that
|
|
74
|
+
prose by construction and can no longer surface a hole. A use case is therefore **not** 1:1 with
|
|
75
|
+
a scenario — one extension may need several scenarios where several path classes reach it, and
|
|
76
|
+
several extensions may reconverge onto one.
|
|
77
|
+
|
|
78
|
+
**Every element of the public surface traces to a use case that needs it.** List each element the
|
|
79
|
+
capability exposes — a flag, an option, a parameter, a prop, an event — against the use case
|
|
80
|
+
requiring it, and name the elements it **may not** be combined with. An element **no use case needs
|
|
81
|
+
is unjustified**: cut it, or name the use case. A pair whose combination is contradictory and
|
|
82
|
+
unstated is a gap, not a detail. This is the same orphan-detection discipline as `## Scenario map`,
|
|
83
|
+
applied one level up: there, a scenario with no edge is an orphan; here, an element with no use case
|
|
84
|
+
is an orphan.
|
|
85
|
+
|
|
86
|
+
Degenerate cases stay cheap. A capability exposing **one** entry point and **no** optional elements
|
|
87
|
+
carries the surface trace in a line, not a table — the obligation is that nothing on the surface is
|
|
88
|
+
unaccounted for, never that a table exists. A single-actor capability lists one actor; the
|
|
89
|
+
enumeration is the discipline, not the length.
|
|
29
90
|
|
|
30
91
|
### `## Control Flow`
|
|
31
92
|
The **control-flow graph (CFG)** the capability runs once invoked, **drawn** as a fenced Mermaid
|
|
@@ -108,8 +169,10 @@ Enrichment (diagrams, formatting) is `spec.md` only; the suite stays plain Gherk
|
|
|
108
169
|
1. **Four sections in order** — `## What` (overview + non-goals), `## Use Cases`, `## Control Flow`,
|
|
109
170
|
`## Scenario map` — plus an optional `## References` last, citing research that backs a decision
|
|
110
171
|
(the claim it supports, not the topic).
|
|
111
|
-
2. **A use case is
|
|
112
|
-
suite, and code share one screaming structure.
|
|
172
|
+
2. **A use case is actor + goal + entry point + extensions**, named to its impl surface (CLI verb /
|
|
173
|
+
function / endpoint) — spec, suite, and code share one screaming structure. No extensions is a
|
|
174
|
+
claim, stated explicitly. **Every surface element traces to a use case that needs it**, with its
|
|
175
|
+
forbidden combinations named; an element no use case needs is an orphan — cut it or justify it.
|
|
113
176
|
3. **The CFG is shared** — use cases enter it (many-to-one); section by sub-graph only when the
|
|
114
177
|
decision logic genuinely differs.
|
|
115
178
|
4. **The scenario map is 1:1 and grouped by use case** — coverage visible per use case; `check-suite`
|
|
@@ -4,4 +4,4 @@ Non-user-invocable SDD skill holding the **default spec-producer procedure**: ho
|
|
|
4
4
|
|
|
5
5
|
Loaded via the harness (`Skill`) by the **conductor** (the main session) when it runs the spec-producer role from the SDD default — the conductor authors **inline** in its own warm context (recorded `produced-by.spec-producer: sdd:automaton`) rather than spawning a producer agent. The grader stays separate: a cold `sdd-spec-judge` reviews the output.
|
|
6
6
|
|
|
7
|
-
References `sdd:spec-governance` (the universal format bar — including the required `## Use Cases` section and the use-case
|
|
7
|
+
References `sdd:spec-format-governance` (the universal format bar — including the required `## Use Cases` section, its actor-first enumeration, and the rule that scenarios derive from the CFG rather than from the stated use-case prose) plus the resolved oracle + builder + architect actor bars (the spec-gate lens set, forward face) as its self-alignment criteria, and `sdd:ownership-governance` for the write-ownership matrix. Bakes in the grilling discipline (breadth-first, depth one-at-a-time, prose before suite) and the reconcile-toward-the-correct-answer rule for contradictions surfaced during grilling.
|
|
@@ -30,9 +30,13 @@ USER_ANSWERS: <answers to previously returned QUESTIONS — or null>
|
|
|
30
30
|
|
|
31
31
|
2. **Reconcile contradictions toward the correct answer, not the popular one.** When grilling surfaces a conflict — between the `spec.md` body 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 a `CONTENT_GAP` rather than picking a direction.
|
|
32
32
|
|
|
33
|
-
3. **Write the `spec.md` body per `sdd:spec-format-governance`.** That bar owns the required structure — the `## Use Cases` section (subject, non-goals, and
|
|
33
|
+
3. **Write the `spec.md` body per `sdd:spec-format-governance`.** That bar owns the required structure — the `## Use Cases` section (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).
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
**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-governance` owns 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 a `CONTENT_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. On `BACKFILL` the 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-governance` owns 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, write `extensions: 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.
|
|
36
|
+
|
|
37
|
+
**Then check the extensions against the CFG — the producer-side mirror of the Architect bar.** Where the node carries a `## Control Flow` graph, 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-governance` grades 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 report `STATUS: complete` with 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. **On `BACKFILL` the four sections are still mandatory** — draw the `## Control Flow` CFG and its `## Scenario map` from the code, never stop at `## Use Cases` (`sdd:spec-format-governance`; `check-spec-structure`'s `incomplete-node` flags a leaf that skips them).
|
|
38
|
+
|
|
39
|
+
4. **Write `<DOMAIN_PATH>/<DOMAIN>.feature`** — pure boolean Gherkin per `sdd: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 Cases` section 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. **On `BACKFILL`, 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`). Each `Then` is 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 `.feature` plain; rubric form is legal only inside an `@rubric`-tagged scenario.
|
|
36
40
|
|
|
37
41
|
**A `Given` is a test vector, not specification** (`sdd:suite-format-governance` carries the canonical bar and the swap test). Author each `Given`'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; on `BACKFILL` it 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 a `Given`.
|
|
38
42
|
|
|
@@ -4,4 +4,4 @@ The single user-facing entry for **changing an SDD project** — triggered by a
|
|
|
4
4
|
|
|
5
5
|
The session that runs this skill **is the conductor** — the in-session realization of the conductor role; the headless realization is the `automaton` agent. A third realization is **in-session plan-mode preview**: when Claude Code plan mode is active, explore runs its reasoning (classify, seed-intent grill, draft the spec + scenario list, cold spec-judge) but writes no repo files — it renders the drafted spec + suite into the plan file and ends at **ExitPlanMode**, dropping the build-to-learn spikes. On approval the next real explore adopts the preview as the settled draft. Plan mode is detected **in-body**, never via the trigger `description`, so it never re-fires per turn. It supersedes the retired spec-as-mission entries (`create-spec` / `revise-spec`): adding, revising, or deduping part of the project spec is now an **explore-phase operation inside a CR**, not a top-level mission.
|
|
6
6
|
|
|
7
|
-
Bakes in: step-1 intake (recover the request or fetch an issue URL; scaffold the `.plan.md`); explore as the live grill (classify spec-type + artifact-types, scaffold the node, seed-intent Q&A, the inline spec-producer + cold spec-judge loop with build-to-learn spikes, the iteration cap, the **freeze re-open guard**, observation routing); the internal spec gate (freeze + per-CR gate line to the conductor's own `ledger/` shard + `status: approved`); deliver (spawned impl-producer builder + the internal impl gate); handoff; and the baked autonomy bar (initial strategy, per-gate verdicts, the three hard floors). Pairs with `pause-mission` / `resume-mission`.
|
|
7
|
+
Bakes in: step-1 intake (recover the request or fetch an issue URL; scaffold the `.plan.md`); explore as the live grill (classify spec-type + artifact-types, scaffold the node, actor-first seed-intent Q&A, the inline spec-producer + cold spec-judge loop with build-to-learn spikes, the iteration cap, the **freeze re-open guard**, observation routing); the internal spec gate (freeze + per-CR gate line to the conductor's own `ledger/` shard + `status: approved`); deliver (spawned impl-producer builder + the internal impl gate); handoff; and the baked autonomy bar (initial strategy, per-gate verdicts, the three hard floors). Pairs with `pause-mission` / `resume-mission`.
|
|
@@ -39,9 +39,9 @@ For each unit the CR touches:
|
|
|
39
39
|
- **Locate or place the node — provisionally.** If a `spec.md` / `README.md` already exists at the target → this is a **revise** (no scaffolding). Otherwise **scaffold** a new node and drop it in a *plausible* home **under the layout the project declared** in its root `spec.md` placement map — `capability-first` groups by what the project *does*, `mirror-source` mirrors the source tree. Placement is judged *within* that declaration, never against a preferred one (`sdd:spec-structure-governance`, "strategy is policy, homes are data"); where no strategy is declared, the `capability-first` default applies. A layered / framework-first **top level** stays discouraged under every strategy (it scatters a capability across folders, breaking node↔folder and degrading scheduling). Consult `project-spec/place-node` (`--concept` → candidate homes; `--name` → "belongs near X" duplicate-catch) and the placement-map routing table (root `spec.md`) for contested overlaps, but **do not agonize**: placement is **provisional** and finalized cheaply at **handoff** (step 4), where a scoped Warden pass relocates it to its blessed home *in the same change* (a pure rename — freeze survives, `sdd:lifecycle-governance`). If the user named no capability, propose a capability folder from the CR and confirm.
|
|
40
40
|
- **Classify the node** (declared, never inferred): `spec-type: behavioral` (a testable unit → `## Use Cases` + a `<unit>.feature`), `reference` (a shipped non-testable artifact → `## Subject`, no `.feature`), or **descriptive** (an index → no marker). Tag the node's cross-cutting **`concept:`** (the concern it serves — e.g. `lifecycle` / `resolution`; a string or list, orthogonal to `spec-type`; it feeds `project-spec/concept-index`). Also classify each touched file's **artifact-type** (the squad key — resolved per file, **not stored**): **by convention first** (`skill` under `skills/`, `subagent` under `agents/`, …; the extension never decides). On a genuine **ambiguity or a user-flagged path**, consult and record the tiebreaker map `.agents/sdd/artifact-types.toml` and **confirm — never guess** (`sdd:artifact-type` model).
|
|
41
41
|
- **Scaffold the skeleton** per `sdd:spec-format-governance` (sections per type; `.feature` form per `sdd:suite-format-governance`). Write **no** control frontmatter (`status` / `project-path` / `approval` / `produced-by`) — those live on the root `spec.md` and belong to the conductor and the gate.
|
|
42
|
-
- **Collect seed intent.** For a **new** feature, ask 3–5 targeted questions
|
|
42
|
+
- **Collect seed intent.** For a **new** feature, ask 3–5 targeted questions — **lead with the actors** (who reaches this capability, and who is affected by its outcome without invoking it), then their goals, then the core problem, observable behavior, edge cases / non-goals, and reviewers who must be heard. Ask for the **public interface last, and never first**: an interface offered up front becomes the anchor the use cases get read off, which is the enumeration failure `sdd:spec-format-governance` exists to prevent. For **backfill** (behavior already in code), skip — the producer reads source, tests, history. For a **revise**, collect what changes and why and the parts it touches.
|
|
43
43
|
|
|
44
|
-
**The grill loop (the user loop).** You are the conductor. Run the spec-producer **inline** (load `sdd:spec-producer-governance`, or persona-load a plugin specialist for the `artifact-types`), **dispatch the cold spec-judge** each round — through the dispatch capability's intent seam when one is available (preferring its **warm** unit, context-cleared fresh via `npx cyberlegion@0.
|
|
44
|
+
**The grill loop (the user loop).** You are the conductor. Run the spec-producer **inline** (load `sdd:spec-producer-governance`, or persona-load a plugin specialist for the `artifact-types`), **dispatch the cold spec-judge** each round — through the dispatch capability's intent seam when one is available (preferring its **warm** unit, context-cleared fresh via `npx cyberlegion@0.3.0 unit clear <ref>` before each round's judgment), else a portable cold subagent — and for build-to-learn **dispatch the impl-producer builder** the same way (its warm unit **keeps** its context across spikes; no reset) in `explore` mode against the **non-frozen** suite — spikes are thrown away; their learnings feed the live grill to steer the spec + suite. Set an **iteration cap** (default **3**; honor a user-named cap), then loop:
|
|
45
45
|
|
|
46
46
|
**Governance provenance relay.** When you dispatch the cold spec-judge, forward the inline spec-producer's declared `governances_loaded` (`sdd:spec-producer-governance`) verbatim through the same dispatch channel, keyed **`producer_governances_declared`** — a brief field when the judge is a cold subagent, a mail envelope field when it runs through an agent pool. Forward it **as-is, including an empty set** — you render **no opinion** on which governances were actually required; that check is the spec-judge's own pre-flight (`sdd:sdd-spec-judge`).
|
|
47
47
|
|
|
@@ -79,7 +79,7 @@ Build-to-keep against the **frozen** suite. The deliver **read-set is scoped** (
|
|
|
79
79
|
|
|
80
80
|
**Rebase onto the target — the last deliver act, before the gate.** Before running the impl gate, **rebase the CR branch onto the current tip of the declared target** (for a commit-to-main project, the equivalent `pull --rebase` onto the latest `main`), so the impl gate judges the **merged tree that will actually land** — keeping history linear and leaving handoff a pure consumer that never re-verifies. A **textual conflict** is resolved as **deliver code work** against the frozen `.feature` (never a `.feature` edit); the gate then runs on the resolved tree. A conflict you **cannot resolve confidently is never guess-resolved** — the frozen suite covers *this CR's* behavior, not the incoming change's, so a wrong resolution could still pass the gate and land broken; **stop and escalate** (in-session ask the user; headless return `needs-input` up the relay) and record a `halt`, never land a low-confidence resolution. Rebasing an *unmerged* CR branch is git-reversible (reflog), so it raises **no new hard floor** — but a conflict resolution that would **narrow** a frozen scenario still fires the existing **Clearance** floor, a semver class over the ceiling **Compatibility**, and a genuine contradiction **Conflict** (autonomy bar, below). The rebase-then-gate is **optimistic**: if the target **advances again** between the passing gate and the push (another CR merged in the window), **re-rebase onto the new tip and re-run the impl gate — do not push until the gate passes on the re-rebased tree**, looping until the push wins, so what lands is always a tree the gate saw green. **The loop is bounded, not forced** — if the target keeps advancing past a small cap of attempts, **stop and escalate** (record a `halt`) rather than spinning forever (a liveness stop, same as the unconfident-conflict halt).
|
|
81
81
|
|
|
82
|
-
**The impl gate (Approved → Implemented, internal).** On entering the gate, overwrite the statusline file with `impl gate`. Dispatch the **cold impl-judge** (`sdd:sdd-impl-judge` or the covering plugin's judge) — same seam-when-available wiring, preferring its warm unit context-cleared fresh via `npx cyberlegion@0.
|
|
82
|
+
**The impl gate (Approved → Implemented, internal).** On entering the gate, overwrite the statusline file with `impl gate`. Dispatch the **cold impl-judge** (`sdd:sdd-impl-judge` or the covering plugin's judge) — same seam-when-available wiring, preferring its warm unit context-cleared fresh via `npx cyberlegion@0.3.0 unit clear <ref>` for this judgment, else a portable cold subagent — to run the verification per frozen scenario plus an orthogonal structural/scope read. Advance to **`status: implemented`** **only when every impl-judge passes** (a frozen scenario with no verification blocks the advance — impl-sync is this suite run, not a stored flag). The three actions: **approve** → `implemented`; **change** → fix the **code** (never the frozen `.feature`), under the same evidence-not-a-work-order remediation the spec gate uses (`sdd:remediation-governance`) — including the **provenance** account that stops a regressing loop; **reject** → redo, or a **Oracle-lens revert** (a frozen scenario proved fatal → unfreeze the `.feature`, return to `draft` — the only place a frozen `.feature` reopens).
|
|
83
83
|
|
|
84
84
|
## Step 4 — handoff
|
|
85
85
|
|
|
@@ -97,13 +97,13 @@ Before you close out, run the **correction-line finalize backstop** (autonomy ba
|
|
|
97
97
|
|
|
98
98
|
Also run the **plan-brief finalize backstop** (autonomy bar, below): reconcile the plan brief's `todos` and its `## NEXT` anchor to the landed state, **in this same change** — so the delivery never ships a landed mission described as in-progress.
|
|
99
99
|
|
|
100
|
-
Before closing out, **reset the mission's warm units**: `npx cyberlegion@0.
|
|
100
|
+
Before closing out, **reset the mission's warm units**: `npx cyberlegion@0.3.0 unit clear <ref>` (context-clear, pane stays warm) or tear down every warm unit this mission dispatched — none carries this mission's context into the next.
|
|
101
101
|
|
|
102
102
|
Once landed, **do not spawn** the formation Warden. Surface a **one-line nudge** that a corpus-wide formation pass is due, pointing to `sdd:manage` ("audit the corpus structure" → `formation-loop`). The pass is **on-demand** — run deliberately, not auto-spawned on every landing; `sdd:manage` owns the trigger. Gate nothing on it.
|
|
103
103
|
|
|
104
104
|
## Autonomy, provenance, and the hard floor (baked in)
|
|
105
105
|
|
|
106
|
-
- **Dispatch transport.** Every spawn beyond this session states a **dispatch intent** — role, brief, expected verdict schema — never a pinned command. When a harness-agnostic dispatch capability is available (detected at runtime; the concrete case is the Legate's `dispatch-governance` composing `cyberlegion` primitives — `agent resolve` + `unit spawn` + `mail await` — with **no** `dispatch` CLI verb, the seam named in the SDD project spec's `design/harness-spawning` node, repo-only), route through its intent seam and let it pick `subagent | channel | run-inline`, **preferring a warm unit** over a cold one-shot spawn; with no capability present, fall back to the portable cold subagent (depth-1) default — grader independence intact either way. **Warmth is a property of the unit/process; coldness of the context**: a judge's fresh-context guarantee (ADR-0016) is transport-agnostic — satisfied by a newly spawned cold subagent **or** a warm unit **context-cleared** to a fresh context before **each** judgment (re-deriving its oracle, carrying none of a prior round's context). Clear a warm unit with **`npx cyberlegion@0.
|
|
106
|
+
- **Dispatch transport.** Every spawn beyond this session states a **dispatch intent** — role, brief, expected verdict schema — never a pinned command. When a harness-agnostic dispatch capability is available (detected at runtime; the concrete case is the Legate's `dispatch-governance` composing `cyberlegion` primitives — `agent resolve` + `unit spawn` + `mail await` — with **no** `dispatch` CLI verb, the seam named in the SDD project spec's `design/harness-spawning` node, repo-only), route through its intent seam and let it pick `subagent | channel | run-inline`, **preferring a warm unit** over a cold one-shot spawn; with no capability present, fall back to the portable cold subagent (depth-1) default — grader independence intact either way. **Warmth is a property of the unit/process; coldness of the context**: a judge's fresh-context guarantee (ADR-0016) is transport-agnostic — satisfied by a newly spawned cold subagent **or** a warm unit **context-cleared** to a fresh context before **each** judgment (re-deriving its oracle, carrying none of a prior round's context). Clear a warm unit with **`npx cyberlegion@0.3.0 unit clear <ref>`** (`<ref>` = unit id / handle / worktree branch or CR ref) — it injects the harness's own fresh-context command (`/clear` on Claude/Codex/Copilot, `/new-chat` on Cursor; fail-loud on a harness with no honest reset) so the **pane stays warm** while the **context goes cold**; it tears nothing down. The **impl-producer builder** instead stays warm and **keeps** its context across the explore spikes and the deliver build (never cleared between those uses). Warm units stay warm for **one mission** — reused within it, then **`unit clear`**'d or torn down at **handoff**, never carrying this mission's context into the next.
|
|
107
107
|
- **Initial strategy** (run start): assess blast radius + the other dimensions and emit a run-level `kind: leash` block to **your own ledger shard** (`ledger/<cr-ref>.<hash>.jsonl` — mint `<hash>` as 6 random hex **once per session** and reuse it for every line you append; `sdd:combat-log-governance`) — `leash` (`auto-none | auto-spec | auto-all`), `by: derived | user`, `approach[]`. It may be user-specified. This block is `kind: leash`, **not** `strategy` — `strategy` is the doctrine Scanner's alone. Ledger lines carry **no `ts`**.
|
|
108
108
|
- **Per-gate verdict.** At each gate, derive the leash against discovered state and either **self-assert within leash** (write `approval.<gate>: { verdict: approve, by: agent, why }`; the spec lands in the async review queue) or **stop** with a verdict packet for the human. **Never advance** when any judge fails, any open marker remains, or (at the impl gate) any frozen scenario's verification does not pass. Human ratification (`by: <name>`, advance `status`) is reserved to the in-session position holding the user channel — by default you, in-session; a headless `automaton` emits the verdict packet and stops, **even when a coordinator relays "the user approved."**
|
|
109
109
|
- **Combat log.** Append `report` / `correction` lines (and the halt that stopped you) to the plan's `*.log.jsonl` (these carry a UTC `ts`); your run-start `leash` block, self-asserted `gate` lines, and the handoff `followup` records go to **your own shard** in the durable `ledger/` directory sibling to `spec.md` — never another writer's shard, never a shared file (`strategy` there is the Scanner's alone). Free text is commit-message-grade — never code, prompts, secrets, or literal values.
|