immune-brain 3.6.5 → 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 +69 -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 +60 -21
- package/plugins/immune-brain/.pi-extension/imm-unattended-batch.ts +932 -0
- package/plugins/immune-brain/.pi-extension/pi-canary-interaction.ts +38 -10
- package/plugins/immune-brain/.pi-extension/runtime-stub.ts +200 -2
- package/plugins/immune-brain/dist/BASELINE.md +48 -15
- package/plugins/immune-brain/dist/claude/mcp-server.mjs +3415 -228
- package/plugins/immune-brain/dist/docs/reference/planning-quality-gate.md +1 -1
- package/plugins/immune-brain/dist/docs/reference/subagent-dispatch-protocol.md +1 -1
- package/plugins/immune-brain/dist/imm-agent-doc-maintain.md +9 -1
- package/plugins/immune-brain/dist/imm-brainstorm.md +49 -35
- package/plugins/immune-brain/dist/imm-doc-prune.md +7 -1
- package/plugins/immune-brain/dist/imm-loop.md +45 -11
- package/plugins/immune-brain/dist/imm-planner.md +65 -28
- package/plugins/immune-brain/dist/imm-pr-fix.md +6 -2
- package/plugins/immune-brain/dist/role-prompts/code-review.md +9 -1
- package/plugins/immune-brain/dist/role-prompts/executor.md +18 -10
- package/plugins/immune-brain/dist/role-prompts/pr-fix.md +5 -2
- package/plugins/immune-brain/runtime/assurance/coordinator.ts +101 -3
- package/plugins/immune-brain/runtime/assurance/verification.ts +13 -2
- 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/github_issue_tracker.ts +1018 -17
- package/plugins/immune-brain/runtime/kernel/canary_application.ts +16 -1
- package/plugins/immune-brain/runtime/kernel/completion.ts +19 -1
- package/plugins/immune-brain/runtime/kernel/reducer.ts +165 -12
- 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/prompts/executor.md +18 -10
- package/plugins/immune-brain/runtime/prompts/pr-fix.md +5 -2
- 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/BASELINE.md +48 -15
- package/plugins/immune-brain/skills/imm-agent-doc-maintain/SKILL.md +20 -4
- package/plugins/immune-brain/skills/imm-brainstorm/SKILL.md +24 -64
- package/plugins/immune-brain/skills/imm-doc-prune/SKILL.md +18 -3
- package/plugins/immune-brain/skills/imm-loop/SKILL.md +21 -6
- package/plugins/immune-brain/skills/imm-planner/SKILL.md +35 -8
- package/plugins/immune-brain/skills/imm-pr-fix/SKILL.md +17 -3
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { DynamicBorder, type ExtensionAPI, type ExtensionContext, type Theme, type ThemeColor } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Container,
|
|
4
|
+
SelectList,
|
|
5
|
+
Text,
|
|
6
|
+
sliceByColumn,
|
|
7
|
+
truncateToWidth,
|
|
8
|
+
visibleWidth,
|
|
9
|
+
type Component,
|
|
10
|
+
type SelectItem,
|
|
11
|
+
} from "@earendil-works/pi-tui";
|
|
3
12
|
|
|
4
13
|
export const USER_ATTENTION_EVENT = "immune-brain:user-attention.v1" as const;
|
|
5
14
|
export const TASK_RAIL_KEY = "immune-brain.task-rail" as const;
|
|
@@ -186,12 +195,7 @@ export async function requestAuthorityDialog<T extends string, R = T | undefined
|
|
|
186
195
|
export function presentTaskRail(ctx: UiContext, view: TaskRailView): void {
|
|
187
196
|
try {
|
|
188
197
|
ctx.ui.setWidget(TASK_RAIL_KEY, (_tui, theme) => {
|
|
189
|
-
return
|
|
190
|
-
render(width: number): string[] {
|
|
191
|
-
return renderTaskRail(view, width, theme);
|
|
192
|
-
},
|
|
193
|
-
invalidate(): void {},
|
|
194
|
-
};
|
|
198
|
+
return safeWidgetRender((width) => renderTaskRail(view, width, theme));
|
|
195
199
|
}, { placement: "aboveEditor" });
|
|
196
200
|
if (view.state === "Completed" || view.state === "Stopped") terminalRailUis.add(ctx.ui);
|
|
197
201
|
else terminalRailUis.delete(ctx.ui);
|
|
@@ -277,6 +281,25 @@ export async function presentTaskOverviewOverlay(
|
|
|
277
281
|
}
|
|
278
282
|
}
|
|
279
283
|
|
|
284
|
+
// pi renders widget lines verbatim and throws in doRender — killing the whole
|
|
285
|
+
// process — when a line exceeds the terminal width. Clamp every line at the
|
|
286
|
+
// widget boundary so line-builder bugs degrade to a truncated row instead.
|
|
287
|
+
function safeWidgetRender(render: (width: number) => string[]): {
|
|
288
|
+
render(width: number): string[];
|
|
289
|
+
invalidate(): void;
|
|
290
|
+
} {
|
|
291
|
+
return {
|
|
292
|
+
render(width: number): string[] {
|
|
293
|
+
try {
|
|
294
|
+
return render(width).map((line) => truncateToWidth(line, width, "…"));
|
|
295
|
+
} catch {
|
|
296
|
+
return [];
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
invalidate(): void {},
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
280
303
|
export function clearTaskRail(ctx: UiContext): void {
|
|
281
304
|
try {
|
|
282
305
|
ctx.ui.setWidget(TASK_RAIL_KEY, undefined);
|
|
@@ -501,13 +524,18 @@ function strings(value: unknown): string[] {
|
|
|
501
524
|
return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : [];
|
|
502
525
|
}
|
|
503
526
|
|
|
527
|
+
// Truncate by terminal columns, not character count — CJK/double-width chars
|
|
528
|
+
// overflow otherwise and pi's doRender crashes the whole process on wide lines.
|
|
504
529
|
function bounded(value: string, max: number): string {
|
|
505
|
-
return value
|
|
530
|
+
return truncateToWidth(value, max, "…");
|
|
506
531
|
}
|
|
507
532
|
|
|
508
533
|
function boundedMiddle(value: string, max: number): string {
|
|
509
|
-
|
|
534
|
+
const width = visibleWidth(value);
|
|
535
|
+
if (width <= max) return value;
|
|
510
536
|
const visible = max - 1;
|
|
511
537
|
const start = Math.ceil(visible / 2);
|
|
512
|
-
|
|
538
|
+
const head = truncateToWidth(sliceByColumn(value, 0, start, true), start, "");
|
|
539
|
+
const tail = truncateToWidth(sliceByColumn(value, width - (visible - start), visible - start, true), visible - start, "");
|
|
540
|
+
return `${head}…${tail}`;
|
|
513
541
|
}
|
|
@@ -174,7 +174,15 @@ export interface TaskRecordRead {
|
|
|
174
174
|
manifest_digest: string;
|
|
175
175
|
};
|
|
176
176
|
}>;
|
|
177
|
-
findings: Array<{
|
|
177
|
+
findings: Array<{
|
|
178
|
+
id: string;
|
|
179
|
+
kind: string;
|
|
180
|
+
status: string;
|
|
181
|
+
summary?: string;
|
|
182
|
+
anchor?: string | null;
|
|
183
|
+
evidence?: unknown;
|
|
184
|
+
counterevidence?: { attestation_id: string; acceptance_id: string } | null;
|
|
185
|
+
}>;
|
|
178
186
|
} | null;
|
|
179
187
|
}
|
|
180
188
|
|
|
@@ -283,7 +291,12 @@ export async function readTaskRecord(
|
|
|
283
291
|
taskId: string,
|
|
284
292
|
): Promise<TaskRecordRead> {
|
|
285
293
|
const mod = await import(/* @vite-ignore */ kernelPath("storage"));
|
|
286
|
-
|
|
294
|
+
// Lock-free read only. `storage.readTaskRecord` wraps this in
|
|
295
|
+
// withKernelStoreLock, which first runs pending-transaction recovery, so a
|
|
296
|
+
// decline, a cancel, or a rejected preflight would otherwise mutate Kernel
|
|
297
|
+
// state before the literal user ever approved anything. Mutating Kernel
|
|
298
|
+
// entrypoints still take their own lock when the batch actually starts.
|
|
299
|
+
return mod.readTaskRecordRaw(root, taskId);
|
|
287
300
|
}
|
|
288
301
|
export async function withKernelStoreLock<T>(root: string, operation: () => T): Promise<T> {
|
|
289
302
|
const mod = await import(/* @vite-ignore */ kernelPath("storage"));
|
|
@@ -403,3 +416,188 @@ export async function deriveAssuranceAuthorization(input: {
|
|
|
403
416
|
const mod = await import(/* @vite-ignore */ kernelPath("assurance_projection"));
|
|
404
417
|
return mod.deriveAssuranceAuthorization(input) as AssuranceAuthorizationReadiness;
|
|
405
418
|
}
|
|
419
|
+
|
|
420
|
+
// --- Batch Authority & Unattended Runner Forwarding ---
|
|
421
|
+
function unattendedPath(module: string): string {
|
|
422
|
+
return `../runtime/unattended/${module}.ts`;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
export type {
|
|
426
|
+
BatchPlan,
|
|
427
|
+
BatchPlanChild,
|
|
428
|
+
BatchPlanBudget,
|
|
429
|
+
BatchPlanDigestChild,
|
|
430
|
+
InitiativeObservationReader,
|
|
431
|
+
} from "../runtime/unattended/types";
|
|
432
|
+
export type {
|
|
433
|
+
BatchAuthorityRegistry,
|
|
434
|
+
BatchAuthorizationBinding,
|
|
435
|
+
ValidatedBatchAuthorization,
|
|
436
|
+
} from "../runtime/kernel/batch_authority";
|
|
437
|
+
export type {
|
|
438
|
+
BatchRunnerKernelPort,
|
|
439
|
+
StartBatchInput,
|
|
440
|
+
BatchRunReport,
|
|
441
|
+
} from "../runtime/unattended/batch_runner";
|
|
442
|
+
export type {
|
|
443
|
+
BatchRunnerGitPort,
|
|
444
|
+
BatchGitPreflightResult,
|
|
445
|
+
} from "../runtime/unattended/batch_git";
|
|
446
|
+
|
|
447
|
+
export async function projectBatchPlan(
|
|
448
|
+
root: string,
|
|
449
|
+
initiativeSlug: string,
|
|
450
|
+
input: any,
|
|
451
|
+
readInitiative?: any,
|
|
452
|
+
): Promise<any> {
|
|
453
|
+
const mod = await import(/* @vite-ignore */ unattendedPath("batch_plan"));
|
|
454
|
+
return mod.projectBatchPlan(root, initiativeSlug, input, readInitiative);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export async function computeBatchPlanDigest(children: any): Promise<string> {
|
|
458
|
+
const mod = await import(/* @vite-ignore */ kernelPath("batch_authority"));
|
|
459
|
+
return mod.computeBatchPlanDigest(children);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
export async function createBatchAuthorityRegistry(): Promise<any> {
|
|
463
|
+
const mod = await import(/* @vite-ignore */ kernelPath("batch_authority"));
|
|
464
|
+
return mod.createBatchAuthorityRegistry();
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
export async function deriveChildEnrollment(root: string, registry: any, input: any): Promise<any> {
|
|
468
|
+
const mod = await import(/* @vite-ignore */ kernelPath("batch_authority"));
|
|
469
|
+
return mod.deriveChildEnrollment(root, registry, input);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
export async function startBatch(input: any): Promise<any> {
|
|
473
|
+
const mod = await import(/* @vite-ignore */ unattendedPath("batch_runner"));
|
|
474
|
+
return mod.startBatch(input);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
export async function runBatchGitPreflight(input: any): Promise<any> {
|
|
478
|
+
const mod = await import(/* @vite-ignore */ unattendedPath("batch_git"));
|
|
479
|
+
return mod.runBatchGitPreflight(input);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
export async function readGitHead(root: string): Promise<string> {
|
|
483
|
+
// The Pi extension must reach Kernel prepare only through the shared Enrollment
|
|
484
|
+
// boundary, so this reads HEAD itself rather than importing the Kernel prepare
|
|
485
|
+
// module. The unattended Git module reads HEAD the same way.
|
|
486
|
+
const { spawnSync } = await import("node:child_process");
|
|
487
|
+
const result = spawnSync("git", ["-C", root, "rev-parse", "HEAD"], { encoding: "utf8" });
|
|
488
|
+
if (result.status !== 0) throw new Error(`git rev-parse HEAD is unavailable for ${root}`);
|
|
489
|
+
return result.stdout.trim();
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Read the immutable terminal audit record for a settled child.
|
|
494
|
+
*
|
|
495
|
+
* A child reaches Kernel settlement before the batch commits it, and settlement
|
|
496
|
+
* clears the live state record, so the batch resume preflight must resolve the
|
|
497
|
+
* child's authorized scope from the audit pair instead. Read-only: neither the
|
|
498
|
+
* audit pair nor this reader mutates Kernel state.
|
|
499
|
+
*/
|
|
500
|
+
export async function readSettledTaskRecord(
|
|
501
|
+
root: string,
|
|
502
|
+
taskId: string,
|
|
503
|
+
): Promise<{ scope_hint: string[]; intent_path: string | undefined } | null> {
|
|
504
|
+
const mod = await import(/* @vite-ignore */ kernelPath("storage"));
|
|
505
|
+
const pair = mod.readAuditTaskPair(root, taskId);
|
|
506
|
+
if (!pair?.record) return null;
|
|
507
|
+
const record = pair.record as {
|
|
508
|
+
intent_snapshot?: { scope_hint?: string[] };
|
|
509
|
+
intent_ref?: { path?: string };
|
|
510
|
+
};
|
|
511
|
+
return {
|
|
512
|
+
scope_hint: record.intent_snapshot?.scope_hint ?? [],
|
|
513
|
+
intent_path: record.intent_ref?.path,
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
export async function pathMatchesScope(path: string, scopePath: string): Promise<boolean> {
|
|
518
|
+
const mod = await import(/* @vite-ignore */ runtimePath("workspace_scope"));
|
|
519
|
+
return mod.pathMatchesScope(path, scopePath);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const GLOBAL_PI_PROGRESSION_KEY = Symbol.for("immune_brain.pi_assurance_progression");
|
|
523
|
+
|
|
524
|
+
export async function getSharedPiProgression(): Promise<any> {
|
|
525
|
+
let progression = (globalThis as any)[GLOBAL_PI_PROGRESSION_KEY];
|
|
526
|
+
if (!progression) {
|
|
527
|
+
const workMod = await import(/* @vite-ignore */ "./imm-canary-work");
|
|
528
|
+
const ports = workMod.createPiAssuranceProgressionPorts();
|
|
529
|
+
const progMod = await import(/* @vite-ignore */ "./pi-canary-assurance-progression");
|
|
530
|
+
progression = new progMod.AssuranceProgression(ports);
|
|
531
|
+
(globalThis as any)[GLOBAL_PI_PROGRESSION_KEY] = progression;
|
|
532
|
+
}
|
|
533
|
+
return progression;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
export async function advancePiTask(root: string, taskId: string): Promise<any> {
|
|
537
|
+
const progression = await getSharedPiProgression();
|
|
538
|
+
const result = await progression.advance(taskId, { cwd: root });
|
|
539
|
+
if (result.state === "completed") return { state: "completed" };
|
|
540
|
+
if (result.state === "stopped") return { state: "stopped" };
|
|
541
|
+
if (result.state === "rework") return { state: "rework", operation: result.operation, summary: result.summary };
|
|
542
|
+
if (result.state === "review_ready") return { state: "review_ready", operation_id: result.operation_id, agent_params: result.agent_params };
|
|
543
|
+
if (result.state === "blocked") return { state: "blocked", reason: result.reason };
|
|
544
|
+
return { state: "failed", reason: (result as { reason?: string }).reason ?? "advance failed" };
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
export async function projectAssuranceForTask(root: string, taskId: string): Promise<any> {
|
|
548
|
+
const [assuranceMod, scopeMod] = await Promise.all([
|
|
549
|
+
import(/* @vite-ignore */ kernelPath("assurance_projection")),
|
|
550
|
+
import(/* @vite-ignore */ runtimePath("workspace_scope")),
|
|
551
|
+
]);
|
|
552
|
+
const diffSnapshotOf = (r: string, record: any) => {
|
|
553
|
+
if (record.contract === "assurance_kernel/task_record/v4") {
|
|
554
|
+
if (!record.git_base_head)
|
|
555
|
+
throw new Error("TaskRecord v4 is missing git_base_head");
|
|
556
|
+
return scopeMod.taskRevisionIdentity(r, record.intent_snapshot.scope_hint, record.git_base_head);
|
|
557
|
+
}
|
|
558
|
+
return scopeMod.taskDiffIdentity(r, record.intent_snapshot.scope_hint);
|
|
559
|
+
};
|
|
560
|
+
return assuranceMod.projectAssurance(root, taskId, diffSnapshotOf);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
export async function findExistingActiveBatch(root: string, initiativeSlug: string): Promise<any> {
|
|
564
|
+
const { join } = await import("node:path");
|
|
565
|
+
const { existsSync, readdirSync, readFileSync } = await import("node:fs");
|
|
566
|
+
const batchesDir = join(root, ".imm", "state", "batches");
|
|
567
|
+
if (!existsSync(batchesDir)) return null;
|
|
568
|
+
const files = readdirSync(batchesDir);
|
|
569
|
+
for (const file of files) {
|
|
570
|
+
if (!file.endsWith(".json")) continue;
|
|
571
|
+
let record: any;
|
|
572
|
+
try {
|
|
573
|
+
record = JSON.parse(readFileSync(join(batchesDir, file), "utf8"));
|
|
574
|
+
} catch {
|
|
575
|
+
// Unreadable Kernel batch state must fail closed: silently treating the
|
|
576
|
+
// initiative as batchless could authorize a parallel run.
|
|
577
|
+
return { corrupt: true, path: file };
|
|
578
|
+
}
|
|
579
|
+
if (record.contract === "assurance_kernel/batch_run_state/v1" && record.initiative_slug === initiativeSlug) {
|
|
580
|
+
const validStates = new Set([
|
|
581
|
+
"prepared",
|
|
582
|
+
"running",
|
|
583
|
+
"needs_human",
|
|
584
|
+
"completed",
|
|
585
|
+
"budget_stopped",
|
|
586
|
+
"failed",
|
|
587
|
+
"rejected",
|
|
588
|
+
]);
|
|
589
|
+
if (
|
|
590
|
+
typeof record.batch_id !== "string" ||
|
|
591
|
+
typeof record.base_head !== "string" ||
|
|
592
|
+
!Array.isArray(record.children) ||
|
|
593
|
+
!validStates.has(record.batch_state)
|
|
594
|
+
) {
|
|
595
|
+
return { corrupt: true, path: file };
|
|
596
|
+
}
|
|
597
|
+
return record;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
|
|
@@ -2,15 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
## Shared Guards
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
|
|
7
|
-
-
|
|
5
|
+
- On explicit invocation, read only common constraints and selected section routes
|
|
6
|
+
from `dist/`; nested modes, examples, recovery, and references load on demand.
|
|
7
|
+
- Ask only when missing information would change the goal, scope, observable behavior, compatibility, risk acceptance, a protected effect, or a fact only the user can supply. Resolve repository facts and delegated technical choices with bounded evidence instead of asking.
|
|
8
|
+
- Keep edits inside the user-requested Direct scope or the enrolled TaskIntent acceptance and `scope_hint`.
|
|
9
|
+
- Stage only explicit task-owned paths. Never use `git add .` or `git add -A` in a dirty worktree.
|
|
10
|
+
- Do not create, switch, or delete Git worktrees; operate only in the Host launch directory.
|
|
8
11
|
- Record reproducible evidence before reporting closure.
|
|
9
|
-
-
|
|
12
|
+
- Required verification must pass before reporting completion; disclosing a gap is not a substitute. Autonomously diagnose, repair, and rerun failing conventional local checks within the authorized scope; never delete, skip, or weaken a valid check to manufacture a pass. If a required check remains failing or cannot run, report the work as incomplete with the concrete blocker.
|
|
13
|
+
- Inspect unknown test scripts before execution. A script named `test` that
|
|
14
|
+
deploys, writes production data, or uses credentials is a protected effect,
|
|
15
|
+
not routine local verification; apply Host Confirmation Boundary before it runs.
|
|
16
|
+
- Unanswered questions block only dependent commitments or execution. Continue
|
|
17
|
+
independent read-only investigation and local alternative drafts; label drafts
|
|
18
|
+
unapproved and never treat silence as consent or finalize a dependent Spec.
|
|
19
|
+
- Disclose unrelated pre-existing failures without repairing them or widening
|
|
20
|
+
scope. If they prevent a required check from passing, report that blocker and
|
|
21
|
+
incomplete verification rather than claiming completion.
|
|
22
|
+
- Use bounded evidence to cover affected callers and state owners for shared-contract, security, migration, persistence, or authority changes; the category alone never requires full-directory reads. Stop expanding once the relevant behavior and verification are understood.
|
|
10
23
|
- Lead with conclusion, evidence, and Next Action.
|
|
11
24
|
- Advisory roles do not implement; Managed execution roles do not close QA.
|
|
12
25
|
- An explicit Managed Skill entry stops host-native mutation and routes scope changes to `imm-planner`; Managed execution remains inside its accepted boundary.
|
|
13
26
|
|
|
27
|
+
Before local edits or checks, read Verification and Local Recovery below. Read-only
|
|
28
|
+
framing does not load that execution guidance.
|
|
29
|
+
|
|
30
|
+
## Verification and Local Recovery
|
|
31
|
+
|
|
32
|
+
- Select required checks from the requested outcome, affected behavior, and project requirements before claiming completion. Documentation changes use relevant link, mirror, and contract checks; local logic uses focused tests; shared behavior, build configuration, cross-module changes, and release preparation widen regression coverage. Never reduce required checks merely because they fail.
|
|
33
|
+
- Reuse a recorded passing local result only while the relevant code, test inputs, command, dependencies, and environment remain unchanged. Changed or uncertain inputs require rerunning affected checks. Role handoff alone does not invalidate local evidence; local evidence never replaces Kernel-owned deterministic QA or fresh snapshot-bound Review.
|
|
34
|
+
- Recover routine local failures within the authorized scope: select an unused port, create temporary outputs, and remove only task-generated disposable files. Never overwrite user data or stop an unrelated process to free a port. Before dependency installation, inspect the existing project command, lifecycle scripts, network use, and credential effects; use it only within existing authorization, without dependency or lockfile changes. Unknown or protected effects follow Host Confirmation Boundary.
|
|
35
|
+
- Retry a failed ordinary operation only after new evidence or a relevant condition changes; do not repeat identical attempts indefinitely. This does not authorize retrying a failed native authority gate or an uncertain remote write.
|
|
36
|
+
- When changing a supported behavior or contract, update its existing tests, remove tests whose protected behavior has retired, merge redundant coverage, and remove orphaned fixtures/helpers within the affected scope. For each removal, identify the retired behavior or the remaining coverage and run the surviving related checks. Never delete by age, count, slowness, or flakiness alone. Temporary tests name their exit condition; no per-test registry or repository-wide audit is required.
|
|
37
|
+
|
|
14
38
|
## Workflow Activation
|
|
15
39
|
|
|
16
40
|
Ordinary host input stays host-native and does not run natural-language Managed
|
|
@@ -46,11 +70,15 @@ returns to `imm-planner`; an enrolled task resumes through `imm-loop` from the
|
|
|
46
70
|
current Assurance projection. Do not create or mutate workflow state while
|
|
47
71
|
classifying a non-mutating request.
|
|
48
72
|
|
|
49
|
-
Stage only explicit task-owned paths. Never use `git add .` or `git add -A` in a dirty worktree.
|
|
50
|
-
|
|
51
73
|
### Host Confirmation Boundary
|
|
52
74
|
|
|
53
|
-
Require exact host confirmation only for privileged effects
|
|
75
|
+
Require exact host confirmation only for privileged effects. For ordinary
|
|
76
|
+
non-Kernel operations, an explicit user approval already covering the same
|
|
77
|
+
operation, target, and impact is sufficient; ask again only for a material delta.
|
|
78
|
+
A generic continuation or configured preference is not blanket authorization.
|
|
79
|
+
Mandatory native gates and hash-bound manifest approvals still apply.
|
|
80
|
+
|
|
81
|
+
Privileged effects include:
|
|
54
82
|
|
|
55
83
|
- publish, release, deployment, or remote-system mutation;
|
|
56
84
|
- destructive or irreversible operations and Git history rewrite;
|
|
@@ -65,7 +93,10 @@ Routine Managed enrollment uses one current-Host native confirmation bound to th
|
|
|
65
93
|
|
|
66
94
|
State mutations, step activations, QA decisions, and plan switches remain
|
|
67
95
|
strictly sequential. Read-only work — repo exploration, advisory review,
|
|
68
|
-
host probing, planner research —
|
|
96
|
+
host probing, planner research — is eligible for parallel dispatch in
|
|
97
|
+
capability terms, but Pi schedules one foreground child at a time: launch one
|
|
98
|
+
child, consume its direct result, then decide whether another child is needed.
|
|
99
|
+
Do not assume multiple foreground Agents run as a concurrent batch.
|
|
69
100
|
|
|
70
101
|
Parallel dispatch is restricted by capability, not by a closed Skill list. Every
|
|
71
102
|
child delegation packet must enforce read-only advisory behavior: no file edits,
|
|
@@ -99,13 +130,15 @@ always run sequentially.
|
|
|
99
130
|
|
|
100
131
|
## Success Criteria
|
|
101
132
|
|
|
102
|
-
- Direct work closes only
|
|
103
|
-
- A Managed
|
|
133
|
+
- Direct work closes only when the requested result is delivered and the required verification passes: a failed or unavailable required check is reported as incomplete work with its concrete blocker, never as completion. Check breadth follows the request and established project requirements, not a universal full-repository rule. Apply Shared Guards and Verification and Local Recovery for in-scope repair and evidence reuse.
|
|
134
|
+
- A Managed task is ready to execute only when the target result, boundary, and
|
|
104
135
|
verification path are clear enough to avoid speculative edits.
|
|
105
|
-
- A Managed
|
|
106
|
-
verification path and the
|
|
107
|
-
-
|
|
108
|
-
|
|
136
|
+
- A Managed task is closable only when execution evidence proves the recorded
|
|
137
|
+
verification path and the TaskRecord still matches the enrolled TaskIntent boundary.
|
|
138
|
+
- Collect missing in-scope evidence and continue under the current owner. Missing
|
|
139
|
+
evidence alone does not require replanning. Escalate only a demonstrated
|
|
140
|
+
scope/acceptance mismatch or protected decision through the current owner's
|
|
141
|
+
revision or authorization path; never silently expand execution or QA scope.
|
|
109
142
|
|
|
110
143
|
## Retirement Completion
|
|
111
144
|
|
|
@@ -135,4 +168,4 @@ Immune-Brain commands and `.imm` state.
|
|
|
135
168
|
|
|
136
169
|
Prefer shallow discovery before full-file reads. Start with file lists,
|
|
137
170
|
`rg` hits, symbol/signature scans, and targeted line ranges; read whole files
|
|
138
|
-
only when the narrower evidence path cannot answer the active
|
|
171
|
+
only when the narrower evidence path cannot answer the active task question.
|