@pilotspace/add 1.0.0 → 1.1.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.
@@ -0,0 +1,206 @@
1
+ # Parallel streams — pipelining independent tasks
2
+
3
+ Load this **only** when a milestone has more than one task and you want to run them
4
+ concurrently. The default ADD path is one task at a time; this rubric is the opt-in
5
+ escape hatch for when independent tasks are queued and a human is ready to review.
6
+
7
+ It changes **no `add.py` code and no phase semantics**. It is a way *you, the
8
+ orchestrator*, drive several tasks at once by reading the dependency DAG that
9
+ `add.py status` already prints, and spawning one worker per ready task.
10
+
11
+ ## The honest frame — this is pipelining, not N× speed
12
+
13
+ With **one human reviewer** you cannot beat `review_time × N_tasks` (the human-led
14
+ seams are serial — `docs/10-setup-and-stages.md:91`). So the win is **not throughput**:
15
+ it is that the reviewer is **never blocked waiting on a build**. While the human reviews
16
+ task A's frozen front, the builds for B·C·D run behind *their* frozen contracts. You hide
17
+ build latency under human latency. Do not promise more than that.
18
+
19
+ ## The two queues
20
+
21
+ Compute both from one `python3 .add/tooling/add.py status` — no new state:
22
+
23
+ - **READY-QUEUE** — tasks in the active milestone where `phase ≠ done` **and** every
24
+ `deps=` task already shows `gate=PASS`. These are the only tasks a worker may pick up.
25
+ A task with unmet deps stays queued; a task finishing PASS unblocks its dependents on
26
+ the next `status`.
27
+ - **REVIEW-QUEUE** — the irreducibly serial part: the **one-approval front** (contract
28
+ freeze) and any **Verify escalation**. One human, one queue. Present these one at a
29
+ time, never in a batch the human will rubber-stamp.
30
+
31
+ ```
32
+ add.py status ─► READY-QUEUE ──spawn workers──► builds run ──► REVIEW-QUEUE ──► done
33
+ (deps=PASS?) (machine span) (concurrent) (human seams,
34
+ ▲ strictly serial)
35
+ └──────────────── a task gating PASS unblocks its dependents ──────────────┘
36
+ ```
37
+
38
+ ## The dial is the throttle (not a new flag)
39
+
40
+ How much concurrency you actually get is set by each task's `autonomy:` header
41
+ (`run.md`), not by this rubric:
42
+
43
+ | `autonomy` (TASK.md) | What serializes on the human | Concurrency |
44
+ |----------------------|------------------------------|-------------|
45
+ | `conservative` | one-approval front **+** every Verify | pure pipelining — builds overlap, both gates queue |
46
+ | `auto` (default) | one-approval front **only**; Verify auto-PASSes on evidence | real concurrency — only the seam + residue escalations queue |
47
+ | `auto` but **high-risk** | refused → forced `conservative` (`unguarded_high_risk_auto`) | back to pipelining, by design |
48
+
49
+ The irreducible floor is **one human approval per task at the contract seam** — the seam
50
+ never drops to zero (`run.md:22`). That floor is correct; do not engineer around it.
51
+
52
+ ## Who writes what — the hard boundary
53
+
54
+ - **You (orchestrator)** own all shared writes: `MILESTONE.md`, and every
55
+ `add.py advance <slug>` / `add.py gate <outcome> <slug>` call. **Always pass the explicit
56
+ `<slug>`** — `advance`/`gate`/`phase` all take an optional task slug and act on it
57
+ (`add.py` `_resolve_task`); omitting it falls back to the single `active_task`, which
58
+ races once more than one stream is live. Name the task every time. Workers never run these.
59
+ - **A worker** owns only its own `.add/tasks/<slug>/` — it builds `src/`, drives the
60
+ tests green, gathers evidence, and writes `SUMMARY.md` + OBSERVE deltas. It touches
61
+ **no sibling stream and no shared file**.
62
+ - **Isolation**: spawn each worker with `isolation="worktree"` so concurrent builds
63
+ cannot collide. The worktree is discarded on failure; the task resets to its last-good
64
+ phase.
65
+
66
+ ## Design for failure (required)
67
+
68
+ - **Fresh worktree base (verify base == HEAD)** — create each worker's worktree from current
69
+ `HEAD` **after** you commit the task's frozen front (spec · scenarios · contract · tests). A
70
+ worktree forked from a stale base forces the worker to recreate the frozen artifacts by hand
71
+ (the v10 dogfood hit exactly this). Before the worker starts, confirm `git -C <worktree>
72
+ rev-parse HEAD` equals the orchestrator's `HEAD`; if it drifted, `git merge` the base in first.
73
+ - **Lease + timeout** — record which worker holds which task; if a worker dies, release
74
+ the claim back to READY (re-spawn, do not assume partial work is sound).
75
+ - **Failure isolates** — a worker that hits a STOP-and-escalate (below) blocks only its
76
+ own task. Siblings keep running; the escalation joins the REVIEW-QUEUE.
77
+ - **Circuit-breaker** — if N workers fail in a wave, stop fanning out and fall back to
78
+ sequential. Repeated failure means the scope was wrong, not the parallelism.
79
+
80
+ ## Merge is serial — integration Verify
81
+
82
+ Parallel build, **serial integration**. After workers return, you merge the worktrees
83
+ one at a time and run the **integration** Verify — the concurrency / architecture / layering
84
+ checks that `run.md:102` says automation cannot judge. Two green tasks in isolation can
85
+ still conflict when merged; this step is where that surfaces. Never auto-pass it.
86
+
87
+ Each worktree carries a full copy of `.add/`. Merge back **only** `src/`, `tests/`, and the
88
+ worker's own `.add/tasks/<slug>/` (TASK.md · SUMMARY.md) — `.add/state.json` and
89
+ `MILESTONE.md` stay orchestrator-owned, or a parallel merge will drag stale state back.
90
+
91
+ ## The worker contract — portable across coding agents
92
+
93
+ A worker **is** the dynamic run (`run.md`) for one task. Keep two things separate:
94
+
95
+ - **The contract** (below) — the prompt. It is **agent-agnostic**: it names no vendor tool,
96
+ no model, no spawn API. It is a durable ADD artifact, like the spec and the tests.
97
+ - **The adapter** (next sections) — the thin, swappable mapping that tells *one* runner
98
+ (Claude Code · Codex · opencode · pi-mono · any CLI agent) how to launch the contract.
99
+
100
+ This split is the whole point: the same frozen contract runs on any agent; only the adapter
101
+ changes. Fill every `{{...}}` per stream. The ADD-specific value is `<touch_boundary>` + the
102
+ "return a verdict, never write shared state" rule — they are identical on every runner.
103
+
104
+ ```xml
105
+ <!-- PROMPT.md — dropped into the worker's worktree, or passed inline. No runner-specific tokens. -->
106
+ <objective>
107
+ Execute the LOCKED dynamic run for task '{{TASK_SLUG}}' in milestone {{MILESTONE}}:
108
+ drive §4 TESTS red→green against the FROZEN contract {{CONTRACT_VERSION}}, converge, and
109
+ resolve verify per autonomy={{AUTONOMY}}. You own ONLY the machine-led span — the two human
110
+ seams (front approval · escalated Verify) are NOT yours.
111
+ </objective>
112
+
113
+ <persona>
114
+ You are a {{DOMAIN}} engineer with 15 years building {{DOMAIN_DETAIL}}.
115
+ A wrong-but-plausible result here is expensive; correctness over speed.
116
+ Work step by step:
117
+ 1. Load the context files. Confirm the start gate: §3 CONTRACT FROZEN @ {{CONTRACT_VERSION}}
118
+ AND §4 TESTS RED for the right reason. If not → STOP and escalate (forward-skip forbidden).
119
+ 2. Build in small batches in src/ until the red tests pass — never weaken or skip a test.
120
+ 3. Converge: loop-until-dry · adversarial-verify every 'done' claim · completeness-critic.
121
+ 4. Resolve verify per the boundary. Write SUMMARY.md + OBSERVE deltas (deltas.md grammar).
122
+ Score confidence (0-1) on Completeness · Clarity · Practicality · Optimization · EdgeCases ·
123
+ Self-Eval; if any < 0.9, refine before returning.
124
+ </persona>
125
+
126
+ <touch_boundary> <!-- from run.md:56-73; the worker's contract, identical on every runner -->
127
+ MAY: rewrite code in src/ · drive tests green WITHOUT weakening them · gather verify evidence.
128
+ MUST NOT: edit the frozen CONTRACT or locked scope · weaken/delete/skip any test ·
129
+ touch §1–§3 front artifacts · write MILESTONE.md / state.json / any sibling stream.
130
+ STOP-and-escalate (return your findings; do not decide):
131
+ • a discovered scope/contract gap → backward-correction, reopen Specify (principle 4)
132
+ • any SECURITY finding → HARD-STOP, always
133
+ • a concurrency/timing OR architecture/layering risk the tests cannot exercise
134
+ • [include this bullet ONLY when autonomy=conservative] the verify gate itself — STOP for the human
135
+ Auto-PASS only if autonomy=auto AND: all tests green · coverage not decreased · no test weakened ·
136
+ no contract edited · loops dry · completeness-critic clean · no residue above. Log it as
137
+ auto-resolved, naming this run as owner — never forge a human signature.
138
+ </touch_boundary>
139
+
140
+ <context_files> <!-- paths relative to the worktree root -->
141
+ .add/PROJECT.md · .add/milestones/{{MILESTONE}}/MILESTONE.md (READ-ONLY) ·
142
+ .add/tasks/{{TASK_SLUG}}/TASK.md · .claude/skills/add/run.md · .claude/skills/add/deltas.md
143
+ </context_files>
144
+
145
+ <expertise>
146
+ Adopt the persona above. If your runner supports specialist injection — a Claude Code skill,
147
+ a Codex/opencode system-prompt preamble, an agent profile — load the one matching {{DOMAIN}}.
148
+ If it does not, the persona IS your expertise.
149
+ </expertise>
150
+
151
+ <tools>
152
+ Navigate with your runner's code-intelligence: mcp__serena under Claude Code; LSP / ctags /
153
+ ripgrep otherwise. Design every IO path for failure — timeouts, retries, rollback.
154
+ </tools>
155
+
156
+ <return> <!-- the worker PROPOSES; the orchestrator RECORDS. A worker never runs add.py. -->
157
+ End with a structured verdict AND write the same into SUMMARY.md in the task dir:
158
+ { task, outcome: PASS|RISK-ACCEPTED|HARD-STOP|ESCALATE, evidence: <tests+coverage>,
159
+ residue: [security|concurrency|architecture findings], deltas: [open competency deltas] }.
160
+ Do NOT touch add.py or any shared file — the orchestrator gates on your verdict.
161
+ </return>
162
+ ```
163
+
164
+ ## Choosing the model — vendor-neutral tiers
165
+
166
+ ADD picks a **tier** from the scope's nature; the adapter maps the tier to the runner's model id.
167
+ The contract is identical whichever model runs it (the model is disposable, like the code):
168
+
169
+ | Tier | When | Claude Code | Any other runner |
170
+ |------|------|-------------|------------------|
171
+ | **mid** | ordinary, well-tested scope; clear contract | `sonnet` | the runner's balanced model |
172
+ | **top** | complex / ambiguous / cross-cutting / large blast radius | `opus` | the runner's strongest reasoning model |
173
+
174
+ Two rules sit **above** model choice and never bend:
175
+ - **High-risk ⇒ `conservative` autonomy, regardless of model** (`run.md` high-risk guard). A
176
+ stronger model does not buy back the human gate.
177
+ - **Security residue always escalates** — no tier and no model auto-passes it.
178
+
179
+ ## The spawn adapter — one thin mapping per runner
180
+
181
+ ADD needs six capabilities from any runner. **Isolation is the one ADD owns itself** (a git
182
+ worktree), so streams stay portable even on a runner with no native sandbox — ADD makes the
183
+ worktree, then points the agent at that directory.
184
+
185
+ | ADD needs | Abstract | Claude Code (verified reference) | Any CLI agent — Codex · opencode · pi-mono · … |
186
+ |-----------|----------|----------------------------------|-----------------------------------------------|
187
+ | spawn a worker | prompt + label | `Task(description=…, prompt=…)` | `cd $WT && <agent> run --prompt-file PROMPT.md` |
188
+ | pick the model | tier → id | `model="opus"\|"sonnet"` | a `--model <id>` flag |
189
+ | isolate | worktree | `isolation="worktree"` | `git worktree add $WT HEAD` (after committing the front; verify base == HEAD), then run inside it |
190
+ | load context | files / cwd | `<context_files>` + repo cwd | run inside `$WT`; paths are relative |
191
+ | domain expertise | skill / preamble | a Claude skill in `<expertise>` | a system-prompt / profile preamble |
192
+ | return a verdict | structured | final message (optionally a schema) | stdout JSON the orchestrator parses |
193
+
194
+ The **hint of `Task` spawn** is the Claude Code column — the worked reference. For any other
195
+ agent the recipe is the same shape: `git worktree add` → point the agent CLI at that dir with
196
+ the chosen model → it reads `PROMPT.md` → you parse its verdict.
197
+
198
+ > **Honesty:** only the Claude Code column is verified. The CLI forms for Codex/opencode/pi-mono
199
+ > are *illustrative shapes*, not confirmed flags — exact syntax differs per runner and version;
200
+ > confirm with the `find-docs` skill. The portable, durable parts are the **contract** and the
201
+ > **six-capability mapping**, never any one runner's flags.
202
+
203
+ When workers return, **you** record each outcome with the explicit slug — `add.py advance <slug>`
204
+ as evidence lands, `add.py gate PASS|RISK-ACCEPTED|HARD-STOP <slug>` at verify — then re-read
205
+ `status` to refill the READY-QUEUE. The worker proposes a verdict; the orchestrator records it.
206
+ That split is exactly what lets a non-Claude worker take part without ever touching shared state.