immune-brain 3.4.0 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -42,7 +42,7 @@ function probeHost(env = process.env, platform = process.platform, hostVersion)
42
42
  }
43
43
 
44
44
  // plugins/immune-brain/runtime/plugin_version.ts
45
- var PLUGIN_VERSION = "3.4.0";
45
+ var PLUGIN_VERSION = "3.6.0";
46
46
 
47
47
  // plugins/immune-brain/runtime/claude/interaction.ts
48
48
  import { createHash, randomUUID } from "node:crypto";
@@ -1275,8 +1275,6 @@ class AssuranceCoordinator {
1275
1275
  this.rejectedReviewOperations.delete(taskId);
1276
1276
  }
1277
1277
  const refreshed = this.active(taskId);
1278
- if (refreshed?.state === "settlement_unknown")
1279
- return refreshed;
1280
1278
  if (refreshed?.state === "running")
1281
1279
  return { state: "blocked", reason: `assurance operation ${refreshed.operation_id} is already running` };
1282
1280
  const operationId = randomUUID2();
@@ -1308,18 +1306,30 @@ class AssuranceCoordinator {
1308
1306
  progress(phase, `Preparing deterministic QA for ${taskId}`);
1309
1307
  await this.ports.advanceBeforeProjection?.();
1310
1308
  ensureOperationLive();
1311
- let projection = await this.ports.projectTask(ctx.cwd, taskId);
1309
+ let projection;
1310
+ try {
1311
+ projection = await this.ports.projectTask(ctx.cwd, taskId);
1312
+ } catch (error) {
1313
+ if (!(error instanceof Error) || !("code" in error) || !["EINTR", "EAGAIN"].includes(String(error.code)))
1314
+ throw error;
1315
+ ensureOperationLive();
1316
+ progress("retrying_projection", "Retrying the initial authority read once; no writes replayed", { retry_attempt: 1 });
1317
+ ensureOperationLive();
1318
+ projection = await this.ports.projectTask(ctx.cwd, taskId);
1319
+ }
1312
1320
  ensureOperationLive();
1313
1321
  if (projection.error)
1314
1322
  return { state: "blocked", reason: projection.error };
1315
- if (projection.projection.lifecycle === "done")
1316
- return { state: "completed" };
1317
- if (projection.projection.lifecycle === "stopped")
1318
- return { state: "stopped" };
1323
+ if (projection.projection.lifecycle === "done" || projection.projection.lifecycle === "stopped") {
1324
+ this.unknownOperations.delete(taskId);
1325
+ return { state: projection.projection.lifecycle === "done" ? "completed" : "stopped" };
1326
+ }
1319
1327
  if (!projection.claim)
1320
1328
  return { state: "blocked", reason: "no active backend claim" };
1321
1329
  if (projection.claim.task_id !== taskId)
1322
1330
  return { state: "blocked", reason: `backend claim belongs to ${projection.claim.task_id}, not ${taskId}` };
1331
+ if (projection.projection.lifecycle === "active")
1332
+ this.unknownOperations.delete(taskId);
1323
1333
  const parked = await this.ports.readTaskRecord(ctx.cwd, taskId);
1324
1334
  ensureOperationLive();
1325
1335
  if (parked.record?.findings.some((finding) => finding.kind === "replan_required" && finding.status === "open"))
@@ -1380,7 +1390,13 @@ class AssuranceCoordinator {
1380
1390
  ensureOperationLive();
1381
1391
  qaVerdict = await this.ports.runQa(assurance.snapshot, assurance.descriptors, runner, {
1382
1392
  signal: operationController.signal,
1383
- onProgress: (item) => progress("verifying", `QA ${item.index}/${item.total} ${item.acceptance_id} ${item.phase}`, { current: item.index, total: item.total, acceptance_id: item.acceptance_id })
1393
+ onProgress: (item) => progress("verifying", `QA ${item.index}/${item.total} ${item.acceptance_id} ${item.phase}`, {
1394
+ current: item.index,
1395
+ total: item.total,
1396
+ acceptance_id: item.acceptance_id,
1397
+ acceptance_phase: item.phase,
1398
+ elapsed_ms: item.elapsed_ms
1399
+ })
1384
1400
  });
1385
1401
  ensureOperationLive();
1386
1402
  const invocation = this.openInvocation(taskId);
@@ -1527,10 +1543,8 @@ class AssuranceCoordinator {
1527
1543
  }
1528
1544
  async submitReview(taskId, ctx, verdictInput) {
1529
1545
  const unknown = this.unknownOperations.get(taskId);
1530
- if (unknown) {
1531
- this.unknownOperations.delete(taskId);
1546
+ if (unknown)
1532
1547
  return { state: "settlement_unknown", operation: unknown.operation, operation_id: unknown.operationId, reason: unknown.reason };
1533
- }
1534
1548
  const rejected = this.rejectedReviewOperations.get(taskId);
1535
1549
  if (rejected)
1536
1550
  return { state: "blocked", reason: rejected.reason };
@@ -2657,11 +2671,16 @@ var INTENT_SIDECAR_RELATIVE_PREFIX = "docs/plans/";
2657
2671
  var RISK_FLOOR_SCOPE_PREFIXES = [
2658
2672
  "plugins/immune-brain/runtime/kernel",
2659
2673
  "plugins/immune-brain/runtime/authority_commit_receipts.ts",
2674
+ "plugins/immune-brain/runtime/assurance",
2675
+ "plugins/immune-brain/runtime/claude/interaction.ts",
2676
+ "plugins/immune-brain/runtime/claude/capability.ts",
2677
+ "plugins/immune-brain/runtime/claude/review_host.ts",
2678
+ "plugins/immune-brain/runtime/claude/kernel_ports.ts",
2679
+ "plugins/immune-brain/runtime/claude/mcp_server.ts",
2660
2680
  "plugins/immune-brain/.pi-extension"
2661
2681
  ];
2662
2682
  var CHANGED_PATH_RISK_FLOOR_PREFIXES = [
2663
- "plugins/immune-brain/runtime/kernel",
2664
- "plugins/immune-brain/.pi-extension",
2683
+ ...RISK_FLOOR_SCOPE_PREFIXES,
2665
2684
  "docs/specs",
2666
2685
  "docs/plans"
2667
2686
  ];
@@ -6372,6 +6391,75 @@ function attemptRef(snapshotDigest2) {
6372
6391
  return `${digest8}-${randomUUID4().slice(0, 6)}`;
6373
6392
  }
6374
6393
 
6394
+ // plugins/immune-brain/runtime/assurance/qa.ts
6395
+ async function runDeterministicQa(snapshot, descriptors, runner, options = {}) {
6396
+ if (snapshot.role !== "qa")
6397
+ throw new Error("deterministic QA requires qa role");
6398
+ if (options.signal?.aborted)
6399
+ throw new VerificationAbortedError;
6400
+ const findings = [];
6401
+ const runVerification = options.runVerification ?? runFixedVerification;
6402
+ for (const [offset, item] of snapshot.acceptance.entries()) {
6403
+ if (options.signal?.aborted)
6404
+ throw new VerificationAbortedError;
6405
+ const descriptor = descriptors.get(item.id);
6406
+ if (!descriptor)
6407
+ throw new Error(`verification descriptor missing for ${item.id}`);
6408
+ const startedAt = Date.now();
6409
+ options.onProgress?.({
6410
+ index: offset + 1,
6411
+ total: snapshot.acceptance.length,
6412
+ acceptance_id: item.id,
6413
+ phase: "running",
6414
+ elapsed_ms: 0
6415
+ });
6416
+ const result = await runVerification(snapshot.root, descriptor, runner, {
6417
+ signal: options.signal
6418
+ });
6419
+ if (options.signal?.aborted)
6420
+ throw new VerificationAbortedError;
6421
+ const failed = result.exit_code !== 0 || result.timed_out;
6422
+ options.onProgress?.({
6423
+ index: offset + 1,
6424
+ total: snapshot.acceptance.length,
6425
+ acceptance_id: item.id,
6426
+ phase: failed ? "failed" : "passed",
6427
+ elapsed_ms: Date.now() - startedAt
6428
+ });
6429
+ if (failed) {
6430
+ findings.push({
6431
+ id: qaFindingId(item.id, snapshotDigest(snapshot)),
6432
+ kind: "blocking",
6433
+ acceptance_id: item.id,
6434
+ summary: `verification failed (exit ${result.exit_code}${result.timed_out ? ", timed out" : ""}) stdout=${Buffer.byteLength(result.stdout)}B stderr=${Buffer.byteLength(result.stderr)}B`,
6435
+ findings_digest: ""
6436
+ });
6437
+ }
6438
+ }
6439
+ if (findings.length > 0) {
6440
+ return {
6441
+ contract: "assurance_kernel/assurance_verdict/v2",
6442
+ role: "qa",
6443
+ task_id: snapshot.task_id,
6444
+ snapshot_digest: snapshotDigest(snapshot),
6445
+ decision: "rework",
6446
+ findings
6447
+ };
6448
+ }
6449
+ return {
6450
+ contract: "assurance_kernel/assurance_verdict/v2",
6451
+ role: "qa",
6452
+ task_id: snapshot.task_id,
6453
+ snapshot_digest: snapshotDigest(snapshot),
6454
+ decision: "pass",
6455
+ approval: {
6456
+ kind: "qa",
6457
+ authority_role: "qa",
6458
+ summary: `all ${snapshot.acceptance.length} fixed verification descriptor(s) passed`
6459
+ }
6460
+ };
6461
+ }
6462
+
6375
6463
  // plugins/immune-brain/runtime/claude/kernel_ports.ts
6376
6464
  function diffSnapshotOf(root, record) {
6377
6465
  if (record.contract === "assurance_kernel/task_record/v4") {
@@ -6436,45 +6524,6 @@ function assertProjectionBinding(before, after, allowDiffChange = false) {
6436
6524
  throw new Error("Task changed after native confirmation; authority aborted before capability issuance");
6437
6525
  }
6438
6526
  }
6439
- async function runDeterministicQa(snapshot, descriptors, runner, options = {}) {
6440
- if (snapshot.role !== "qa")
6441
- throw new Error("deterministic QA requires qa role");
6442
- if (options.signal?.aborted)
6443
- throw new VerificationAbortedError;
6444
- const findings = [];
6445
- for (const [offset, item] of snapshot.acceptance.entries()) {
6446
- if (options.signal?.aborted)
6447
- throw new VerificationAbortedError;
6448
- const descriptor = descriptors.get(item.id);
6449
- if (!descriptor)
6450
- throw new Error(`verification descriptor missing for ${item.id}`);
6451
- const startedAt = Date.now();
6452
- options.onProgress?.({ index: offset + 1, total: snapshot.acceptance.length, acceptance_id: item.id, phase: "running", elapsed_ms: 0 });
6453
- const result = await runFixedVerification(snapshot.root, descriptor, runner, { signal: options.signal });
6454
- const failed = result.exit_code !== 0 || result.timed_out;
6455
- options.onProgress?.({ index: offset + 1, total: snapshot.acceptance.length, acceptance_id: item.id, phase: failed ? "failed" : "passed", elapsed_ms: Date.now() - startedAt });
6456
- if (failed) {
6457
- findings.push({
6458
- id: qaFindingId(item.id, snapshotDigest(snapshot)),
6459
- kind: "blocking",
6460
- acceptance_id: item.id,
6461
- summary: `verification failed (exit ${result.exit_code}${result.timed_out ? ", timed out" : ""})`,
6462
- findings_digest: ""
6463
- });
6464
- }
6465
- }
6466
- if (findings.length > 0) {
6467
- return { contract: "assurance_kernel/assurance_verdict/v2", role: "qa", task_id: snapshot.task_id, snapshot_digest: snapshotDigest(snapshot), decision: "rework", findings };
6468
- }
6469
- return {
6470
- contract: "assurance_kernel/assurance_verdict/v2",
6471
- role: "qa",
6472
- task_id: snapshot.task_id,
6473
- snapshot_digest: snapshotDigest(snapshot),
6474
- decision: "pass",
6475
- approval: { kind: "qa", authority_role: "qa", summary: `all ${snapshot.acceptance.length} fixed verification descriptor(s) passed` }
6476
- };
6477
- }
6478
6527
  function qaOutcomes(record) {
6479
6528
  return Object.fromEntries(record.attestations.filter((item) => item.kind === "qa").flatMap((item) => item.acceptance_results).map((result) => [result.acceptance_id, { status: result.status, summary: result.summary }]));
6480
6529
  }
@@ -1,25 +1,34 @@
1
- # Immune-Brain Pi Preferences
1
+ # Immune-Brain Host Preferences
2
2
 
3
3
  Pi and Claude Code are supported code-agent hosts. Immune-Brain does not load an
4
4
  agent-local TOML file or Immune-Brain-specific environment overrides. User and
5
- project preferences belong in Pi-injected `AGENTS.md` instructions.
5
+ project preferences belong in the Host's agent instruction files.
6
6
 
7
7
  ## Precedence
8
8
 
9
9
  Planner preferences resolve in this order:
10
10
 
11
11
  1. a literal instruction in the current request;
12
- 2. the repository root `AGENTS.md`;
13
- 3. `~/.pi/agent/AGENTS.md`; or
14
- 4. the Skill's documented default or an explicit user question.
12
+ 2. the repository root agent instruction file, whichever the repository tracks:
13
+ `AGENTS.md` or `CLAUDE.md`;
14
+ 3. the Host's user-level agent instruction file; or
15
+ 4. an explicit user question.
15
16
 
16
- Invalid values are reported rather than guessed.
17
+ Hosts differ in which files they auto-load: Pi injects `AGENTS.md`, while Claude
18
+ Code auto-loads `CLAUDE.md` and does not read `~/.pi/agent/AGENTS.md` at all. A
19
+ Skill therefore reads sources 2 and 3 directly instead of assuming the Host
20
+ placed them in context, and reports which sources it checked.
21
+
22
+ Invalid values are reported rather than guessed. A preference with no documented
23
+ default resolves to a user question, never to a silently chosen value.
17
24
 
18
25
  ## Initiative Carrier
19
26
 
20
27
  The Initiative carrier preference applies only to proposals split across
21
28
  multiple TaskIntents. Ordinary TaskIntents remain tracked by Kernel
22
- TaskRecords. Set one of these fixed directives in `AGENTS.md`:
29
+ TaskRecords. There is no built-in carrier default; when no directive is found,
30
+ Planner asks. Set one of these fixed directives in the repository root
31
+ `AGENTS.md` or `CLAUDE.md`:
23
32
 
24
33
  ```md
25
34
  ## Immune-Brain Preferences
@@ -33,7 +42,7 @@ TaskRecords. Set one of these fixed directives in `AGENTS.md`:
33
42
  - Initiative carrier default: github
34
43
  ```
35
44
 
36
- A repository directive overrides the global directive. A configured `github`
45
+ A repository directive overrides the user-level directive. A configured `github`
37
46
  default is standing opt-in for GitHub projection, but the literal user still
38
47
  confirms the Initiative name, immutable slug, complete Parent/Child decomposition,
39
48
  granularity, and dependencies before the first remote mutation. Planner reports
@@ -6,162 +6,146 @@ description: Use to run an enrolled TaskIntent to completion through Kernel-gove
6
6
  # Immune-Brain: Loop
7
7
 
8
8
  This skill adheres to the **[BASELINE.md](BASELINE.md)**.
9
- At every runtime role boundary, call the read-only `imm_loop_action` Tool. Use
10
- `route` for active Steps, bounded repair, architecture exploration, advisory
11
- review, Compounder, Kernel ownership, or scope expansion. Use `dispatch_role`
12
- for `qa`, `code-review`, and `ui-review`, then invoke the returned foreground
13
- Agent envelope exactly. Brainstorm and Planner use the same Tool for bounded
14
- `arch-explorer` and explicit-lens `advisory-reviewer` dispatches. Loop may
15
- dispatch `compounder` only when a closed Step supplies structured evidence for
16
- a reusable Learning; routine work without that evidence returns `next: none`
17
- and creates no Learning. Do not discover or load a Pi Skill for these roles. The Managed Path public entries remain `imm-brainstorm`, `imm-planner`, and `imm-loop`; standalone `imm-pr-fix`, `imm-doc-prune`, and `imm-agent-doc-maintain` are host-native and are never dispatched as the Loop role.
18
- Dispatch authorization follows the [shared Subagent Dispatch
19
- Protocol](docs/reference/subagent-dispatch-protocol.md#authorization-authority).
20
- Same-boundary `follow_up` is not a Plan mutation; it repeats the current
21
- execution, QA, and originating review gate. All internal Agent dispatch
22
- envelopes use `run_in_background: false` and return a direct result to the Parent
23
- before any workflow mutation.
24
-
25
- ## Workflow Profiles
26
-
27
- - `direct` has no Plan or Ledger and never invokes this skill.
28
- - `standard` keeps execution in the main context, closes a Plan Step when the runtime accepts passing evidence, and therefore does not dispatch the internal QA role per Step. It still dispatches every runtime-required final code/UI review gate. The last gate pass atomically performs internal terminal settlement when `compounder_requirement.required` is false.
29
- - `strict` preserves the full internal loop: each Step reaches isolated QA before final review, internal Compounder handoff, and terminal settlement. A missing profile is strict.
30
- - Reviewer `follow_up` targets always retain isolated QA. Standard Plans allow at
31
- most two completed/open rounds; `review_budget_state.budget_stop` is a hard
32
- stop. Never attempt a third Loop runtime action.
33
- - `workflow_profile`, `compounder_requirement`, and `review_budget_state` from
34
- the live Kernel / Loop projection are authoritative. Do not infer or override
35
- them in the host.
36
-
37
- ## Core Responsibilities
38
-
39
- - **Main-context completion loop**: Drive the enrolled Kernel task in the current Host conversation until completion or a safe stop.
40
- - **Context-preserving execution**: Call `imm_loop_action` with `op: route`, then follow the returned `executor` context in the current Parent conversation. Implement only the active Step or pending same-boundary `follow_up`, then record structured execution evidence through the Loop runtime action. A bounded test failure uses the returned internal `test-fixer` dispatch with its explicit delegated test-file list; PR feedback or CI repair uses the returned internal `pr-fix` dispatch inside the current Plan boundary.
41
- - **Independent authority isolation**: Use the host `Agent` subagent primitive for `awaiting_qa_decision` and for the exact runtime-reported review gate. Standard Plan Steps close from accepted passing evidence before an internal QA boundary exists; Strict Steps and all follow-ups retain isolated QA. The parent records accepted child decisions through the Loop runtime action.
42
- - **Observable progress**: Update only at major phase changes: Step start, execution evidence recorded, QA/review result, or terminal stop. Always emit a terminal summary.
43
- - **Kernel projection authority**: Re-read `imm_kernel_canary` `status` after every persisted action. Conversation memory never overrides the Kernel projection.
44
- - **External tracker boundary**: The host may attach one opted-in GitHub Issue projection after terminal settlement. Only a fresh claimless `done`/`stopped` projection plus its exact terminal tombstone projects `completed`/`not planned`; Enrollment performs no GitHub projection. Report tracker failures separately, but never treat them as evidence, stop the Loop, repeat a Kernel mutation, or import Issue state.
45
- - **Scope boundary**: Scope expansion always returns to `imm-planner`; Executor, test repair, and PR/CI repair stop with the concrete missing scope and verification reason instead of widening execution.
46
- - **Action authority**: The loop always enters through `imm_loop_action`; its projected `next` authority is `executor`, `test-fixer`, `pr-fix`, `arch-explorer`, `advisory-reviewer`, `compounder`, `imm_kernel_canary`, `imm-planner`, or `none`.
47
-
48
- ## Kernel Loop
49
-
50
- Repeat this sequence; do not silently stop while a valid action remains:
51
-
52
- 1. Call `imm_loop_action` with `op: route` (or `dispatch_role` at a QA/review boundary) and follow the projected `next` authority.
53
- 2. Emit one progress line: `[target][phase] result | next: action`.
54
- 3. Execute exactly one allowed action:
55
- - Kernel ownership: call `imm_kernel_canary` for that owned task. Freeze the completed artifacts, then call `advance_assurance`; when it returns `review_ready`, invoke the foreground reviewer and pass its structured verdict to `submit_review`. When the projection calls for `request_authorization` or `approve_breaking_intent_revision`, invoke the exact Tool operation directly without asking the user for chat pre-confirmation; the native host interaction is the single authority decision. Invoke `repair_authority_state` directly for a proven stale claim; Kernel revalidation removes only the redundant claim without user interaction.
56
- - Active Step / `rework_needed`: follow the returned `executor` context in the current conversation, implement only the active Step or pending same-boundary `follow_up`, verify, record structured execution evidence through the Loop runtime action, and continue. A bounded test-only repair may request internal `test-fixer` with `focus_delta.specific_changes`; PR review or CI repair may request internal `pr-fix` with the current `plan_id`, changed-file boundary, and verification. Both return child evidence to the Parent and cannot widen scope.
57
- - `awaiting_qa_decision`: call `imm_loop_action` with `op: dispatch_role`, role `qa`, the current projection, Plan verification, recorded evidence, and current target identity. Invoke the returned foreground Agent envelope exactly. A `rework` or `replan` must carry validated `notes`.
58
- - `review_required`: map the exact `pending_review_gate` (`imm-code-review` or `imm-ui-review`) to the internal `code-review` or `ui-review` role and call `imm_loop_action` with `op: dispatch_role`, passing `pending_review_gate`, `review_changed_files`, and `review_changed_files_signature`. Invoke the returned foreground Agent envelope exactly. Record a validated pass, or open a same-boundary follow-up through the Loop runtime action.
59
- - `awaiting_user_successor_decision`: stop immediately with `recommended_authority: user`, no next skill, and no runtime action. This boundary must not dispatch Planner, transition, Compounder, or a new Pi session/subagent. Only a literal user may supply a concrete validated successor Plan through the native authority gate; the internal runtime token is `--approve-successor`, never a public Skill or user-facing entry.
60
- 4. After every accepted runtime write, discard the old snapshot and read a fresh Kernel / Loop projection. Emit a result line only when the write completes a major phase or a subagent round.
61
-
62
- Use Pi native `Agent` subagents. Do not spawn Pi child processes or invoke a separate `imm-loop` CLI.
63
-
64
- ## Authority and Failure Guards
65
-
66
- - Implementation requires a validated Plan and active Step or accepted pending `follow_up`.
67
- - The parent may implement but must not issue its own QA or review pass.
68
- - QA and reviewer children must not edit files, write Plans, mutate Kernel state, or close decisions directly.
69
- - Missing `Agent` support, failed or malformed child output, stale child target, runtime write failure, invalid projection, missing credentials, unclear verification, repeated unchanged failure, or user cancellation stops fail-closed with an explicit reason and no decision write.
70
- - A Managed native authority failure reports its stable reason and exactly one same-Host recovery action. Never recommend another Host, worktree, Direct Path, unmanaged implementation, or automatic retry as a fallback.
71
- - `replan_needed` stops at `imm-planner`; do not widen scope or rewrite the active Plan. A replacement must use a new sequential Plan path after the current Plan reaches `completed`, or after a literal user explicitly marks it `cancelled` or `superseded`.
72
- - Plans never suspend, resume, queue, or execute in parallel. Do not insert a repair Plan ahead of the current Plan.
73
- - Same-boundary review `follow_up` repeats execution, independent QA, and the originating review gate.
74
- - Runtime `review_required` is the single review-gate authority. Do not invent hidden gates.
75
- - `imm-compounder` is an internal role and is never invoked as a public Skill. A `complete` projection carries an explicit internal Compounder handoff because the runtime determined it is required. A Standard Plan with optional Compounder is atomically finished by the last review gate and does not emit that handoff. Strict Plans preserve the successful order: current Steps and QA, required reviews, internal Compounder handoff, terminal settlement, then `awaiting_user_successor_decision` for a non-terminal Roadmap slice.
76
- - Successor approval is non-delegable. QA, review, Planner, Compounder, and the loop cannot approve or activate a successor, and the loop must not turn a command template into an executable successor invocation.
77
-
78
- ## Stop Conditions
79
-
80
- Stop only for:
81
-
82
- - `complete` with an explicit internal Compounder handoff before terminal settlement
83
- - `terminal_plan_complete` after a contracted terminal Plan or a legacy Plan without successor metadata has passed internal Compounder handoff and terminal settlement; stop with no next skill, authority, or action
84
- - `awaiting_user_successor_decision` after finish, with literal user authority and no automatic action
85
- - `replan_needed`
86
- - blocker or required user input
87
- - runtime, tool, subagent, or output-contract failure
88
- - user cancellation (no decision write; Plan termination is a separate explicit user-confirmed runtime action)
89
- - repeated unchanged failure
90
- - explicit Step, rework, review, follow-up, or elapsed-time budget exhaustion
91
-
92
- Session-local budgets are advisory. Persisted Step, QA, review, and follow-up state controls recovery. After interruption, re-enter only by reading a fresh projection: a completed runtime write is honored once; an interrupted pre-write action is not claimed; cancellation performs no decision write; repeated unchanged failure stops unless the next attempt names a strategy change; explicit budgets stop before another action.
93
-
94
- ## Observable Output Contract
95
-
96
- Do not narrate projection reads or routine runtime writes. Emit compact progress only for Step start, completed execution evidence, QA/review decisions, failures that change the plan, and terminal stop. Every subagent round still emits exactly one dispatch line and exactly one collection/result line:
97
9
 
98
- ```text
99
- [Step 1/3][Executor] evidence recorded | next: QA
100
- [Step 1/3][QA] Agent dispatched
101
- [Step 1/3][QA] Agent collected: pass | next: imm-code-review
102
- ```
103
-
104
- Do not emit a successful collection line for timeout, cancellation, malformed output, or stale identity; emit the explicit failure stop instead.
105
-
106
- Every exit, including failure, must include:
10
+ ## Kernel Canary Routing and Authority
11
+
12
+ Only explicit `imm-loop` entry starts or resumes this loop. Ordinary host input
13
+ stays host-native; it never resumes a Managed owner implicitly. Read the current
14
+ Host's `imm_kernel_canary` `status` first and verify the exact active backend
15
+ claim, TaskIntent, and TaskRecord. Invalid or contradictory projections fail
16
+ closed. A candidate TaskIntent is not Enrollment authority.
17
+
18
+ TaskIntent defines the goal, acceptance, and `scope_hint`; TaskRecord and the
19
+ Kernel projection own lifecycle, artifact state, freshness, and next obligation.
20
+ Conversation memory, GitHub Issues, and `CONTEXT.md` never override them.
21
+ Historical prose Plans and State Ledgers are read-only history, not execution
22
+ instructions. Do not create Steps, workflow profiles, follow-up ledgers, or
23
+ successor Plans to drive a Kernel task.
24
+
25
+ At every internal role boundary call the read-only `imm_loop_action` Tool. Use
26
+ `route` for current-context Executor work, bounded repair, architecture
27
+ exploration, advisory review, Compounder, Kernel ownership, or scope expansion.
28
+ Use Kernel ownership for an enrolled task. This Tool projects authority; it does
29
+ not record execution evidence, mutate task state, or replace Kernel operations.
30
+ Follow the [Subagent Dispatch Protocol](docs/reference/subagent-dispatch-protocol.md#authorization-authority).
31
+ Never load an internal role as a public Skill or spawn another loop process.
32
+ The standalone `imm-pr-fix`, `imm-doc-prune`, and `imm-agent-doc-maintain` are host-native
33
+ maintenance entries, never dispatched as the Loop role. Internal `test-fixer`
34
+ and `pr-fix` repairs remain bounded by the enrolled TaskIntent.
35
+
36
+ ## Execution Loop
37
+
38
+ Continue while the current projection has a valid action:
39
+
40
+ 1. For active artifacts, implement only the enrolled acceptance within
41
+ `scope_hint` in the current conversation. Run focused checks. Executor checks
42
+ are diagnostic evidence, not a QA or Review approval.
43
+ 2. Before Assurance, call `freeze_artifacts` while TaskRecord is `active:active`.
44
+ A bound active Spec and its archive path must both be inside `scope_hint`.
45
+ The Kernel owns byte-preserving archival and the frozen snapshot.
46
+ 3. Call `advance_assurance` in the foreground and consume its direct terminal
47
+ result. Deterministic QA runs fixed acceptance descriptors atomically inside
48
+ the Host integration. Do not dispatch a separate per-Step QA Agent.
49
+ 4. On `review_ready`, invoke the returned `agent_params` as one exact foreground
50
+ Agent call, then pass its structured verdict to `submit_review`. Do not
51
+ replace this snapshot-bound reviewer with a generic role dispatch. The Parent
52
+ cannot issue its own QA or Review pass.
53
+ 5. Follow the returned Kernel obligation. Fresh QA suffices for routine work;
54
+ material and critical work additionally require fresh independent Review.
55
+ Normal completion does not require a second user confirmation.
56
+ 6. For rework, follow the projected artifact state before editing. Resolve
57
+ findings only after fixing and verifying their cause. Changed snapshots
58
+ invalidate old evidence; freeze and run the newly required obligations.
59
+ 7. Stop on terminal `done` or `stopped`, unresolved user decisions, explicit
60
+ cancellation, or a failure without a safe projected action.
61
+
62
+ Use the fresh projection returned by a successful operation when supplied. Read
63
+ `status` after interruption, ambiguous mutation results, absent projections, or
64
+ suspected external changes. Never repeat a mutation merely to obtain its result.
65
+ Kernel CAS and freshness checks remain mandatory; reducing Parent reads does
66
+ not bypass them. Do not poll or create detached jobs.
67
+
68
+ ## Decisions and Recovery
69
+
70
+ - Scope expansion always returns to `imm-planner`. Collect all currently known missing
71
+ paths, caller/test/generated mirrors, and verification reasons in one request.
72
+ Do not edit outside scope while waiting or widen it piecemeal without new
73
+ evidence. Bounded test or PR repair stays inside the same TaskIntent.
74
+ - Invoke `approve_breaking_intent_revision` with the complete next intent
75
+ directly; the native Host gate is the single user decision. Do not overwrite
76
+ enrolled intent sidecars or ask for chat pre-confirmation.
77
+ - On `awaiting_user`, invoke `request_authorization` directly. It is reserved
78
+ for a concrete unresolved decision or explicit stop, not risk tier alone.
79
+ - Invoke `repair_authority_state` directly for a proven stale claim. Kernel
80
+ revalidation removes only the redundant claim without user interaction.
81
+ - A Managed native authority failure stays fail-closed. Report its stable reason
82
+ and exactly one same-Host recovery action. Never recommend another Host,
83
+ worktree, Direct Path, unmanaged implementation, or automatic retry.
84
+ - After interruption, read a fresh projection and run only the pending obligation.
85
+ A committed QA result is honored; an interrupted precommit QA run produces no
86
+ approval. Do not rerun fresh QA simply because Review was interrupted.
87
+ - Malformed or stale reviewer output is not a verdict. Keep the existing
88
+ reservation only if the Host reports it valid; use its exact recovery action.
89
+ Do not fabricate a pass or blindly redispatch Review.
90
+ - Missing tools, credentials, invalid projections, or repeated unchanged failures
91
+ stop with a concrete cause. Cancellation performs no decision write and is not
92
+ task termination. Explicit task stop uses its native authority gate.
93
+
94
+ ## Review and Learning
95
+
96
+ Reviewers are read-only and bound to the frozen snapshot. They cannot edit files,
97
+ write planning artifacts, mutate Kernel state, or settle decisions. Report all
98
+ substantiated blockers in one round, tied to acceptance or a concrete regression;
99
+ separate optional advice from blockers. Suggestions alone do not justify rework.
100
+ Use the returned verdict schema exactly, including omission of unsupported fields.
101
+
102
+ `dispatch_role` for `qa`, `code-review`, or `ui-review` is used only when an
103
+ explicit runtime-supported role boundary requests it, followed by the returned
104
+ foreground Agent envelope exactly. It is not an extra gate on Kernel Assurance.
105
+ All internal Agent envelopes use `run_in_background: false`.
106
+
107
+ The internal Compounder is optional: only closed work with structured evidence
108
+ of a reusable Learning may route to it. Routine completion creates no Learning.
109
+ It cannot approve successors or delay terminal settlement. A projection with
110
+ `recommended_authority: user` must not dispatch successor work automatically.
111
+ Do not create, switch,
112
+ or delete Git worktrees; operate only in the Host launch directory.
113
+
114
+ The Host may attach an opted-in GitHub projection after settlement. Only a fresh claimless
115
+ `done`/`stopped` projection plus its exact terminal tombstone projects
116
+ `completed`/`not planned`; Enrollment performs no GitHub projection. Report a
117
+ tracker failure separately; never use it as evidence, a Loop blocker, or a reason to
118
+ repeat a Kernel mutation.
119
+
120
+ ## Observable Output
121
+
122
+ Emit progress at execution start, QA/Review phase changes, failures, and terminal
123
+ stop. Every Agent round has one dispatch line and one result line; never claim a
124
+ successful collection on timeout, cancellation, malformed output, or stale identity.
125
+ Normal conversation and visible Tool calls are the observation surface. Do not
126
+ narrate routine projection reads or add Footer status content.
127
+
128
+ Every exit includes a concise summary:
107
129
 
108
130
  ```text
109
- Plan:
110
- Completed Steps:
131
+ Task:
132
+ Completed work:
111
133
  QA:
112
134
  Review:
113
135
  Stop reason:
114
136
  Next action:
115
137
  ```
116
138
 
117
- Normal conversation text and visible tool calls are the correctness-level observation surface. Extension widgets are optional decoration only.
118
-
119
- ## Boundary
120
-
121
- - **Allowed**: Coordinate Kernel / Loop projections, current-conversation Executor work, isolated QA/review children, runtime decision recording, same-boundary follow-up, and terminal handoff reporting.
122
- - **Blocked**: Plan edits, parent-owned QA/review pass, hidden review gates, direct Kernel-store edits, child-owned state mutation, automatic Compounder execution, and external loop runners.
123
- - **Workflow guard**: Kernel and Loop projections choose the next authority; each authority keeps its existing Skill contract.
124
-
125
- ## Output artifact
126
-
127
- A visible completion trace plus terminal summary containing Plan, completed Steps, QA state, review state, stop reason, and next action.
128
-
129
- ## Next Action
130
-
131
- - If no validated Plan exists: stop and route to `imm-planner`.
132
- - If an allowed Loop action exists: continue the loop without another user command.
133
- - If work is fully closed but not finished: report the explicit internal Compounder handoff and wait for terminal settlement.
134
- - If the projection is `awaiting_user_successor_decision`: report the candidate and preconditions, ask for the user's decision, and stop without dispatch.
135
-
136
- ## Output style
137
-
138
- Default user-facing shape: checkpoint progress lines, then `Conclusion -> Evidence -> Next action` at the terminal boundary.
139
-
140
- ## Kernel Canary Routing
141
-
142
- When the Kernel projection reports an active/draining backend claim, keep
143
- `imm-loop` as the user-facing entry and call the current Host's Kernel integration
144
- for that owned task. Enrollment and Review authorization use the current Host's
145
- native gates. When the projection calls for `request_authorization` or
146
- `approve_breaking_intent_revision`, invoke the exact Tool operation directly
147
- without asking the user for chat pre-confirmation; the native Host interaction is
148
- the single authority decision. Invoke
149
- `repair_authority_state` directly for a proven stale claim; Kernel revalidation
150
- removes only the redundant claim without user interaction. Do not invoke the
151
- removed `imm-canary-work` Skill as
152
- a separate entry point. Invalid or contradictory projections fail closed. After
153
- implementation and focused verification, freeze the artifacts and call
154
- `advance_assurance`. If it returns `review_ready`, invoke the foreground
155
- reviewer and pass its structured verdict to `submit_review`;
156
- `request_authorization` is reserved for an unresolved user decision or an
157
- explicit stop. Critical work completes after fresh QA and Review without a
158
- second user confirmation.
159
- Every QA/Review operation stays foreground and returns its next projected
160
- obligation directly to the Parent. The host performs any opted-in GitHub Issue
161
- projection only after the corresponding authority mutation: only a fresh
162
- claimless `done`/`stopped` projection with its exact terminal tombstone projects
163
- terminal closure (`completed`/`not planned`); Enrollment performs no GitHub
164
- projection. Treat the attached tracker result as non-authoritative observation.
165
- Report its failure separately, but never use it as evidence, a stop condition,
166
- or a reason to repeat a Kernel mutation. A terminal tombstone alone never
167
- blocks unrelated v3 routing.
139
+ For `settlement_unknown`, call `advance_assurance` once to reconcile the Kernel
140
+ projection before resuming; never replay the uncertain write directly. The runtime
141
+ retries only explicit `EINTR`/`EAGAIN` failures of its initial projection read, once,
142
+ with cancellation checks. Semantic authority errors and mutation failures are not
143
+ retryable reads. For `review_preparation_failed`, repair the reported transport or
144
+ environment cause before advancing; committed QA remains valid. For
145
+ `verdict_invalid`, correct the existing payload once and resubmit without another
146
+ reviewer dispatch. If correction fails, report the schema failure and stop the
147
+ correction loop.
148
+
149
+ For failures, name the cause, stages already committed, the safe retry boundary,
150
+ and exactly one next action. Distinguish user approval from environment repair
151
+ and runtime failure. Do not ask the user to manually switch internal roles.