immune-brain 5.2.0 → 5.5.1

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 (77) hide show
  1. package/README.md +4 -4
  2. package/README.zh-CN.md +4 -4
  3. package/package.json +2 -1
  4. package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
  5. package/plugins/immune-brain/.pi-extension/imm-canary-enroll.ts +54 -70
  6. package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +163 -28
  7. package/plugins/immune-brain/.pi-extension/imm-unattended-batch.ts +71 -10
  8. package/plugins/immune-brain/.pi-extension/pi-canary-tool-failure.ts +1 -1
  9. package/plugins/immune-brain/.pi-extension/pi-run-continuation.ts +161 -0
  10. package/plugins/immune-brain/agents/immune-brain-reviewer.md +26 -2
  11. package/plugins/immune-brain/dist/BASELINE.md +17 -1
  12. package/plugins/immune-brain/dist/claude/mcp-server.mjs +16145 -12745
  13. package/plugins/immune-brain/dist/docs/reference/code-quality-guard.md +3 -1
  14. package/plugins/immune-brain/dist/docs/reference/immune-brain-config.md +41 -1
  15. package/plugins/immune-brain/dist/docs/reference/planning-quality-gate.md +1 -1
  16. package/plugins/immune-brain/dist/imm-brainstorm.md +1 -1
  17. package/plugins/immune-brain/dist/imm-planner.md +63 -19
  18. package/plugins/immune-brain/dist/imm-run-batch.md +398 -0
  19. package/plugins/immune-brain/dist/imm-run.md +89 -344
  20. package/plugins/immune-brain/dist/role-prompts/code-review.md +26 -2
  21. package/plugins/immune-brain/dist/role-prompts/executor.md +35 -10
  22. package/plugins/immune-brain/hooks/hooks.json +22 -2
  23. package/plugins/immune-brain/runtime/assurance/coordinator.ts +203 -13
  24. package/plugins/immune-brain/runtime/assurance/delivery_workspace.ts +2 -1
  25. package/plugins/immune-brain/runtime/assurance/enrollment_git_base.ts +99 -14
  26. package/plugins/immune-brain/runtime/assurance/phase_entry.ts +10 -26
  27. package/plugins/immune-brain/runtime/assurance/qa.ts +126 -43
  28. package/plugins/immune-brain/runtime/assurance/qa_findings.ts +8 -0
  29. package/plugins/immune-brain/runtime/assurance/review_evidence.ts +48 -0
  30. package/plugins/immune-brain/runtime/assurance/run_continuation.ts +284 -0
  31. package/plugins/immune-brain/runtime/assurance/verdict_authority.ts +46 -4
  32. package/plugins/immune-brain/runtime/assurance/verification.ts +83 -35
  33. package/plugins/immune-brain/runtime/assurance/workflow_autocommit.ts +222 -0
  34. package/plugins/immune-brain/runtime/claude/interaction.ts +11 -2
  35. package/plugins/immune-brain/runtime/claude/kernel_ports.ts +199 -48
  36. package/plugins/immune-brain/runtime/claude/lane_guard.ts +30 -20
  37. package/plugins/immune-brain/runtime/claude/mcp_server.ts +105 -9
  38. package/plugins/immune-brain/runtime/claude/run_continuation.ts +274 -0
  39. package/plugins/immune-brain/runtime/commands/kernel.ts +41 -103
  40. package/plugins/immune-brain/runtime/github_issue_tracker.ts +60 -2
  41. package/plugins/immune-brain/runtime/kernel/application.ts +4 -1
  42. package/plugins/immune-brain/runtime/kernel/assurance_projection.ts +103 -20
  43. package/plugins/immune-brain/runtime/kernel/canary_application.ts +57 -7
  44. package/plugins/immune-brain/runtime/kernel/completion.ts +28 -4
  45. package/plugins/immune-brain/runtime/kernel/enrollment.ts +48 -8
  46. package/plugins/immune-brain/runtime/kernel/intent.ts +169 -104
  47. package/plugins/immune-brain/runtime/kernel/reducer.ts +136 -6
  48. package/plugins/immune-brain/runtime/kernel/risk_floor.ts +286 -0
  49. package/plugins/immune-brain/runtime/kernel/storage_layout_migration.ts +83 -1
  50. package/plugins/immune-brain/runtime/kernel/storage_paths.ts +1 -1
  51. package/plugins/immune-brain/runtime/kernel/types.ts +49 -3
  52. package/plugins/immune-brain/runtime/kernel/validation.ts +147 -7
  53. package/plugins/immune-brain/runtime/loop_contract.ts +5 -0
  54. package/plugins/immune-brain/runtime/plan_core.ts +15 -8
  55. package/plugins/immune-brain/runtime/plugin_source_skew.ts +58 -0
  56. package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
  57. package/plugins/immune-brain/runtime/prompts/code-review.md +26 -2
  58. package/plugins/immune-brain/runtime/prompts/executor.md +35 -10
  59. package/plugins/immune-brain/runtime/unattended/batch_delegation.ts +5 -3
  60. package/plugins/immune-brain/runtime/unattended/batch_disposition.ts +40 -10
  61. package/plugins/immune-brain/runtime/unattended/batch_final_verification.ts +57 -3
  62. package/plugins/immune-brain/runtime/unattended/batch_git.ts +424 -66
  63. package/plugins/immune-brain/runtime/unattended/batch_integration.ts +2 -1
  64. package/plugins/immune-brain/runtime/unattended/batch_kernel_port.ts +13 -0
  65. package/plugins/immune-brain/runtime/unattended/batch_lanes.ts +43 -24
  66. package/plugins/immune-brain/runtime/unattended/batch_plan.ts +6 -2
  67. package/plugins/immune-brain/runtime/unattended/batch_preflight.ts +102 -41
  68. package/plugins/immune-brain/runtime/unattended/batch_reasons.ts +9 -3
  69. package/plugins/immune-brain/runtime/unattended/batch_reconfirmation.ts +9 -9
  70. package/plugins/immune-brain/runtime/unattended/batch_runner.ts +90 -32
  71. package/plugins/immune-brain/runtime/unattended/batch_state.ts +102 -4
  72. package/plugins/immune-brain/runtime/unattended/parent_delivery_consolidation.ts +248 -0
  73. package/plugins/immune-brain/runtime/workspace_scope.ts +126 -18
  74. package/plugins/immune-brain/skills/BASELINE.md +17 -1
  75. package/plugins/immune-brain/skills/imm-brainstorm/SKILL.md +4 -3
  76. package/plugins/immune-brain/skills/imm-planner/SKILL.md +8 -2
  77. package/plugins/immune-brain/skills/imm-run/SKILL.md +12 -8
@@ -10,7 +10,10 @@ This skill adheres to the **[BASELINE.md](BASELINE.md)**.
10
10
  ## Kernel Canary Routing and Authority
11
11
 
12
12
  Only explicit `imm-run` entry starts or resumes this loop. Ordinary host input
13
- stays host-native; it never resumes a Managed owner implicitly. While a
13
+ stays host-native; it never creates an execution binding. An already-bound run
14
+ keeps its binding across status questions and in-scope clarification. Explicit
15
+ cancel, planning entry or session replacement releases response continuation;
16
+ Kernel ownership changes only through its own operations. While a
14
17
  non-terminal TaskRecord holds the workspace, both Hosts add a read-only notice
15
18
  to ordinary input (Pi `before_agent_start`, Claude Code `UserPromptSubmit`)
16
19
  naming the task, its next obligation and its scope: before committing or
@@ -18,9 +21,12 @@ modifying files inside that scope, read `status` and tell the user the task is
18
21
  active and what it waits for. The notice resumes nothing. Read the current
19
22
  Host's `status` projection first and verify the exact active backend claim,
20
23
  TaskIntent, and TaskRecord. Invalid or contradictory projections fail closed. A
21
- candidate TaskIntent is not Enrollment authority.
24
+ candidate TaskIntent is not Enrollment authority. For a Parent Issue, route to
25
+ [Unattended Batch Opt-In](imm-run-batch.md#unattended-batch-opt-in) after this authority
26
+ read. A Child entry verifies prerequisite settlement and integration before its
27
+ single-task native gate; it starts no other Slice.
22
28
 
23
- Enrollment is the first step of an explicit `imm-run` entry and belongs to no
29
+ Enrollment is the first step of a single-task explicit `imm-run` entry and belongs to no
24
30
  other Skill. When the entry finds no active claim, resolve the validated
25
31
  candidate the user named (or the Planner's recommended first Task when the entry
26
32
  names none and exactly one candidate fits), then invoke the current Host's
@@ -31,6 +37,18 @@ candidate and reports its stable reason plus exactly one same-Host recovery
31
37
  action; never recommend another Host, worktree, Direct Path, unmanaged
32
38
  implementation, or automatic retry.
33
39
 
40
+ The Enrollment gate lists every in-scope path that is already staged, modified
41
+ or untracked. Confirming the gate claims exactly the listed paths as task work,
42
+ so a task may start from work the user already began; no clean scope is
43
+ required. An in-scope path that changed after the gate text was built was not
44
+ shown, so it refuses the Enrollment: enroll again to review it. Changes outside
45
+ the scope stay the user's and are never claimed.
46
+
47
+ `status` is a read, not a freeze. It stays readable while the scope holds
48
+ unstaged or untracked paths and returns them as a `warnings` entry beside the
49
+ projection. Freezing a snapshot still refuses those paths, and an in-scope path
50
+ carrying a skip-worktree or assume-unchanged index flag still refuses both.
51
+
34
52
  Before the first Enrollment of a candidate TaskIntent, confirm the Planner
35
53
  returned `tracker_associated` — but only when the candidate belongs to an
36
54
  identified GitHub-carried Initiative. Standalone TaskIntents and Local
@@ -70,14 +88,23 @@ read-only boundary remains prompt text; the Pi dispatch rules are unchanged.
70
88
  Before a child dispatch, read the [Subagent Dispatch Protocol](docs/reference/subagent-dispatch-protocol.md#authorization-authority).
71
89
  Never load an internal role as a public Skill or spawn another loop process;
72
90
  the only exception is a Lane's Executor Host under
73
- [Lane Executor Supervision](#lane-executor-supervision).
91
+ [Lane Executor Supervision](imm-run-batch.md#lane-executor-supervision).
74
92
  The standalone `imm-pr-fix`, `imm-doc-prune`, `imm-doc-slim`, and `imm-test-prune`
75
93
  are host-native maintenance entries, never dispatched as the Loop role. Internal
76
94
  `test-fixer` and `pr-fix` repairs remain bounded by the enrolled TaskIntent.
77
95
 
78
96
  ## Execution Loop
79
97
 
80
- Continue while the current projection has a valid action:
98
+ Continue while the current projection has a valid action. Pi's response boundary
99
+ and Claude's Stop Hook re-read facts for the active session binding. A valid action
100
+ returns to this Loop; waiting Review/Executor invocations keep their existing call
101
+ identity. Submit a returned verdict before editing; use projected recovery after
102
+ a rejected submission. Only changed task/delivery facts or scoped source bytes
103
+ reset substantive progress. Three unchanged observations stop with one recovery
104
+ action; status, formatting and repeated failed commands do not reset the count.
105
+ Host native-gate failures pause with same-Host recovery and never auto-retry.
106
+ A single Slice ends at its own terminal proof; a Parent uses whole-plan completion
107
+ from the [batch contract](imm-run-batch.md#unattended-batch-opt-in).
81
108
 
82
109
  1. For active artifacts, implement only the enrolled acceptance within the
83
110
  `scope_hint` envelope in the current conversation. New helpers or tests
@@ -87,15 +114,20 @@ Continue while the current projection has a valid action:
87
114
  to the user. If a file mixes pre-existing user changes with task changes and
88
115
  the task-owned hunks cannot be isolated reliably, stop with that ownership
89
116
  conflict instead of staging the whole file. Staging grants no commit or push
90
- authority. Complete the [Executor Delivery Evidence](role-prompts/executor.md#delivery-evidence)
91
- table before the first Assurance attempt and update affected rows after repair.
117
+ authority. The runtime commits an Enrollment precondition's committable set
118
+ itself; never commit those paths by hand and never ask the user to. Complete the [Executor Delivery Evidence](role-prompts/executor.md#delivery-evidence)
119
+ table for rework only; a first delivery needs no table.
92
120
  Executor checks are diagnostic evidence, not a QA or Review approval.
93
121
  2. Call `advance_assurance` in the foreground and consume its direct terminal
94
122
  result. The Kernel freezes the artifacts itself before QA: it binds Git
95
123
  content identity in place without relocating source paths. A simple task has
96
124
  TaskIntent only; a complex task may bind one active Spec. Deterministic QA
97
- runs all descriptors in a disposable delivery materialization, never against
98
- unchecked live worktree source. Do not dispatch a separate per-Step QA Agent.
125
+ runs all descriptors in the task's working directory. Before the first
126
+ command and after every command, the tracked content inside the task's scope
127
+ must equal the frozen snapshot; a difference fails as
128
+ `protected_input_or_output_drift`. Content outside the scope, and untracked
129
+ or ignored files, are the user's environment and are not compared. Do not
130
+ dispatch a separate per-Step QA Agent.
99
131
  3. On `review_ready`, invoke the returned `agent_params` as one exact foreground
100
132
  Agent call, then pass its structured verdict to `submit_review`. Do not
101
133
  replace this snapshot-bound reviewer with a generic role dispatch. The Parent
@@ -135,333 +167,6 @@ suspected external changes. Never repeat a mutation merely to obtain its result.
135
167
  Kernel CAS and freshness checks remain mandatory; reducing Parent reads does
136
168
  not bypass them. Do not poll or create detached jobs.
137
169
 
138
- ## Unattended Batch Opt-In
139
-
140
- The only unattended batch entry is the privileged Host tool `start_unattended_batch`
141
- with its `initiative_slug` parameter. That parameter is the opt-in (lane mode adds an optional `max_parallel`, see [Parallel Batch Opt-In](#parallel-batch-opt-in)): absent the call,
142
- `imm-run` behavior is byte-identical to per-task Enrollment, and no batch state,
143
- branch, or Batch Authorization exists. The Standalone Hosts expose the same tool
144
- name and the same required parameter; it is never a batch of tasks the Host chose.
145
- When an Initiative is referenced by its tracker Issue (e.g. `github #<number>`),
146
- extract `initiative_slug` from the Issue body `<!-- immune-brain:initiative-id=<slug> -->`
147
- marker or title prefix before invoking the tool.
148
-
149
- The Initiative's carrier decides where the children are read from. When
150
- `docs/initiatives/<initiative_slug>.md` exists, the Host reads that Local carrier
151
- and performs no GitHub operation for the plan; otherwise it reads the GitHub
152
- Parent Issue's native Sub-issues. A Local carrier yields one child per Slice:
153
- each `## <slice-id>: <result>` section names exactly one Task under `Tasks:` and
154
- may add one `Blocked by: <task-id>, <task-id>` line. A Slice that names no Task or
155
- several, or a dependency outside the Initiative, refuses the plan before any
156
- confirmation.
157
-
158
- Invoking it authorizes only a user-confirmed batch of already-planned child
159
- TaskIntents. The Host projects the batch plan from the Initiative's published
160
- children, excludes every `critical` child, renders the ordered child list, budget,
161
- and plan digest through its native confirmation, and issues one Kernel Batch
162
- Authorization for that exact plan. The extension mints no capability and owns no
163
- batch state transition: the shared `startBatch` driver in
164
- `runtime/unattended/` owns every batch transition, and each child is still
165
- enrolled, assured, and settled by the Kernel under an ordinary TaskRecord.
166
-
167
- A successful child Enrollment returns a `running` report with `handoff.role`
168
- `executor`; the child remains `enrolled`. The Parent implements that TaskIntent
169
- in the current foreground conversation, stages only its scoped changes, and
170
- runs focused diagnostics before Kernel Assurance. Re-entering the batch before
171
- implementation returns the same handoff without QA or another confirmation.
172
- The runtime owns no model invocation and adds no persisted execution lifecycle.
173
-
174
- After diagnostics pass, the Parent advances Kernel QA and dispatches any reserved
175
- foreground Review once using the exact returned `agent_params`, then submits its
176
- structured verdict. An open Review reservation stays with that Host invocation;
177
- batch re-entry waits for it rather than redispatching. When a batch child's
178
- foreground terminal mutation reaches Kernel `done`, the same tool call stages
179
- only that child's generated terminal audit evidence and re-enters the batch under
180
- the still-valid authorization, opening no gate. The driver reconciles settlement,
181
- adopts or creates the one scope-bound commit, then enrolls the next ready child
182
- or settles the batch as `completed`; the result carries the batch report as
183
- `batch`. A reserved Review, a parked child and a stopped child end where they do
184
- today and are never committed automatically. If the re-entry fails, the Kernel
185
- result is unchanged and `batch` carries one recovery action: call
186
- `start_unattended_batch` with the same slug, which is also how to continue by
187
- hand. A commit that fast-forwards the batch branch outside the runner is adopted,
188
- not attributed to a child; any other HEAD movement still fails closed. Ordinary Executor handoff and below-limit
189
- QA repair do not park the batch; genuine budget/authority stops remain fail-closed.
190
-
191
- Batch execution never pushes a ref, opens or updates a pull request, resolves a
192
- user decision, or creates, switches, or deletes a Git worktree. Its sole Git
193
- effect is the batch branch `imm/<initiative-slug>` plus one scope-bounded commit
194
- per completed child.
195
-
196
- ### Parallel Batch Opt-In
197
-
198
- Lane mode is opt-in through the optional `max_parallel` parameter of
199
- `start_unattended_batch`; absent it, everything above is the whole contract and the
200
- run stays serial and byte-identical. `max_parallel` is a positive integer; the
201
- Standalone Hosts expose the same optional `lane_offers` list, each entry naming a
202
- `task_id` and an absolute `path` of an already existing Git worktree. The runner
203
- admits an offered Lane only when it shares the coordinator repository, is not the
204
- coordinator worktree, is on the branch `imm-lane/<initiative-slug>/<task-id>` at the
205
- named base, is clean and has no active run; otherwise it refuses the offer with a
206
- stable reason and writes nothing. A call that passes `lane_offers` without
207
- `max_parallel` resumes the recorded lane batch with its recorded `max_parallel`;
208
- without a recorded active lane batch it is refused before any gate opens. The runner still never creates, switches or
209
- deletes a Git worktree: when a child needs a Lane the report carries a
210
- `lane-steward` handoff and the Lane is provisioned outside the runner.
211
-
212
- In a Lane the child is enrolled, assured and settled exactly as in a serial batch.
213
- The runner then commits the settled delivery on the Lane branch and fast-forwards
214
- the batch branch only to a candidate whose changed paths and per-path content equal
215
- that commit; a mismatch or conflict moves nothing and parks the child.
216
- With `max_parallel` above 1 the reconcile tick keeps up to that many Lanes in
217
- flight and reports one `provision` or `executor` handoff per child in `handoffs[]`.
218
- Only children whose scopes are provably disjoint run together; a child whose scope
219
- overlaps an in-flight Lane waits until that Lane is integrated. Settled children
220
- integrate serially, and a parked child ends only itself and its dependents while a
221
- disjoint sibling keeps moving. A lost Lane parks as `batch_lane_lost`, and
222
- `qa_failure_limit` counts each child separately. A completed settlement inside a
223
- Lane changes Kernel state only and writes nothing to the tracker: the coordinator
224
- closes the child's Issue after it integrates that child's commit, exactly once,
225
- and reports the attempt in `tracker_observations`. A parked or lost child is
226
- never integrated, so its Issue stays open; an explicit stop inside a Lane still
227
- projects `not planned` at once.
228
-
229
- The lane batch confirmation offers one opt-in choice, off by default: delegate
230
- to the coordinator the approval of each Lane child's breaking Intent revisions
231
- that stay inside that child's TaskIntent as authorized for the batch (ADR 0018).
232
- The answer is recorded on the batch record as `revision_delegation`; a batch
233
- confirmed without it behaves exactly as before, and the grant ends with that
234
- batch — a terminal, retired or later batch never uses it. When an integrated
235
- child's TaskIntent equals the last revision applied under that grant, the runner
236
- reseals `plan_digest` and records both digests in `reseals`, so later children
237
- continue without retiring the batch. Any other Intent change still fails closed
238
- as `plan_changed` and takes the ADR 0016 retirement path.
239
-
240
- Before a new lane batch provisions any Lane, the runner compares the Kernel
241
- contract identifiers (TaskRecord, tombstone, projection, store schema) of the
242
- coordinator's runtime with those of the runtime a Lane Executor loads — never the
243
- plugin version number — and refuses with `batch_runtime_contract_mismatch`,
244
- naming both sources, when they differ; a match adds no confirmation. A Lane whose
245
- state exists but whose contract the coordinator refuses to read parks as
246
- `batch_lane_contract_mismatch` with the original parse error, distinct from a
247
- missing Lane's `batch_lane_lost`.
248
-
249
- Inside a Lane, the Pi extension and the Claude Code `PreToolUse` hook refuse an
250
- `edit`/`write` (Claude: `Edit`, `Write`, `MultiEdit`, `NotebookEdit`) whose
251
- resolved target lies outside the Lane, naming the Lane path. A shell command is
252
- not intercepted; this is no bash sandbox. When a lane batch is re-entered with a
253
- dirty coordinator checkout, each dirty path is restored to HEAD only if every one
254
- of them is an unstaged modification or untracked file that a Lane of this batch
255
- changed (its bytes differ from that Lane's base) and whose bytes equal the Lane's,
256
- in its worktree or a Lane-branch commit. The read-only preflight only attributes;
257
- the runner restores after the batch is authorized. The bytes are
258
- backed up first under `.imm/state/batches/restores/`, and the backup is recorded
259
- in the batch record and report as `restores`. If any change has another origin,
260
- or is staged or deleted, no file is touched and the refusal names it; never
261
- stage such changes to get past the refusal. A resume with a different
262
- `max_parallel` is refused with `batch_parallel_mismatch`. A Lane holds no batch
263
- state and its Host session never re-enters the batch.
264
-
265
- #### Lane Preferences
266
-
267
- A repository can keep standing lane-mode choices next to its other Immune-Brain
268
- preferences. Before the first `start_unattended_batch` call for an Initiative,
269
- the Parent resolves each of the four directives below in this order, reading the
270
- source directly rather than assuming the Host injected it into context:
271
-
272
- 1. a literal user instruction for the current request;
273
- 2. the directive in the repository root agent instruction file, whichever this
274
- repository tracks: `AGENTS.md` or `CLAUDE.md`;
275
- 3. the same directive in the Host's user-level agent instruction file; or
276
- 4. the behavior without a directive, given in the table.
277
-
278
- | Directive | Value | Effect | Without it |
279
- | --- | --- | --- | --- |
280
- | `Lane max parallel: <n>` | positive integer | The Parent passes it as `max_parallel` when it starts a batch, which selects lane mode. The native confirmation still shows it. | No `max_parallel`: the batch is serial unless the user asks otherwise |
281
- | `Lane Executor Host: <host>` | `claude-code` or `pi` | Every Lane's Executor Host is that Host. When the `lane-steward` did not report it available in a Lane, that Lane has no Executor Host; the Parent does not fall back to the other one. | The Parent's own Host type, else the other allowlisted Host |
282
- | `Lane Executor model: <model>` | a model identifier of the configured Executor Host | Passed to the Executor Host as `--model <model>` | The Executor Host's own default |
283
- | `Lane Executor effort: <level>` | a level the configured Executor Host accepts | Passed as `--effort <level>` to `claude-code` and as `--thinking <level>` to `pi` | The Executor Host's own default |
284
- | `Batch final verification: <command>; <command>` | plain commands without shell syntax or quoting, at most 8 | Passed as `final_verification` when a new lane batch starts and shown in its native confirmation; the runner runs them on the batch branch once every child is integrated and writes each command's exit status and timing into the completion report as `final_verification`. A failing command reports the batch as not passed; integrated commits are never rolled back | The commands the repository instruction file names for its full test suite and type check, else none and the completion report says nothing was run |
285
-
286
- A model identifier and an effort level mean something only to one Host, so
287
- `Lane Executor model` and `Lane Executor effort` apply only together with
288
- `Lane Executor Host` from the same or a higher source; without it they are
289
- reported and not applied. A repository directive overrides the user-level one.
290
- Report an invalid value and ask instead of guessing or clamping. After resolving
291
- them, display one non-blocking line with each selected value and its source. On
292
- a resume the recorded `max_parallel` stands and the directive is not passed
293
- again. The directives configure how the Parent starts sessions; the runner reads
294
- none of them, and they grant no permission or trust option.
295
-
296
- A repository that names its full test and type-check commands in prose (for
297
- example "uses `bun test`; type checking is `bun run typecheck`") supplies them as
298
- the final verification without a directive; the Parent never invents a command
299
- the repository does not name.
300
-
301
- #### Lane Executor Supervision
302
-
303
- The Parent launches and supervises every Lane's Executor Host; no other role
304
- starts one. This is the one case in which the Parent starts another Loop
305
- process, and it starts it only in an admitted Lane. For each `executor` handoff
306
- whose Lane has no live session of its own, the Parent starts exactly one
307
- **supervised session** and keeps its handle. Handoffs of one report start
308
- together; a Lane never has two sessions.
309
-
310
- A supervised session is defined by what it guarantees, not by a Host's name:
311
-
312
- - It is a separate Host process whose working directory is the Lane, so its
313
- Kernel root is the Lane's own Authority Store. A subagent that runs inside the
314
- Parent's process shares the Parent's root and is never a Lane Executor.
315
- - It is given one explicit `imm-run` entry for that `task_id`, and nothing else.
316
- - When it stops working — it exits, or it settles waiting for input — control
317
- returns to the Parent without the Parent polling or sleeping.
318
- - The Parent can stop it.
319
-
320
- The Parent Host and the Executor Host are chosen independently. The Executor
321
- Host is any allowlisted Host (`claude-code` or `pi`) that the `lane-steward`
322
- reported available in that Lane. A `Lane Executor Host` directive under
323
- [Lane Preferences](#lane-preferences) decides it; without one, prefer the
324
- Parent's own Host type, and use the other when only it is available. The child's QA and Review then run under that
325
- Executor Host's own Assurance adapter in the Lane. The Executor Host loads the
326
- same Immune-Brain plugin or package the Parent runs: a Parent started from a
327
- local plugin directory passes that same directory to the Executor Host. The
328
- Parent adds no permission or trust option of its own; the Executor Host runs
329
- under the user's own settings, with the model and effort of its own defaults
330
- unless Lane Preferences name them. How the Parent obtains a supervised session
331
- depends on where the Parent runs; the first matching row applies, and the user
332
- is not asked to choose:
333
-
334
- | Parent Host | Supervised session | Stop |
335
- | --- | --- | --- |
336
- | Either Host, inside Herdr (`HERDR_ENV=1`) | One Herdr tab per Lane holding an interactive Executor Host, under [Herdr Lane Tabs](#herdr-lane-tabs) | Close the tab the Parent created |
337
- | Claude Code | The Host's background command execution, running the Executor Host's non-interactive entry in the Lane; its completion notice re-invokes the Parent. The `Agent` tool does not qualify. | The Host's own stop for that background task |
338
- | Pi | A background process facility from the Pi user's own configuration that notifies the Parent on exit. Pi ships none that Immune-Brain may assume. | That facility's own stop |
339
- | Any Host without one | None. The Parent launches nothing. | — |
340
-
341
- When the Parent Host offers no supervised session, or no allowlisted Executor
342
- Host is available in the Lane, the Parent does not substitute a detached job, an
343
- in-process subagent or serial in-place work. It reports each `executor` handoff
344
- to the user with the Lane path, `task_id` and the `imm-run` entry to start
345
- there, and calls `start_unattended_batch` again when the user says a Lane has
346
- finished. Supervision is per Lane: Lanes that can be supervised are, and the
347
- rest are reported.
348
-
349
- ##### Herdr Lane Tabs
350
-
351
- Inside Herdr the Parent drives the `herdr` CLI itself; the runtime and the
352
- `lane-steward` never do. Each Lane gets a tab of its own, so its Executor Host
353
- has a full-size terminal the user can read. For each `executor` handoff without
354
- a live tab:
355
-
356
- 1. Take the Lane from the handoff's `lane_path`. Pick the Executor Host as above;
357
- `claude-code` is Herdr kind `claude` and `pi` is kind `pi`.
358
- 2. Create the tab without taking focus, in the Parent's own workspace and rooted
359
- in the Lane:
360
- `herdr tab create --workspace "$HERDR_WORKSPACE_ID" --cwd <lane_path> --label <name> --no-focus`.
361
- Without `--workspace` the tab lands in whichever workspace has focus. `<name>`
362
- is a label of at most 32 characters such as the Slice ID; a `task_id` is
363
- usually too long. Read `tab.tab_id` and `root_pane.pane_id` from the JSON
364
- result and keep `task_id → tab_id, pane_id`: the pane ID addresses the
365
- session, the tab ID closes it.
366
- 3. Start the Host in that tab's root pane:
367
- `herdr agent start <name> --kind <kind> --pane <pane_id> -- <host arguments>`.
368
- Host arguments are only those that load the Parent's plugin and those that
369
- [Lane Preferences](#lane-preferences) resolved for model and effort.
370
- 4. Submit the entry and nothing else (later text follows only the instruction
371
- rule below), and confirm the turn began:
372
- `herdr agent prompt <pane_id> "<imm-run entry> <task_id>" --wait --until working --until blocked --timeout 30000`.
373
- The entry is the Executor Host's own `imm-run` invocation as that Host names
374
- it: a Claude Code Host that loaded the plugin from a directory names it
375
- `/immune-brain:imm-run`.
376
- 5. Supervise with `herdr agent wait <pane_id>` as a Host background command, so
377
- its return re-invokes the Parent. Start it only after step 4 reported
378
- `working`: a wait attached to a still-`idle` session returns at once. Do not
379
- loop on `herdr agent get` or read the pane to judge progress.
380
-
381
- `agent_not_ready` from step 3, or a `blocked` state at any time, means the tab
382
- shows a dialog only the user may answer: workspace trust, sign-in, a permission
383
- request, a question, or a native confirmation such as an Intent revision gate.
384
- The Parent sends that tab no keys and no prompt, and never answers such a dialog
385
- for the user. As soon as the wait returns `blocked` it tells the user which tab
386
- and `task_id` is waiting and what the dialog asks, without waiting to be asked,
387
- leaves the tab open, and continues the other Lanes; once the user has answered, step 3's tab is resumed
388
- from step 4 if the entry was never submitted, otherwise from step 5. `idle` or
389
- `done` is a session end for the rules below, although the tab stays open: the
390
- Parent calls `start_unattended_batch`, and a relaunch submits the entry again in
391
- the same tab instead of creating another. When that report shows the child
392
- neither settled nor waiting on a user decision, the Parent tells the user which
393
- tab and `task_id` went idle and what the Kernel projection still requires.
394
-
395
- The Parent may send one text instruction to a Lane session, and only while it is
396
- `idle` and its child is still running in the Lane: a correction to the
397
- Executor's approach, never an answer to a dialog. It first calls
398
- `start_unattended_batch` with `lane_instruction` (`task_id`, `text`, `kind`
399
- `instruction` or `correction`, and the `session_state` it just observed with
400
- `herdr agent get`). The runner records the text in the batch record and report
401
- as `interventions` and answers `lane_instruction.accepted`; only when accepted
402
- does the Parent submit it with `herdr agent prompt <pane_id> "<text>" --wait
403
- --until working --until blocked --timeout 30000` and re-arm step 5. A `blocked`
404
- or `working` session is refused and receives nothing. Every instruction the
405
- coordinator sent is therefore in the report, so Executor-initiated behavior and
406
- coordinator intervention can be told apart afterwards. This never applies to a
407
- Review agent: a dispatched reviewer is still never continued or re-prompted.
408
-
409
- When a Lane child exhausts its rework budget (the per-child `qa_failure_limit`)
410
- it does not park for the user at once: the report carries a
411
- `{ role: "coordinator", action: "correct" }` handoff and the runner makes no
412
- further attempt for that child. The Parent reads the findings of every round
413
- from that Lane's Kernel state, decides whether they point at one root cause, and
414
- writes one design-level correction — the invariant to hold and the shared seam to
415
- fix — never a patch of its own. It starts a new Executor session in the Lane
416
- (the old context is not reused; the new session resumes from the Kernel
417
- projection and the Lane workspace alone) and sends the correction as
418
- `lane_instruction` kind `correction`; the runner counts it. At most two
419
- corrections are spent per child: the third exhaustion parks the child as
420
- `batch_correction_limit_reached`, its dependents are skipped, siblings that do not
421
- depend on it keep executing and integrating, and the batch reports it at the end.
422
- Single tasks outside a batch keep their existing budget behavior, and Review
423
- independence is unchanged. A Review rework budget that the Kernel turns into a
424
- `replan_required` decision still needs the user's own native decision.
425
-
426
- Every live Lane session keeps exactly one `herdr agent wait` armed, so `blocked`
427
- and idle-without-settlement wake the Parent on their own; a Parent that has
428
- nothing else to do still ends its turn with those waits armed. A failed or timed-out `herdr` command
429
- proves nothing about delivery; inspect the session's state before repeating it.
430
-
431
- The Parent only creates: it closes no tab, including the tabs it created, and
432
- every tab stays open for the user to read and close. It splits no pane and
433
- creates no workspace. Outside Herdr the Parent never invokes `herdr`.
434
-
435
- Supervision is event-driven. Each session end is the cue to call
436
- `start_unattended_batch` again with the same Initiative, and that report is the
437
- only progress signal: a child's state and `next_obligation` come from its Lane's
438
- Kernel projection, never from the session's output or exit status. When the
439
- report still carries an `executor` handoff for a child whose session has ended,
440
- the Parent starts it once more; after a second end without Kernel progress, or
441
- when the report shows the child waiting on a user decision or an open Review
442
- reservation, it stops relaunching and reports that child to the user while its
443
- siblings continue. The Parent stops no session: when the report shows a child
444
- parked or settled while its session is still working, the Parent tells the user
445
- which tab and `task_id` to close. A session that stays open changes no Kernel
446
- or batch state, so the next report states what remains. Handles are not
447
- authority: after an interruption
448
- the Parent calls `start_unattended_batch` first and launches only for the
449
- handoffs it returns.
450
-
451
- After a child is integrated, its Lane is clean and its `.imm/audit/<task-id>/`
452
- pair is reachable from the batch branch, the report carries a
453
- `{ role: "lane-steward", action: "release" }` handoff for that Lane. A parked,
454
- failed, dirty or unintegrated Lane, or one whose audit pair is not on the batch
455
- branch, is never offered for release. The runner removes no worktree and deletes
456
- no branch: it records the child `released` only when a later tick observes the
457
- Lane path gone, and a Lane that is still present stays `integrated` while the
458
- batch still completes. The `lane-steward` internal role handles a `provision`
459
- handoff; it follows the project's own instructions to prepare a Lane, starts no
460
- Host session, and reports "cannot supply" rather than improvising. A `release`
461
- handoff is the user's to carry out: the Parent removes no Lane and dispatches no
462
- one to remove it. It reports each such Lane once, with its `task_id`, Lane path
463
- and tab, as ready for the user to close and remove.
464
-
465
170
  ## Decisions and Recovery
466
171
 
467
172
  - Resume from authority facts, not prose. After an uncertain interruption, bind
@@ -492,6 +197,24 @@ is recorded as a separate follow-up rather than resolved here.
492
197
  reasons in one request. Do not edit outside scope while waiting or widen it
493
198
  piecemeal without new evidence. Bounded test or PR repair stays inside the same
494
199
  TaskIntent.
200
+ - Exception to the bullet above, the Loop owner's own call: a same-directory
201
+ addition. When the new entry is a concrete file in a directory where the scope
202
+ already names a concrete file, and it is not a path the project's risk floor
203
+ names in `.imm/risk-floor.json`,
204
+ submit `revise_intent` with the complete next intent. It classifies
205
+ `compatible`, applies without a native gate, and the next Review prompt names
206
+ the added paths as self-served (ADR 0021). A revision that only removes
207
+ entries is `compatible` as well: narrowing removes authority, so it applies
208
+ through `revise_intent` without a gate, provided at least one entry remains.
209
+ A glob, new directory or floor path is breaking, and so is an addition
210
+ combined with a removed entry; a directory written without a trailing
211
+ slash is refused by the Host before submission, so name concrete files or
212
+ widen with a glob entry through `approve_breaking_intent_revision`. The envelope check for a revision is judged against the next
213
+ scope, so a worktree that already holds the added files no longer blocks it.
214
+ - Revision ownership: the Loop owner prepares a scope or acceptance revision in
215
+ the executing session. Planner's route is for a change of goal, bound Spec
216
+ design, or decomposition, and returns any other proposal to the executing
217
+ session. No Host refuses a file edit because of the session's entry.
495
218
  - Effects are separate grants. A stage-only recovery restores staging and grants
496
219
  no commit, push, or publication; an existing exact approval, including a valid
497
220
  batch capability bounded to one child, stays usable without another chat gate.
@@ -501,14 +224,16 @@ is recorded as a separate follow-up rather than resolved here.
501
224
  - Text instructions are contracts, not a hard bash sandbox. They guide and are
502
225
  reviewed; the Kernel authority gates remain the real boundary.
503
226
  - In a Lane whose batch confirmation delegated in-envelope revisions
504
- (ADR 0018), the Executor does not open the gate for a revision that only
505
- changes acceptance or narrows `scope_hint`: it stops and returns the complete
506
- next intent to the Parent, which submits it as `lane_revision` on
507
- `start_unattended_batch`. The runner applies it as a delegated approval
227
+ (ADR 0018), the Executor does not open the gate for a breaking revision that
228
+ changes acceptance, alone or with a narrowed `scope_hint`: it stops and
229
+ returns the complete next intent to the Parent, which submits it as
230
+ `lane_revision` on `start_unattended_batch`. The runner applies it as a delegated approval
508
231
  (actor `batch-coordinator`, confirmation `delegated-batch:<batch_id>@<time>`)
509
232
  or refuses it with `batch_delegation_refused` and a `fallback`; on refusal the
510
233
  Executor uses its own native gate below. Widening scope, changing risk, goal
511
- or the bound Spec is never delegated, and nobody answers a dialog in a tab.
234
+ or the bound Spec is never delegated, and nobody answers a dialog in a tab. A
235
+ revision that only narrows `scope_hint` is compatible and is not delegated:
236
+ the Executor applies it with `revise_intent`.
512
237
  - Invoke `approve_breaking_intent_revision` with the complete next intent
513
238
  directly; the native Host gate is the single user decision. Do not overwrite
514
239
  enrolled intent sidecars or ask for chat pre-confirmation. A breaking revision
@@ -544,14 +269,30 @@ is recorded as a separate follow-up rather than resolved here.
544
269
  Use its canonical descriptor reference/digest, phase/outcome, timing and byte
545
270
  counts to diagnose; QA diagnostic metadata is capped at 16 KiB and contains no
546
271
  stdout/stderr, argv, environment values or arbitrary executor error text.
272
+ The stage decides what else a failed result carries. A `prepare` stage ending
273
+ in timeout, nonzero exit or output limit adds `prepare_observation` to the
274
+ direct Tool result only: the execution conditions (the task's working
275
+ directory), the declared timeout, and at most 2048 bytes of
276
+ the end of stderr with control characters other than newline and tab removed. It is never persisted. A failing `check`
277
+ stage returns no output text at all. A `protected_input_or_output_drift`
278
+ failure adds `prepare_observation.drift_paths`, at most 64 in-scope paths that
279
+ differ from the frozen snapshot, to the direct Tool result only; restore or
280
+ stage those paths before a fresh attempt. The Lane batch integration recheck
281
+ is the one run that still uses an isolated copy with no worktree
282
+ `node_modules`, because its merge candidate is never checked out; a
283
+ reproduction in the live worktree is not equivalent to that run.
547
284
  A frozen child with `run_qa` pending returns to Parent; batch re-entry does not
548
285
  blindly retry an unchanged failure. Fix the environment before a fresh attempt.
549
286
  Scope/authority exceptions still use their existing native gates. A committed
550
287
  QA result is honored; an interrupted precommit QA run produces no approval.
551
288
  Do not rerun fresh QA simply because Review was interrupted.
552
- - Malformed or stale reviewer output is not a verdict. Keep the existing
553
- reservation only if the Host reports it valid; use its exact recovery action.
554
- Do not fabricate a pass or blindly redispatch Review.
289
+ - Provider quota or interruption is not Review budget exhaustion. Preserve
290
+ fresh QA and follow the Host's exact `recovery_action`; an unchanged envelope
291
+ returned by `advance_assurance` alone does not authorize redispatch of an
292
+ already-dispatched reservation. Malformed or stale reviewer output is not a
293
+ verdict. Keep a reservation only if the Host reports it valid; obtain a new
294
+ one only through its supported recovery. If the returned action cannot clear
295
+ the observed fault, report that concrete Host blocker rather than loop.
555
296
  - Missing tools, credentials, invalid projections, or repeated unchanged failures
556
297
  stop with a concrete cause. Cancellation performs no decision write and is not
557
298
  task termination. Explicit task stop uses its native authority gate.
@@ -562,6 +303,10 @@ Reviewers are read-only and bound to the frozen snapshot. They cannot edit files
562
303
  write planning artifacts, mutate Kernel state, or settle decisions. Report all
563
304
  substantiated blockers in one round, tied to acceptance or a concrete regression;
564
305
  separate optional advice from blockers. Suggestions alone do not justify rework.
306
+ Inspect archived pass advice in `attestations[].advisory_findings`, not only
307
+ record-level `findings`. Cite its record/attestation before claiming it is
308
+ archived; session-only notes are not durable evidence. Reuse this storage rather
309
+ than creating another advisory archive.
565
310
  Use the returned verdict schema exactly, including omission of unsupported fields.
566
311
  A Review pass verdict's approval must carry `inspected_paths`: an array of
567
312
  unique repository-relative path strings listing every path of the reviewed
@@ -46,6 +46,27 @@ cite the acceptance whose principle it violates as `acceptance_id` and
46
46
  to be written into the acceptance text; a missing literal clause is not itself a
47
47
  finding and does not call for an Intent revision.
48
48
 
49
+ ## Trigger and Threat Model
50
+
51
+ `evidence.trigger` must read "concrete input or state → observable wrong
52
+ result". A finding that cannot name the wrong result is not blocking. Judge
53
+ against the threat model and supported environment declared in the Spec or
54
+ TaskIntent goal: a defect that needs an attacker, input source, repository
55
+ format, encoding, or platform outside that declaration is advisory. When
56
+ nothing is declared, assume inputs come from the repository's own tooling and
57
+ the user's trusted workspace. `security_boundary` means a security, data-loss,
58
+ or authority boundary the change actually crosses.
59
+
60
+ From Review round 3 the manifest carries `prior_review_commit` and
61
+ `delta_paths`: the paths the latest rework changed. Review that delta and its
62
+ direct interactions. A blocking finding is admitted only when at least one
63
+ `caller_chain` entry names a path in `delta_paths`, or `violated.kind` is
64
+ `security_boundary`; an edge case that already existed in round 1 is advisory
65
+ unless it crosses a security, data-loss, or authority boundary. A verdict that
66
+ blocks outside the delta is rejected for resubmission. When the manifest carries
67
+ `delta_skipped` instead, no delta exists for the round and this rule does not
68
+ apply.
69
+
49
70
  ## Invariant and Evidence Coverage
50
71
 
51
72
  Judge whether the change actually closes the invariant its acceptance names,
@@ -95,7 +116,7 @@ contract: `contract`, `role`, `task_id`, `snapshot_digest`, `decision` (`pass`
95
116
  or `rework`), and for `pass` include `approval` (`kind`, `authority_role`,
96
117
  `summary`), for `rework` include `findings` (`id`, `kind`, `acceptance_id`,
97
118
  `summary`, `evidence`). Every rework finding's `evidence` must carry
98
- `trigger` (the concrete inputs or state that reach the defect), a non-empty
119
+ `trigger` (the concrete input or state that reaches the defect and the observable wrong result it produces), a non-empty
99
120
  `caller_chain` (ordered repository paths or symbols), and `violated`
100
121
  (`kind`: `acceptance` or `security_boundary`, `ref`: the acceptance id or
101
122
  boundary name). Do not invent fields, and never send an anchor yourself: the
@@ -104,6 +125,9 @@ violated.ref, caller_chain}`, so an identical claim keeps one stable identity
104
125
  across review rounds while a different call chain is a different claim. A
105
126
  passing review carries no blocking findings; non-blocking notes may ride along as
106
127
  `kind: "advisory"` findings, and every finding, advisory included, needs the
107
- same machine-checkable evidence. If the
128
+ same machine-checkable evidence. Advisory notes are archived on a pass and never
129
+ become Executor work. A rework carries only `kind: "blocking"` findings, at
130
+ least one: the coordinator rejects a rework with an advisory finding or without
131
+ a blocking one, so submit `pass` with `inspected_paths` when nothing blocks. If the
108
132
  checkpoint is `awaiting_user_successor_decision`, stop without dispatch; only
109
133
  a literal user may invoke `--approve-successor`.