immune-brain 4.6.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 (64) hide show
  1. package/README.md +154 -37
  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 -44
  6. package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +142 -474
  7. package/plugins/immune-brain/.pi-extension/imm-unattended-batch.ts +54 -84
  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 +7369 -7016
  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 +23 -8
  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} +33 -7
  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 +83 -67
  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/verdict_authority.ts +347 -0
  32. package/plugins/immune-brain/runtime/claude/kernel_ports.ts +62 -369
  33. package/plugins/immune-brain/runtime/claude/mcp_server.ts +2 -0
  34. package/plugins/immune-brain/runtime/claude/review_host.ts +48 -16
  35. package/plugins/immune-brain/runtime/claude/role_agents.ts +83 -0
  36. package/plugins/immune-brain/runtime/commands/kernel.ts +3 -6
  37. package/plugins/immune-brain/runtime/kernel/application.ts +6 -3
  38. package/plugins/immune-brain/runtime/kernel/assurance_projection.ts +15 -8
  39. package/plugins/immune-brain/runtime/kernel/canary_application.ts +5 -3
  40. package/plugins/immune-brain/runtime/kernel/enrollment.ts +149 -5
  41. package/plugins/immune-brain/runtime/kernel/index.ts +3 -1
  42. package/plugins/immune-brain/runtime/kernel/storage.ts +170 -11
  43. package/plugins/immune-brain/runtime/kernel/storage_paths.ts +13 -0
  44. package/plugins/immune-brain/runtime/loop_contract.ts +22 -22
  45. package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
  46. package/plugins/immune-brain/runtime/prompts/code-review.md +7 -0
  47. package/plugins/immune-brain/runtime/prompts/executor.md +35 -2
  48. package/plugins/immune-brain/runtime/role_prompt_bridge.ts +27 -0
  49. package/plugins/immune-brain/runtime/unattended/batch_git.ts +57 -27
  50. package/plugins/immune-brain/runtime/unattended/batch_kernel_port.ts +106 -0
  51. package/plugins/immune-brain/runtime/unattended/batch_preflight.ts +12 -14
  52. package/plugins/immune-brain/runtime/unattended/batch_reconfirmation.ts +34 -29
  53. package/plugins/immune-brain/runtime/unattended/batch_runner.ts +26 -90
  54. package/plugins/immune-brain/runtime/workspace_scope.ts +34 -0
  55. package/plugins/immune-brain/skills/BASELINE.md +4 -4
  56. package/plugins/immune-brain/skills/imm-doc-prune/SKILL.md +1 -1
  57. package/plugins/immune-brain/skills/{imm-agent-doc-maintain → imm-doc-slim}/SKILL.md +9 -9
  58. package/plugins/immune-brain/skills/imm-planner/SKILL.md +4 -2
  59. package/plugins/immune-brain/skills/imm-pr-fix/SKILL.md +1 -1
  60. package/plugins/immune-brain/skills/{imm-review-retro → imm-retro}/SKILL.md +7 -7
  61. package/plugins/immune-brain/skills/{imm-review-retro → imm-retro}/scripts/review_retro.ts +46 -21
  62. package/plugins/immune-brain/skills/{imm-loop → imm-run}/SKILL.md +7 -7
  63. package/plugins/immune-brain/skills/registry.yaml +9 -9
  64. package/plugins/immune-brain/.pi-extension/runtime-stub.ts +0 -581
@@ -1,14 +1,14 @@
1
1
  ---
2
- name: imm-review-retro
2
+ name: imm-retro
3
3
  description: Use when the user explicitly requests Immune-Brain ranking of models by cross-model review load or a project usage retro.
4
4
  ---
5
5
 
6
- # Immune-Brain: Review Retro
6
+ # Immune-Brain: Retro
7
7
 
8
- Use [`../../dist/imm-review-retro.md`](../../dist/imm-review-retro.md) as the
8
+ Use [`../../dist/imm-retro.md`](../../dist/imm-retro.md) as the
9
9
  canonical contract index, not a whole-document read. This is a
10
10
  standalone host-native analysis entry, not a Managed Path continuation
11
- and not an `imm-loop` internal-role dispatch.
11
+ and not an `imm-run` internal-role dispatch.
12
12
 
13
13
  Mandatory constraints: read-only on pi session logs. Do not edit code, tests,
14
14
  Specs, or workflow state. Do not write session logs or `.imm/` files.
@@ -18,6 +18,6 @@ Read each linked heading body up to the next heading; nested sections and
18
18
  references load only under their own condition. Never read the whole contract
19
19
  or all references as an entry prerequisite.
20
20
 
21
- - common: [Boundary](../../dist/imm-review-retro.md#boundary), [Invocation](../../dist/imm-review-retro.md#invocation)
22
- - running the analyzer: [Counting rules](../../dist/imm-review-retro.md#counting-rules), [CLI](../../dist/imm-review-retro.md#cli)
23
- - interpreting the report: [Report](../../dist/imm-review-retro.md#report), [Caveats](../../dist/imm-review-retro.md#caveats)
21
+ - common: [Boundary](../../dist/imm-retro.md#boundary), [Invocation](../../dist/imm-retro.md#invocation)
22
+ - running the analyzer: [Counting rules](../../dist/imm-retro.md#counting-rules), [CLI](../../dist/imm-retro.md#cli)
23
+ - interpreting the report: [Report](../../dist/imm-retro.md#report), [Caveats](../../dist/imm-retro.md#caveats)
@@ -5,11 +5,13 @@
5
5
  * Usage: bun review_retro.ts <days> [--root <sessions-dir>] [--project <substr>] [--top N]
6
6
  *
7
7
  * Counting rules (the 口径 that keeps the numbers honest):
8
- * review executed = Agent(subagent_type="Review") tool call
9
- * avgSc / pass% = average score (0-10) and PASS rate from [SCORE: ...] tags in Review toolResult
8
+ * review executed = Agent(subagent_type="Review", any case) tool call
9
+ * avgSc = average score (0-10) from [SCORE: ...] tags in Review toolResult (the contract has no score)
10
+ * pass% = PASS rate over judged reviews: assurance_verdict `decision`, else the [VERDICT: ...] tag
10
11
  * kernel:submit_review = the *registration* of that same review, reported separately (never added)
11
- * attribution = the model behind the most recent edit/write before the review (the code's author)
12
- * findings = imm_kernel_canary record_finding, deduped per session, harness bookkeeping split out
12
+ * attribution = the model behind the most recent edit/write/apply_patch before the review (the code's author)
13
+ * findings = submit_review verdict.findings plus legacy record_finding, deduped per session,
14
+ * harness bookkeeping split out
13
15
  */
14
16
  import { createReadStream, existsSync, readdirSync } from "node:fs";
15
17
  import { homedir } from "node:os";
@@ -18,12 +20,14 @@ import { createInterface } from "node:readline";
18
20
  import { pathToFileURL } from "node:url";
19
21
 
20
22
  const BOOKKEEPING = /recorded cleanly|receipt recorded|round recorded|no findings?\b/i;
21
- const EDIT_TOOLS = new Set(["edit", "write", "multiedit"]);
23
+ const EDIT_TOOLS = new Set(["edit", "write", "multiedit", "apply_patch"]);
22
24
  const SCORE_RE = /\[SCORE:\s*([\d.]+)\s*(?:\/\s*10)?\]/i;
23
25
  const VERDICT_RE = /\[VERDICT:\s*(\w+)\]/i;
24
26
  const RISK_RE = /\[RISK:\s*(\w+)\]/i;
25
27
  const BLOCK_RE = /\[BLOCKING:\s*(\d+)\]/i;
26
28
  const ADVIS_RE = /\[ADVISORY:\s*(\d+)\]/i;
29
+ const VERDICT_CONTRACT = "assurance_kernel/assurance_verdict";
30
+ const DECISION_RE = /"decision"\s*:\s*"(\w+)"/;
27
31
 
28
32
  type ReviewTag = {
29
33
  score: number;
@@ -48,6 +52,11 @@ function parseReviewTag(text: string): ReviewTag | null {
48
52
  };
49
53
  }
50
54
 
55
+ function parseDecision(text: string): string | null {
56
+ if (!text.includes(VERDICT_CONTRACT)) return null;
57
+ return DECISION_RE.exec(text)?.[1]?.toLowerCase() ?? null;
58
+ }
59
+
51
60
  function extractText(content: unknown): string {
52
61
  if (typeof content === "string") return content;
53
62
  if (Array.isArray(content)) {
@@ -136,6 +145,8 @@ export async function run(argv: string[]): Promise<string> {
136
145
  const findingsRaw = new Map<string, number>();
137
146
  const scores = new Map<string, number[]>();
138
147
  const verdicts = new Map<string, number>();
148
+ const judged = new Map<string, number>();
149
+ const passed = new Map<string, number>();
139
150
  const risks = new Map<string, number>();
140
151
  let files = 0;
141
152
 
@@ -144,6 +155,16 @@ export async function run(argv: string[]): Promise<string> {
144
155
  let cwd = "";
145
156
  let used = false;
146
157
  const pending = new Map<string, string>();
158
+ const addFinding = (owner: string, finding: unknown) => {
159
+ const f = norm(finding);
160
+ const summ = String(f.summary ?? "");
161
+ const kind = BOOKKEEPING.test(summ) ? "bookkeeping" : String(f.kind ?? "");
162
+ const rawKey = `${owner}\0${kind}`;
163
+ bump(findingsRaw, rawKey);
164
+ const uniq = findUniq.get(rawKey) ?? new Set();
165
+ uniq.add(`${path}\0${summ.slice(0, 160)}`);
166
+ findUniq.set(rawKey, uniq);
167
+ };
147
168
  const rl = createInterface({ input: createReadStream(path, { encoding: "utf8" }) });
148
169
  for await (const raw of rl) {
149
170
  const line = raw.trim();
@@ -179,7 +200,7 @@ export async function run(argv: string[]): Promise<string> {
179
200
  if (EDIT_TOOLS.has(name)) {
180
201
  bump(dev, mo);
181
202
  editor = mo;
182
- } else if (name === "Agent" && a.subagent_type === "Review") {
203
+ } else if (name === "Agent" && String(a.subagent_type ?? "").toLowerCase() === "review") {
183
204
  const owner = editor ?? "no-edit (review-only)";
184
205
  bump(rev, owner);
185
206
  const ep = episode.get(owner) ?? new Set();
@@ -197,15 +218,10 @@ export async function run(argv: string[]): Promise<string> {
197
218
  const t = tasks.get(owner) ?? new Set();
198
219
  t.add(`${cwd}\0${String(a.task_id ?? "")}`);
199
220
  tasks.set(owner, t);
221
+ const found = norm(act.verdict).findings;
222
+ if (Array.isArray(found)) for (const f of found) addFinding(owner, f);
200
223
  } else if (op === "record_finding") {
201
- const f = norm(act.finding);
202
- const summ = String(f.summary ?? "");
203
- const kind = BOOKKEEPING.test(summ) ? "bookkeeping" : String(f.kind ?? "");
204
- const rawKey = `${owner}\0${kind}`;
205
- bump(findingsRaw, rawKey);
206
- const uniq = findUniq.get(rawKey) ?? new Set();
207
- uniq.add(`${path}\0${summ.slice(0, 160)}`);
208
- findUniq.set(rawKey, uniq);
224
+ addFinding(owner, act.finding);
209
225
  }
210
226
  }
211
227
  }
@@ -214,7 +230,13 @@ export async function run(argv: string[]): Promise<string> {
214
230
  const owner = pending.get(tcid);
215
231
  if (!owner) continue;
216
232
  pending.delete(tcid);
217
- const tag = parseReviewTag(extractText(m.content));
233
+ const text = extractText(m.content);
234
+ const tag = parseReviewTag(text);
235
+ const decision = parseDecision(text);
236
+ if (decision || tag) {
237
+ bump(judged, owner);
238
+ if (decision ? decision === "pass" : tag?.verdict === "PASS") bump(passed, owner);
239
+ }
218
240
  if (!tag) continue;
219
241
  const sl = scores.get(owner) ?? [];
220
242
  sl.push(tag.score);
@@ -230,7 +252,9 @@ export async function run(argv: string[]): Promise<string> {
230
252
  const emit = (s = "") => lines.push(s);
231
253
  emit(`window: last ${args.days}d (UTC >= ${cut}Z) | sessions with activity: ${files} | root: ${args.root}`);
232
254
  emit("review = Agent(Review) executed; attributed to the model that last edited the code under review");
233
- emit("avgSc/pass% = parsed from Review [SCORE: .../10] [VERDICT: ...] tags (shows '-' if untagged)");
255
+ emit("avgSc = parsed from Review [SCORE: .../10] tags (shows '-' if untagged)");
256
+ emit("pass% = assurance_verdict decision, else the [VERDICT: ...] tag, over judged reviews (shows '-' if none)");
257
+ emit("block/advis = submit_review verdict.findings plus legacy record_finding, deduped per session");
234
258
  emit("");
235
259
  const hdr =
236
260
  `${"model".padEnd(42)}${"devEdits".padStart(9)}${"turns".padStart(6)}${"reviews".padStart(8)}${"uniq".padStart(5)}${"rev/100ed".padStart(10)}${"avgSc".padStart(6)}${"pass%".padStart(6)}${"registr".padStart(8)}${"block".padStart(6)}${"advis".padStart(6)}${"noisy".padStart(6)}`;
@@ -250,8 +274,8 @@ export async function run(argv: string[]): Promise<string> {
250
274
  const rate = d ? ((100 * r) / d).toFixed(1) : "-";
251
275
  const sl = scores.get(mo) ?? [];
252
276
  const avgSc = sl.length ? (sl.reduce((x, y) => x + y, 0) / sl.length).toFixed(1) : "-";
253
- const passCnt = verdicts.get(`${mo}\0PASS`) ?? 0;
254
- const passPct = sl.length ? `${Math.round((100 * passCnt) / sl.length)}%` : "-";
277
+ const judgedCnt = judged.get(mo) ?? 0;
278
+ const passPct = judgedCnt ? `${Math.round((100 * (passed.get(mo) ?? 0)) / judgedCnt)}%` : "-";
255
279
  const block = findUniq.get(`${mo}\0blocking`)?.size ?? 0;
256
280
  const advis = findUniq.get(`${mo}\0advisory`)?.size ?? 0;
257
281
  const noisy = findUniq.get(`${mo}\0bookkeeping`)?.size ?? 0;
@@ -264,8 +288,9 @@ export async function run(argv: string[]): Promise<string> {
264
288
  const totAvg = totalScores.length
265
289
  ? (totalScores.reduce((x, y) => x + y, 0) / totalScores.length).toFixed(1)
266
290
  : "-";
267
- const totPass = shown.reduce((n, mo) => n + (verdicts.get(`${mo}\0PASS`) ?? 0), 0);
268
- const totPassPct = totalScores.length ? `${Math.round((100 * totPass) / totalScores.length)}%` : "-";
291
+ const totPass = shown.reduce((n, mo) => n + (passed.get(mo) ?? 0), 0);
292
+ const totJudged = shown.reduce((n, mo) => n + (judged.get(mo) ?? 0), 0);
293
+ const totPassPct = totJudged ? `${Math.round((100 * totPass) / totJudged)}%` : "-";
269
294
  const totBlock = [...findUniq.entries()].reduce((n, [k, v]) => n + (k.endsWith("\0blocking") ? v.size : 0), 0);
270
295
  const totAdvis = [...findUniq.entries()].reduce((n, [k, v]) => n + (k.endsWith("\0advisory") ? v.size : 0), 0);
271
296
  const totNoisy = [...findUniq.entries()].reduce((n, [k, v]) => n + (k.endsWith("\0bookkeeping") ? v.size : 0), 0);
@@ -286,7 +311,7 @@ export async function run(argv: string[]): Promise<string> {
286
311
  else for (const [name, n] of toolRows) emit(`${String(n).padStart(5)} ${name}`);
287
312
 
288
313
  emit("");
289
- emit("=== review quality & scores (new rubric) ===");
314
+ emit("=== review quality & scores (tagged reviews only) ===");
290
315
  const scoredModels = [...scores.keys()]
291
316
  .filter((m) => (scores.get(m) ?? []).length > 0)
292
317
  .sort((a, b) => (scores.get(b)?.length ?? 0) - (scores.get(a)?.length ?? 0));
@@ -1,11 +1,11 @@
1
1
  ---
2
- name: imm-loop
2
+ name: imm-run
3
3
  description: Use when the user explicitly requests execution or resumption of an Immune-Brain task.
4
4
  ---
5
5
 
6
6
  # Immune-Brain: Loop
7
7
 
8
- Use [`../../dist/imm-loop.md`](../../dist/imm-loop.md) as the canonical contract
8
+ Use [`../../dist/imm-run.md`](../../dist/imm-run.md) as the canonical contract
9
9
  index, not a whole-document read, in the current host conversation. Explicit entry only:
10
10
  ordinary host input never resumes a Managed owner implicitly.
11
11
 
@@ -23,8 +23,8 @@ Read each linked heading body up to the next heading; nested sections and
23
23
  references load only under their own condition. Never read the whole contract
24
24
  or all references as an entry prerequisite.
25
25
 
26
- - common: [Shared Guards](../../dist/BASELINE.md#shared-guards), [Workflow Activation](../../dist/BASELINE.md#workflow-activation), [Host Confirmation Boundary](../../dist/BASELINE.md#host-confirmation-boundary), [Kernel Canary Routing and Authority](../../dist/imm-loop.md#kernel-canary-routing-and-authority)
27
- - unattended batch run, or any question about whether `imm-loop` starts one: [Unattended Batch Opt-In](../../dist/imm-loop.md#unattended-batch-opt-in)
28
- - steady execution: [Verification and Local Recovery](../../dist/BASELINE.md#verification-and-local-recovery), [Execution Loop](../../dist/imm-loop.md#execution-loop), [Observable Output](../../dist/imm-loop.md#observable-output)
29
- - rework, scope expansion, breaking revision, user decision, stop, interruption or unknown state before any action: [Decisions and Recovery](../../dist/imm-loop.md#decisions-and-recovery), [Failure Output](../../dist/imm-loop.md#failure-output); re-read `status`, then the pending obligation. Rework submits the verdict before editing, and an uncertain interruption resumes from exact task/run authority facts rather than a summary.
30
- - review or post-settlement learning: [Review and Learning](../../dist/imm-loop.md#review-and-learning)
26
+ - common: [Shared Guards](../../dist/BASELINE.md#shared-guards), [Workflow Activation](../../dist/BASELINE.md#workflow-activation), [Host Confirmation Boundary](../../dist/BASELINE.md#host-confirmation-boundary), [Kernel Canary Routing and Authority](../../dist/imm-run.md#kernel-canary-routing-and-authority)
27
+ - unattended batch run, or any question about whether `imm-run` starts one: [Unattended Batch Opt-In](../../dist/imm-run.md#unattended-batch-opt-in)
28
+ - steady execution: [Verification and Local Recovery](../../dist/BASELINE.md#verification-and-local-recovery), [Execution Loop](../../dist/imm-run.md#execution-loop), [Observable Output](../../dist/imm-run.md#observable-output)
29
+ - rework, scope expansion, breaking revision, user decision, stop, interruption or unknown state before any action: [Decisions and Recovery](../../dist/imm-run.md#decisions-and-recovery), [Failure Output](../../dist/imm-run.md#failure-output); re-read `status`, then the pending obligation. Rework submits the verdict before editing, and an uncertain interruption resumes from exact task/run authority facts rather than a summary.
30
+ - review or post-settlement learning: [Review and Learning](../../dist/imm-run.md#review-and-learning)
@@ -18,10 +18,10 @@ skills:
18
18
  role_class: authority
19
19
  canonical: true
20
20
  output_artifacts: [validated_plan]
21
- next_actions: [imm-loop]
21
+ next_actions: [imm-run]
22
22
  boundary: Owns plan creation and revision; no executor edits.
23
- - name: imm-loop
24
- path: skills/imm-loop/SKILL.md
23
+ - name: imm-run
24
+ path: skills/imm-run/SKILL.md
25
25
  role: coordinate
26
26
  title: Run
27
27
  role_class: coordinator
@@ -47,19 +47,19 @@ skills:
47
47
  output_artifacts: [prune_report]
48
48
  next_actions: []
49
49
  boundary: Prune stale current documentation after explicit manifest approval; no Managed authority mutation or authority-artifact deletion.
50
- - name: imm-agent-doc-maintain
51
- path: skills/imm-agent-doc-maintain/SKILL.md
50
+ - name: imm-doc-slim
51
+ path: skills/imm-doc-slim/SKILL.md
52
52
  role: execute
53
- title: Agent Doc Maintain
53
+ title: Doc Slim
54
54
  role_class: repair
55
55
  canonical: true
56
56
  output_artifacts: [maintain_report]
57
57
  next_actions: []
58
58
  boundary: Minimize tracked agent-instruction context after explicit manifest approval; no Managed authority mutation, contract installation, or reference-document creation.
59
- - name: imm-review-retro
60
- path: skills/imm-review-retro/SKILL.md
59
+ - name: imm-retro
60
+ path: skills/imm-retro/SKILL.md
61
61
  role: execute
62
- title: Review Retro
62
+ title: Retro
63
63
  role_class: discovery
64
64
  canonical: true
65
65
  output_artifacts: [retro_report]