@pilotspace/add 1.16.1 → 2.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 (113) hide show
  1. package/CHANGELOG.md +227 -0
  2. package/GETTING-STARTED.md +20 -64
  3. package/README.md +128 -56
  4. package/agents/add.md +68 -0
  5. package/bin/cli.js +229 -29
  6. package/package.json +2 -3
  7. package/personas-teacher/VENDOR.md +6 -0
  8. package/skill/add/SKILL.md +100 -134
  9. package/skill/add/adopt.md +28 -0
  10. package/skill/add/beyond.md +36 -0
  11. package/skill/add/deltas.md +25 -2
  12. package/skill/add/design.md +56 -74
  13. package/skill/add/{report-template.md → gate-udd.md} +28 -37
  14. package/skill/add/intake.md +65 -29
  15. package/skill/add/loop.md +35 -23
  16. package/skill/add/phases/build.md +78 -0
  17. package/skill/add/phases/direction.md +280 -0
  18. package/skill/add/phases/verify.md +160 -0
  19. package/skill/add/run.md +13 -30
  20. package/skill/add/terms.md +18 -0
  21. package/tooling/add.py +2520 -2933
  22. package/tooling/add_engine/autonomy.py +2 -37
  23. package/tooling/add_engine/components.py +4 -87
  24. package/tooling/add_engine/constants.py +153 -87
  25. package/tooling/add_engine/guidelines.py +9 -11
  26. package/tooling/add_engine/io_state.py +82 -2
  27. package/tooling/add_engine/predicates.py +90 -2
  28. package/tooling/add_engine/search.py +6 -6
  29. package/tooling/add_engine/taskdoc.py +15 -10
  30. package/tooling/templates/CONVENTIONS.md.tmpl +1 -1
  31. package/tooling/templates/GLOSSARY.md.tmpl +10 -4
  32. package/tooling/templates/MILESTONE.md.tmpl +20 -16
  33. package/tooling/templates/PLAN.md.tmpl +128 -0
  34. package/tooling/templates/PROJECT.md.tmpl +6 -1
  35. package/tooling/templates/PROMPT.persona.md.tmpl +17 -21
  36. package/tooling/templates/personas/_template.md.tmpl +35 -29
  37. package/tooling/templates/personas/build-engineer.md.tmpl +45 -0
  38. package/tooling/templates/personas/data-steward.md.tmpl +45 -0
  39. package/tooling/templates/personas/evidence-verifier.md.tmpl +45 -0
  40. package/tooling/templates/personas/platform-engineer.md.tmpl +45 -0
  41. package/tooling/templates/personas/product-lead.md.tmpl +51 -0
  42. package/tooling/templates/personas/quality-auditor.md.tmpl +47 -0
  43. package/tooling/templates/personas/release-manager.md.tmpl +52 -0
  44. package/tooling/templates/personas/security-gatekeeper.md.tmpl +45 -0
  45. package/tooling/templates/personas/software-architect.md.tmpl +45 -0
  46. package/tooling/templates/personas/stream-orchestrator.md.tmpl +44 -0
  47. package/tooling/templates/personas/technical-writer.md.tmpl +49 -0
  48. package/tooling/templates/personas/ux-experience-lead.md.tmpl +48 -0
  49. package/tooling/templates/specs/SPEC.md.tmpl +18 -0
  50. package/tooling/templates/udd-wireframe.md +1 -1
  51. package/agents/add-advisor.md +0 -31
  52. package/agents/add-build.md +0 -29
  53. package/agents/add-design.md +0 -32
  54. package/agents/add-persona.md +0 -31
  55. package/agents/add-verify.md +0 -34
  56. package/docs/00-introduction.md +0 -46
  57. package/docs/01-principles.md +0 -71
  58. package/docs/02-the-flow.md +0 -113
  59. package/docs/03-step-1-specify.md +0 -123
  60. package/docs/04-step-2-scenarios.md +0 -90
  61. package/docs/05-step-3-contract.md +0 -80
  62. package/docs/06-step-4-tests.md +0 -85
  63. package/docs/07-step-5-build.md +0 -82
  64. package/docs/08-step-6-verify.md +0 -105
  65. package/docs/09-the-loop.md +0 -75
  66. package/docs/10-setup-and-stages.md +0 -118
  67. package/docs/11-governance.md +0 -91
  68. package/docs/12-roles.md +0 -99
  69. package/docs/13-adoption.md +0 -67
  70. package/docs/14-foundation.md +0 -142
  71. package/docs/15-foundations-and-lineage.md +0 -106
  72. package/docs/16-releasing.md +0 -182
  73. package/docs/17-components.md +0 -143
  74. package/docs/18-personas.md +0 -80
  75. package/docs/README.md +0 -77
  76. package/docs/add-competencies.png +0 -0
  77. package/docs/add-flow.png +0 -0
  78. package/docs/add-foundation.png +0 -0
  79. package/docs/add-hierarchy.png +0 -0
  80. package/docs/add-milestone-task-lifecycle.png +0 -0
  81. package/docs/add-task-growth-wheel.png +0 -0
  82. package/docs/appendix-a-templates.md +0 -88
  83. package/docs/appendix-b-prompts.md +0 -154
  84. package/docs/appendix-c-glossary.md +0 -176
  85. package/docs/appendix-d-worked-example.md +0 -231
  86. package/docs/appendix-e-checklists.md +0 -92
  87. package/docs/appendix-f-requirements-matrix.md +0 -171
  88. package/docs/appendix-g-references.md +0 -106
  89. package/skill/add/advisor.md +0 -80
  90. package/skill/add/compact-foundation.md +0 -40
  91. package/skill/add/components.md +0 -52
  92. package/skill/add/confidence.md +0 -32
  93. package/skill/add/fold.md +0 -63
  94. package/skill/add/graduate.md +0 -39
  95. package/skill/add/phases/0-ground.md +0 -64
  96. package/skill/add/phases/0-setup.md +0 -103
  97. package/skill/add/phases/1-specify.md +0 -61
  98. package/skill/add/phases/2-scenarios.md +0 -48
  99. package/skill/add/phases/3-contract.md +0 -60
  100. package/skill/add/phases/4-tests.md +0 -59
  101. package/skill/add/phases/5-build.md +0 -62
  102. package/skill/add/phases/6-verify.md +0 -69
  103. package/skill/add/phases/7-observe.md +0 -47
  104. package/skill/add/phases/fast-lane.md +0 -31
  105. package/skill/add/release.md +0 -61
  106. package/skill/add/scope.md +0 -72
  107. package/skill/add/sensitivity.md +0 -51
  108. package/skill/add/setup-review.md +0 -48
  109. package/skill/add/soul.md +0 -58
  110. package/skill/add/streams.md +0 -268
  111. package/tooling/add_engine/release.py +0 -86
  112. package/tooling/templates/TASK.fast.md.tmpl +0 -77
  113. package/tooling/templates/TASK.md.tmpl +0 -216
@@ -1,268 +0,0 @@
1
- # Parallel streams — pipelining independent tasks
2
-
3
- Load this when a milestone has more than one task and you want to run them concurrently.
4
- **Default:** when a project confirms `parallel + auto` as its run mode at setup
5
- (`phases/0-setup.md` "Run mode"), parallel streaming is the project default — an **opt-out**, not
6
- the opt-in it once was; downgrade in one step (`add.py autonomy set conservative --project`, or
7
- just run tasks one at a time). A project that kept the conservative run mode still treats this
8
- rubric as the opt-in escape hatch.
9
-
10
- It changes **no `add.py` code and no phase semantics**. It is a way *you, the orchestrator*,
11
- drive several tasks at once by reading the dependency DAG `add.py status` already prints and
12
- spawning one worker per ready task.
13
-
14
- ## The honest frame — this is pipelining, not N× speed
15
-
16
- With **one human reviewer** you cannot beat `review_time × N_tasks` (decision points are serial).
17
- The win: the reviewer is **never blocked waiting on a build** — builds for B·C·D run behind *their*
18
- frozen contracts while the human reviews A. Build latency hides under human latency.
19
-
20
- ## The two queues
21
-
22
- Both from one `add.py status` — no new state:
23
-
24
- - **READY-QUEUE** — tasks where `phase ≠ done` **and** every `deps=` task shows `gate=PASS`.
25
- Unmet deps stay queued; a PASS unblocks dependents.
26
- - **REVIEW-QUEUE** — the serial part: **bundle approval** (contract freeze) + any **Verify
27
- escalation**. One human, one queue; present one at a time, never batched.
28
-
29
- ```
30
- add.py status ─► READY-QUEUE ──spawn workers──► builds run ──► REVIEW-QUEUE ──► done
31
- (deps=PASS?) (machine span) (concurrent) (decision points, serial)
32
-
33
- └──────── a task gating PASS unblocks its dependents ──────────────────────────┘
34
- ```
35
-
36
- ## The DAG strategy — let the engine schedule the waves (`add.py waves`)
37
-
38
- Do **not** eyeball the READY-QUEUE by hand once a milestone has more than a couple of tasks.
39
- `add.py waves` (read-only) groups not-done tasks into **topological waves**, names the **critical
40
- path**, and emits an advisory **tier hint**:
41
-
42
- ```
43
- $ add.py waves
44
- milestone: v13-onboarding-polish
45
- wave 1: dag-scheduler, setup-suggest-milestone, setup-domain-deepdive, soul-artifact
46
- wave 2: setup-run-mode (deps: dag-scheduler), soul-self-improve (deps: soul-artifact)
47
- critical path: dag-scheduler → setup-run-mode (2 tasks)
48
- tier hint: top → dag-scheduler, setup-run-mode; mid → the rest
49
- ```
50
-
51
- - **Wave = a fan-out batch.** Every task in a wave has all in-milestone deps PASS, so the whole
52
- wave is spawnable at once (`isolation="worktree"`). Finish a wave, gate tasks PASS, then
53
- `add.py waves` again — the next wave is unblocked.
54
- - **Run the widest wave first** to hide the most build latency under human review latency.
55
- - **Spend your strongest model on the critical path.** Critical-path tasks gate the most
56
- downstream work; off-path tasks take **mid**. The tier hint is advisory — override when you
57
- know a task is harder than its position suggests.
58
- - **Prefer the named roster per worker** — `add-build` for a tests/build-phase worker, `add-design`
59
- for design-phase, `add-verify` for verify-phase (full roster + when-to-spawn in advisor.md) — over
60
- a generic ad-hoc spawn.
61
- - **`--json`** (`{ milestone, waves, critical_path, critical_path_len, tiers, blocked }`) feeds
62
- a runner that spawns programmatically. `blocked` lists tasks whose dep cannot be satisfied
63
- within this milestone; a `dependency_cycle` is refused with the offending members named.
64
-
65
- The irreducible floor holds — `waves` decides *order and model*, never *whether the human gate fires*.
66
-
67
- ## The autonomy level is the throttle (not a new flag)
68
-
69
- | `autonomy` (TASK.md) | What serializes on the human | Concurrency |
70
- |----------------------|------------------------------|-------------|
71
- | `conservative` / `manual` | bundle approval **+** every Verify | pure pipelining — builds overlap, both gates queue |
72
- | `auto` (default) | bundle approval **only**; Verify auto-PASSes on evidence | real concurrency — only the decision point + residue escalations queue |
73
- | `auto` but **high-risk** | refused → must lower (`unguarded_high_risk_auto`) | back to pipelining, by design |
74
-
75
- The irreducible floor is **one human approval per task at the contract decision point** — that
76
- floor never drops to zero (`run.md:22`). Do not engineer around it.
77
-
78
- ## Who writes what — the hard boundary
79
-
80
- <constraints>
81
- - **You (orchestrator)** own all shared writes: `MILESTONE.md`, and every `add.py advance <slug>` /
82
- `add.py gate <outcome> <slug>` call. Always pass the explicit `<slug>` — **name the task every time** —
83
- omitting it falls back to the single `active_task`, which races once more than one stream is live.
84
- Workers never run these.
85
- - **A worker** owns only its own `.add/tasks/<slug>/` — it builds `src/`, drives tests green,
86
- gathers evidence, and writes `SUMMARY.md` + OBSERVE deltas. It touches **no sibling stream and
87
- no shared file** — never write shared state (state.json, MILESTONE.md, a sibling's files).
88
- - **Isolation**: spawn each worker with `isolation="worktree"` so concurrent builds cannot
89
- collide. The worktree is discarded on failure; the task resets to its last-good phase.
90
- </constraints>
91
-
92
- ## Design for failure (required)
93
-
94
- - **Fresh worktree base (verify base == HEAD)** — cut each worktree from current `HEAD` **after**
95
- committing the frozen bundle; confirm `git -C <worktree> rev-parse HEAD` equals the orchestrator's
96
- `HEAD` (drifted → `git merge` first). On a pool runner (e.g. Claude Code) the check **shifts** to
97
- the worker's **step-0** (sync + re-echo `rev-parse HEAD`), verified at **merge-time**. The engine
98
- gates this (`engine-merge-base-enforcement`): `add.py wave-verify` before the first merge-back
99
- refuses a mismatched/pending echo (`unverified_fork_base`) or off-template ledger
100
- (`wave_ledger_malformed`); `add.py check` is the standing monitor.
101
- - **Materialize gitignored engine content** — `git worktree add` checks out TRACKED files only;
102
- `.add/tooling` (engine) and `.add/docs` (book) are gitignored and will be ABSENT even when the
103
- worktree's HEAD matches — copy them in before the worker's first `add.py` call, or its
104
- `phase`/`advance` commands have no engine to run at all (confirmed 3-for-3 this session).
105
- - **Lease + timeout** — record which worker holds which task (wave ledger); a dead worker releases
106
- its claim back to READY.
107
- - **Failure isolates** — a worker's STOP-and-escalate blocks only its own task; siblings run on, the
108
- escalation joins the REVIEW-QUEUE.
109
- - **Circuit-breaker** — if N workers fail in a wave, stop fanning out and fall back to sequential.
110
- Repeated failure means the scope was wrong, not the parallelism.
111
-
112
- ## Wave ledger — the wave's resume point
113
-
114
- **The file** — `.add/milestones/<m>/WAVE.md`, orchestrator-owned. ONE live wave per milestone;
115
- opening a second while one is live is refused (`wave_already_live`). **Workers never read
116
- WAVE.md** — the orchestrator copies relevant decisions into each worker's PROMPT.md at spawn.
117
-
118
- ```markdown
119
- # WAVE.md — transient wave ledger (orchestrator-owned · one live wave per milestone)
120
- wave: <n> · opened: <date> · status: live|merging
121
- base: <orchestrator HEAD at spawn — the sha every fork must equal>
122
-
123
- ### Roster (lease ledger)
124
- | task | lease (worker) | fork-base (pasted) | autonomy | spawned | timeout |
125
- |--------|----------------|---------------------------------------------|----------|---------|---------|
126
- | <slug> | wt-a | <paste `git -C <wt> rev-parse HEAD` output> | auto | <time> | <dur> |
127
-
128
- ### Mid-wave decisions
129
- - <date> <decision a later or respawned worker must honor — copy it into that worker's PROMPT.md>
130
-
131
- ### Merge order (serial; integration Verify per merge)
132
- 1. <slug> → 2. <slug>
133
- ```
134
-
135
- **Evidence cells, not ticks.** The fork-base cell holds the PASTED output of
136
- `git -C <worktree> rev-parse HEAD` and must equal `base:`. Filling the row requires running the
137
- command — words-exist ≠ method-works. Spawning a worker whose roster row lacks that evidence is
138
- refused (`unverified_fork_base`). On a pool runner the cell holds the worker's **step-0**
139
- post-sync echo (still `== base:`) and the refusal **shifts to merge-time**.
140
-
141
- **Lifecycle — open → consume → digest → delete.** Open when the first worker spawns. At wave
142
- close, absorb the evidence digest — base · roster fork-base · merge order · integration-Verify
143
- outcome — into `MILESTONE.md` as an append-only `## Wave log` block, then remove the file.
144
- Removing WAVE.md before the digest is absorbed is refused (`digest_not_absorbed`).
145
-
146
- **Resume rule.** On session start, a live WAVE.md is the wave's resume point: re-orient from the
147
- file — roster, bases, decisions, merge order — never from conversational memory.
148
-
149
- ## Merge is serial — integration Verify
150
-
151
- Parallel build, **serial integration**. After workers return, merge worktrees one at a time and
152
- run the **integration** Verify — the concurrency / architecture / layering checks automation
153
- cannot judge. Two green tasks in isolation can still conflict when merged. Never auto-pass it.
154
-
155
- Each worktree carries a full copy of `.add/`. Merge back **only** `src/`, `tests/`, and the
156
- worker's own `.add/tasks/<slug>/` (TASK.md · SUMMARY.md) — `.add/state.json`, `MILESTONE.md`,
157
- and the live `WAVE.md` stay orchestrator-owned.
158
-
159
- ## The worker contract — portable across coding agents
160
-
161
- A worker **is** the dynamic run (`run.md`) for one task. The contract below is **agent-agnostic**:
162
- no vendor tool, no model, no spawn API — a durable ADD artifact. The adapter (next sections) is
163
- the thin, swappable mapping for one runner. Fill every `{{...}}` per stream.
164
-
165
- ```xml
166
- <!-- PROMPT.md — dropped into the worker's worktree, or passed inline. No runner-specific tokens. -->
167
- <objective>
168
- Execute the LOCKED dynamic run for task '{{TASK_SLUG}}' in milestone {{MILESTONE}}:
169
- drive §4 TESTS red→green against the FROZEN contract {{CONTRACT_VERSION}}, converge, and
170
- resolve verify per autonomy={{AUTONOMY}}. You own ONLY the machine-led span — the two human
171
- decision points (bundle approval · escalated Verify) are NOT yours.
172
- </objective>
173
-
174
- <persona>
175
- Load `.add/personas/{{PERSONA_SLUG}}.md` (Identity→you · Critical Rules→constraints · Success
176
- Metrics→done-bar); no match → the generic default below. Portable body + per-runner spawn stubs:
177
- `templates/PROMPT.persona.md.tmpl` (one canonical body; Claude Code verified, the rest illustrative).
178
- You are a {{DOMAIN}} engineer with 15 years building {{DOMAIN_DETAIL}}.
179
- A wrong-but-plausible result here is expensive; correctness over speed.
180
- Work step by step:
181
- 1. Load the context files. Confirm the start gate: §3 CONTRACT FROZEN @ {{CONTRACT_VERSION}}
182
- AND §4 TESTS RED for the right reason. If not → STOP and escalate (forward-skip forbidden).
183
- 2. Build in small batches in src/ until the red tests pass — never weaken or skip a test.
184
- 3. Converge: loop-until-dry · adversarial-verify every 'done' claim · completeness-critic.
185
- 4. Resolve verify per the boundary. Write SUMMARY.md + OBSERVE deltas (deltas.md grammar).
186
- Score confidence (0-1) on Completeness · Clarity · Practicality · Optimization · EdgeCases ·
187
- Self-Eval; if any < 0.9, refine before returning.
188
- </persona>
189
-
190
- <strategy>
191
- The task's §5 plan — the Strategy (ordered batches) order and the Known-problem fixes — is
192
- your PREFERRED starting path, not a hard rule. Improve on it when a better strategy emerges
193
- as you build; on done, report the strategy you ACTUALLY used so the orchestrator can update
194
- §5 for the audit trail.
195
- </strategy>
196
-
197
- <touch_boundary> <!-- from run.md; the worker's contract, identical on every runner -->
198
- MAY: rewrite code in src/ · drive tests green WITHOUT weakening them · gather verify evidence.
199
- MUST NOT: edit the frozen CONTRACT or locked scope · weaken/delete/skip any test ·
200
- touch §1–§3 bundle artifacts · write MILESTONE.md / state.json / any sibling stream.
201
- STOP-and-escalate (return your findings; do not decide):
202
- • a discovered scope/contract gap → backward-correction, reopen Specify (principle 4)
203
- • any SECURITY finding → HARD-STOP, always
204
- • a concurrency/timing OR architecture/layering risk the tests cannot exercise
205
- • [include this bullet when autonomy is conservative OR manual] the verify gate itself — STOP for the human
206
- Auto-PASS only if autonomy=auto AND: all tests green · coverage not decreased · no test weakened ·
207
- no contract edited · loops dry · completeness-critic clean · no residue above. Log it as
208
- auto-resolved, naming this run as owner — never forge a human signature.
209
- </touch_boundary>
210
-
211
- <context_files> <!-- paths relative to the worktree root -->
212
- .add/PROJECT.md · .add/milestones/{{MILESTONE}}/MILESTONE.md (READ-ONLY) ·
213
- .add/tasks/{{TASK_SLUG}}/TASK.md · .claude/skills/add/run.md · .claude/skills/add/deltas.md
214
- </context_files>
215
-
216
- <expertise>
217
- If your runner supports specialist injection (a Claude Code skill, a system-prompt preamble, an
218
- agent profile), load the one matching {{DOMAIN}}. Otherwise the persona above IS your expertise.
219
- </expertise>
220
-
221
- <tools>
222
- Navigate with your runner's code-intelligence: mcp__serena under Claude Code; LSP / ctags /
223
- ripgrep otherwise. Design every IO path for failure — timeouts, retries, rollback.
224
- </tools>
225
-
226
- <return> <!-- the worker PROPOSES; the orchestrator RECORDS. A worker never runs add.py. -->
227
- End with a structured verdict AND write the same into SUMMARY.md in the task dir, then
228
- **commit SUMMARY.md + deltas.md** in the worktree (uncommitted files survive only by harness
229
- courtesy — commit them so the serial-integration merge-back carries your report):
230
- { task, outcome: PASS|RISK-ACCEPTED|HARD-STOP|ESCALATE, evidence: <tests+coverage>,
231
- residue: [security|concurrency|architecture findings], deltas: [open lessons learned] }.
232
- Do NOT touch add.py or any shared file — the orchestrator gates on your verdict.
233
- </return>
234
- ```
235
-
236
- ## Choosing the model — vendor-neutral tiers
237
-
238
- ADD picks a **tier** from the scope's nature; the adapter maps the tier to the runner's model id.
239
-
240
- | Tier | When | Claude Code | Any other runner |
241
- |------|------|-------------|------------------|
242
- | **mid** | ordinary, well-tested scope; clear contract | `sonnet` | the runner's balanced model |
243
- | **top** | complex / ambiguous / cross-cutting / broad scope of impact | `opus` | the runner's strongest reasoning model |
244
-
245
- Two rules sit **above** model choice: **high-risk ⇒ a lowered rung (`conservative` or `manual`),
246
- regardless of model** — a stronger model does not buy back the human gate. And **security residue
247
- always escalates** — no tier auto-passes it.
248
-
249
- ## The spawn adapter — one thin mapping per runner
250
-
251
- ADD needs six capabilities from any runner. **Isolation ADD owns itself** (a git worktree), so
252
- streams stay portable even without a native sandbox.
253
-
254
- | ADD needs | Abstract | Claude Code (verified reference) | Any CLI agent — Codex · opencode · pi-mono · … |
255
- |-----------|----------|----------------------------------|-----------------------------------------------|
256
- | spawn a worker | prompt + label | `Task(description=…, prompt=…)` | `cd $WT && <agent> run --prompt-file PROMPT.md` |
257
- | pick the model | tier → id | `model="opus"\|"sonnet"` | a `--model <id>` flag |
258
- | isolate | worktree | `isolation="worktree"` | `git worktree add $WT HEAD` (after committing the bundle; verify base == HEAD), then run inside it |
259
- | load context | files / cwd | `<context_files>` + repo cwd | run inside `$WT`; paths are relative |
260
- | domain expertise | skill / preamble | a Claude skill in `<expertise>` | a system-prompt / profile preamble |
261
- | return a verdict | structured | final message (optionally a schema) | stdout JSON the orchestrator parses |
262
-
263
- > **Honesty:** only the Claude Code column is verified. The CLI forms for Codex/opencode/pi-mono
264
- > are *illustrative shapes* — confirm exact syntax with the `find-docs` skill.
265
-
266
- When workers return, **you** record each outcome with the explicit slug — `add.py advance <slug>`
267
- as evidence lands, `add.py gate PASS|RISK-ACCEPTED|HARD-STOP <slug>` at verify — then re-read
268
- `status` to refill the READY-QUEUE. The worker proposes; the orchestrator records.
@@ -1,86 +0,0 @@
1
- """add_engine.release — the RELEASE-pillar render helpers (engine-modularization 14/N).
2
-
3
- Render the CHANGELOG block and the append-only RELEASES.md attribution row, locate the
4
- ledger, find closed milestones / key decisions for a cut, and summarise the in-flight build.
5
- A closed, unpatched cluster (transitive-closure AST = zero outbound). Deps: constants + stdlib.
6
- """
7
- from __future__ import annotations
8
-
9
- import re
10
- from pathlib import Path
11
-
12
- from add_engine.constants import RELEASES_FILE
13
-
14
-
15
- def _releases_path(root: Path) -> Path:
16
- """The append-only release ledger — at the PROJECT ROOT (root IS the .add dir, so its
17
- parent), a sibling of CHANGELOG.md. NOT inside .add/."""
18
- return root.parent / RELEASES_FILE
19
-
20
- def _closed_milestones(state: dict) -> list[dict]:
21
- """Every CLOSED milestone (its milestone-done gate passed): LIVE done milestones
22
- (status == 'done', still in state) + ARCHIVED milestones (all were PASS-done before
23
- archive — see _archived_task_slugs). Each: {slug, title, tier}."""
24
- out: list[dict] = []
25
- for slug, m in (state.get("milestones") or {}).items():
26
- if m.get("status") == "done":
27
- out.append({"slug": slug, "title": m.get("title", slug), "tier": "live"})
28
- for rec in state.get("archived") or []:
29
- if rec.get("slug"):
30
- out.append({"slug": rec["slug"], "title": rec.get("title", rec["slug"]),
31
- "tier": "archived"})
32
- return out
33
-
34
- def _key_decisions_for(root: Path, slug: str) -> list[str]:
35
- """Best-effort §Key-Decisions rows from PROJECT.md that NAME this milestone slug — the
36
- consolidated decisions the changelog can cite. Fail-open: a missing section / unreadable
37
- foundation / no slug match -> [] (a gather never raises). READ-ONLY."""
38
- try:
39
- text = (root / "PROJECT.md").read_text(encoding="utf-8")
40
- except OSError:
41
- return []
42
- m = re.search(r"^#{1,6}[^\n]*key decision[^\n]*$(.*?)(?=^#{1,6}\s|\Z)", text, re.S | re.M | re.I)
43
- if not m:
44
- return []
45
- return [st.lstrip("-* ").strip() for st in (ln.strip() for ln in m.group(1).splitlines())
46
- if st.startswith(("-", "*")) and slug in st]
47
-
48
- def _build_in_flight(state: dict) -> bool:
49
- """release_build_in_flight proxy (PURE): is any ACTIVE task mid-build without a recorded green
50
- gate — phase ∈ {build, verify} AND gate == 'none'? The tool-agnostic engine never runs the
51
- suite, so an entered-but-ungated build is the recorded-evidence stand-in for 'the suite is red'."""
52
- return any(t.get("phase") in ("build", "verify") and t.get("gate") == "none"
53
- for t in (state.get("tasks") or {}).values())
54
-
55
- def _render_changelog_block(version: str, day: str, bundle: list[dict],
56
- changed_by_slug: dict) -> str:
57
- """A CHANGELOG block: `## <version> — <date>` + one bullet per bundled milestone (title +
58
- carried-delta / key-decision counts from release_data['changed'])."""
59
- lines = [f"## {version} — {day}", ""]
60
- if bundle:
61
- for m in bundle:
62
- c = changed_by_slug.get(m["slug"], {})
63
- lines.append(f"- {m['title']} — {c.get('carried_deltas', 0)} carried · "
64
- f"{len(c.get('key_decisions', []))} key decision(s)")
65
- else:
66
- lines.append("- (no milestone bundled)")
67
- return "\n".join(lines) + "\n\n"
68
-
69
- def _render_releases_row(version: str, day: str, bundle: list[dict],
70
- waiver_slugs: list[str], evidence: str | None,
71
- actor: str | None = None, loose: list[dict] | None = None) -> str:
72
- """One append-only RELEASES.md row — the attribution source (`milestones:` membership +,
73
- additively, `loose tasks:` membership for done milestone-free standalones). The `actor:`
74
- line records WHO cut the release (structured-actor stamping); absent on a legacy row
75
- (back-compat) when no actor is supplied. `loose` defaults to None so existing callers keep
76
- working; the `loose tasks:` line always renders (`none` when empty), the other lines unchanged."""
77
- ms = ", ".join(m["slug"] for m in bundle) if bundle else "none"
78
- lt = ", ".join(t["slug"] for t in loose) if loose else "none"
79
- wv = ", ".join(waiver_slugs) if waiver_slugs else "none"
80
- actor_line = f"actor: {actor}\n" if actor else ""
81
- return (f"## {version} — {day}\n"
82
- f"milestones: {ms}\n"
83
- f"loose tasks: {lt}\n"
84
- f"waivers: {wv}\n"
85
- f"{actor_line}"
86
- f"evidence: {evidence or 'recorded by add.py release'}\n\n")
@@ -1,77 +0,0 @@
1
- # TASK: {{title}}
2
-
3
- slug: {{slug}} · created: {{date}} · stage: {{stage}}
4
- milestone: {{milestone}}
5
- autonomy: {{autonomy}} <!-- Multi-component repo? add a `component: <name>` line (declared in .add/components.toml) to bind this fast task to a component — its root joins §5 Scope and its green-bar/verify surface at the gate. Omit for single-component projects. -->
6
- phase: ground <!-- fast lane: ground -> specify -> contract -> tests -> build -> verify -> observe -> done -->
7
- fast: true <!-- the fast lane: a small task, collapsed flow + minimal template. Omit --fast for full rigor. -->
8
-
9
- > Fast lane — one small task, minimal sections, filled top-to-bottom. The trust floor still
10
- > holds: a FROZEN §3 contract · ≥1 red test before build · a recorded §6 gate (security = HARD-STOP).
11
- > The acceptance scenario collapses into §1 `Accept:`; OBSERVE is one optional line at the gate.
12
-
13
- ---
14
-
15
- ## 0 · GROUND — the real codebase
16
-
17
- Touches (files · symbols): <path:symbol — what it is / how it is keyed>
18
- Context (working folder): <docs · config · data the task touches — task-delta only>
19
- Honors (patterns / conventions): <PROJECT.md / CONVENTIONS.md anchors — task-delta>
20
- Anchors the contract cites: <the symbols §3 will name>
21
-
22
- ---
23
-
24
- ## 1 · SPECIFY — the rules
25
-
26
- Feature: <name>
27
- Must:
28
- - <required behavior>
29
- Reject:
30
- - <bad input / situation> -> "<error_code>"
31
- Accept: <the one acceptance scenario, Given/When/Then condensed to one line — it drives the §4 test>
32
- Assumptions: ⚠ <the one most likely wrong> — why; if wrong: <cost> (or "none material — biggest risk: X")
33
-
34
- ---
35
-
36
- ## 3 · CONTRACT — freeze the shape
37
-
38
- ```
39
- <the shape that freezes: signature / fields · success + each rejection's response>
40
- ```
41
-
42
- `Least-sure flag surfaced at freeze:` <[spec|contract|test] the point most likely wrong — why; if wrong: cost>
43
- Status: DRAFT
44
- <!-- The freeze IS the one approval. Approved -> Status: FROZEN @ vN — approved by <name>.
45
- Changing a frozen contract = change request back to SPECIFY. -->
46
-
47
- ---
48
-
49
- ## 4 · TESTS — failing-first (red)
50
-
51
- Plan: test_<accept> — assert the §1 Accept line's Then (behavior, not internals).
52
- Tests live in: `./tests/` · MUST run red (missing implementation) before Build.
53
-
54
- ---
55
-
56
- ## 5 · BUILD — AI writes code
57
-
58
- Scope (may touch): `./src/` <every file the build may write — declared before the §3 freeze>
59
- Strategy & known-problem fixes: <ordered build steps · the trap each known problem must dodge>
60
- Strategy actually used: <fill at verify — what you ACTUALLY did, or "as planned"; harvested into §7 Decisions>
61
- Code lives in: `./src/` · Constraints: change no test, no contract; allow-list packages only.
62
-
63
- ---
64
-
65
- ## 6 · VERIFY — evidence + gate
66
-
67
- - [ ] all tests pass · coverage held · no test or contract altered during build
68
- - [ ] green was EARNED — no overfit / vacuous asserts / stubbed-away logic
69
- - [ ] no exposed secrets, injection openings, or unexpected dependencies (security = HARD-STOP)
70
-
71
- Build expectations (from §1 Accept + §3 CONTRACT): <the observable outcome a correct build must produce — confirmed by <how / where>>
72
-
73
- ### GATE RECORD
74
- Outcome: <PASS | RISK-ACCEPTED | HARD-STOP>
75
- Reviewed by: <name> · date: <date>
76
- <!-- A security finding is ALWAYS HARD-STOP. Record exactly one outcome — no silent pass.
77
- OBSERVE (optional): one `[SPEC · open]` or competency-delta line here if the loop taught the foundation something. -->
@@ -1,216 +0,0 @@
1
- # TASK: {{title}}
2
-
3
- slug: {{slug}} · created: {{date}} · stage: {{stage}}
4
- milestone: {{milestone}}
5
- autonomy: {{autonomy}} <!-- inherited from the project default (PROJECT.md); explicit level: manual < conservative < auto (visible · overridable) — lower below if a high-risk task needs it, or run `add.py autonomy set`. Multi-component repo (monorepo/multi-repo)? add a `component: <name>` line (declared in `.add/components.toml`) to ADD that component's root to your §5 Scope; omit for single-component projects (byte-identical default). -->
6
- phase: ground <!-- ground -> specify -> scenarios -> contract -> tests -> build -> verify -> observe -> done -->
7
- <!-- high-risk/method-defining scope? declare `risk: high` on the slug line above and lower the
8
- autonomy level to `manual` or `conservative` — the engine refuses an unguarded completion
9
- (`unguarded_high_risk_auto`, run.md guard). A comment is never a declaration. -->
10
-
11
- > One file = one task. Fill sections top-to-bottom; the `add` skill drives each phase.
12
- > When a phase is unclear, read its book chapter in `.add/docs/` (linked per section).
13
- > The phase marker above is the single source of truth — keep it in sync via `add.py phase`.
14
-
15
- ---
16
-
17
- ## 0 · GROUND — the real codebase ▸ docs/02-the-flow.md
18
-
19
- Touches (files · symbols · signatures): <path:symbol — what it is / how it is keyed>
20
- Context (working folder): <docs · todos · config · data the task touches — task-delta only>
21
- Honors (patterns / conventions): <PROJECT.md / CONVENTIONS.md anchors — task-delta only, never a re-scan>
22
- Seams consulted: <SEAMS.md entry cited instead of re-deriving, e.g. .add/SEAMS.md#scope-token-grammar — optional, omit if none apply>
23
- Anchors the contract cites: <the symbols §3 will name>
24
- Issues/Risks (→ feed §1): <problems · traps · untestable risks found in the real code — task-delta; §1 builds on these>
25
- Related intent: <PROJECT.md § · GLOSSARY term(s) · originating request/milestone rationale — the WHY; task-delta>
26
- Ground SHA: <`git rev-parse --short HEAD` at ground time — cite symbols, not bare line numbers; any line ref is "as of" this commit>
27
-
28
- ---
29
-
30
- ## 1 · SPECIFY — the rules ▸ docs/03-step-1-specify.md
31
-
32
- Feature: <name>
33
- Framings weighed: <chosen> (chosen) · <alternative> · <alternative>
34
- Must:
35
- <must>
36
- - <required behavior>
37
- </must>
38
- Reject:
39
- <reject>
40
- - <bad input / situation> -> "<error_code>"
41
- </reject>
42
- After:
43
- <after>
44
- - <state that is true once it succeeds>
45
- </after>
46
- Assumptions — lowest-confidence first:
47
- <assumptions>
48
- ⚠ <the one assumption most likely to be wrong> — lowest confidence because <why>; if wrong: <cost>
49
- - [ ] <next assumption, ranked> — confirm or deny; never carry an open one forward
50
- </assumptions>
51
-
52
- <!-- EXIT: every rule stated, every rejection named; assumptions ranked lowest-confidence first, the top one or two ⚠-flagged with why + cost (or, for trivial scope, an honest "none material" that still names the single biggest risk). -->
53
-
54
- ---
55
-
56
- ## 2 · SCENARIOS — pass/fail cases ▸ docs/04-step-2-scenarios.md
57
-
58
- <scenarios>
59
-
60
- ```gherkin
61
- Scenario: <short name> # <Must/Reject item this covers, e.g. M1 or R1>
62
- Given <starting situation>
63
- When <action>
64
- Then <expected result>
65
- And <what must remain unchanged> # required for every rejection
66
- ```
67
-
68
- </scenarios>
69
-
70
- <!-- EXIT: one scenario per Must AND per Reject; each result is observable. -->
71
-
72
- ---
73
-
74
- ## 3 · CONTRACT — freeze the shape ▸ docs/05-step-3-contract.md
75
-
76
- ```
77
- <METHOD> <path> body: { <fields> }
78
- 200 -> { <success fields> }
79
- 4xx -> { error: "<code>" | "<code>" }
80
- Schema: <tables/fields touched, and access pattern>
81
- ```
82
-
83
- Glossary deltas: <new domain term(s) this task introduces, `Term: definition` — or "none">
84
- Status: DRAFT
85
- Reported: <yes — the freeze report (banner/ARC/SHAPE) rendered before this froze | no>
86
- <!-- The freeze IS the one approval — lead it with the bundle's lowest-confidence flag: the 1–2
87
- points most likely wrong across the whole bundle, tagged [spec|scenario|contract|test], each
88
- with why + cost (the §1 ⚠ assumptions feed it; a flag may point at a scenario or the contract
89
- too — see run.md). Approved -> Status: FROZEN @ vN — approved by <name>. Changing a frozen
90
- contract = change request back to SPECIFY.
91
- EXIT: frozen + every spec rejection has a contracted response + names match GLOSSARY (new
92
- terms declared as a Glossary delta) + the bundle's lowest-confidence flag was surfaced at
93
- the freeze (or an honest "none material"). -->
94
-
95
- ---
96
-
97
- ## 4 · TESTS — failing-first suite (red) ▸ docs/06-step-4-tests.md
98
-
99
- Coverage target: <e.g. 90%>
100
- Plan (one test per scenario, asserting behavior not internals):
101
- <test_plan>
102
- - test_<scenario>: arrange <Given> / act <When> / assert <Then> + assert <unchanged> · covers: <M#, R:code — optional>
103
- </test_plan>
104
-
105
- Tests live in: `./tests/` · MUST run red (missing implementation) before Build.
106
- <!-- declare paths as backticked tokens on this line: `./…` = this task dir ·
107
- a token with "/" = project root · a bare name = sibling of the previous
108
- token's dir · a directory counts its *.py files (non-recursive); reports
109
- mark declared counts with † · anything resolving outside the project root counts 0 -->
110
-
111
- <!-- EXIT: one test per scenario; suite red for the RIGHT reason; target recorded. -->
112
-
113
- ---
114
-
115
- ## 5 · BUILD — AI writes code ▸ docs/07-step-5-build.md
116
-
117
- Scope (may touch): `./src/` <fill before the §3 freeze — every file the build may write>
118
- Strategy (ordered batches): <1. … 2. … — the planned build order; guidance, not enforced; preferred architecture/pattern strategies; advise solution/method to resolve issues/implement features>
119
-
120
- Persona (optional): <name the persona file under `.add/personas/` this build embodies as a domain stance atop SOUL.md — advisory, never lowers a gate; absent = generic>
121
- Spawn isolation (default): <prefer isolation: "worktree" for any subagent build/verify spawn, not only explicit parallel mode; shared-tree needs a stated reason — see worktree-isolated-spawn-default>
122
- Known-problem fixes: <trap → planned fix — the failure modes this build must dodge; guidance, not enforced>
123
- Strategy actually used: <fill at VERIFY — the strategy you ACTUALLY used (or "as planned"); harvested into the §7 Decisions (ADR) block as the [AI] build decision>
124
- Safety rule (feature-specific): <e.g. debit+credit in one atomic transaction>
125
- Code lives in: `./src/`
126
- Constraints: do NOT change any test or the contract; allow-list packages only; ask if unclear.
127
-
128
- <!-- Scope tokens, backticked, FIRST declaring line: `./…` = this task dir · a token
129
- with "/" = project root · a bare name = sibling of the previous token's dir ·
130
- outside-root resolutions are dropped fail-closed · a DIRECTORY token covers its
131
- whole subtree (containment — diverges from §4's non-recursive counting) ·
132
- absent line = UNDECLARED (pre-existing tasks grandfathered, never retro-red) ·
133
- engine enforcement (touched ⊆ declared) is live: a completing verify gate refuses an
134
- out-of-scope build (scope_violation → self-heal) and add.py check surfaces it.
135
- EXIT: all green; coverage held; no test/contract touched; no unlisted dependency. -->
136
-
137
- ---
138
-
139
- ## 6 · VERIFY — evidence + non-functional review ▸ docs/08-step-6-verify.md
140
-
141
- - [ ] all tests pass
142
- - [ ] coverage did not decrease
143
- - [ ] no test or contract was altered during build
144
- - [ ] the green was EARNED, not gamed — no overfit to fixtures, vacuous asserts, or stubbed-away logic (score with an adversarial refute-read — a subagent recommended under `autonomy: auto`; a confirmed cheat is HARD-STOP)
145
- - [ ] concurrency / timing of the risky operation is safe
146
- - [ ] no exposed secrets, injection openings, or unexpected dependencies
147
- - [ ] layering & dependencies follow CONVENTIONS.md
148
- - [ ] a person reviewed and approved the change
149
-
150
- ### Build expectations — what "correct" looks like (fill BEFORE build; confirm each at the gate)
151
- > Pre-declare the OBSERVABLE outcomes a correct build must produce — derived from §2 SCENARIOS
152
- > + §3 CONTRACT — so this gate checks the build is RIGHT, not merely that tests are green. Each
153
- > row is evidence you can SEE, not a restatement of a test name.
154
- - [ ] <observable outcome a correct build must produce> — confirmed by <how / where>
155
- - [ ] <another observable outcome> — confirmed by <evidence seen>
156
-
157
- ### Deep checks — do not skim (fill the path that applies; the resolver judges which)
158
- - [ ] WIRING (code) — every new symbol is referenced; record where / how confirmed
159
- - [ ] DEAD-CODE (code) — no new unused or orphaned symbol introduced
160
- - [ ] SEMANTIC (prose / non-code) — read in full, not skimmed: <what read · what confirmed>
161
-
162
- ### Live-verify evidence — confirm the §0 GROUND anchors still resolve (fill at the gate)
163
- > §0's Ground SHA anchors the symbols cited at ground time to that commit — code moves during
164
- > build. Before the gate, re-resolve every symbol §3 CONTRACT cites against the CURRENT tree
165
- > (not the Ground SHA) so a stale anchor is caught here, not by a future reader chasing a moved
166
- > line.
167
- - [ ] every symbol §3 CONTRACT cites still resolves in the current tree — confirmed by <how / where>
168
- - [ ] any anchor that moved/renamed since Ground SHA is named here, not left silent
169
-
170
- ### Refute-read verdict — the earned-green check (record it; required for an auto-PASS)
171
- > Under autonomy: auto the AI auto-resolves Verify, so the earned-green refute-read MUST be
172
- > recorded here (the engine never spawns it — you do; NOT-EARNED -> `add.py heal`). The engine
173
- > MEASURES it is filled (`audit: refute_unrecorded`); it never auto-blocks — a human spot-audit
174
- > is the backstop. A human-gated (conservative/manual) task may leave it for the human's judgment.
175
- Verdict: <EARNED | NOT-EARNED>
176
- By: <self | agent-id> · adversarially checked: <what was probed>
177
-
178
- ### Advisor 3-lens verdict — sequential (security → concurrency → architecture)
179
- > Under autonomy: auto run the 3-lens checklist and record the verdict here. Lenses run in
180
- > order; a Security HARD-STOP ends the checklist (leave remaining lenses blank). Binding for
181
- > sensitivity: mechanical (advisor-gate-relax reads it); advisory for all other sensitivities.
182
- > The engine MEASURES this block is filled (audit: advisor_verdict_unrecorded); it never blocks.
183
- Advisor: <agent-id | self>
184
- 1. Security: <CLEAR | HARD-STOP: finding>
185
- 2. Concurrency: <CLEAR | RESIDUE: finding>
186
- 3. Architecture: <CLEAR | RESIDUE: finding>
187
- Verdict: <PASS | HARD-STOP>
188
- Residue: <none | summary>
189
- Binding: <yes — mechanical | advisory — <sensitivity>>
190
-
191
- ### GATE RECORD
192
- Reported: <yes — the gate report (banner/ARC) rendered before this outcome recorded | no>
193
- Outcome: <PASS | RISK-ACCEPTED | HARD-STOP>
194
- If RISK-ACCEPTED -> owner: <name> · ticket: <link> · expires: <date> (never for a security gap)
195
- Reviewed by: <name> · date: <date>
196
-
197
- <!-- A security finding is ALWAYS HARD-STOP. Record exactly one outcome — no silent pass. The Advisor 3-lens verdict and the Refute-read verdict are both measured by `add.py audit` (`advisor_verdict_unrecorded` · `refute_unrecorded`) — neither is engine-blocked; a human spot-audit is the backstop for any finding the AI did not surface or record. -->
198
-
199
- ---
200
-
201
- ## 7 · OBSERVE — feed the next loop ▸ docs/09-the-loop.md
202
-
203
- Watch (reuse scenarios as monitors): <error rate / per-rejection rate / latency>
204
-
205
- ### Decisions (ADR)
206
- <harvested at done from §1/§3/§5/§6 — do not hand-edit; one actor-tagged line per decision, refilled only while this placeholder stands>
207
-
208
- ### Spec delta
209
- Forward changes for the next loop — each re-enters at Specify as the next task. One line
210
- each, tagged `[SPEC · open|seeded|dropped]`, with evidence (e.g. `[SPEC · open] rate-limit
211
- the retry path (evidence: prod herd spikes)`). See the `add` skill's `deltas.md`.
212
-
213
- ### Competency deltas
214
- What did this loop teach the foundation? One line each, tagged by competency
215
- (`DDD · SDD · UDD · TDD · ADD`), status `open`, with evidence. See the `add` skill's `deltas.md`.
216
- <!-- e.g. - [DDD · open] the model missed multi-tenancy (evidence: scenario_x failed) -->