immune-brain 4.5.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +157 -39
  2. package/README.zh-CN.md +160 -40
  3. package/package.json +1 -1
  4. package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
  5. package/plugins/immune-brain/.pi-extension/imm-canary-enroll.ts +42 -45
  6. package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +189 -476
  7. package/plugins/immune-brain/.pi-extension/imm-unattended-batch.ts +77 -102
  8. package/plugins/immune-brain/.pi-extension/pi-canary-assurance-progression.ts +7 -2
  9. package/plugins/immune-brain/.pi-extension/tsconfig.json +2 -2
  10. package/plugins/immune-brain/agents/immune-brain-advisory-reviewer.md +23 -0
  11. package/plugins/immune-brain/agents/immune-brain-qa.md +42 -0
  12. package/plugins/immune-brain/agents/immune-brain-reviewer.md +90 -1
  13. package/plugins/immune-brain/agents/immune-brain-ui-review.md +21 -0
  14. package/plugins/immune-brain/dist/BASELINE.md +4 -4
  15. package/plugins/immune-brain/dist/claude/mcp-server.mjs +9924 -9654
  16. package/plugins/immune-brain/dist/docs/reference/planning-quality-gate.md +3 -3
  17. package/plugins/immune-brain/dist/docs/reference/subagent-dispatch-protocol.md +30 -1
  18. package/plugins/immune-brain/dist/imm-brainstorm.md +1 -1
  19. package/plugins/immune-brain/dist/imm-doc-prune.md +2 -2
  20. package/plugins/immune-brain/dist/{imm-agent-doc-maintain.md → imm-doc-slim.md} +9 -9
  21. package/plugins/immune-brain/dist/imm-planner.md +60 -20
  22. package/plugins/immune-brain/dist/imm-pr-fix.md +1 -1
  23. package/plugins/immune-brain/dist/{imm-review-retro.md → imm-retro.md} +26 -13
  24. package/plugins/immune-brain/dist/{imm-loop.md → imm-run.md} +44 -11
  25. package/plugins/immune-brain/dist/registry.yaml +9 -9
  26. package/plugins/immune-brain/dist/role-prompts/code-review.md +7 -0
  27. package/plugins/immune-brain/dist/role-prompts/executor.md +35 -2
  28. package/plugins/immune-brain/runtime/assurance/coordinator.ts +138 -69
  29. package/plugins/immune-brain/runtime/assurance/host_port.ts +20 -0
  30. package/plugins/immune-brain/runtime/assurance/qa.ts +2 -2
  31. package/plugins/immune-brain/runtime/assurance/review_evidence.ts +4 -0
  32. package/plugins/immune-brain/runtime/assurance/verdict_authority.ts +347 -0
  33. package/plugins/immune-brain/runtime/claude/interaction.ts +1 -2
  34. package/plugins/immune-brain/runtime/claude/kernel_ports.ts +135 -396
  35. package/plugins/immune-brain/runtime/claude/mcp_server.ts +5 -4
  36. package/plugins/immune-brain/runtime/claude/review_host.ts +63 -16
  37. package/plugins/immune-brain/runtime/claude/role_agents.ts +83 -0
  38. package/plugins/immune-brain/runtime/commands/kernel.ts +3 -6
  39. package/plugins/immune-brain/runtime/github_issue_tracker.ts +738 -677
  40. package/plugins/immune-brain/runtime/kernel/application.ts +7 -7
  41. package/plugins/immune-brain/runtime/kernel/assurance_projection.ts +15 -8
  42. package/plugins/immune-brain/runtime/kernel/authority_port.ts +5 -14
  43. package/plugins/immune-brain/runtime/kernel/batch_authority.ts +30 -49
  44. package/plugins/immune-brain/runtime/kernel/canary_application.ts +6 -5
  45. package/plugins/immune-brain/runtime/kernel/canary_eligibility.ts +0 -1
  46. package/plugins/immune-brain/runtime/kernel/capability_registry.ts +7 -9
  47. package/plugins/immune-brain/runtime/kernel/enrollment.ts +170 -17
  48. package/plugins/immune-brain/runtime/kernel/enrollment_authority.ts +5 -11
  49. package/plugins/immune-brain/runtime/kernel/index.ts +3 -1
  50. package/plugins/immune-brain/runtime/kernel/storage.ts +170 -11
  51. package/plugins/immune-brain/runtime/kernel/storage_paths.ts +13 -0
  52. package/plugins/immune-brain/runtime/kernel/types.ts +2 -1
  53. package/plugins/immune-brain/runtime/kernel/validation.ts +3 -1
  54. package/plugins/immune-brain/runtime/loop_contract.ts +22 -22
  55. package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
  56. package/plugins/immune-brain/runtime/prompts/code-review.md +7 -0
  57. package/plugins/immune-brain/runtime/prompts/executor.md +35 -2
  58. package/plugins/immune-brain/runtime/role_prompt_bridge.ts +27 -0
  59. package/plugins/immune-brain/runtime/unattended/batch_git.ts +66 -28
  60. package/plugins/immune-brain/runtime/unattended/batch_kernel_port.ts +106 -0
  61. package/plugins/immune-brain/runtime/unattended/batch_plan.ts +3 -9
  62. package/plugins/immune-brain/runtime/unattended/batch_preflight.ts +132 -45
  63. package/plugins/immune-brain/runtime/unattended/batch_reasons.ts +0 -6
  64. package/plugins/immune-brain/runtime/unattended/batch_reconfirmation.ts +40 -36
  65. package/plugins/immune-brain/runtime/unattended/batch_runner.ts +98 -209
  66. package/plugins/immune-brain/runtime/unattended/batch_state.ts +36 -14
  67. package/plugins/immune-brain/runtime/unattended/types.ts +0 -2
  68. package/plugins/immune-brain/runtime/workspace_scope.ts +78 -8
  69. package/plugins/immune-brain/skills/BASELINE.md +4 -4
  70. package/plugins/immune-brain/skills/imm-doc-prune/SKILL.md +1 -1
  71. package/plugins/immune-brain/skills/{imm-agent-doc-maintain → imm-doc-slim}/SKILL.md +9 -9
  72. package/plugins/immune-brain/skills/imm-planner/SKILL.md +4 -2
  73. package/plugins/immune-brain/skills/imm-pr-fix/SKILL.md +1 -1
  74. package/plugins/immune-brain/skills/{imm-review-retro → imm-retro}/SKILL.md +7 -7
  75. package/plugins/immune-brain/skills/{imm-review-retro → imm-retro}/scripts/review_retro.ts +46 -21
  76. package/plugins/immune-brain/skills/{imm-loop → imm-run}/SKILL.md +7 -7
  77. package/plugins/immune-brain/skills/registry.yaml +9 -9
  78. package/plugins/immune-brain/.pi-extension/runtime-stub.ts +0 -584
  79. package/plugins/immune-brain/runtime/unattended/confirmation_deadline.ts +0 -33
@@ -1,30 +1,29 @@
1
1
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
  import { Type } from "typebox";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
+ // The Pi batch adapter imports the host-neutral runtime modules statically,
5
+ // exactly as the Claude adapter does; the adapter-owned helpers it drives
6
+ // (the shared session progression accessors and the batch projection) live in
7
+ // ./imm-canary-work.ts next to the assurance machinery they use.
8
+ import { readSettledTaskEvidence } from "../runtime/kernel/storage";
4
9
  import {
5
10
  createBatchAuthorityRegistry,
6
- deriveChildEnrollment,
7
- startBatch,
8
- batchQaFailureFacts,
9
- readTaskRecord,
10
- advancePiTask,
11
- projectAssuranceForTask,
12
- runEnrollmentRehearsal,
13
- enrollCanaryTask,
14
- createEnrollmentAuthorityRegistry,
15
11
  type BatchAuthorityRegistry,
12
+ } from "../runtime/kernel/batch_authority";
13
+ import { createEnrollmentAuthorityRegistry } from "../runtime/kernel/enrollment_authority";
14
+ import {
15
+ startBatch,
16
16
  type BatchRunnerKernelPort,
17
- type BatchRunnerGitPort,
18
17
  type BatchRunReport,
19
- type InitiativeObservationReader,
20
- } from "./runtime-stub";
18
+ } from "../runtime/unattended/batch_runner";
19
+ import { createBatchKernelPort } from "../runtime/unattended/batch_kernel_port";
20
+ import type { BatchRunnerGitPort } from "../runtime/unattended/batch_git";
21
+ import type { InitiativeObservationReader } from "../runtime/unattended/types";
22
+ import { advancePiTask } from "./imm-canary-work";
21
23
  import { batchReason } from "../runtime/unattended/batch_reasons";
22
- import { startConfirmationDeadline } from "../runtime/unattended/confirmation_deadline";
23
24
  import {
24
25
  authorizeBatch,
25
26
  projectBatchPreflight,
26
- readActiveClaimTaskId,
27
- isOwnBatchClaim,
28
27
  } from "../runtime/unattended/batch_preflight";
29
28
  import {
30
29
  presentTaskRail,
@@ -34,6 +33,30 @@ import {
34
33
  } from "./pi-canary-interaction";
35
34
  import { throwToolFailure } from "./pi-canary-tool-failure";
36
35
 
36
+ /**
37
+ * Read the Authority Store's settled Run evidence for a child and project its
38
+ * scope and intent sidecar from that Run only.
39
+ *
40
+ * A child reaches Kernel settlement before the batch commits it, and settlement
41
+ * clears the live state record, so the batch resume preflight must resolve the
42
+ * child's authorized scope from the settled run instead. Read-only: neither the
43
+ * store read nor this reader mutates Kernel state. Currently caller-free: the
44
+ * shared `batch_preflight.ts` performs its own settled read, and this reader
45
+ * answers with the current Run's evidence — an earlier Run's exported pair or
46
+ * a stale flat pair is never returned for a re-enrolled Task.
47
+ */
48
+ export async function readSettledTaskRecord(
49
+ root: string,
50
+ taskId: string,
51
+ ): Promise<{ scope_hint: string[]; intent_path: string | undefined } | null> {
52
+ const settled = readSettledTaskEvidence(root, taskId);
53
+ if (!settled) return null;
54
+ return {
55
+ scope_hint: settled.record.intent_snapshot.scope_hint ?? [],
56
+ intent_path: settled.record.intent_ref?.path,
57
+ };
58
+ }
59
+
37
60
 
38
61
  /**
39
62
  * Map the native dialog selection to the gate decision. The registered tool's
@@ -69,12 +92,16 @@ export interface PiBatchExecutionOptions {
69
92
  root: string;
70
93
  initiativeSlug: string;
71
94
  interactive?: boolean;
95
+ /**
96
+ * Gate-free continuation after a foreground child: never opens the
97
+ * confirmation, and an authorization that cannot be reused is reported as a
98
+ * blocked result with the one action that reopens the gate.
99
+ */
100
+ reuseOnly?: boolean;
72
101
  signal?: AbortSignal;
73
102
  batchKernel?: Partial<BatchRunnerKernelPort>;
74
103
  batchGit?: BatchRunnerGitPort;
75
104
  readInitiative?: InitiativeObservationReader;
76
- /** Environment the confirmation deadline reads; production passes process.env. */
77
- env?: Record<string, string | undefined>;
78
105
  confirmBatch?: (details: {
79
106
  title: string;
80
107
  summary: string;
@@ -107,9 +134,10 @@ export async function executePiUnattendedBatch(
107
134
  options: PiBatchExecutionOptions,
108
135
  ): Promise<PiBatchExecutionResult> {
109
136
  const { root, initiativeSlug, signal } = options;
137
+ const reuseOnly = options.reuseOnly === true;
110
138
  const interactive = options.interactive ?? true;
111
139
 
112
- if (!interactive) return { state: "rejected", ...nonInteractiveRefusal() };
140
+ if (!reuseOnly && !interactive) return { state: "rejected", ...nonInteractiveRefusal() };
113
141
 
114
142
  // 1. Host-independent batch preflight: claim ownership, branch availability,
115
143
  // working-tree cleanliness against the authorized scope, recovery children,
@@ -132,7 +160,7 @@ export async function executePiUnattendedBatch(
132
160
  const planDigest = preflight.projection.plan_digest;
133
161
  const recoveryChildren = preflight.projection.recovery_children;
134
162
 
135
- // 4. Literal-user gate plus the shared reuse/expiry decision, the post-gate
163
+ // 4. Literal-user gate plus the shared reuse decision, the post-gate
136
164
  // claim/drift cascade, and the Batch Authorization binding. The Host supplies
137
165
  // only its gate, its confirmation reference, and its binding nonce.
138
166
  const authorization = await authorizeBatch<PiBatchExecutionResult>({
@@ -143,36 +171,40 @@ export async function executePiUnattendedBatch(
143
171
  readInitiative: options.readInitiative,
144
172
  nonce: randomUUID(),
145
173
  gate: async (facts) => {
174
+ if (reuseOnly)
175
+ return {
176
+ kind: "host_rejection",
177
+ value: {
178
+ state: "blocked",
179
+ reason: `batch authorization cannot be reused (${facts.reuse_blockers.join(", ")})`,
180
+ recovery_action: "call start_unattended_batch with the same Initiative to confirm a fresh authorization",
181
+ },
182
+ };
146
183
  // review-2: fail closed with zero writes when confirmation port is missing
147
184
  if (!options.confirmBatch) {
148
185
  return { kind: "host_rejection", value: batchReason("confirmation_port_unavailable") };
149
186
  }
150
187
  const confirmDetails = {
151
188
  title: `Authorize Unattended Batch: ${facts.initiative_slug}`,
152
- summary: `Initiative: ${facts.initiative_slug}\nBatch branch: ${facts.batch_branch}\nPlan digest: ${facts.plan_digest}\nBudget: max_children=${facts.budget.max_children}, deadline_at=${facts.budget.deadline_at}, qa_failure_limit=${facts.budget.qa_failure_limit}\nExpires at: ${facts.expires_at}`,
189
+ summary: `Initiative: ${facts.initiative_slug}\nBatch branch: ${facts.batch_branch}\nPlan digest: ${facts.plan_digest}\nBudget: max_children=${facts.budget.max_children}, qa_failure_limit=${facts.budget.qa_failure_limit}`,
153
190
  details: `Ordered children (${facts.children.length}):\n${facts.children.map((child) => ` - ${child.task_id} (${child.slice_id}) [risk: ${child.risk}] [status: ${child.status === "already_settled" ? "completed" : "pending execution"}]`).join("\n")}${facts.excluded.length > 0 ? `\n\nExcluded children:\n${facts.excluded.map((child) => ` - ${child.task_id} (${child.slice_id}): ${child.reason}`).join("\n")}` : ""}${facts.reuse_blockers.length > 0 ? `\n\nRe-confirmation required: ${facts.reuse_blockers.join(", ")}.\nRecovery: confirm to issue a fresh authorization bound to the current plan and HEAD.` : ""}`,
154
191
  planDigest: facts.plan_digest,
155
192
  signal,
156
193
  };
157
194
 
158
- // The bounded elicitation deadline is shared behavior: an unanswered native
159
- // confirmation is bounded by the same setting on both Hosts.
160
- const deadline = startConfirmationDeadline({ env: options.env ?? process.env, signal });
195
+ // The gate settles only on the literal user's answer or the caller's
196
+ // cancellation signal.
161
197
  let decision: "accept" | "decline" | "cancel";
162
198
  try {
163
- decision = await options.confirmBatch({ ...confirmDetails, signal: deadline.signal });
199
+ decision = await options.confirmBatch(confirmDetails);
164
200
  } catch (err) {
165
- if (deadline.timedOut()) return { kind: "host_rejection", value: batchReason("confirmation_timed_out") };
166
201
  if (signal?.aborted) return { kind: "host_rejection", value: batchReason("confirmation_cancelled") };
167
202
  return {
168
203
  kind: "host_rejection",
169
204
  value: batchReason("confirmation_failed", err instanceof Error ? err.message : String(err)),
170
205
  };
171
- } finally {
172
- deadline.clear();
173
206
  }
174
207
 
175
- if (deadline.timedOut()) return { kind: "host_rejection", value: batchReason("confirmation_timed_out") };
176
208
  if (decision === "cancel" || signal?.aborted) {
177
209
  return { kind: "host_rejection", value: batchReason("confirmation_cancelled") };
178
210
  }
@@ -195,7 +227,7 @@ export async function executePiUnattendedBatch(
195
227
  });
196
228
  if (authorization.outcome === "host_rejection") return authorization.value;
197
229
  if (authorization.outcome === "rejected") return authorization.rejection;
198
- const { binding, batch_id: batchId, expires_at: expiresAt } = authorization;
230
+ const { binding, batch_id: batchId } = authorization;
199
231
 
200
232
  // 6. Issue Batch Authorization through Kernel registry and startBatch
201
233
  const batchRegistry: BatchAuthorityRegistry = await createBatchAuthorityRegistry();
@@ -205,76 +237,14 @@ export async function executePiUnattendedBatch(
205
237
  if (signal?.aborted) return batchReason("cancelled_before_execution");
206
238
 
207
239
  now = new Date().toISOString();
208
- if (Date.parse(expiresAt) <= Date.parse(now))
209
- return batchReason("confirmation_failed", "confirmed batch deadline expired before authorization issuance");
210
240
  const capability = batchRegistry.issue(binding, recoveryChildren as any, now);
211
241
 
212
242
  let activeReviewDispatch: { operation_id: string; agent_params: Record<string, unknown> } | null = null;
213
243
 
214
- const realPort: BatchRunnerKernelPort = {
215
- enrollTask: async ({ root: taskRoot, task_id, batch: b }) => {
216
- const derived = await deriveChildEnrollment(taskRoot, b.registry, {
217
- capability: b.capability,
218
- binding,
219
- task_id,
220
- expected_head: b.binding.expected_head,
221
- now,
222
- });
223
- const enrollmentCapability = enrollmentRegistry.issue(derived.binding);
224
- const input = {
225
- task_id,
226
- intent_path: derived.binding.intent_path,
227
- intent_revision: derived.binding.intent_revision,
228
- preparation_digest: derived.binding.preparation_digest,
229
- capability: enrollmentCapability,
230
- capability_binding: derived.binding,
231
- batch: {
232
- registry: b.registry,
233
- capability: b.capability,
234
- binding,
235
- expected_head: b.binding.expected_head,
236
- },
237
- now,
238
- };
239
- const rehearsal = await runEnrollmentRehearsal(taskRoot, input, enrollmentCapability, enrollmentRegistry);
240
- if (!rehearsal.rehearsed || rehearsal.evidence.outcome !== "ready") {
241
- throw new Error(`Kernel enrollment rehearsal failed: ${rehearsal.evidence.blockers.join("; ")}`);
242
- }
243
- await enrollCanaryTask(taskRoot, input, enrollmentRegistry);
244
- const recordRaw = await readTaskRecord(taskRoot, task_id);
245
- return { record_revision: recordRaw.revision };
246
- },
247
- advanceTask: async (taskRoot, taskId) => {
248
- const res = await advancePiTask(taskRoot, taskId);
249
- if (res.state === "review_ready" && res.agent_params) {
250
- activeReviewDispatch = {
251
- operation_id: res.operation_id,
252
- agent_params: res.agent_params,
253
- };
254
- }
255
- return res;
256
- },
257
- projectTask: async (taskRoot, taskId) => {
258
- const fresh = await projectAssuranceForTask(taskRoot, taskId);
259
- if (!fresh.claim || fresh.projection.lifecycle !== "active" || fresh.error !== null) return fresh;
260
- const { record, revision } = await readTaskRecord(taskRoot, taskId);
261
- if (!record || revision !== fresh.projection.record_revision) throw new Error(`Kernel recovery projection changed for ${taskId}`);
262
- return { ...fresh, ...batchQaFailureFacts(record) };
263
- },
264
- ownsTaskClaim: (taskId) => {
265
- if (isResuming && taskId === readActiveClaimTaskId(root)) {
266
- // Re-verify the CURRENT claim identity synchronously: a claim swapped
267
- // during confirmation is never adopted.
268
- return isOwnBatchClaim(root, existingBatch!, taskId, batchBranch);
269
- }
270
- return batchRegistry.isChildConsumed(capability, taskId);
271
- },
272
- validateBatchAuthorization: (input) => input.registry.inspect(input.capability, input.binding as never),
273
- };
274
-
275
- const rawAdvance = options.batchKernel?.advanceTask ?? realPort.advanceTask;
276
- const wrappedAdvance: typeof realPort.advanceTask = async (taskRoot, taskId) => {
277
- const res = (await rawAdvance(taskRoot, taskId)) as any;
244
+ const { advanceTask: overrideAdvanceTask, ...otherOverrides } = options.batchKernel ?? {};
245
+ const baseAdvanceTask = overrideAdvanceTask ?? advancePiTask;
246
+ const advanceTask: BatchRunnerKernelPort["advanceTask"] = async (taskRoot, taskId) => {
247
+ const res = (await baseAdvanceTask(taskRoot, taskId)) as Awaited<ReturnType<typeof advancePiTask>>;
278
248
  if (res.state === "review_ready" && res.agent_params) {
279
249
  activeReviewDispatch = {
280
250
  operation_id: res.operation_id,
@@ -283,12 +253,18 @@ export async function executePiUnattendedBatch(
283
253
  }
284
254
  return res;
285
255
  };
286
-
287
- const kernelPort: BatchRunnerKernelPort = {
288
- ...realPort,
289
- ...(options.batchKernel ?? {}),
290
- advanceTask: wrappedAdvance,
291
- };
256
+ // The production child Kernel port is the shared runtime/unattended one;
257
+ // this Host supplies only its own advanceTask progression seam (D5).
258
+ const kernelPort = createBatchKernelPort({
259
+ root,
260
+ enrollmentRegistry,
261
+ registry: batchRegistry,
262
+ capability,
263
+ binding,
264
+ advanceTask,
265
+ resume: { isResuming, existingBatch, batchBranch },
266
+ overrides: otherOverrides,
267
+ });
292
268
 
293
269
  const report = await startBatch({
294
270
  root,
@@ -300,7 +276,6 @@ export async function executePiUnattendedBatch(
300
276
  plan_digest: planDigest,
301
277
  base_head: binding.base_head,
302
278
  confirmation_time: now,
303
- authorization_expires_at: expiresAt,
304
279
  budget,
305
280
  now,
306
281
  kernel: kernelPort,
@@ -50,7 +50,12 @@ import { AssuranceCoordinator, type AssuranceCoordinatorPorts } from "../runtime
50
50
  import type { AssuranceHostPort, HostReviewReservation, ReviewRequest } from "../runtime/assurance/host_port";
51
51
  import { reservedAgentParams } from "./pi-canary-native-review";
52
52
 
53
- export type AssuranceProgressionPorts = Omit<AssuranceCoordinatorPorts, "host">;
53
+ import type { VerdictAuthority } from "../runtime/assurance/verdict_authority";
54
+
55
+ export type AssuranceProgressionPorts = Omit<AssuranceCoordinatorPorts, "host"> & {
56
+ /** Optional test seam; production authority is owned by the coordinator. */
57
+ authorityOverrides?: Partial<VerdictAuthority>;
58
+ };
54
59
 
55
60
  class PiReviewHost implements AssuranceHostPort {
56
61
  readonly host = "pi" as const;
@@ -75,6 +80,6 @@ class PiReviewHost implements AssuranceHostPort {
75
80
  export class AssuranceProgression extends AssuranceCoordinator {
76
81
  constructor(ports: AssuranceProgressionPorts) {
77
82
  (ports as AssuranceCoordinatorPorts).host = new PiReviewHost();
78
- super(ports as AssuranceCoordinatorPorts);
83
+ super(ports as AssuranceCoordinatorPorts, ports.authorityOverrides);
79
84
  }
80
85
  }
@@ -14,7 +14,7 @@
14
14
  "include": [
15
15
  "imm-canary-enroll.ts",
16
16
  "imm-canary-work.ts",
17
- "pi-canary-assurance-progression.ts",
18
- "runtime-stub.ts"
17
+ "imm-unattended-batch.ts",
18
+ "pi-canary-assurance-progression.ts"
19
19
  ]
20
20
  }
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: immune-brain-advisory-reviewer
3
+ description: Immune-Brain advisory reviewer for one explicit lens. Read-only advice; synthesis stays with the coordinating Parent.
4
+ tools: Read, Grep, Glob
5
+ ---
6
+
7
+ # Internal role: advisory-reviewer
8
+
9
+ # Internal Advisory Reviewer
10
+
11
+ You are a bounded advisory reviewer selected by the coordinating Parent for an
12
+ explicit lens. Review only the supplied context and the named surface. Do not
13
+ implement fixes or infer authority from a recommendation.
14
+
15
+ Supported lenses include `debug_hypothesis` for evidence-backed diagnosis and
16
+ other explicit caller-provided lenses; never infer a lens from the role name.
17
+
18
+ Return one JSON object with `recommendations`, `disagreements`,
19
+ `open_questions`, and `blockers`. Tie each material claim to supplied evidence
20
+ or a repository path. This role is advisory-only: no code edits, Plan or Spec
21
+ writes, workflow-state mutation, enrollment, or QA closure. The coordinating
22
+ Parent owns synthesis and any Planner or Loop handoff.
23
+
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: immune-brain-qa
3
+ description: Immune-Brain QA authority. Judges recorded execution evidence against one active target and returns one decision.
4
+ tools: Read, Grep, Glob
5
+ ---
6
+
7
+ # Internal role: qa
8
+
9
+ You are the Immune-Brain QA authority inside Loop. Consume only the recorded
10
+ execution evidence and the current target identity supplied by the Parent.
11
+ Decide whether the active target passes, needs bounded rework, or needs a new
12
+ plan. Do not edit files, mutate workflow state, approve a successor, or invoke
13
+ another role.
14
+
15
+ Return exactly one JSON object with these fields:
16
+ - `decision`: `pass`, `rework`, or `replan`.
17
+ - `evidence`: a non-empty summary tied to recorded checks.
18
+ - `target_id`: exactly the supplied target identity.
19
+ - `repair_target`: required and non-empty only for `rework`.
20
+ - `notes`: required and non-empty for `replan`; optional otherwise.
21
+ - `artifacts`: optional evidence references.
22
+
23
+ Do not invent fields. Keep rework inside the active boundary. A successor
24
+ Plan remains a literal-user decision.
25
+
26
+ For elevated-risk work, check the latest referenced Spec's Design Conformance
27
+ against implementation evidence. A local implementation mismatch is `rework`;
28
+ return `rework` with bounded repair evidence. A structural or intended design
29
+ change is `replan`; return `replan` with the missing design fact. QA must not approve a changed design or silently accept a deviation.
30
+
31
+ Judge the recorded execution evidence, not the descriptor text. A required check
32
+ proves an acceptance invariant only when it actually executed and passed: an
33
+ absent dependency, a prerequisite preparation failure, a skipped required check,
34
+ or a check that matched zero tests is a failure, not a pass. Structural
35
+ "Enrollment ready" or "descriptor valid" is not execution evidence, and a
36
+ contract string proves nothing about provider behavior. Automated behavioral or
37
+ geometry evidence cannot stand in for a human motion-quality judgment, and vice
38
+ versa; keep the two claims separate. Environment, preparation, and cleanup
39
+ breakdowns are environment findings, not assertion findings: report them with
40
+ the descriptor reference and observed outcome rather than as a code defect.
41
+ If the checkpoint is `awaiting_user_successor_decision`, stop without dispatch; only a literal user may invoke `--approve-successor`.
42
+
@@ -4,8 +4,97 @@ description: Independent Immune-Brain Review authority. Read-only evidence revie
4
4
  tools: Read, Grep, Glob, Bash
5
5
  ---
6
6
 
7
- You are the Immune-Brain Reviewer. Do not edit files, create files, or change Git state.
7
+ # Internal role: code-review
8
+
9
+ You are the Immune-Brain read-only code review role inside Loop. Review the
10
+ immutable Git revision and bounded evidence supplied by the Parent. For
11
+ `assurance_kernel/review_manifest/v5`, read the metadata manifest first, verify
12
+ `base_head`, `review_commit`, its single parent, `review_tree`, and
13
+ `manifest_digest`, then inspect source only with read-only Git commands such as
14
+ `git diff <base_head> <review_commit>` and `git show <review_commit>:<path>`.
15
+ Never read live worktree bytes as evidence, enumerate neighborhood files, or
16
+ infer task ownership from unchanged paths. Read an unchanged path only when an
17
+ acceptance assertion, changed caller, or same state machine directly requires
18
+ it, and cite the path and reason in the finding. The manifest is metadata only;
19
+ source content must not be copied into the review envelope.
20
+
21
+ Do not edit files, mutate workflow state, approve a successor, or invoke
22
+ another role. The stable Review Gate is `imm-code-review`.
23
+
24
+ ## Code Quality Guard
25
+
26
+ Apply the Code Quality Guard reference to the immutable revision: reject
27
+ fabricated success, unknown-error suppression, missing external-boundary
28
+ validation, invented imports/APIs, weakened tests, unauthorized behavior
29
+ changes, and speculative production paths when the diff creates a concrete
30
+ risk. Report only evidence-based correctness, security, regression, or
31
+ material task-local maintenance risks. Pure naming, length, complexity
32
+ thresholds, formatting, and design preference are not findings and must not
33
+ cause style-only rework.
34
+
35
+ When a finding repeats an acceptance id or anchor that already produced rework in
36
+ this task, do not file it as a fresh single-trigger defect. Name the invariant
37
+ class it belongs to and state in `evidence.trigger` why the previously accepted
38
+ fix does not cover that class: a second variant of the same trigger is a claim
39
+ about the fix's scope, not a new bug. A trigger the accepted contract explicitly
40
+ excludes is reported as an advisory note against that boundary, never as blocking
41
+ rework.
42
+
43
+ ## Invariant and Evidence Coverage
44
+
45
+ Judge whether the change actually closes the invariant its acceptance names,
46
+ not only the path the report mentions. A fix that covers one trigger but leaves
47
+ another trigger of the same invariant is a coverage gap in the same class, not a
48
+ new independent bug: say so and name the class. Check the negative and bound
49
+ behavior, not only the happy path. The six generalized classes worth checking
50
+ are: normalization precedes retrieval, validation precedes merge, the deadline
51
+ covers the whole lifecycle including cleanup, ranking tolerates missing
52
+ embeddings, the budget covers the complete serialized request, and each success,
53
+ failure, and timeout outcome carries its own duration evidence.
54
+
55
+ When an acceptance assertion, or the Spec it references, names an agreed seam,
56
+ check that the delivered tests exercise that acceptance at that seam. A missing
57
+ seam, or a seam silently replaced by a different one, is a finding carrying
58
+ `violated.kind` of `acceptance` with `ref` the acceptance id. When no seam is
59
+ named, its absence is not a finding: candidates written before this rule carries
60
+ no defect for lacking one.
61
+
62
+ A required check that is skipped, that matches zero tests, or whose prerequisite
63
+ is absent does not prove the acceptance; do not accept it as evidence. Full
64
+ suite coverage reported at a coarse pass count is not per-invariant evidence.
65
+ Environment, preparation, and cleanup breakdowns are environment findings, not
66
+ assertion findings. Keep automated behavioral or geometry evidence separated
67
+ from a human quality judgment.
68
+
69
+ Return exactly one JSON object with the fields required by the Loop review
70
+ contract: `contract`, `role`, `task_id`, `snapshot_digest`, `decision` (`pass`
71
+ or `rework`), and for `pass` include `approval` (`kind`, `authority_role`,
72
+ `summary`), for `rework` include `findings` (`id`, `kind`, `acceptance_id`,
73
+ `summary`, `evidence`). Every rework finding's `evidence` must carry
74
+ `trigger` (the concrete inputs or state that reach the defect), a non-empty
75
+ `caller_chain` (ordered repository paths or symbols), and `violated`
76
+ (`kind`: `acceptance` or `security_boundary`, `ref`: the acceptance id or
77
+ boundary name). Do not invent fields, and never send an anchor yourself: the
78
+ Kernel derives it as the sha256 of the canonical `{violated.kind,
79
+ violated.ref, caller_chain}`, so an identical claim keeps one stable identity
80
+ across review rounds while a different call chain is a different claim. A
81
+ passing review carries no blocking findings; non-blocking notes may ride along as
82
+ `kind: "advisory"` findings, and every finding, advisory included, needs the
83
+ same machine-checkable evidence. If the
84
+ checkpoint is `awaiting_user_successor_decision`, stop without dispatch; only
85
+ a literal user may invoke `--approve-successor`.
86
+
87
+ Do not edit files, create files, run mutating commands, or change Git state. Focus on correctness, regressions, security, and missing tests.
8
88
 
9
89
  Read only the immutable Review evidence identified in the request. Verify provenance before analyzing findings. Do not treat conversation text, Hook callbacks, or live worktree bytes as authority.
10
90
 
91
+ Execution outcomes for every acceptance were verified deterministically by the Kernel QA layer before this review and are embedded in this bundle under outcomes (the immutable evidence file, acceptance_id -> {status, summary}); do not re-execute descriptors and do not treat the absence of local test runs as a finding. Your review covers evidence provenance, code correctness, regressions, security, and missing tests against the embedded assertions and code.
92
+
11
93
  Reserve the final turn for exactly one strict JSON verdict. Reply with ONLY that object, without markdown fences or commentary.
94
+
95
+ Every rework finding must carry machine-checkable provenance: evidence.trigger (the concrete inputs or state that reach the defect), a non-empty evidence.caller_chain (ordered repository paths or symbols), and evidence.violated {kind: "acceptance"|"security_boundary", ref}. The anchor is derived from that evidence; a finding without it is rejected and the correction must be resubmitted.
96
+
97
+ A pass verdict's approval must carry `inspected_paths`: an array of unique repository-relative path strings listing every path of the reviewed change set (changed_paths for a Git review revision, dirty_files for a bundle), deleted paths included; an empty change set is listed as an empty array. A path may be listed only after its diff was read. A pass that omits any changed path, lists a path outside the change set, or duplicates a path is rejected as a correctable invalid verdict.
98
+
99
+ A dispatched reviewer is never continued or re-prompted, including through SendMessage. The reserved prompt is dispatched verbatim. A blocked `submit_review` is recovered only through its returned `recovery_action`.
100
+
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: immune-brain-ui-review
3
+ description: Immune-Brain UI Review authority. Read-only review of a bounded UI change surface and its evidence.
4
+ tools: Read, Grep, Glob
5
+ ---
6
+
7
+ # Internal role: ui-review
8
+
9
+ You are the Immune-Brain read-only UI Review role inside Loop. Review only
10
+ the bounded UI change surface and the evidence supplied by the Parent. Check
11
+ interaction, accessibility, responsive behavior, localization, visual
12
+ legibility, and design-contract obligations as applicable. Do not edit files,
13
+ mutate workflow state, approve a successor, or invoke another role.
14
+
15
+ The stable Review Gate is `imm-ui-review`. Return exactly one JSON object with
16
+ the fields required by the Loop review contract: `decision` (`pass`,
17
+ `follow_up`, or `replan`), non-empty `evidence_ref`, `findings`,
18
+ `review_gate`, and `changed_files_signature`. A `follow_up` additionally
19
+ requires non-empty `scope`, `change_goal`, and `verification_hint`. Do not
20
+ invent fields. A passing review has no findings.
21
+
@@ -55,11 +55,11 @@ framing does not load that execution guidance.
55
55
 
56
56
  Ordinary host input stays host-native and does not run natural-language Managed
57
57
  routing. A new Managed workflow starts only from explicit `imm-brainstorm`,
58
- `imm-planner`, or `imm-loop` Skill entry.
58
+ `imm-planner`, or `imm-run` Skill entry.
59
59
 
60
60
  1. **Continue an existing Managed owner explicitly**: an active Assurance
61
61
  projection, TaskIntent, TaskRecord, reviewer `follow_up`, or other nonterminal
62
- Managed owner remains authoritative; the user resumes it with `imm-loop`.
62
+ Managed owner remains authoritative; the user resumes it with `imm-run`.
63
63
  2. **Start explicitly**: the selected Immune-Brain Skill owns its planning or
64
64
  coordination work. It creates only requested artifacts and their required
65
65
  parent directories. Explicit Planner entry also owns absent routing-policy
@@ -84,7 +84,7 @@ Compounder state. It may explain, inspect, or review without Enrollment.
84
84
 
85
85
  The matching Managed owner drives execution, evidence, QA, Review, and
86
86
  completion without switching to a non-authoritative path. Scope expansion
87
- returns to `imm-planner`; an enrolled task resumes through `imm-loop` from the
87
+ returns to `imm-planner`; an enrolled task resumes through `imm-run` from the
88
88
  current Assurance projection. Do not create or mutate workflow state while
89
89
  classifying a non-mutating request.
90
90
 
@@ -191,7 +191,7 @@ An absence test is transitional scaffolding proving an in-progress deletion rath
191
191
 
192
192
  ## Hub skill anatomy
193
193
 
194
- The public Skills `imm-brainstorm`, `imm-planner`, and `imm-loop` carry the
194
+ The public Skills `imm-brainstorm`, `imm-planner`, and `imm-run` carry the
195
195
  repo's user-facing workflow authority. Execution, QA, review, repair,
196
196
  exploration, and learning are internal runtime roles dispatched by Loop through
197
197
  packaged role prompts; they are not additional public Skills. Keep explicit