immune-brain 4.4.0 → 4.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
- package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +19 -2
- package/plugins/immune-brain/.pi-extension/imm-unattended-batch.ts +10 -2
- package/plugins/immune-brain/.pi-extension/pi-canary-tool-failure.ts +6 -1
- package/plugins/immune-brain/.pi-extension/runtime-stub.ts +11 -6
- package/plugins/immune-brain/dist/claude/mcp-server.mjs +343 -152
- package/plugins/immune-brain/dist/imm-loop.md +35 -2
- package/plugins/immune-brain/dist/role-prompts/executor.md +6 -0
- package/plugins/immune-brain/runtime/assurance/coordinator.ts +160 -12
- package/plugins/immune-brain/runtime/assurance/qa.ts +57 -42
- package/plugins/immune-brain/runtime/claude/kernel_ports.ts +20 -8
- package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
- package/plugins/immune-brain/runtime/prompts/executor.md +6 -0
- package/plugins/immune-brain/runtime/unattended/batch_plan.ts +1 -1
- package/plugins/immune-brain/runtime/unattended/batch_preflight.ts +38 -8
- package/plugins/immune-brain/runtime/unattended/batch_reasons.ts +6 -0
- package/plugins/immune-brain/runtime/unattended/batch_runner.ts +84 -146
- package/plugins/immune-brain/runtime/unattended/batch_state.ts +11 -0
package/package.json
CHANGED
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
type UserAttentionEventV1,
|
|
65
65
|
type UserAttentionReason,
|
|
66
66
|
} from "./pi-canary-interaction";
|
|
67
|
-
import { isToolFailureState, throwToolFailure, type ToolFailureV1 } from "./pi-canary-tool-failure";
|
|
67
|
+
import { isToolFailureState, throwToolFailure, type AssuranceFailureDetails, type ToolFailureV1 } from "./pi-canary-tool-failure";
|
|
68
68
|
import { resolveUxLanguage, uxText } from "./ux-language";
|
|
69
69
|
|
|
70
70
|
/** Host-native UI language; see ux-language.ts. Resolved once per process. */
|
|
@@ -1737,6 +1737,11 @@ async function enrichAssuranceResult(
|
|
|
1737
1737
|
taskId: string,
|
|
1738
1738
|
result: Record<string, unknown>,
|
|
1739
1739
|
): Promise<Record<string, unknown>> {
|
|
1740
|
+
if (result.recovery_error) {
|
|
1741
|
+
// Do not replay a failed observation for Host decoration or tracker hygiene.
|
|
1742
|
+
const taskState = { error: typeof result.reason === "string" ? result.reason : "authority projection unavailable" };
|
|
1743
|
+
return { ...result, task_state: taskState, next_action: nextActionForAssuranceResult(result, taskState) };
|
|
1744
|
+
}
|
|
1740
1745
|
const projection = await projectAssuranceState(ctx.cwd, taskId);
|
|
1741
1746
|
const taskState: AssuranceTaskState = projection.error
|
|
1742
1747
|
? { error: projection.error }
|
|
@@ -1761,11 +1766,13 @@ async function enrichAssuranceResult(
|
|
|
1761
1766
|
}
|
|
1762
1767
|
|
|
1763
1768
|
function nextActionForAssuranceResult(result: Record<string, unknown>, taskState: AssuranceTaskState): string {
|
|
1769
|
+
const derived = result.recovery as { next_action: string } | undefined;
|
|
1770
|
+
if (derived) return derived.next_action;
|
|
1764
1771
|
const recovery = recoveryActionForAssuranceFailure(
|
|
1765
1772
|
"error" in taskState ? taskState.error : result.reason,
|
|
1766
1773
|
);
|
|
1767
1774
|
if (recovery) return recovery;
|
|
1768
|
-
if ("error" in taskState) return "inspect authority state";
|
|
1775
|
+
if (result.recovery_error || "error" in taskState) return "inspect authority state";
|
|
1769
1776
|
if (result.state === "review_preparation_failed") return "repair Review preparation, then retry advance_assurance; QA is already committed";
|
|
1770
1777
|
if (result.code === "verdict_invalid") return "fix the verdict payload and resubmit submit_review; the Review reservation remains active; do not re-dispatch the reviewer";
|
|
1771
1778
|
if (taskState.lifecycle === "done" || taskState.lifecycle === "stopped") return "none";
|
|
@@ -1872,6 +1879,7 @@ function failCanaryTool(
|
|
|
1872
1879
|
code: string,
|
|
1873
1880
|
message: string,
|
|
1874
1881
|
nextAction: string,
|
|
1882
|
+
details: AssuranceFailureDetails = {},
|
|
1875
1883
|
): never {
|
|
1876
1884
|
return throwToolFailure({
|
|
1877
1885
|
tool: "imm_kernel_canary",
|
|
@@ -1881,6 +1889,7 @@ function failCanaryTool(
|
|
|
1881
1889
|
code,
|
|
1882
1890
|
message,
|
|
1883
1891
|
next_action: nextAction,
|
|
1892
|
+
...details,
|
|
1884
1893
|
});
|
|
1885
1894
|
}
|
|
1886
1895
|
|
|
@@ -1890,6 +1899,7 @@ function throwIfCanaryToolFailure(
|
|
|
1890
1899
|
result: Record<string, unknown>,
|
|
1891
1900
|
): void {
|
|
1892
1901
|
if (!isToolFailureState(result.state)) return;
|
|
1902
|
+
const details = result as AssuranceFailureDetails;
|
|
1893
1903
|
failCanaryTool(
|
|
1894
1904
|
taskId,
|
|
1895
1905
|
operation,
|
|
@@ -1903,6 +1913,13 @@ function throwIfCanaryToolFailure(
|
|
|
1903
1913
|
typeof result.next_action === "string"
|
|
1904
1914
|
? result.next_action
|
|
1905
1915
|
: "inspect authority state",
|
|
1916
|
+
// Preserve only the coordinator's bounded observation metadata.
|
|
1917
|
+
{
|
|
1918
|
+
...(details.diagnostics ? { diagnostics: details.diagnostics } : {}),
|
|
1919
|
+
...(details.environment_failure ? { environment_failure: true } : {}),
|
|
1920
|
+
...(details.recovery ? { recovery: details.recovery } : {}),
|
|
1921
|
+
...(details.recovery_error ? { recovery_error: details.recovery_error } : {}),
|
|
1922
|
+
},
|
|
1906
1923
|
);
|
|
1907
1924
|
}
|
|
1908
1925
|
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
createBatchAuthorityRegistry,
|
|
6
6
|
deriveChildEnrollment,
|
|
7
7
|
startBatch,
|
|
8
|
+
batchQaFailureFacts,
|
|
8
9
|
readTaskRecord,
|
|
9
10
|
advancePiTask,
|
|
10
11
|
projectAssuranceForTask,
|
|
@@ -114,7 +115,7 @@ export async function executePiUnattendedBatch(
|
|
|
114
115
|
// working-tree cleanliness against the authorized scope, recovery children,
|
|
115
116
|
// plan digest, and base HEAD are one shared projection, so neither Host
|
|
116
117
|
// re-implements a batch decision.
|
|
117
|
-
|
|
118
|
+
let now = new Date().toISOString();
|
|
118
119
|
const preflight = await projectBatchPreflight({
|
|
119
120
|
root,
|
|
120
121
|
initiative_slug: initiativeSlug,
|
|
@@ -203,6 +204,9 @@ export async function executePiUnattendedBatch(
|
|
|
203
204
|
// review-2: verify cancellation signal right before authority issuance and startBatch
|
|
204
205
|
if (signal?.aborted) return batchReason("cancelled_before_execution");
|
|
205
206
|
|
|
207
|
+
now = new Date().toISOString();
|
|
208
|
+
if (Date.parse(expiresAt) <= Date.parse(now))
|
|
209
|
+
return batchReason("confirmation_failed", "confirmed batch deadline expired before authorization issuance");
|
|
206
210
|
const capability = batchRegistry.issue(binding, recoveryChildren as any, now);
|
|
207
211
|
|
|
208
212
|
let activeReviewDispatch: { operation_id: string; agent_params: Record<string, unknown> } | null = null;
|
|
@@ -251,7 +255,11 @@ export async function executePiUnattendedBatch(
|
|
|
251
255
|
return res;
|
|
252
256
|
},
|
|
253
257
|
projectTask: async (taskRoot, taskId) => {
|
|
254
|
-
|
|
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) };
|
|
255
263
|
},
|
|
256
264
|
ownsTaskClaim: (taskId) => {
|
|
257
265
|
if (isResuming && taskId === readActiveClaimTaskId(root)) {
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import type { AssuranceAdvanceResult } from "../runtime/assurance/coordinator";
|
|
2
|
+
|
|
3
|
+
export type AssuranceFailureDetails = Pick<AssuranceAdvanceResult,
|
|
4
|
+
"diagnostics" | "environment_failure" | "recovery" | "recovery_error">;
|
|
5
|
+
|
|
6
|
+
export interface ToolFailureV1 extends AssuranceFailureDetails {
|
|
2
7
|
contract: "immune_brain/tool_failure/v1";
|
|
3
8
|
tool: "imm_canary_enrollment" | "imm_kernel_canary";
|
|
4
9
|
task_id: string;
|
|
@@ -171,10 +171,12 @@ export interface TaskRecordRead {
|
|
|
171
171
|
manifest_digest: string;
|
|
172
172
|
};
|
|
173
173
|
}>;
|
|
174
|
+
history: import("../runtime/kernel/types").TaskRecord["history"];
|
|
174
175
|
findings: Array<{
|
|
175
176
|
id: string;
|
|
176
177
|
kind: string;
|
|
177
178
|
status: string;
|
|
179
|
+
acceptance_id?: string | null;
|
|
178
180
|
summary?: string;
|
|
179
181
|
anchor?: string | null;
|
|
180
182
|
evidence?: unknown;
|
|
@@ -451,6 +453,7 @@ export type {
|
|
|
451
453
|
BatchAuthorizationBinding,
|
|
452
454
|
ValidatedBatchAuthorization,
|
|
453
455
|
} from "../runtime/kernel/batch_authority";
|
|
456
|
+
export { batchQaFailureFacts } from "../runtime/unattended/batch_runner";
|
|
454
457
|
export type {
|
|
455
458
|
BatchRunnerKernelPort,
|
|
456
459
|
StartBatchInput,
|
|
@@ -553,12 +556,14 @@ export async function getSharedPiProgression(): Promise<any> {
|
|
|
553
556
|
export async function advancePiTask(root: string, taskId: string): Promise<any> {
|
|
554
557
|
const progression = await getSharedPiProgression();
|
|
555
558
|
const result = await progression.advance(taskId, { cwd: root });
|
|
556
|
-
|
|
557
|
-
if (result.state === "
|
|
558
|
-
if (result.state === "
|
|
559
|
-
if (result.state === "
|
|
560
|
-
if (result.state === "
|
|
561
|
-
return { state:
|
|
559
|
+
const facts = { diagnostics: result.diagnostics, environment_failure: result.environment_failure, recovery: result.recovery };
|
|
560
|
+
if (result.state === "completed") return { state: "completed", ...facts };
|
|
561
|
+
if (result.state === "stopped") return { state: "stopped", ...facts };
|
|
562
|
+
if (result.state === "rework") return { state: "rework", operation: result.operation, summary: result.summary, ...facts };
|
|
563
|
+
if (result.state === "review_ready") return { state: "review_ready", operation_id: result.operation_id, agent_params: result.agent_params, ...facts };
|
|
564
|
+
if (result.state === "review_preparation_failed") return { state: result.state, operation: result.operation, operation_id: result.operation_id, reason: result.reason, ...facts };
|
|
565
|
+
if (result.state === "blocked") return { state: "blocked", reason: result.reason, ...facts };
|
|
566
|
+
return { state: "failed", reason: (result as { reason?: string }).reason ?? "advance failed", ...facts };
|
|
562
567
|
}
|
|
563
568
|
|
|
564
569
|
export async function projectAssuranceForTask(root: string, taskId: string): Promise<any> {
|