immune-brain 5.3.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.
- package/README.md +4 -4
- package/README.zh-CN.md +4 -4
- package/package.json +2 -1
- package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
- package/plugins/immune-brain/.pi-extension/imm-canary-enroll.ts +54 -70
- package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +163 -28
- package/plugins/immune-brain/.pi-extension/imm-unattended-batch.ts +71 -10
- package/plugins/immune-brain/.pi-extension/pi-canary-tool-failure.ts +1 -1
- package/plugins/immune-brain/.pi-extension/pi-run-continuation.ts +161 -0
- package/plugins/immune-brain/agents/immune-brain-reviewer.md +26 -2
- package/plugins/immune-brain/dist/BASELINE.md +13 -1
- package/plugins/immune-brain/dist/claude/mcp-server.mjs +16130 -12734
- package/plugins/immune-brain/dist/docs/reference/code-quality-guard.md +3 -1
- package/plugins/immune-brain/dist/docs/reference/immune-brain-config.md +41 -1
- package/plugins/immune-brain/dist/docs/reference/planning-quality-gate.md +1 -1
- package/plugins/immune-brain/dist/imm-planner.md +57 -16
- package/plugins/immune-brain/dist/imm-run-batch.md +398 -0
- package/plugins/immune-brain/dist/imm-run.md +89 -344
- package/plugins/immune-brain/dist/role-prompts/code-review.md +26 -2
- package/plugins/immune-brain/dist/role-prompts/executor.md +35 -10
- package/plugins/immune-brain/hooks/hooks.json +21 -1
- package/plugins/immune-brain/runtime/assurance/coordinator.ts +203 -13
- package/plugins/immune-brain/runtime/assurance/delivery_workspace.ts +2 -1
- package/plugins/immune-brain/runtime/assurance/enrollment_git_base.ts +99 -14
- package/plugins/immune-brain/runtime/assurance/phase_entry.ts +1 -7
- package/plugins/immune-brain/runtime/assurance/qa.ts +126 -43
- package/plugins/immune-brain/runtime/assurance/qa_findings.ts +8 -0
- package/plugins/immune-brain/runtime/assurance/review_evidence.ts +48 -0
- package/plugins/immune-brain/runtime/assurance/run_continuation.ts +284 -0
- package/plugins/immune-brain/runtime/assurance/verdict_authority.ts +46 -4
- package/plugins/immune-brain/runtime/assurance/verification.ts +83 -35
- package/plugins/immune-brain/runtime/assurance/workflow_autocommit.ts +222 -0
- package/plugins/immune-brain/runtime/claude/interaction.ts +11 -2
- package/plugins/immune-brain/runtime/claude/kernel_ports.ts +199 -48
- package/plugins/immune-brain/runtime/claude/lane_guard.ts +8 -15
- package/plugins/immune-brain/runtime/claude/mcp_server.ts +105 -9
- package/plugins/immune-brain/runtime/claude/run_continuation.ts +274 -0
- package/plugins/immune-brain/runtime/commands/kernel.ts +41 -103
- package/plugins/immune-brain/runtime/github_issue_tracker.ts +60 -2
- package/plugins/immune-brain/runtime/kernel/application.ts +4 -1
- package/plugins/immune-brain/runtime/kernel/assurance_projection.ts +103 -20
- package/plugins/immune-brain/runtime/kernel/canary_application.ts +57 -7
- package/plugins/immune-brain/runtime/kernel/completion.ts +28 -4
- package/plugins/immune-brain/runtime/kernel/enrollment.ts +48 -8
- package/plugins/immune-brain/runtime/kernel/intent.ts +169 -104
- package/plugins/immune-brain/runtime/kernel/reducer.ts +136 -6
- package/plugins/immune-brain/runtime/kernel/risk_floor.ts +286 -0
- package/plugins/immune-brain/runtime/kernel/storage_layout_migration.ts +83 -1
- package/plugins/immune-brain/runtime/kernel/storage_paths.ts +1 -1
- package/plugins/immune-brain/runtime/kernel/types.ts +49 -3
- package/plugins/immune-brain/runtime/kernel/validation.ts +147 -7
- package/plugins/immune-brain/runtime/loop_contract.ts +5 -0
- package/plugins/immune-brain/runtime/plan_core.ts +15 -8
- package/plugins/immune-brain/runtime/plugin_source_skew.ts +58 -0
- package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
- package/plugins/immune-brain/runtime/prompts/code-review.md +26 -2
- package/plugins/immune-brain/runtime/prompts/executor.md +35 -10
- package/plugins/immune-brain/runtime/unattended/batch_delegation.ts +5 -3
- package/plugins/immune-brain/runtime/unattended/batch_disposition.ts +40 -10
- package/plugins/immune-brain/runtime/unattended/batch_final_verification.ts +57 -3
- package/plugins/immune-brain/runtime/unattended/batch_git.ts +424 -66
- package/plugins/immune-brain/runtime/unattended/batch_integration.ts +2 -1
- package/plugins/immune-brain/runtime/unattended/batch_kernel_port.ts +13 -0
- package/plugins/immune-brain/runtime/unattended/batch_lanes.ts +43 -24
- package/plugins/immune-brain/runtime/unattended/batch_plan.ts +6 -2
- package/plugins/immune-brain/runtime/unattended/batch_preflight.ts +102 -41
- package/plugins/immune-brain/runtime/unattended/batch_reasons.ts +9 -3
- package/plugins/immune-brain/runtime/unattended/batch_reconfirmation.ts +9 -9
- package/plugins/immune-brain/runtime/unattended/batch_runner.ts +90 -32
- package/plugins/immune-brain/runtime/unattended/batch_state.ts +102 -4
- package/plugins/immune-brain/runtime/unattended/parent_delivery_consolidation.ts +248 -0
- package/plugins/immune-brain/runtime/workspace_scope.ts +126 -18
- package/plugins/immune-brain/skills/BASELINE.md +13 -1
- package/plugins/immune-brain/skills/imm-planner/SKILL.md +5 -0
- 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
|
|
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
|
|
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.
|
|
91
|
-
|
|
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
|
|
98
|
-
|
|
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
|
|
505
|
-
changes acceptance or
|
|
506
|
-
next intent to the Parent, which submits it as
|
|
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
|
-
-
|
|
553
|
-
|
|
554
|
-
|
|
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
|
|
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.
|
|
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`.
|