cyber-sdd 0.0.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.
Files changed (133) hide show
  1. package/.claude-plugin/plugin.json +17 -0
  2. package/.codex-plugin/plugin.json +17 -0
  3. package/.plugin/plugin.json +17 -0
  4. package/README.md +159 -0
  5. package/agents/sdd-automaton.md +97 -0
  6. package/agents/sdd-impl-judge.md +214 -0
  7. package/agents/sdd-scanner.md +120 -0
  8. package/agents/sdd-spec-judge.md +224 -0
  9. package/agents/sdd-warden.md +101 -0
  10. package/package.json +24 -0
  11. package/skills/align-spec/README.md +20 -0
  12. package/skills/align-spec/SKILL.md +111 -0
  13. package/skills/align-spec/scripts/align-spec.mts +187 -0
  14. package/skills/architect-impl-governance/README.md +46 -0
  15. package/skills/architect-impl-governance/SKILL.md +45 -0
  16. package/skills/architect-spec-governance/README.md +48 -0
  17. package/skills/architect-spec-governance/SKILL.md +59 -0
  18. package/skills/blast-estimate/README.md +47 -0
  19. package/skills/blast-estimate/SKILL.md +133 -0
  20. package/skills/blast-estimate/scripts/blast-estimate.mts +583 -0
  21. package/skills/builder-impl-governance/README.md +47 -0
  22. package/skills/builder-impl-governance/SKILL.md +47 -0
  23. package/skills/builder-spec-governance/README.md +49 -0
  24. package/skills/builder-spec-governance/SKILL.md +36 -0
  25. package/skills/check-partition-quality/README.md +22 -0
  26. package/skills/check-partition-quality/SKILL.md +51 -0
  27. package/skills/check-partition-quality/scripts/check-partition-quality.mts +336 -0
  28. package/skills/check-plan-safety/README.md +17 -0
  29. package/skills/check-plan-safety/SKILL.md +60 -0
  30. package/skills/check-plan-safety/scripts/check-plan-safety.mts +145 -0
  31. package/skills/check-project-specs/README.md +19 -0
  32. package/skills/check-project-specs/SKILL.md +69 -0
  33. package/skills/check-project-specs/scripts/check-project-specs.mts +217 -0
  34. package/skills/check-scenario-overlap/README.md +19 -0
  35. package/skills/check-scenario-overlap/SKILL.md +74 -0
  36. package/skills/check-scenario-overlap/scripts/check-scenario-overlap.mts +249 -0
  37. package/skills/check-spec-structure/README.md +17 -0
  38. package/skills/check-spec-structure/SKILL.md +66 -0
  39. package/skills/check-spec-structure/scripts/check-spec-structure.mts +346 -0
  40. package/skills/collision-ladder/README.md +18 -0
  41. package/skills/collision-ladder/SKILL.md +83 -0
  42. package/skills/collision-ladder/scripts/collision-ladder.mts +657 -0
  43. package/skills/combat-log-governance/README.md +13 -0
  44. package/skills/combat-log-governance/SKILL.md +257 -0
  45. package/skills/concept-index/README.md +13 -0
  46. package/skills/concept-index/SKILL.md +38 -0
  47. package/skills/concept-index/scripts/concept-index.mts +245 -0
  48. package/skills/discover-plans/README.md +16 -0
  49. package/skills/discover-plans/SKILL.md +74 -0
  50. package/skills/discover-plans/scripts/discover-plans.mts +212 -0
  51. package/skills/discover-specs/README.md +15 -0
  52. package/skills/discover-specs/SKILL.md +76 -0
  53. package/skills/discover-specs/scripts/discover-specs.mts +396 -0
  54. package/skills/doctrine-loop/README.md +15 -0
  55. package/skills/doctrine-loop/SKILL.md +97 -0
  56. package/skills/formation-loop/README.md +17 -0
  57. package/skills/formation-loop/SKILL.md +140 -0
  58. package/skills/gate-validation-governance/README.md +12 -0
  59. package/skills/gate-validation-governance/SKILL.md +87 -0
  60. package/skills/impl-producer-governance/README.md +48 -0
  61. package/skills/impl-producer-governance/SKILL.md +85 -0
  62. package/skills/init/README.md +27 -0
  63. package/skills/init/SKILL.md +68 -0
  64. package/skills/init/scripts/wire-statusline.mts +276 -0
  65. package/skills/lifecycle-governance/README.md +11 -0
  66. package/skills/lifecycle-governance/SKILL.md +168 -0
  67. package/skills/manage/README.md +9 -0
  68. package/skills/manage/SKILL.md +62 -0
  69. package/skills/manage-ignore/README.md +19 -0
  70. package/skills/manage-ignore/SKILL.md +52 -0
  71. package/skills/manage-ignore/scripts/manage-ignore.mts +294 -0
  72. package/skills/manage-scenario-bridge/README.md +20 -0
  73. package/skills/manage-scenario-bridge/SKILL.md +60 -0
  74. package/skills/manage-scenario-bridge/scripts/manage-scenario-bridge.mts +156 -0
  75. package/skills/manage-spec-anchors/README.md +18 -0
  76. package/skills/manage-spec-anchors/SKILL.md +56 -0
  77. package/skills/manage-spec-anchors/scripts/manage-spec-anchors.mts +328 -0
  78. package/skills/mission-graph/README.md +15 -0
  79. package/skills/mission-graph/SKILL.md +67 -0
  80. package/skills/mission-graph/scripts/mission-graph.mts +844 -0
  81. package/skills/oracle-spec-governance/README.md +45 -0
  82. package/skills/oracle-spec-governance/SKILL.md +45 -0
  83. package/skills/ownership-governance/README.md +65 -0
  84. package/skills/ownership-governance/SKILL.md +104 -0
  85. package/skills/pause-mission/README.md +18 -0
  86. package/skills/pause-mission/SKILL.md +112 -0
  87. package/skills/place-node/README.md +12 -0
  88. package/skills/place-node/SKILL.md +47 -0
  89. package/skills/place-node/scripts/place-node.mts +157 -0
  90. package/skills/plan-retirement/README.md +32 -0
  91. package/skills/plan-retirement/SKILL.md +90 -0
  92. package/skills/plan-retirement/scripts/retire-plans.mts +196 -0
  93. package/skills/plugin-contract-governance/README.md +12 -0
  94. package/skills/plugin-contract-governance/SKILL.md +112 -0
  95. package/skills/remediation-governance/README.md +46 -0
  96. package/skills/remediation-governance/SKILL.md +78 -0
  97. package/skills/resolve-governances/README.md +18 -0
  98. package/skills/resolve-governances/SKILL.md +50 -0
  99. package/skills/resolve-governances/scripts/resolve-governances.mts +515 -0
  100. package/skills/resolve-tracking/SKILL.md +64 -0
  101. package/skills/resolve-tracking/scripts/resolve-tracking.mts +213 -0
  102. package/skills/resume-mission/README.md +12 -0
  103. package/skills/resume-mission/SKILL.md +53 -0
  104. package/skills/scaffold-project-spec/README.md +7 -0
  105. package/skills/scaffold-project-spec/SKILL.md +192 -0
  106. package/skills/sdd/README.md +7 -0
  107. package/skills/sdd/SKILL.md +92 -0
  108. package/skills/solution-producer-governance/README.md +9 -0
  109. package/skills/solution-producer-governance/SKILL.md +44 -0
  110. package/skills/spec-format-governance/README.md +73 -0
  111. package/skills/spec-format-governance/SKILL.md +114 -0
  112. package/skills/spec-gate/README.md +26 -0
  113. package/skills/spec-gate/SKILL.md +201 -0
  114. package/skills/spec-gate/scripts/check-spec-state.mts +601 -0
  115. package/skills/spec-gate/scripts/check-suite.mts +501 -0
  116. package/skills/spec-gate/scripts/classify-edit-class.mts +411 -0
  117. package/skills/spec-producer-governance/README.md +7 -0
  118. package/skills/spec-producer-governance/SKILL.md +86 -0
  119. package/skills/spec-structure-governance/README.md +40 -0
  120. package/skills/spec-structure-governance/SKILL.md +169 -0
  121. package/skills/ssa-lowering/README.md +26 -0
  122. package/skills/ssa-lowering/SKILL.md +181 -0
  123. package/skills/start-mission/README.md +7 -0
  124. package/skills/start-mission/SKILL.md +115 -0
  125. package/skills/suite-format-governance/README.md +75 -0
  126. package/skills/suite-format-governance/SKILL.md +299 -0
  127. package/skills/suite-format-governance/references/rubric.md +313 -0
  128. package/skills/touch-set-correction/README.md +16 -0
  129. package/skills/touch-set-correction/SKILL.md +67 -0
  130. package/skills/touch-set-correction/scripts/touch-set-correction.mts +418 -0
  131. package/skills/verify-scenarios/README.md +17 -0
  132. package/skills/verify-scenarios/SKILL.md +109 -0
  133. package/skills/verify-scenarios/scripts/verify-scenarios.mts +386 -0
@@ -0,0 +1,45 @@
1
+ # oracle-spec-governance
2
+
3
+ This is an internal SDD governance about scope and the kill-or-ship call at the spec gate.
4
+
5
+ Before a capability's spec is approved, someone has to ask the uncomfortable questions: is this one
6
+ thing or two things glued together? Is it worth building at all? Does every scenario in its suite
7
+ actually belong to it? This governance is that question list — the **Oracle** bar. It judges the
8
+ **capability itself**, read from its spec and suite together — not how the document is written,
9
+ which is a different bar (`spec-format-governance`).
10
+
11
+ ## What it requires — the bar
12
+
13
+ | Check | What it demands |
14
+ | --- | --- |
15
+ | **One coherent intent** | The capability delivers a single nameable outcome. Two concerns are two capabilities — split them, each into its own node. Test: can you name the outcome without "and"? |
16
+ | **Bounded, stated scope** | What is out of scope is named. A capability that keeps absorbing adjacent problems is scope creep — cut it back. |
17
+ | **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
+ | **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
+ | **Worth shipping, or kill** | The Why names a real problem and who feels it. If the value does not clear the cost of building, the verdict is kill. |
20
+ | **Kill-or-revert** | A capability that passes every check but proves fatal goes back to Draft — surface the deal-breaker. |
21
+ | **No premature commitment** | A decision that need not be made yet is deferred to the last responsible moment. |
22
+
23
+ ## Usage
24
+
25
+ - **spec-producer:** self-aligns on scope against this bar before writing the spec
26
+ - **spec-judge:** grades kill-or-ship cold at the **spec-gate**
27
+
28
+ The same bar is loaded by both faces, but producer and judge stay separate agents. Oracle has no
29
+ impl-gate face, so this is the only Oracle bar. It is SDD's default for the `oracle` bar — a plugin
30
+ may bind its own per artifact-type, and this one loads only when the registry leaves `oracle`
31
+ unbound.
32
+
33
+ ## Related governances
34
+
35
+ This bar owns whether the capability is the right thing to commit to. Its neighbors own everything
36
+ around that:
37
+
38
+ - **`spec-format-governance`** — how the `spec.md` document itself is structured and written; this
39
+ bar deliberately does not read the prose.
40
+ - **`builder-spec-governance`** — the Builder bar at the same gate: testability and coverage of the
41
+ `.feature`, not scope.
42
+ - **`architect-spec-governance`** — the Architect bar at the same gate: structural fit of the spec
43
+ and solution, not whether it should exist.
44
+
45
+ Internal SDD governance (`user-invocable: false`). Not triggered by users directly.
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: oracle-spec-governance
3
+ description: "Partial Skill: invoke by name only"
4
+ user-invocable: false
5
+ metadata:
6
+ actor: oracle
7
+ gate: spec
8
+ compose: union
9
+ ---
10
+
11
+ # Oracle-Spec Governance — the scope & kill-or-ship bar
12
+
13
+ The **Oracle** bar at the **spec gate**: is this **capability** worth committing, and is its scope the
14
+ node's to hold? Judges the capability (read from its spec + suite), not the document's prose — that is
15
+ `sdd:spec-format-governance`. Loaded by both faces — the spec-producer self-aligns on scope before
16
+ writing, the cold spec-judge judges kill-or-ship. Oracle has no impl face. The SDD default for the
17
+ `oracle` bar; a plugin may bind its own per artifact-type, and this loads when the registry leaves
18
+ `oracle` unbound.
19
+
20
+ ## The bar
21
+
22
+ - **One coherent intent.** The capability delivers a single nameable outcome. **Two concerns are two
23
+ capabilities** — split them, each into its own node. Test: can you name the outcome without "and"?
24
+ - **Scope is bounded and stated.** What is out of scope is named. A capability that keeps absorbing
25
+ adjacent problems is scope creep — cut it back.
26
+ - **The suite's decisions are the node's to hold.** Every scenario tests a **decision the node owns**.
27
+ A property **co-owned** across a seam — activation/routing, a sibling's behavior, harness wiring —
28
+ is out of scope: relocate it to the node that owns it, or kill it.
29
+ - **Strict — a non-decision is killed.** An **invariant** that always holds is not acceptance and does
30
+ not enter the suite. The one exception is a user **`@pinned`** scenario, kept whatever strict prunes.
31
+ - **Worth shipping, or kill.** The Why names a real problem and who feels it. If value does not clear
32
+ the cost of building, the verdict is **kill**.
33
+ - **Kill-or-revert is allowed.** A capability that passes every check but proves fatal goes back to
34
+ Draft — surface the deal-breaker.
35
+ - **No premature commitment.** Defer a decision that need not be made yet to the last responsible
36
+ moment.
37
+
38
+ ## Key points (read-check)
39
+
40
+ 1. **One coherent intent** — two concerns are two capabilities; bounded and stated scope.
41
+ 2. **Every scenario tests a decision the node owns** — a co-owned seam property is out of scope
42
+ (relocate or kill).
43
+ 3. **Strict** — an invariant / non-decision does not enter the suite; only a user `@pinned` scenario
44
+ escapes.
45
+ 4. **Worth shipping or kill** — value must clear the build cost; a fatal proof reverts to Draft.
@@ -0,0 +1,65 @@
1
+ # ownership-governance
2
+
3
+ This is an internal SDD governance about write ownership.
4
+
5
+ It answers one question for every artifact in the SDD workflow: **who may write it — and who never
6
+ may.** Every act in the workflow has a write leash, and this skill is the canonical matrix. One
7
+ writer per field or artifact; no role writes outside the spec it owns or spawns specs on its own.
8
+
9
+ ## Who writes what
10
+
11
+ The full matrix lives in the skill body; condensed, the ownership falls into a few hands:
12
+
13
+ | Artifact | Written by | Notable exclusions |
14
+ | --- | --- | --- |
15
+ | `spec.md` body + the `.feature` | the **spec-producer** | the conductor, judges, other producers |
16
+ | A `@pinned` scenario | the **user** (in-session) | every agent role — it proposes, never executes |
17
+ | `<unit>.solution.md` | the **solution-producer** | the spec-producer, judges |
18
+ | Implementation + its verification | the **impl-producer** | the impl-judge (it *runs*, never authors) |
19
+ | `status` + human ratification of `approval` | the **gate skill** (`spec-gate`), in-session position only | the conductor, any producer |
20
+ | Coordination state — `<!-- open: -->` markers, `produced-by`, run-level leash, self-asserted approvals, plan brief, combat-log and ledger lines | the **conductor** | producers, judges, the gate skill |
21
+ | Ledger `strategy` lines | the doctrine-loop **Scanner** | everyone else |
22
+
23
+ Appended log and ledger lines carry a pseudonymous `handle`; the in-file attribution is advisory —
24
+ the git commit signature is the attestation.
25
+
26
+ ## The three standing rules
27
+
28
+ - **Producer write boundary.** A spec-producer writes the `spec.md` body and the `.feature` only —
29
+ never the control frontmatter or the resolution state. A required input it cannot supply comes
30
+ back as a `CONTENT_GAP`; the conductor turns it into an `<!-- open: -->` marker. Producers never
31
+ write markers directly.
32
+ - **Ratification authority is positional.** A human-attributed gate write belongs to the in-session
33
+ position holding the real user channel. A headless conductor — a spawned subagent with no user
34
+ channel — writes only self-assertions and pauses; it never writes a human ratification, even when
35
+ a coordinator relays "the user approved". A relayed claim is not user confirmation.
36
+ - **Never write a frozen `.feature`.** Once a suite carries `@frozen`, no role may add, remove, or
37
+ rewrite its scenarios. A gap that requires changing specified behavior is a `BLOCKER` returned
38
+ upward, never an in-place edit. The freeze binds the contract only — the combat log and ledger
39
+ shards stay writable. Judges never patch: they report.
40
+
41
+ `@pinned` scenarios sit outside freeze entirely: they are grounded in **ownership**, so the user's
42
+ authority over them holds at `draft` and survives a re-open.
43
+
44
+ ## Usage
45
+
46
+ - **Every producer:** knows the boundary of what it owns and returns `CONTENT_GAP` for what it
47
+ cannot supply.
48
+ - **Every judge:** reports findings, never patches `spec.md` or the suite.
49
+ - **The conductor:** writes the coordination state — markers, `produced-by`, the run-level leash,
50
+ self-asserted gate entries, and its append-only log and ledger lines.
51
+ - **`start-mission` / `spec-gate`:** the gate skill is the sole writer of `status` and human
52
+ ratifications, from the in-session position only.
53
+
54
+ ## Related governances
55
+
56
+ This contract owns *who writes*. Its neighbors own the surrounding definitions:
57
+
58
+ - **`lifecycle-governance`** — the field definitions, and what freezing *means* as a state; this
59
+ bar carries only the write constraint.
60
+ - **`gate-validation-governance`** — the legality of the resulting state after a write.
61
+ - **`combat-log-governance`** — the plan/ledger write split and the record shapes.
62
+ - **`suite-format-governance`** — the `@pinned` marker itself and its seed-growth role; this bar
63
+ carries only its ownership.
64
+
65
+ Internal SDD governance (`user-invocable: false`). Not triggered by users directly.
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: ownership-governance
3
+ description: "Partial Skill: invoke by name only"
4
+ user-invocable: false
5
+ ---
6
+
7
+ # SDD Ownership Governance
8
+
9
+ Who may write what. Every act in the SDD workflow has a write leash; this skill is the canonical
10
+ matrix. The field definitions are in `sdd:lifecycle-governance`; the legality of the resulting state
11
+ is in `sdd:gate-validation-governance`; the plan/ledger write split is in `sdd:combat-log-governance`.
12
+
13
+ ## Write-ownership matrix
14
+
15
+ | Field / artifact | Written by | Never written by |
16
+ |---|---|---|
17
+ | `status` | the gate skill (`spec-gate`) — on a human verdict, or to match a conductor self-assertion within leash | the conductor, any producer |
18
+ | `project-path` | the **conductor** (at scaffold; `scaffold-project-spec`) | producers, the gate skill |
19
+ | run-level leash + approach — the `kind: leash` ledger line (session-local; to the conductor's own ledger shard, **not** spec.md frontmatter — the conductor's autonomy bar, `start-mission`) | the **conductor** (initial evaluation) | producers, the gate skill |
20
+ | `approval` **self-assertion** (`verdict: approve`/`pause` + `by: agent`/none + `why`) | the **conductor** (synthesis only) | producers, the gate skill |
21
+ | `approval` **human ratification** (`verdict: approve`/`reject` + `by: <name>`) | the gate skill (`spec-gate`), **in-session position only** | the conductor, any producer, any spawned delegate |
22
+ | `<!-- open: -->` markers | the **conductor** | producers (they *emit gaps*, not markers) |
23
+ | `produced-by` map | the **conductor** (records the resolved producer per role at production) | producers, judges, the gate skill |
24
+ | contested-type → chosen-plugin state (`.agents/sdd/`) | the **conductor** (or `start-mission` for a contested artifact-type); **distinct from `produced-by`** | producers, judges, the gate skill |
25
+ | combat-log `report` / `correction` / `halt` lines | the **conductor** (append-only, to the plan's `*.log.jsonl`) | producers, judges, the gate skill |
26
+ | ledger `gate` line — self-asserted (`by: agent`) | the **conductor** (append-only, to its own ledger shard) | producers, judges |
27
+ | ledger `gate` line — human-ratified (`by: <name>`) | the gate skill (`spec-gate`), **in-session position only** | the conductor, producers, judges |
28
+ | ledger `followup` line — the durable follow-up record (`class: blocking`/`backlog`) | the **conductor** (append-only, to its own ledger shard, at handoff, **unconditionally** — no permission, no forge, no human) | producers, judges, the gate skill |
29
+ | ledger `strategy` lines | the doctrine-loop Scanner (append-only) | the conductor, producers, judges |
30
+ | `spec.md` body + the `.feature` | the **spec-producer** | the conductor, judges, solution/impl producers |
31
+ | a **`@pinned` scenario** (user-owned) | the **user** (in-session) | every agent role — may **propose**, never **executes** a change/removal without in-session user authorization |
32
+ | `<unit>.solution.md` | the **solution-producer** | the spec-producer, judges |
33
+ | plan brief + `todos` | the **conductor** | producers, judges |
34
+ | implementation + its verification | the **impl-producer** | the impl-judge (it *runs*, never authors) |
35
+
36
+ Each appended `*.log.jsonl` / ledger-shard line carries its writer's pseudonymous `handle`
37
+ (`SDD_HANDLE` if set, else omitted — attribution falls back to the git commit author; **never**
38
+ `user.email`, never a `git config` read); combat-log lines additionally carry a write-time UTC `ts`,
39
+ while ledger lines carry none (`sdd:combat-log-governance`). The in-file `handle` / `by` is
40
+ **advisory** — the git commit signature is the attestation.
41
+
42
+ ## Producer write boundary
43
+
44
+ A **spec-producer** writes the `spec.md` body and the `.feature` only. It must **not** write the
45
+ control frontmatter (`status`, `project-path`, `approval`, `produced-by`) or the `.agents/sdd/`
46
+ resolution state. A required input it cannot supply or infer is returned as a `CONTENT_GAP` — the
47
+ conductor turns it into an `<!-- open: -->` marker. Producers do not write markers directly.
48
+
49
+ The **conductor** writes `<!-- open: -->` markers, the `produced-by` map, the run-level leash (the
50
+ `kind: leash` line to its own ledger shard, session-local — not a spec.md frontmatter field), and — when it
51
+ self-asserts a gate within the effective leash — the provisional `approval.<gate>` entry
52
+ (`verdict: approve` + `by: agent` with the `why` derivation; a halt is `verdict: pause` with its
53
+ `why` and no `by`). There is no `leash` field in the `approval` entry — the leash is the run-level
54
+ record on the ledger. The **gate skill** writes `status` (on a human verdict or to match the
55
+ conductor's in-leash self-assertion) and the human ratification of `approval` (rewriting `by: agent`
56
+ → `by: <name>`).
57
+
58
+ **Ratification authority is positional.** A human-attributed gate write — `status → approved |
59
+ implemented`, a verdict carrying `by: <name>`, the human-ratified ledger `gate` line, and the freeze
60
+ — belongs to the **in-session position** that holds the real user channel. By default this is
61
+ trivially satisfied: the **conductor is the main session**, so the position that grills *is* the
62
+ position that ratifies. The rule bites only in the **headless / fan-out fallback**, where the
63
+ automaton runs as a **spawned subagent** with no user channel: it then writes only `by: agent`
64
+ self-assertions and `pause` halts, and on a human gate emits a verdict packet and stops — it never
65
+ writes a human ratification, **even when a coordinator relays "the user approved"** (a relayed claim
66
+ is not user confirmation). This is positional, not definitional: the same conductor definition run
67
+ in-session may perform the write. A self-assertion is **provisional**: the act is delegable, the
68
+ accountability is not — the human ratifies the trail. No role writes outside the spec it owns or
69
+ spawns specs on its own.
70
+
71
+ ## Freeze (write constraint)
72
+
73
+ **Never write a frozen `.feature`.** Once a `.feature` carries its `@frozen` tag, no role — producer,
74
+ judge, solution-producer, or conductor — may add, remove, or rewrite its scenarios. A discovered gap
75
+ that requires changing specified behavior is a `BLOCKER` returned upward (the file must unfreeze and
76
+ its layer revert to `draft` — the gate/skill decides), never an in-place edit. The matching lifecycle
77
+ rule (what freezing *means* as a state) is in `sdd:lifecycle-governance`.
78
+
79
+ The freeze binds the **contract only** (`spec.md` + the suite). The combat log (the plan's
80
+ `*.log.jsonl`) and the durable `ledger/` shards are **exempt**: they are operational provenance, never
81
+ frozen, and the conductor and Scanner keep appending to their own shards within their boundaries above
82
+ even while a file sits `@frozen`.
83
+
84
+ A judge — spec-judge or impl-judge — must not modify `spec.md` or the suite: it reports, it does
85
+ not patch.
86
+
87
+ ## User-owned scenarios (`@pinned`)
88
+
89
+ A `@pinned` scenario is **user-owned** — the one scenario the spec-producer does **not**
90
+ own. Any agent role may **propose** changing or removing it, but **never executes** the change
91
+ without **in-session user authorization** — the authority of a human ratification (positional, not
92
+ relayable, not self-assertable within leash). Only the user applies `@pinned`. This is grounded in
93
+ **ownership, not freeze**: it holds at `draft` and survives a re-open, since ownership does not lapse
94
+ when a file unfreezes. The marker and its seed-growth role are `sdd:suite-format-governance`.
95
+
96
+ ## Key points (read-check)
97
+
98
+ 1. **One writer per field/artifact** (the matrix) — no role writes outside the spec it owns or spawns.
99
+ 2. **Never write a frozen `.feature`** — a behavior-changing gap is a `BLOCKER` returned upward, never
100
+ an in-place edit.
101
+ 3. **Human ratification is positional** — the in-session channel only; never relayed, never
102
+ self-asserted within leash.
103
+ 4. **A `@pinned` scenario is user-owned** — the agent proposes, never executes a change or removal
104
+ without in-session user authorization.
@@ -0,0 +1,18 @@
1
+ # pause-mission
2
+
3
+ Project-private workflow skill for **checkpointing an in-progress SDD mission into its plan
4
+ brief** (`.agents/plans/<cr-ref>.plan.md`). Invoke it when stopping mid-mission ("pause",
5
+ "checkpoint", "save state to the plan", "stop here") to update the todo statuses and rewrite
6
+ the `## NEXT — resume here` anchor, then commit — so the working tree is clean and the next
7
+ session resumes without rediscovery.
8
+
9
+ Pass **`--approve`** to also clear the mission for **headless dispatch** — it sets the brief's
10
+ top-level `status: approved` (a human review act; a headless automaton never self-approves), the
11
+ go-signal the gateway's dispatch loop selects on.
12
+
13
+ The checkpoint is **self-sufficient**: any later session that opens the plan can continue from
14
+ it — [`resume-mission`](../resume-mission/README.md) is one convenient reader, not a required
15
+ pair. Modeled after the handoff-skill pattern (reference artifacts instead of restating, keep it
16
+ commit-message-grade, lead the `## NEXT` anchor with the next action *and the skill to invoke for
17
+ it*) but targeted at the durable tracked plan rather than a temp file. `internal: true` —
18
+ contributor tooling.
@@ -0,0 +1,112 @@
1
+ ---
2
+ name: pause-mission
3
+ description: "Checkpoint an in-progress SDD mission INTO its plan brief so any later session can pick it up. Use this skill when asked to 'pause', 'wrap up for now', or 'stop here' mid-mission — update the plan's todo statuses and rewrite its ## NEXT anchor so a fresh session continues exactly where you left off. Pass --approve to also clear the mission for headless dispatch (sets the brief's status: approved)."
4
+ argument-hint: "[what the next session should focus on] [--approve]"
5
+ ---
6
+
7
+ # Pause an SDD mission into its plan
8
+
9
+ An SDD mission's durable handoff is its **plan brief** at `.agents/plans/<cr-ref>.plan.md`. A
10
+ pause writes this session's state back into that plan so **any** next session can pick the
11
+ mission up by reading it — no special tool required (`resume-mission` is one convenient reader;
12
+ the plan stands on its own). Capture *enough to continue, nothing to relitigate.*
13
+
14
+ ## Procedure
15
+
16
+ 1. **Honor the focus.** If the user named what the pause should emphasize, scope the checkpoint
17
+ to it; otherwise checkpoint the whole live frontier.
18
+
19
+ 2. **Locate the plan — scaffold it if missing.** Find `.agents/plans/<cr-ref>.plan.md`. If none
20
+ exists, create a minimal one (frontmatter `todos` + a `## NEXT` anchor) so the checkpoint has
21
+ a durable home; a pause always leaves a plan behind.
22
+
23
+ 3. **Update the todo statuses.** In the frontmatter `todos`, set each touched todo to its true
24
+ `status` (`pending | in_progress | completed`). Mark the one you were on `in_progress`; never
25
+ mark a todo `completed` unless it truly is — partial work stays `in_progress` with a one-line
26
+ note of what remains. Add a todo for any new work or decision that surfaced this session.
27
+
28
+ 4. **Rewrite the `## NEXT — resume here` anchor** (create it if absent) so a cold reader can
29
+ start in under a minute. Order it for pickup, **action first**:
30
+ - **The next action — first, concrete, runnable.** One line the resumer can act on
31
+ immediately: the file or unit to touch *and the skill or command to invoke for it* — e.g.
32
+ "build `<unit>`'s spec + suite via `start-mission`, then run the project's spec check," never
33
+ a vague "continue authoring."
34
+ - **Blocking decisions** — open scope calls and unresolved `<!-- open: -->` markers, each with
35
+ its options, so the next session *resolves* rather than rediscovers them.
36
+ - **Findings the commits won't show** — only what isn't obvious from the diff and changes the
37
+ next move. Skip the play-by-play.
38
+ - **A pointer to the working method / resolved decisions** already in the plan body ("do not
39
+ relearn — see `## Resolved decisions`").
40
+
41
+ Lead with the action; put history and findings *below* it. A resumer needs *what to do* first
42
+ and *what happened* second.
43
+
44
+ 5. **Reference, don't restate.** Point to commits (SHAs), files (**repo-relative paths**), design
45
+ rules, and issues by reference — never paste their contents. The plan is an index to the work,
46
+ not a copy of it. A file the brief depends on must live **in the repo**: if the source is a
47
+ machine-local doc (a plan-mode plan under `~/.claude/plans/…`), bring it in as a sibling
48
+ `<cr-ref>.design.md` and reference that, never the external absolute path.
49
+
50
+ 6. **Keep it commit-message-grade — the safe-to-publish floor.** The plan is tracked and committed,
51
+ so it carries the same floor as the combat log (`combat-log-governance`): **never committed** —
52
+ secrets, keys, prompts, PII, **absolute paths, OS usernames/hostnames, `$HOME`/`$USER`**, or any
53
+ machine-local reference outside the repo. Describe the decision or its class, not literal payloads
54
+ or machine-local locations.
55
+
56
+ 7. **Commit the checkpoint.** Before committing, run the plan-brief leak guard over the brief —
57
+ `node "<sdd-skills>/check-plan-safety/scripts/check-plan-safety.mts" --path <brief> --check` (the
58
+ `check-plan-safety` engine). A hit **blocks the commit**: scrub the machine-local reference (bring
59
+ the content in-repo, reference it repo-relative) and re-run. Then commit the plan update (`docs:`)
60
+ so the pause is durable in git and the working tree is clean. Leave no uncommitted work behind.
61
+
62
+ ## Reconcile-forward checkpoint
63
+
64
+ When the mission's live state is "this CR's work is already merged, not something this session
65
+ ran live" (e.g. resuming a plan and finding its commits already landed on `main`), treat it as a
66
+ checkpoint whose input is git/ledger evidence instead of a live conductor session — same
67
+ procedure above, plus one gate before declaring the plan retirement-ready:
68
+
69
+ - **Only for a CR-bearing mission.** A mission that opened a real CR and reached
70
+ `status: approved` or `implemented` gets this check. A non-CR mission (the `start-mission`
71
+ escape hatch — no suite-relevant behavior, no CR opened, no gate invoked) needs none; mark it
72
+ complete on its own merits.
73
+ - **Run the gate floor.** Run `checkGateFloor` (`plugins/sdd/skills/spec-gate/scripts/
74
+ check-spec-state.mts`, wired into `pnpm verify:specs`) before marking the plan
75
+ retirement-ready. A clean floor → mark it. A violation (the status is approved/implemented but
76
+ the ledger has no matching gate approve line) → do **not** mark the plan retirement-ready on
77
+ git evidence alone; record the violation explicitly in `## NEXT` so a human resolves it (either
78
+ the ledger line was genuinely never written, or it needs relocating/re-checking).
79
+
80
+ **Write scope.** A checkpoint writes **only the plan brief** — the `todos`, the `## NEXT` anchor,
81
+ and (with `--approve`) the top-level `status`. It never touches `spec.md`'s `status` or `approval`:
82
+ the mission's contract lifecycle is the gates', not the checkpoint's.
83
+
84
+ ## Clear for headless dispatch — `--approve`
85
+
86
+ A plain pause never touches the brief's top-level `status`. When invoked with **`--approve`**, the
87
+ checkpoint additionally sets the brief's **`status: approved`** — the human review act that clears
88
+ the mission for the gateway's headless dispatch queue (the go-signal `dispatch` selects on; the
89
+ enum + the three-way `status` distinction live in the SDD `provenance-model`). Rules:
90
+
91
+ - **Human act only.** Setting `approved` is a review decision — a person has read the brief (todos,
92
+ `## NEXT`, the run-level leash) and cleared it. A **headless automaton never self-approves**: with
93
+ no user channel it may checkpoint progress but must **refuse `--approve`** and leave `status`
94
+ unchanged (the same positional-authority rule that reserves a human-ratified gate verdict).
95
+ - **Idempotent.** Approving an already-`approved` brief leaves it `approved`.
96
+ - **Flag-only.** It writes the one frontmatter field; it does not dispatch the mission (that is the
97
+ gateway) and does not touch the run-level leash — `approved` says *run it*, the leash says *how far*.
98
+
99
+ ## What a good pause is not
100
+
101
+ - **Not a transcript.** Capture decisions and the next action, not a play-by-play.
102
+ - **Not a duplicate.** If it already lives in a commit, an ADR, the spec, or an issue, link it.
103
+ - **Not buried.** The next action leads the anchor; if a resumer has to hunt for where to start,
104
+ the pause failed.
105
+ - **Not self-referential.** The plan never tells its reader to "invoke `resume-mission`" or
106
+ explains how to resume — a session reading the plan is already past that, and the
107
+ `## NEXT — resume here` heading orients a human on its own. Open `## NEXT` with the *work*.
108
+ - **Not final-sounding.** A pause is a *resumable* checkpoint — leave the live frontier and the
109
+ open questions explicit, not smoothed into a summary that hides where to begin.
110
+
111
+ The plan is self-sufficient: any session that opens it can continue. `resume-mission` reads this
112
+ back conveniently, but is not required.
@@ -0,0 +1,12 @@
1
+ # place-node
2
+
3
+ Internal SDD skill — the concrete engine for the **place-node** step. Given a new node's `concept`
4
+ (and optional name), suggests a **provisional** capability home (derived from where that concept
5
+ already lives) and catches possible duplicates, so explore places a node in one lookup.
6
+
7
+ ```bash
8
+ node scripts/place-node.mts --spec-dir <spec> --concept resolution --name leash
9
+ ```
10
+
11
+ Read-only and advisory; placement is finalized at handoff. See [`SKILL.md`](./SKILL.md) for the full
12
+ contract. Not user-invocable.
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: place-node
3
+ description: "Partial Skill: invoke by name only — project-spec/place-node's engine that suggests a capability home and surfaces duplicates for a new node — used by explore, not triggered by users directly."
4
+ user-invocable: false
5
+ metadata:
6
+ internal: true
7
+ ---
8
+
9
+ # Place Node
10
+
11
+ The concrete engine for the **place-node** step. Given a new
12
+ node's `concept` (and optional name), it suggests a **provisional** capability home and catches possible
13
+ duplicates, so explore places a node without holding the whole tree in its head (it scans the project-spec's
14
+ `concept:` frontmatter and ranks the capability folders those facets already sit in). Self-contained `.mts`
15
+ (the repo's node-≥23.6 / no-deps convention).
16
+
17
+ ## Run it
18
+
19
+ ```bash
20
+ node "<skill>/scripts/place-node.mts" --spec-dir <spec> --concept <c> [--name <n>]
21
+ ```
22
+
23
+ - `--concept` — suggests the capability folders where that concept's facets already sit, ranked by count
24
+ (the provisional home). A concept no node yet carries → an empty suggestion: pick any plausible
25
+ capability, finalized at handoff.
26
+ - `--name` — surfaces existing nodes whose path overlaps the name ("belongs near X" duplicate-catch).
27
+
28
+ The home is **derived** from the project-spec's own `concept:` tags — where that concept's facets
29
+ already sit — never a stored routing list (the `corpus/discovery` no-drift rule). For genuinely
30
+ contested overlaps, the human tie-break rules live in the placement-map routing table (root
31
+ `spec.md`), which this tool points to rather than re-deriving.
32
+
33
+ **Strategy-neutral by construction — and not this tool's call.** The derivation follows the tree as
34
+ it actually is, so it returns a correctly-shaped home under whatever layout the project declared: a
35
+ `mirror-source` project's concepts sit in mirror-shaped folders, and "where the siblings already
36
+ are" answers that as well as it answers capability-first. This tool therefore neither reads nor
37
+ recommends a strategy. Choosing one belongs to `scaffold-project-spec`, recording it to the root
38
+ `spec.md` placement map, and judging fit against it to the formation Warden
39
+ (`sdd:spec-structure-governance`).
40
+
41
+ ## Boundaries
42
+
43
+ Read-only and advisory — it **writes nothing** (no scaffold, no relocation, no frontmatter); placement is
44
+ provisional and finalized at handoff (the `start-mission` handoff step), so a
45
+ suggestion never has to be correct — only useful. Frontmatter only — no node body is read. When `node` is
46
+ absent, an agent does the same by hand: read the `concept:` tags, see where that concept already lives,
47
+ and place near them.
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+ // place-node — project-spec/place-node's concrete engine. Given a new node's concept (and optional name),
3
+ // suggests a provisional capability home and surfaces possible duplicates, so explore places a node in
4
+ // one lookup instead of holding the tree in its head.
5
+ //
6
+ // Derivation, not a registry: the home for a concept is where that concept's facets already sit — read
7
+ // live from the project-spec's `concept:` tags, never a stored routing list (the corpus/discovery no-drift
8
+ // rule). Read-only and advisory: it writes nothing, and placement is finalized at handoff.
9
+ //
10
+ // No dependencies (the repo's node-≥23.6 / no-deps convention). Pure functions are exported for
11
+ // node:test; running the file directly drives the CLI.
12
+
13
+ import { readdirSync, readFileSync } from 'node:fs'
14
+ import { join } from 'node:path'
15
+
16
+ const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', '.turbo', '.next', 'coverage'])
17
+
18
+ export interface NodeRecord {
19
+ /** Path relative to the spec directory (POSIX). */
20
+ relPath: string
21
+ /** The top-level folder — the capability. */
22
+ capability: string
23
+ /** Display form — a README.md node shows its folder, a design doc shows the file. */
24
+ display: string
25
+ concepts: string[]
26
+ }
27
+
28
+ export interface HomeSuggestion {
29
+ capability: string
30
+ count: number
31
+ }
32
+
33
+ // ── Frontmatter parse (concept only — the placement signal) ──
34
+ export function parseConcepts(text: string): string[] {
35
+ const m = /^---\r?\n([\s\S]*?)\r?\n---\s*(?:\r?\n|$)/.exec(text)
36
+ if (!m) return []
37
+ const lines = m[1].split('\n').map((l) => l.replace(/\r$/, ''))
38
+ for (let i = 0; i < lines.length; i++) {
39
+ const line = lines[i]
40
+ if (line.length - line.trimStart().length !== 0) continue
41
+ const [key, ...rest] = line.trim().split(':')
42
+ if (key !== 'concept') continue
43
+ const value = rest.join(':').trim()
44
+ if (value.startsWith('[') && value.endsWith(']')) {
45
+ return value
46
+ .slice(1, -1)
47
+ .split(',')
48
+ .map((s) => unquote(s.trim()))
49
+ .filter((s) => s.length > 0)
50
+ }
51
+ if (value !== '') return [unquote(value)]
52
+ // block list
53
+ const out: string[] = []
54
+ for (let j = i + 1; j < lines.length; j++) {
55
+ const item = lines[j]
56
+ if (item.trim() === '') continue
57
+ if (item.length - item.trimStart().length === 0) break
58
+ const dash = /^\s*-\s+(.*)$/.exec(item)
59
+ if (dash) out.push(unquote(dash[1].trim()))
60
+ }
61
+ return out
62
+ }
63
+ return []
64
+ }
65
+
66
+ function unquote(v: string): string {
67
+ return v.replace(/^["']|["']$/g, '')
68
+ }
69
+
70
+ function displayPath(relPath: string): string {
71
+ const p = relPath.replace(/\\/g, '/')
72
+ return p.endsWith('/README.md') ? p.slice(0, -'README.md'.length) : p
73
+ }
74
+
75
+ // ── Scan the project-spec — every concept-tagged node ──
76
+ export function scanProjectSpec(specDir: string): NodeRecord[] {
77
+ const records: NodeRecord[] = []
78
+ walk(specDir, specDir, records)
79
+ return records
80
+ }
81
+
82
+ function walk(dir: string, specDir: string, out: NodeRecord[]): void {
83
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
84
+ if (entry.name.startsWith('.') || SKIP_DIRS.has(entry.name)) continue
85
+ const full = join(dir, entry.name)
86
+ if (entry.isDirectory()) {
87
+ walk(full, specDir, out)
88
+ } else if (entry.name.endsWith('.md')) {
89
+ const concepts = parseConcepts(readFileSync(full, 'utf8'))
90
+ if (concepts.length === 0) continue
91
+ const relPath = full.slice(specDir.length + 1).replace(/\\/g, '/')
92
+ out.push({ relPath, capability: relPath.split('/')[0], display: displayPath(relPath), concepts })
93
+ }
94
+ }
95
+ }
96
+
97
+ // ── Suggest a home — where the concept's facets already sit, ranked by count ──
98
+ export function suggestHomes(records: NodeRecord[], concept: string): HomeSuggestion[] {
99
+ const counts = new Map<string, number>()
100
+ for (const rec of records) {
101
+ if (!rec.concepts.includes(concept)) continue
102
+ counts.set(rec.capability, (counts.get(rec.capability) ?? 0) + 1)
103
+ }
104
+ return [...counts.entries()]
105
+ .map(([capability, count]) => ({ capability, count }))
106
+ .sort((a, b) => b.count - a.count || a.capability.localeCompare(b.capability))
107
+ }
108
+
109
+ // ── Duplicate-catch — existing nodes whose path/name overlaps the candidate name ──
110
+ export function findNear(records: NodeRecord[], name: string): NodeRecord[] {
111
+ const needle = name.trim().toLowerCase()
112
+ if (needle === '') return []
113
+ return records
114
+ .filter((rec) => rec.relPath.toLowerCase().includes(needle))
115
+ .sort((a, b) => a.display.localeCompare(b.display))
116
+ }
117
+
118
+ // ── Render ──
119
+ function render(homes: HomeSuggestion[], near: NodeRecord[], concept: string, name: string): string {
120
+ const lines: string[] = [`place-node: concept=${concept || '(none)'} name=${name || '(none)'}`]
121
+ if (homes.length > 0) {
122
+ lines.push(`homes[${homes.length}]{capability,facets}:`)
123
+ for (const h of homes) lines.push(` ${h.capability},${h.count}`)
124
+ } else {
125
+ lines.push('homes[0]: (new concept — pick any plausible capability; finalized at handoff)')
126
+ }
127
+ if (near.length > 0) {
128
+ lines.push(`near[${near.length}]:`)
129
+ for (const n of near) lines.push(` ${n.display}`)
130
+ } else {
131
+ lines.push('near[0]: (no name overlap)')
132
+ }
133
+ lines.push('note: placement is provisional — finalized at handoff')
134
+ return lines.join('\n')
135
+ }
136
+
137
+ // ── CLI ──
138
+ export function main(argv: string[]): number {
139
+ let specDir = '.'
140
+ let concept = ''
141
+ let name = ''
142
+ for (let i = 0; i < argv.length; i++) {
143
+ const a = argv[i]
144
+ if (a === '--spec-dir') specDir = argv[++i] ?? '.'
145
+ else if (a === '--concept') concept = argv[++i] ?? ''
146
+ else if (a === '--name') name = argv[++i] ?? ''
147
+ }
148
+ const records = scanProjectSpec(specDir)
149
+ const homes = concept ? suggestHomes(records, concept) : []
150
+ const near = name ? findNear(records, name) : []
151
+ process.stdout.write(`${render(homes, near, concept, name)}\n`)
152
+ return 0
153
+ }
154
+
155
+ if (import.meta.url === `file://${process.argv[1]}`) {
156
+ process.exit(main(process.argv.slice(2)))
157
+ }
@@ -0,0 +1,32 @@
1
+ # plan-retirement
2
+
3
+ Internal, non-user-invocable SDD skill carrying the Doctrine loop's **last retro step** — the
4
+ gated, idempotent **tracked deletion** of a retired mission plan. It holds a self-contained
5
+ `scripts/retire-plans.mts` (node ≥23.6, no deps; an agent fallback when `node` is absent).
6
+
7
+ **Distill and delete are decoupled.** The Scanner distills the combat log into ledger `strategy`
8
+ early (at `→ implemented`); this sweep deletes the plan **later**, gated on source = `done`/merged
9
+ **and** distilled. The two signals **split by verifiability**: **source** stays the caller's
10
+ judgment (`sdd:doctrine-loop` Scanner passes the source-cleared set via `--retire`; it needs
11
+ network/`gh`), while **distilled** is **verified mechanically by the sweep** against the project
12
+ ledger (`--ledger <dir>`) — a `strategy` entry with `distills == <cr-ref>` must exist (keyed on the
13
+ `distills` field, never an `evidence` mention; unratified still counts). The distilled gate guards
14
+ an **existing** combat log: a cr-ref whose `<cr-ref>.log.jsonl` was **never written** (a non-gated
15
+ mission — hand-run, chore-tracked, investigation) has nothing to distill, so it retires on clearance
16
+ + presence alone, no distilling entry required. The sweep is the mechanical, **fail-closed**
17
+ filesystem act — it deletes a cr-ref's whole **transient artifact set** (`<cr-ref>.plan.md` +
18
+ `<cr-ref>.log.jsonl` plus the optional transient CR-level planning briefs `<cr-ref>.design.md`,
19
+ `<cr-ref>.operations.md`, `<cr-ref>.evidence.md`) only for a cr-ref that is cleared, present
20
+ (`<cr-ref>.plan.md` on disk), **and** (distilled **or** has no log to distill); a cleared, present
21
+ cr-ref whose log **exists** but is undistilled fails closed, taking its briefs with it. Anything not
22
+ cleared, not present, missing, or already gone is a no-op (idempotent, safe to re-run). Omitting
23
+ `--ledger` fail-closes to deleting nothing (the no-log branch only applies once a ledger is present
24
+ to consult).
25
+
26
+ The briefs **ride along, never gate**: they do not widen the distilled gate (which keys on the
27
+ combat log's presence only — a brief owes no distillation, so a cr-ref with briefs but no
28
+ `log.jsonl` still retires clearance-only), and they do not anchor presence (`<cr-ref>.plan.md`
29
+ alone does — a brief without a `plan.md` is untouched). Each brief is deleted only if present; an
30
+ absent one is a no-op, same as the missing log half.
31
+
32
+ Tests (`scripts/retire-plans.test.mts`) run under `pnpm verify:specs`.