immune-brain 3.6.6 → 3.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -3
- package/README.zh-CN.md +23 -3
- package/package.json +2 -1
- package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
- package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +29 -19
- package/plugins/immune-brain/.pi-extension/imm-unattended-batch.ts +932 -0
- package/plugins/immune-brain/.pi-extension/runtime-stub.ts +200 -2
- package/plugins/immune-brain/dist/claude/mcp-server.mjs +3404 -227
- package/plugins/immune-brain/dist/imm-loop.md +22 -0
- package/plugins/immune-brain/dist/role-prompts/code-review.md +9 -1
- package/plugins/immune-brain/runtime/assurance/coordinator.ts +101 -3
- package/plugins/immune-brain/runtime/claude/interaction.ts +16 -3
- package/plugins/immune-brain/runtime/claude/kernel_ports.ts +840 -17
- package/plugins/immune-brain/runtime/claude/mcp_server.ts +72 -10
- package/plugins/immune-brain/runtime/kernel/canary_application.ts +9 -0
- package/plugins/immune-brain/runtime/kernel/completion.ts +19 -1
- package/plugins/immune-brain/runtime/kernel/reducer.ts +162 -11
- package/plugins/immune-brain/runtime/kernel/refutation.ts +82 -0
- package/plugins/immune-brain/runtime/kernel/types.ts +34 -1
- package/plugins/immune-brain/runtime/kernel/validation.ts +202 -9
- package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
- package/plugins/immune-brain/runtime/prompts/code-review.md +9 -1
- package/plugins/immune-brain/runtime/unattended/batch_git.ts +775 -0
- package/plugins/immune-brain/runtime/unattended/batch_plan.ts +203 -0
- package/plugins/immune-brain/runtime/unattended/batch_runner.ts +1224 -0
- package/plugins/immune-brain/runtime/unattended/batch_state.ts +360 -0
- package/plugins/immune-brain/runtime/unattended/types.ts +60 -0
- package/plugins/immune-brain/skills/imm-loop/SKILL.md +1 -0
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ Immune-Brain adds a structured engineering workflow on top of Pi:
|
|
|
13
13
|
- **You describe what you want** in natural language — the agent figures out whether to clarify, plan, or execute.
|
|
14
14
|
- **Plans become trackable tasks** (`TaskIntent` + `TaskRecord`) so progress survives across sessions, not just chat history.
|
|
15
15
|
- **Quality is enforced by code, not promises** — automated QA and isolated review must pass before a task is marked done.
|
|
16
|
+
- **Ready Initiatives can run as a batch** — one confirmed batch authorization lets `imm-loop` work through a published Initiative's children serially, while every child is still enrolled, QA'd, reviewed, and settled on its own.
|
|
16
17
|
|
|
17
18
|
Pi and Claude Code are the supported hosts. Undeclared adapters remain unsupported. Minimum Claude Code is `2.1.236`, the lowest version verified with interactive server-initiated MCP elicitation. Current real-Host evidence is recorded in [Claude native elicitation conformance](docs/verification/claude-native-elicitation-authority-conformance.md); historical reports remain under [docs/verification/archive/](docs/verification/archive/). Either host can use the model provider you configure — Immune-Brain works on top of Kernel authority, not a vendor chat.
|
|
18
19
|
|
|
@@ -25,6 +26,7 @@ Pi and Claude Code are the supported hosts. Undeclared adapters remain unsupport
|
|
|
25
26
|
- [How to Use](#how-to-use)
|
|
26
27
|
- [The 6 Skills](#the-6-skills)
|
|
27
28
|
- [Lifecycle](#lifecycle)
|
|
29
|
+
- [Unattended Batch Runs](#unattended-batch-runs)
|
|
28
30
|
- [Configuration](#configuration)
|
|
29
31
|
- [Project Layout](#project-layout)
|
|
30
32
|
- [FAQ](#faq)
|
|
@@ -85,6 +87,7 @@ You rarely need to remember skill names — **just describe your intent**:
|
|
|
85
87
|
| Idea is fuzzy, needs scoping | "Help me think through a notification system" | → `imm-brainstorm` clarifies questions, no code changes |
|
|
86
88
|
| Goal is clear, needs a plan | "Plan the dark-mode feature" or let Pi route there | → `imm-planner` writes `TaskIntent` + specs in `docs/plans/` |
|
|
87
89
|
| Plan is approved, ready to build | "Start building" / `imm-loop` | → Executor builds, QA verifies, Review checks |
|
|
90
|
+
| A published Initiative is ready to run | "Run initiative `<slug>` unattended" | → Host's `start_unattended_batch`: one native confirmation covers the ordered plan digest, children run serially |
|
|
88
91
|
| PR needs fixes after review | `imm-pr-fix` on that PR | → Standalone repair, no new managed task |
|
|
89
92
|
| Docs are stale after changes | `imm-doc-prune` with manifest | → Prunes only approved stale docs |
|
|
90
93
|
| Agent instruction files are bloated | `imm-agent-doc-maintain` with manifest | → Keeps only necessary non-discoverable rules |
|
|
@@ -131,6 +134,7 @@ The three Managed skills form one continuous pipeline with a single authority mo
|
|
|
131
134
|
- **Trigger:** explicit `imm-loop` (start, resume, or check a managed task).
|
|
132
135
|
- **What it does:** drives one task end to end through foreground tools — Executor edits inside the frozen scope, deterministic QA executes every acceptance descriptor, an isolated Review subagent audits material/critical tasks, and the Kernel settles terminal evidence. Interrupted workflows resume from on-disk state; the Kernel projection is authoritative.
|
|
133
136
|
- **What it never does:** skips or weakens a failing check, runs without your Enrollment/revision/authorization gates, or continues after lineage or authority drift — it fails closed.
|
|
137
|
+
- **Finding evidence:** every Review finding carries machine-checkable provenance (`trigger`, `caller_chain`, `violated`). A claim that fresh passing QA evidence already contradicts is recorded as `refuted` and only blocks again if that evidence goes stale.
|
|
134
138
|
- **Exit:** `done` task record with QA + Review attestations in `.imm/audit/<task-id>/`.
|
|
135
139
|
|
|
136
140
|
### Standalone maintenance entries
|
|
@@ -178,10 +182,23 @@ Key invariants:
|
|
|
178
182
|
- **One active step at a time**, edits only inside that step's boundary.
|
|
179
183
|
- **Scope (`scope_hint`) is frozen at enrollment** — out-of-scope files are ignored.
|
|
180
184
|
- **Evidence before closure** — QA is the only authority that can close a step.
|
|
185
|
+
- **Findings carry evidence** — a refuted Review finding suppresses work only while the QA evidence bound to it stays fresh for the current revision, intent hash, and diff; when that evidence goes stale the finding blocks again, and nothing stored is rewritten by the invalidation.
|
|
186
|
+
- **Batches are opt-in and bounded** — an unattended batch exists only after you confirm the Host's `start_unattended_batch`; each child keeps its own enrollment, QA, review, and settlement.
|
|
181
187
|
- **Advisory never implements**, execution never self-approves.
|
|
182
188
|
|
|
183
189
|
---
|
|
184
190
|
|
|
191
|
+
## Unattended Batch Runs
|
|
192
|
+
|
|
193
|
+
When an Initiative has several ready children, you can run them as one serial batch instead of task by task.
|
|
194
|
+
|
|
195
|
+
- **Entry is explicit:** the Host's privileged `start_unattended_batch` tool, taking the Initiative slug. Nothing batch-related exists until it is called — without it, `imm-loop` behaves exactly like per-task enrollment and creates no batch state, branch, or authorization.
|
|
196
|
+
- **One confirmation, one digest:** the native gate (Pi TUI dialog or Claude MCP elicitation) shows the ordered child list and the shared plan digest; that single literal-user act is the whole Batch Authorization.
|
|
197
|
+
- **Per-child authority survives:** every child is still enrolled, frozen, QA'd, reviewed, and settled by the Kernel on its own `TaskRecord`. The batch is the scope of one authorization, never a new authority layer.
|
|
198
|
+
- **Bounds:** only published, non-`critical` children run, serially on a dedicated batch branch. The run parks when a child needs a human decision or a budget, deadline, authorization, or commit failure stops it, and dependents of a blocked child are skipped rather than reordered. The runner never pushes, opens PRs, resolves user decisions, or creates, switches, or deletes Git worktrees.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
185
202
|
## Configuration
|
|
186
203
|
|
|
187
204
|
Immune-Brain has **no separate config file**. Preferences live in your host's agent instruction file at the repo root — `AGENTS.md` (Pi) or `CLAUDE.md` (Claude Code):
|
|
@@ -236,6 +253,10 @@ docs/specs/ # Living specs (updated in place)
|
|
|
236
253
|
|
|
237
254
|
**QA failed — what now?** QA returns `rework` or `replan_required`. `imm-loop` routes back to the executor or to `imm-planner` for scope changes. No manual reset needed.
|
|
238
255
|
|
|
256
|
+
**A review finding stopped blocking — why?** It was refuted: fresh deterministic QA evidence shows the acceptance it names passes. The refutation is bound to that exact evidence, so the finding blocks again the moment the evidence goes stale for the current revision, intent hash, or diff.
|
|
257
|
+
|
|
258
|
+
**Can it run a whole Initiative without me?** Only as far as you authorize. Confirm `start_unattended_batch` with the Initiative slug and the runner works through the published, non-`critical` children serially on one batch branch — parking as soon as a child needs a human decision or the run hits a budget, deadline, authorization, or commit failure. It never pushes, opens PRs, or settles user decisions for you.
|
|
259
|
+
|
|
239
260
|
**Can I use it outside Pi?** Yes. Local interactive Claude Code is supported from version `2.1.236`; its plugin uses a digest-bound native MCP elicitation gate for the same Kernel-backed workflow.
|
|
240
261
|
|
|
241
262
|
---
|
|
@@ -256,13 +277,13 @@ This repo uses [Changesets](https://github.com/changesets/changesets) for versio
|
|
|
256
277
|
|
|
257
278
|
Setup: add `NPM_TOKEN` (npm access token with publish permission) to GitHub repo secrets. Workflow is `.github/workflows/release.yml` using `changesets/action@v1`.
|
|
258
279
|
|
|
259
|
-
**
|
|
280
|
+
**Manual publish (fallback):**
|
|
260
281
|
```bash
|
|
261
|
-
npm publish --access public #
|
|
282
|
+
npm publish --access public # requires npm login / NPM_TOKEN
|
|
262
283
|
# or
|
|
263
284
|
bun run changeset:publish
|
|
264
285
|
```
|
|
265
|
-
The package
|
|
286
|
+
The package publishes to npm as `immune-brain` (current release `3.6.6`) with `publishConfig.access=public` already set. After the initial publish, all future releases go through changesets.
|
|
266
287
|
|
|
267
288
|
See `CHANGELOG.md` and `.changeset/config.json` (changelog: `@changesets/changelog-github`, repo: `dereknex/immune-brain`).
|
|
268
289
|
|
package/README.zh-CN.md
CHANGED
|
@@ -13,6 +13,7 @@ Immune-Brain 在 Pi 之上提供结构化的工程工作流:
|
|
|
13
13
|
- **你用自然语言描述需求**,Agent 自动判断是先澄清、先规划,还是直接执行。
|
|
14
14
|
- **计划变为可追踪的任务**(`TaskIntent` + `TaskRecord`),进度落盘持久化,不依赖对话历史。
|
|
15
15
|
- **质量由代码强制保障** — 自动化 QA 与隔离式 Review 必须通过,任务才会完成。
|
|
16
|
+
- **已就绪的 Initiative 可以整批运行** — 一次确认的 Batch Authorization 让 `imm-loop` 串行推进已发布 Initiative 的各个 child,而每个 child 仍然独立 Enrollment、独立 QA/Review、独立结算。
|
|
16
17
|
|
|
17
18
|
Pi 与 Claude Code 是支持的宿主。未声明的适配器仍不受支持。Claude Code 最低版本为 `2.1.236`,这是已通过交互式 server-initiated MCP elicitation 验证的最低版本。当前真实 Host 证据见 `docs/verification/claude-native-elicitation-authority-conformance.md`;历史报告归档于 `docs/verification/archive/`。
|
|
18
19
|
|
|
@@ -25,6 +26,7 @@ Pi 与 Claude Code 是支持的宿主。未声明的适配器仍不受支持。C
|
|
|
25
26
|
- [如何使用](#如何使用)
|
|
26
27
|
- [6 个 Skills](#6-个-skills)
|
|
27
28
|
- [生命周期](#生命周期)
|
|
29
|
+
- [无人值守批次运行](#无人值守批次运行)
|
|
28
30
|
- [配置](#配置)
|
|
29
31
|
- [项目结构](#项目结构)
|
|
30
32
|
- [常见问题](#常见问题)
|
|
@@ -85,6 +87,7 @@ QA 与 Review 以 foreground Tool 形式运行并回传结果,返回 `phase=do
|
|
|
85
87
|
| 想法模糊,需要收敛 | "帮我梳理一下通知系统的方案" | → `imm-brainstorm` 提问澄清,不改代码 |
|
|
86
88
|
| 目标明确,需要计划 | "规划一下深色模式功能" 或让 Pi 自动路由 | → `imm-planner` 产出 `TaskIntent` + spec |
|
|
87
89
|
| 计划已确认,准备开干 | "开始构建" / `imm-loop` | → Executor 构建 → QA 验证 → Review 审查 |
|
|
90
|
+
| 已发布的 Initiative 可以整批跑了 | "把 initiative `<slug>` 无人值守跑完" | → Host 的 `start_unattended_batch`:一次原生确认绑定有序 plan digest,child 串行执行 |
|
|
88
91
|
| PR 被评论 / CI 挂了 | 对该 PR 使用 `imm-pr-fix` | → 独立修复,不创建新 managed 任务 |
|
|
89
92
|
| 文档过时需要清理 | `imm-doc-prune` + manifest | → 仅删除已审批的过时文档 |
|
|
90
93
|
| Agent instruction 文件膨胀 | `imm-agent-doc-maintain` + manifest | → 只保留不可直接推导的必要规则 |
|
|
@@ -133,10 +136,23 @@ Executor、QA、Review、Compounder 等为 `imm-loop` 内部调度的角色,
|
|
|
133
136
|
- **一次仅一个活跃步骤**,编辑仅在步骤边界内。
|
|
134
137
|
- **范围(`scope_hint`)在 enrollment 时冻结**,范围外文件被忽略。
|
|
135
138
|
- **先记录证据再关闭** — 只有 QA 能关闭步骤。
|
|
139
|
+
- **Finding 必须携带证据** — 被反证的 Review finding 只在绑定它的 QA 证据对当前 revision、intent hash 与 diff 仍然新鲜时压制工作;证据过期后 finding 重新阻塞,且这个失效过程不重写任何已存状态。
|
|
140
|
+
- **批次必须显式授权且有边界** — 只有你确认 Host 的 `start_unattended_batch` 之后才存在无人值守批次;每个 child 仍各自 Enrollment、QA、Review 与结算。
|
|
136
141
|
- **Advisory 不实现,执行不自审。**
|
|
137
142
|
|
|
138
143
|
---
|
|
139
144
|
|
|
145
|
+
## 无人值守批次运行
|
|
146
|
+
|
|
147
|
+
当一个 Initiative 下已经有多个就绪的 child,可以把它们作为一批串行跑完,而不用逐个任务手动推进。
|
|
148
|
+
|
|
149
|
+
- **入口显式:** Host 的 privileged tool `start_unattended_batch`(参数为 Initiative slug)。未调用之前不存在任何 batch state、分支或授权;未调用时 `imm-loop` 行为与逐任务 Enrollment 完全一致。
|
|
150
|
+
- **一次确认、一个 digest:** 原生 gate(Pi TUI 弹窗或 Claude MCP elicitation)展示有序 child 列表与共享 plan digest,这一次 literal-user 确认就是全部 Batch Authorization。
|
|
151
|
+
- **每个 child 的 authority 不变:** 每个 child 仍由 Kernel 单独 Enrollment、冻结、QA、Review 并以自己的 `TaskRecord` 结算。批次只是一次授权的覆盖范围,不是新的授权层级。
|
|
152
|
+
- **边界:** 只跑已发布且非 `critical` 的 child,在专属 batch 分支上串行执行;一旦某个 child 需要人决策,或遇到预算/截止时间/授权/提交失败就暂停,被阻塞 child 的依赖项标记为跳过而不是调序。runner 不 push、不开 PR、不代替用户结算 decision、也不创建/切换/删除 Git worktree。
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
140
156
|
## 配置
|
|
141
157
|
|
|
142
158
|
Immune-Brain **没有独立配置文件**,偏好设置写在仓库根目录下当前 Host 的 agent 指令文件里——`AGENTS.md`(Pi)或 `CLAUDE.md`(Claude Code):
|
|
@@ -191,6 +207,10 @@ docs/specs/ # Living specs(原地更新)
|
|
|
191
207
|
|
|
192
208
|
**QA 失败怎么办?** QA 返回 `rework` 或 `replan_required`,`imm-loop` 会自动路由回 Executor 或 `imm-planner` 调整范围,无需手动重置。
|
|
193
209
|
|
|
210
|
+
**Review finding 突然不再阻塞了?** 它被反证了:新鲜的确定性 QA 证据表明它声称的 acceptance 是通过的。反证绑定到那份具体证据,所以证据一旦对当前 revision、intent hash 或 diff 失效,该 finding 会重新阻塞。
|
|
211
|
+
|
|
212
|
+
**能不能整个 Initiative 不用我盯着?** 只能在你授权范围内。用 Initiative slug 确认 `start_unattended_batch` 后,runner 会在一个 batch 分支上串行推进已发布且非 `critical` 的 child — 一旦某个 child 需要人决策,或遇到预算/截止时间/授权/提交失败就暂停。它不会替你 push、开 PR 或结算用户决策。
|
|
213
|
+
|
|
194
214
|
**可以在 Pi 之外使用吗?** 可以从 `2.1.236` 起在本地交互式 Claude Code 中使用同一套 Kernel;Claude plugin 通过绑定 digest 的原生 MCP elicitation gate 获取 authority,未声明的适配器不受支持。
|
|
195
215
|
|
|
196
216
|
---
|
|
@@ -211,13 +231,13 @@ docs/specs/ # Living specs(原地更新)
|
|
|
211
231
|
|
|
212
232
|
配置:在 GitHub 仓库 Secrets 中添加 `NPM_TOKEN`(有发布权限的 npm token)。Workflow 为 `.github/workflows/release.yml`,基于 `changesets/action@v1`。
|
|
213
233
|
|
|
214
|
-
|
|
234
|
+
**手动发布(回退方案):**
|
|
215
235
|
```bash
|
|
216
|
-
npm publish --access public #
|
|
236
|
+
npm publish --access public # 需 npm login / NPM_TOKEN
|
|
217
237
|
# 或
|
|
218
238
|
bun run changeset:publish
|
|
219
239
|
```
|
|
220
|
-
包名为
|
|
240
|
+
包名为 `immune-brain`(当前版本 `3.6.6`),已配置 `publishConfig.access=public`。首次发布后,后续所有版本均通过 changesets 管理。
|
|
221
241
|
|
|
222
242
|
详见 `CHANGELOG.md` 与 `.changeset/config.json`(changelog: `@changesets/changelog-github`,repo: `dereknex/immune-brain`)。
|
|
223
243
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "immune-brain",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.7",
|
|
4
4
|
"description": "Immune-Brain agent skill system",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -82,6 +82,7 @@
|
|
|
82
82
|
"plugins/immune-brain/runtime/loop_contract.ts",
|
|
83
83
|
"plugins/immune-brain/runtime/plugin_version.ts",
|
|
84
84
|
"plugins/immune-brain/runtime/assurance",
|
|
85
|
+
"plugins/immune-brain/runtime/unattended",
|
|
85
86
|
"plugins/immune-brain/runtime/claude",
|
|
86
87
|
"plugins/immune-brain/runtime/prompts",
|
|
87
88
|
".claude-plugin",
|
|
@@ -71,6 +71,7 @@ import {
|
|
|
71
71
|
} from "./pi-canary-interaction";
|
|
72
72
|
import { isToolFailureState, throwToolFailure, type ToolFailureV1 } from "./pi-canary-tool-failure";
|
|
73
73
|
import { taskDiffIdentity, taskRevisionIdentity, captureGitTaskSnapshot } from "../runtime/workspace_scope";
|
|
74
|
+
import { reviewReworkFindings } from "../runtime/assurance/coordinator";
|
|
74
75
|
import {
|
|
75
76
|
AssuranceProgression,
|
|
76
77
|
buildReviewPrompt,
|
|
@@ -144,6 +145,7 @@ const KERNEL_OPERATIONS = [
|
|
|
144
145
|
"freeze_artifacts",
|
|
145
146
|
"record_finding",
|
|
146
147
|
"resolve_finding",
|
|
148
|
+
"refute_finding",
|
|
147
149
|
"revise_intent",
|
|
148
150
|
"complete",
|
|
149
151
|
] as const;
|
|
@@ -307,11 +309,17 @@ export function createPiAssuranceProgressionPorts(
|
|
|
307
309
|
} satisfies AssuranceProgressionPorts;
|
|
308
310
|
}
|
|
309
311
|
|
|
312
|
+
const GLOBAL_PI_PROGRESSION_KEY = Symbol.for("immune_brain.pi_assurance_progression");
|
|
313
|
+
|
|
310
314
|
export default function (
|
|
311
315
|
pi: ExtensionAPI,
|
|
312
316
|
dependencies: CanaryWorkExtensionDependencies = {},
|
|
313
317
|
) {
|
|
318
|
+
// One progression per extension load, published for the batch gate to reuse.
|
|
319
|
+
// Reusing whatever instance a previous load left behind would leak another
|
|
320
|
+
// session's Review reservations into this one, so the load always replaces it.
|
|
314
321
|
const progression = new AssuranceProgression(createPiAssuranceProgressionPorts(dependencies));
|
|
322
|
+
(globalThis as any)[GLOBAL_PI_PROGRESSION_KEY] = progression;
|
|
315
323
|
|
|
316
324
|
let railContext: ExtensionContext | undefined;
|
|
317
325
|
const refreshTaskRail = async (ctx: ExtensionContext) => {
|
|
@@ -449,6 +457,11 @@ export default function (
|
|
|
449
457
|
}),
|
|
450
458
|
}),
|
|
451
459
|
Type.Object({ op: Type.Literal("resolve_finding"), finding_id: Type.String() }),
|
|
460
|
+
Type.Object({
|
|
461
|
+
op: Type.Literal("refute_finding"),
|
|
462
|
+
finding_id: Type.String(),
|
|
463
|
+
attestation_id: Type.String(),
|
|
464
|
+
}),
|
|
452
465
|
Type.Object({
|
|
453
466
|
op: Type.Literal("revise_intent"),
|
|
454
467
|
next_intent: TASK_INTENT_SCHEMA,
|
|
@@ -536,7 +549,7 @@ export default function (
|
|
|
536
549
|
if ((action.op === "request_stop" || action.op === "request_authorization" || action.op === "approve_breaking_intent_revision") && ctx.mode !== "tui")
|
|
537
550
|
return failCanaryTool(taskId, action.op, "blocked", "tui_required", "literal-user authorization is TUI-only", "invoke the TUI Tool");
|
|
538
551
|
const result = action.op === "advance_assurance"
|
|
539
|
-
? await progression.advance(taskId, ctx, signal, (update) => {
|
|
552
|
+
? await progression.advance(taskId, ctx, signal, (update: any) => {
|
|
540
553
|
onUpdate?.(update);
|
|
541
554
|
presentTaskRailResult(ctx, taskId, update.details as Record<string, unknown> | undefined);
|
|
542
555
|
})
|
|
@@ -1070,7 +1083,11 @@ export function deriveAuthorizationOperation(input: {
|
|
|
1070
1083
|
return { blocked: "no unique host-derived authorization operation" };
|
|
1071
1084
|
}
|
|
1072
1085
|
|
|
1073
|
-
|
|
1086
|
+
/**
|
|
1087
|
+
* Ordinary Kernel operation mapping, exported so the conformance suite can
|
|
1088
|
+
* prove the Tool schema and this projection cannot drift apart.
|
|
1089
|
+
*/
|
|
1090
|
+
export function toCanaryOperation(action: { op: string }, actorId: string) {
|
|
1074
1091
|
switch (action.op) {
|
|
1075
1092
|
case "freeze_artifacts":
|
|
1076
1093
|
return { op: "freeze_artifacts", actor_id: actorId };
|
|
@@ -1082,6 +1099,13 @@ function toCanaryOperation(action: { op: string }, actorId: string) {
|
|
|
1082
1099
|
};
|
|
1083
1100
|
case "resolve_finding":
|
|
1084
1101
|
return { op: "resolve_finding", finding_id: (action as unknown as { finding_id: string }).finding_id, actor_id: actorId };
|
|
1102
|
+
case "refute_finding":
|
|
1103
|
+
return {
|
|
1104
|
+
op: "refute_finding",
|
|
1105
|
+
finding_id: (action as unknown as { finding_id: string }).finding_id,
|
|
1106
|
+
attestation_id: (action as unknown as { attestation_id: string }).attestation_id,
|
|
1107
|
+
actor_id: actorId,
|
|
1108
|
+
};
|
|
1085
1109
|
case "revise_intent":
|
|
1086
1110
|
return { op: "revise_intent", next_intent: (action as unknown as { next_intent: unknown }).next_intent, actor_id: actorId };
|
|
1087
1111
|
case "complete":
|
|
@@ -1373,15 +1397,7 @@ async function applyAssuranceVerdict(
|
|
|
1373
1397
|
return result;
|
|
1374
1398
|
};
|
|
1375
1399
|
if (verdict.decision === "rework") {
|
|
1376
|
-
const findings = verdict
|
|
1377
|
-
id: finding.id,
|
|
1378
|
-
kind: finding.kind,
|
|
1379
|
-
status: "open",
|
|
1380
|
-
acceptance_id: finding.acceptance_id,
|
|
1381
|
-
source: "review",
|
|
1382
|
-
review_round: null,
|
|
1383
|
-
summary: finding.summary,
|
|
1384
|
-
}));
|
|
1400
|
+
const findings = reviewReworkFindings(verdict);
|
|
1385
1401
|
const now = new Date().toISOString();
|
|
1386
1402
|
const capability = await mintCapability(registry, {
|
|
1387
1403
|
authority_kind: authorityKind,
|
|
@@ -1650,14 +1666,7 @@ async function mintCapability(
|
|
|
1650
1666
|
expires_at: new Date(Date.now() + 10 * 60 * 1000).toISOString(),
|
|
1651
1667
|
findings_digest:
|
|
1652
1668
|
input.action_kind === "request_rework"
|
|
1653
|
-
? await findingsDigestV2(
|
|
1654
|
-
(input.findings as Array<{ id: string; kind: string; acceptance_id: string | null; summary: string }>).map((f) => ({
|
|
1655
|
-
id: f.id,
|
|
1656
|
-
kind: f.kind,
|
|
1657
|
-
acceptance_id: f.acceptance_id,
|
|
1658
|
-
summary: f.summary,
|
|
1659
|
-
})),
|
|
1660
|
-
)
|
|
1669
|
+
? await findingsDigestV2(input.findings as never[])
|
|
1661
1670
|
: null,
|
|
1662
1671
|
};
|
|
1663
1672
|
return registry.issue(binding);
|
|
@@ -1930,6 +1939,7 @@ export {
|
|
|
1930
1939
|
classifyReviewWorkload,
|
|
1931
1940
|
deriveQaJobTimeoutMs,
|
|
1932
1941
|
parseAssuranceVerdict,
|
|
1942
|
+
reviewReworkFindings,
|
|
1933
1943
|
snapshotDigest,
|
|
1934
1944
|
QA_JOB_TIMEOUT_SECONDS,
|
|
1935
1945
|
REVIEW_DISPATCH_TIMEOUT_MS,
|