immune-brain 4.1.0 → 4.3.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.
- package/README.md +48 -22
- package/README.zh-CN.md +48 -22
- package/package.json +1 -1
- package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
- package/plugins/immune-brain/.pi-extension/imm-canary-enroll.ts +19 -5
- package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +18 -2
- package/plugins/immune-brain/.pi-extension/runtime-stub.ts +14 -12
- package/plugins/immune-brain/dist/BASELINE.md +8 -2
- package/plugins/immune-brain/dist/claude/mcp-server.mjs +180 -94
- package/plugins/immune-brain/dist/imm-loop.md +6 -1
- package/plugins/immune-brain/dist/imm-planner.md +59 -5
- package/plugins/immune-brain/runtime/assurance/enrollment_git_base.ts +83 -0
- package/plugins/immune-brain/runtime/claude/interaction.ts +1 -0
- package/plugins/immune-brain/runtime/claude/kernel_ports.ts +39 -27
- package/plugins/immune-brain/runtime/claude/mcp_server.ts +1 -0
- package/plugins/immune-brain/runtime/commands/kernel.ts +7 -1
- package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
- package/plugins/immune-brain/skills/BASELINE.md +8 -2
|
@@ -55,7 +55,12 @@ Continue while the current projection has a valid action:
|
|
|
55
55
|
1. For active artifacts, implement only the enrolled acceptance within the
|
|
56
56
|
`scope_hint` envelope in the current conversation. New helpers or tests
|
|
57
57
|
inside an approved directory or glob do not require a revision. Run focused
|
|
58
|
-
checks.
|
|
58
|
+
checks. Before `advance_assurance`, inspect ownership and stage only the exact
|
|
59
|
+
task-owned paths needed for delivery. Do not hand routine task-owned staging
|
|
60
|
+
to the user. If a file mixes pre-existing user changes with task changes and
|
|
61
|
+
the task-owned hunks cannot be isolated reliably, stop with that ownership
|
|
62
|
+
conflict instead of staging the whole file. Staging grants no commit or push
|
|
63
|
+
authority. Executor checks are diagnostic evidence, not a QA or Review approval.
|
|
59
64
|
2. Call `advance_assurance` in the foreground and consume its direct terminal
|
|
60
65
|
result. The Kernel freezes the artifacts itself before QA: it binds Git
|
|
61
66
|
content identity in place without relocating source paths. A simple task has
|
|
@@ -76,7 +76,8 @@ Then route deterministically:
|
|
|
76
76
|
coordination, except a Loop-requested revision follows Enrolled Intent Revision
|
|
77
77
|
below to prepare a non-authoritative proposal for that same owner;
|
|
78
78
|
- an active or otherwise nonterminal v3 Plan remains on its existing v3 route;
|
|
79
|
-
- no routing policy
|
|
79
|
+
- no routing policy on an otherwise unowned workspace triggers automatic policy
|
|
80
|
+
activation below before producing any planning artifact;
|
|
80
81
|
- a valid `kernel_task_intent` retirement policy produces one TaskIntent draft
|
|
81
82
|
through the current Host's explicit `imm-planner`;
|
|
82
83
|
- an invalid, unreadable, untracked, or tracked-deleted policy rejects new
|
|
@@ -107,6 +108,46 @@ workspace claim, and final authority preconditions without executing acceptance
|
|
|
107
108
|
descriptors. A routine task proceeds from that single confirmation through
|
|
108
109
|
enrollment, execution and QA without a second human stop.
|
|
109
110
|
|
|
111
|
+
**Automatic policy activation**
|
|
112
|
+
|
|
113
|
+
Explicit `imm-planner` entry includes local routing setup, including for plan-only
|
|
114
|
+
requests. When the routing projection reports `policy_status: legacy_v3` and
|
|
115
|
+
`ownership: absent`, and neither Kernel nor nonterminal v3 ownership exists,
|
|
116
|
+
perform these steps without a separate enablement question:
|
|
117
|
+
|
|
118
|
+
1. Create `docs/plans/` if needed. Require real directories without symlink
|
|
119
|
+
components; create `docs/plans/managed-task-routing-policy.json` exclusively
|
|
120
|
+
(fail if it already exists), using exactly the JSON below with two-space
|
|
121
|
+
indentation, the shown field order, and one trailing newline.
|
|
122
|
+
2. Run `git add -- docs/plans/managed-task-routing-policy.json` only for the file
|
|
123
|
+
created in this activation. Preserve all other worktree and index changes;
|
|
124
|
+
do not commit, force-add an ignored file, or alter Git configuration.
|
|
125
|
+
3. Re-run `imm-plan --routing-status --json` through the resolved wrapper.
|
|
126
|
+
Continue canonical TaskIntent authoring only when `policy_status: active`,
|
|
127
|
+
`route: kernel_task_intent`, and `ownership: tracked_clean` all hold. Report
|
|
128
|
+
automatic activation briefly and continue planning in the same turn.
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"contract": "immune_brain/managed_task_routing_policy/v1",
|
|
133
|
+
"revision": 1,
|
|
134
|
+
"new_task_route": "kernel_task_intent",
|
|
135
|
+
"v3_new_plan_sync": "retired",
|
|
136
|
+
"legacy_v3_mode": "drain_read_only",
|
|
137
|
+
"terminal_import": "disabled"
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
An already active policy needs no write or staging. An existing invalid,
|
|
142
|
+
untracked, unreadable, tracked-deleted, or divergent policy is not an activation
|
|
143
|
+
candidate: preserve it and report `routing_policy_invalid`. If creation,
|
|
144
|
+
staging, or verification fails, report the concrete blocker and retain any
|
|
145
|
+
created file; stop before authoring, without overwriting existing bytes or
|
|
146
|
+
falling back to v3. A repository/user prohibition on policy setup or staging
|
|
147
|
+
blocks only this dependent planning step. Activation grants no execution
|
|
148
|
+
authority; the native Enrollment gate remains required. Read-only routing
|
|
149
|
+
queries and the canonical author command retain their existing runtime behavior.
|
|
150
|
+
|
|
110
151
|
## Candidate Authoring
|
|
111
152
|
|
|
112
153
|
Read this section before creating new candidate artifacts, after request routing
|
|
@@ -133,6 +174,12 @@ file creation; then it validates the created artifact with
|
|
|
133
174
|
continue through Kernel `revise_intent` authority and are not a Planner
|
|
134
175
|
overwrite path.
|
|
135
176
|
|
|
177
|
+
After authoring, inspect ownership and stage only the exact Planner-produced
|
|
178
|
+
Spec and TaskIntent paths before validation and handoff. Do not hand routine
|
|
179
|
+
Planner-owned staging to the user. This grants no commit, push, broad staging,
|
|
180
|
+
or authority over pre-existing user changes; a mixed-change ownership conflict
|
|
181
|
+
stops only the affected handoff.
|
|
182
|
+
|
|
136
183
|
Before authoring a TaskIntent that adds a field or verdict branch to a state
|
|
137
184
|
machine, enumerate every consumer of that value and of the version gates around
|
|
138
185
|
it: the producing side, each branch or switch that reads it, and any migration or
|
|
@@ -263,7 +310,12 @@ script or host tool through its literal `command`; do not infer a language,
|
|
|
263
310
|
package manager, or runner. Add `environment.prepare` only when the check needs
|
|
264
311
|
explicit setup, and declare only the generated directories it needs in
|
|
265
312
|
`environment.writable_paths`. Never hide package installation inside an
|
|
266
|
-
acceptance command.
|
|
313
|
+
acceptance command. For every descriptor, identify whether its executable is
|
|
314
|
+
provided by the QA host or by tracked delivery content, where every dependency
|
|
315
|
+
comes from in the disposable delivery, what explicit setup is required, and
|
|
316
|
+
which declared writable paths that setup or check creates. A dependency found
|
|
317
|
+
only in the Planner's live worktree, including an absolute local `node_modules`
|
|
318
|
+
path, is not delivery provenance. Prefer the highest existing observable behavioral test seam
|
|
267
319
|
and the fewest sufficient seams; never use the full test suite, a build, network
|
|
268
320
|
access, or redundant heavyweight checks as acceptance. Cite relevant test prior
|
|
269
321
|
art and explain how the selected seam catches the intended regression. This is
|
|
@@ -271,7 +323,9 @@ a planning heuristic: it must not weaken acceptance-specific focused
|
|
|
271
323
|
verification descriptors or add a mandatory user confirmation. Use the smallest
|
|
272
324
|
`timeout_ms` and `max_output_bytes` that cover deterministic post-implementation
|
|
273
325
|
QA. A v1 descriptor is historical-only and requires explicit Intent revision
|
|
274
|
-
before execution.
|
|
326
|
+
before execution. Report `valid` and `enrollment_ready` only as structural and
|
|
327
|
+
Enrollment readiness; only a completed deterministic QA result proves that a
|
|
328
|
+
descriptor executed and passed.
|
|
275
329
|
|
|
276
330
|
## Core Responsibilities
|
|
277
331
|
|
|
@@ -410,7 +464,7 @@ optional advisory dispatch fails, continue inline and record the reason.
|
|
|
410
464
|
|
|
411
465
|
## Boundary
|
|
412
466
|
|
|
413
|
-
- **Allowed**: Write a TaskIntent. Add a Spec only for complex work. Initiative planning carriers and necessary domain vocabulary.
|
|
467
|
+
- **Allowed**: Write a TaskIntent. Add a Spec only for complex work. Activate an absent routing policy under Kernel TaskIntent Routing. Initiative planning carriers and necessary domain vocabulary.
|
|
414
468
|
- **Blocked**: Implementation edits, direct Kernel-store writes, enrolled intent overwrites, and QA/Review decisions.
|
|
415
469
|
- **Workflow guard**: Execution continues through native Enrollment and explicit `imm-loop`. Planner owns design and decomposition, not execution authority.
|
|
416
470
|
|
|
@@ -452,7 +506,7 @@ a State Ledger. Keep historical Plan validation strictly read-only.
|
|
|
452
506
|
|
|
453
507
|
## Verification
|
|
454
508
|
|
|
455
|
-
- Validate every candidate through `imm-kernel intent validate <path> --json` after authoring and staging. Require `valid: true` and `enrollment_ready: true` before Enrollment.
|
|
509
|
+
- Validate every candidate through `imm-kernel intent validate <path> --json` after authoring and staging. Require `valid: true` and `enrollment_ready: true` before Enrollment. When `git_base_initialization_required: true`, report that the existing native Enrollment confirmation includes an empty root commit; leave initialization to the Host. An invalid `git_base` blocks Enrollment and requires Git repair.
|
|
456
510
|
- For complex work, verify Spec design metadata, document language, reference closure, concrete descriptor paths, and complete Brainstorm traceability before handoff. Simple TaskIntent-only work verifies those properties on the Intent.
|
|
457
511
|
- Enrollment validates descriptor structure only. Deterministic QA owns descriptor execution after implementation; planning does not run the acceptance suite.
|
|
458
512
|
- Managed execution handoff is Git-tracked TaskIntent author/validate plus current-Host native Enrollment. Do not sync a v3 State Ledger or invoke a missing dispatcher.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
2
|
+
import { preparePiCanary, readGitHead, revalidatePiCanary, type PiCanaryPreparation, type PiCanaryPrepareInput } from "../kernel/pi_canary_prepare";
|
|
3
|
+
import { withKernelStoreLock } from "../kernel/storage";
|
|
4
|
+
|
|
5
|
+
export type EnrollmentGitBase = { state: "committed"; head: string } | { state: "unborn"; branch: string };
|
|
6
|
+
|
|
7
|
+
function git(root: string, args: string[], input?: string, env = process.env): string {
|
|
8
|
+
return execFileSync("git", args, { cwd: root, encoding: "utf8", input, env, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Read-only. A missing branch is bootstrap-able; a broken existing ref is not. */
|
|
12
|
+
export function inspectEnrollmentGitBase(root: string): EnrollmentGitBase {
|
|
13
|
+
if (git(root, ["rev-parse", "--is-inside-work-tree"]) !== "true")
|
|
14
|
+
throw new Error("Enrollment requires a Git working tree");
|
|
15
|
+
try { return { state: "committed", head: readGitHead(root) }; } catch { /* Inspect the unborn case below. */ }
|
|
16
|
+
const branch = git(root, ["symbolic-ref", "--no-recurse", "HEAD"]);
|
|
17
|
+
if (!branch.startsWith("refs/heads/")) throw new Error("Enrollment HEAD must name a local branch");
|
|
18
|
+
const ref = spawnSync("git", ["show-ref", "--verify", "--quiet", branch], { cwd: root });
|
|
19
|
+
const symbolic = spawnSync("git", ["symbolic-ref", "-q", branch], { cwd: root });
|
|
20
|
+
if (ref.status !== 1 || symbolic.status !== 1)
|
|
21
|
+
throw new Error("Enrollment Git HEAD is invalid; only an absent branch can be initialized");
|
|
22
|
+
return { state: "unborn", branch };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function enrollmentGitBaseNotice(base: EnrollmentGitBase): string | undefined {
|
|
26
|
+
return base.state === "unborn"
|
|
27
|
+
? `Git: create an empty initial commit on ${base.branch} before Enrollment; staged files and working tree remain unchanged. This commit remains if later Enrollment fails or is cancelled.`
|
|
28
|
+
: undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function identityEnv(root: string): NodeJS.ProcessEnv {
|
|
32
|
+
const configured = (key: string): string => {
|
|
33
|
+
const result = spawnSync("git", ["config", "--get", key], { cwd: root, encoding: "utf8" });
|
|
34
|
+
if (result.status !== 0 && result.status !== 1) throw new Error(`Cannot read Git identity: ${key}`);
|
|
35
|
+
return result.stdout?.trim() ?? "";
|
|
36
|
+
};
|
|
37
|
+
const name = configured("user.name") || "Immune-Brain Enrollment";
|
|
38
|
+
const email = configured("user.email") || "enrollment@immune-brain.local";
|
|
39
|
+
return { ...process.env,
|
|
40
|
+
GIT_AUTHOR_NAME: process.env.GIT_AUTHOR_NAME || name, GIT_AUTHOR_EMAIL: process.env.GIT_AUTHOR_EMAIL || email,
|
|
41
|
+
GIT_COMMITTER_NAME: process.env.GIT_COMMITTER_NAME || name, GIT_COMMITTER_EMAIL: process.env.GIT_COMMITTER_EMAIL || email,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Called only after native confirmation. Never stages files or writes Git config. */
|
|
46
|
+
export function initializeEnrollmentGitBase(
|
|
47
|
+
root: string, input: PiCanaryPrepareInput, previous: PiCanaryPreparation,
|
|
48
|
+
base: EnrollmentGitBase, signal?: AbortSignal,
|
|
49
|
+
): PiCanaryPreparation {
|
|
50
|
+
const assertUnchanged = () => {
|
|
51
|
+
signal?.throwIfAborted();
|
|
52
|
+
if (!revalidatePiCanary(root, input, previous).unchanged
|
|
53
|
+
|| JSON.stringify(inspectEnrollmentGitBase(root)) !== JSON.stringify(base))
|
|
54
|
+
throw new Error("Workspace or Git branch changed after confirmation; retry Enrollment");
|
|
55
|
+
};
|
|
56
|
+
assertUnchanged();
|
|
57
|
+
if (base.state === "committed") return previous;
|
|
58
|
+
return withKernelStoreLock(root, () => {
|
|
59
|
+
// CAS the captured branch itself, never HEAD: a concurrent symbolic HEAD
|
|
60
|
+
// switch must not redirect the write to another branch. Recheck HEAD after
|
|
61
|
+
// the write and report any created base if the workspace changed.
|
|
62
|
+
let created: string | undefined;
|
|
63
|
+
try {
|
|
64
|
+
assertUnchanged();
|
|
65
|
+
if (!previous.intent || previous.backend_claim.present || previous.task_record_v3?.present || previous.workspace.current_working !== null)
|
|
66
|
+
throw new Error("Empty Git base initialization requires an unowned workspace and a tracked TaskIntent");
|
|
67
|
+
const tree = git(root, ["hash-object", "-t", "tree", "-w", "--stdin"], "");
|
|
68
|
+
const commit = git(root, ["commit-tree", tree, "-m", "chore: initialize empty Enrollment base"], undefined, identityEnv(root));
|
|
69
|
+
assertUnchanged();
|
|
70
|
+
git(root, ["update-ref", "--no-deref", base.branch, commit, "0".repeat(commit.length)]);
|
|
71
|
+
created = commit;
|
|
72
|
+
const current = preparePiCanary(root, input);
|
|
73
|
+
const withoutGit = ({ digest, git_base_head, git_error, ...owners }: PiCanaryPreparation) => owners;
|
|
74
|
+
if (git(root, ["symbolic-ref", "--no-recurse", "HEAD"]) !== base.branch || current.git_base_head !== commit
|
|
75
|
+
|| JSON.stringify(withoutGit(current)) !== JSON.stringify(withoutGit(previous)))
|
|
76
|
+
throw new Error("Workspace changed during empty Git base initialization; retry Enrollment");
|
|
77
|
+
return current;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
if (created) throw new Error(`${error instanceof Error ? error.message : String(error)}; empty initial commit ${created} remains`);
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
} from "../kernel/enrollment_authority";
|
|
40
40
|
import { enrollCanaryTask, runEnrollmentRehearsal } from "../kernel/enrollment";
|
|
41
41
|
import { reconcileKernelAuthority, repairKernelAuthority } from "../kernel/storage";
|
|
42
|
+
import { inspectEnrollmentGitBase, enrollmentGitBaseNotice, initializeEnrollmentGitBase } from "../assurance/enrollment_git_base";
|
|
42
43
|
import { preparePiCanary, revalidatePiCanary } from "../kernel/pi_canary_prepare";
|
|
43
44
|
import { runDeterministicQa } from "../assurance/qa";
|
|
44
45
|
import { taskDiffIdentity, taskRevisionIdentity } from "../workspace_scope";
|
|
@@ -524,6 +525,7 @@ export class ClaudeRuntime {
|
|
|
524
525
|
intentRevision?: number;
|
|
525
526
|
intentContentHash?: string;
|
|
526
527
|
bindingDigest?: string;
|
|
528
|
+
gitBaseNotice?: string;
|
|
527
529
|
} = {}): Promise<{ confirmation_ref: string }> {
|
|
528
530
|
throwIfCancelled(meta.signal);
|
|
529
531
|
const probe = probeHost(this.env, process.platform, this.hostVersion);
|
|
@@ -557,45 +559,55 @@ export class ClaudeRuntime {
|
|
|
557
559
|
|
|
558
560
|
async enroll(taskId: string, meta: ToolMeta) {
|
|
559
561
|
const now = new Date().toISOString();
|
|
560
|
-
|
|
562
|
+
let preparation = await preparePiCanary(this.cwd, { task_id: taskId, now });
|
|
561
563
|
const intent = await readTaskIntentForRecord(this.cwd, taskId);
|
|
564
|
+
const gitBase = inspectEnrollmentGitBase(this.cwd);
|
|
562
565
|
const gate = await this.gate("enroll", { ...meta, taskId }, {
|
|
563
566
|
risk: intent.intent.risk,
|
|
564
567
|
intentRevision: preparation.intent?.revision,
|
|
565
568
|
intentContentHash: preparation.intent?.content_hash,
|
|
566
569
|
bindingDigest: preparation.digest,
|
|
570
|
+
gitBaseNotice: enrollmentGitBaseNotice(gitBase),
|
|
567
571
|
});
|
|
568
572
|
const { unchanged } = await revalidatePiCanary(this.cwd, { task_id: taskId, now }, preparation);
|
|
569
573
|
if (!unchanged) throw new NativeAuthorityError("workspace_changed", "workspace changed after native confirmation");
|
|
570
574
|
if (!preparation.intent) throw new Error("enrollment requires a readable TaskIntent");
|
|
571
575
|
throwIfCancelled(meta.signal);
|
|
572
|
-
|
|
573
|
-
const
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
576
|
+
preparation = initializeEnrollmentGitBase(this.cwd, { task_id: taskId, now }, preparation, gitBase, meta.signal);
|
|
577
|
+
const gitBaseNote = gitBase.state === "unborn" ? `; empty initial commit ${preparation.git_base_head} remains` : "";
|
|
578
|
+
try {
|
|
579
|
+
if (!preparation.intent) throw new Error("Enrollment requires a readable TaskIntent");
|
|
580
|
+
const nonce = enrollmentNonce();
|
|
581
|
+
const binding: EnrollmentCapabilityBinding = {
|
|
582
|
+
task_id: taskId,
|
|
583
|
+
intent_path: preparation.intent.path,
|
|
584
|
+
intent_revision: preparation.intent.revision,
|
|
585
|
+
intent_content_hash: preparation.intent.content_hash,
|
|
586
|
+
preparation_digest: preparation.digest,
|
|
587
|
+
actor_id: LITERAL_USER_ACTOR_ID,
|
|
588
|
+
confirmation_ref: gate.confirmation_ref,
|
|
589
|
+
expires_at: new Date(Date.now() + 10 * 60 * 1000).toISOString(),
|
|
590
|
+
nonce,
|
|
591
|
+
};
|
|
592
|
+
const capability = this.enrollmentRegistry.issue(binding);
|
|
593
|
+
const input = {
|
|
594
|
+
task_id: taskId,
|
|
595
|
+
intent_path: binding.intent_path,
|
|
596
|
+
intent_revision: binding.intent_revision,
|
|
597
|
+
preparation_digest: binding.preparation_digest,
|
|
598
|
+
capability,
|
|
599
|
+
capability_binding: binding,
|
|
600
|
+
now,
|
|
601
|
+
};
|
|
602
|
+
const rehearsal = runEnrollmentRehearsal(this.cwd, input, capability, this.enrollmentRegistry);
|
|
603
|
+
if (!rehearsal.rehearsed || rehearsal.evidence.outcome !== "ready") {
|
|
604
|
+
throw new Error(`Kernel enrollment rehearsal failed: ${rehearsal.evidence.blockers.join("; ")}`);
|
|
605
|
+
}
|
|
606
|
+
return enrollCanaryTask(this.cwd, input, this.enrollmentRegistry);
|
|
607
|
+
} catch (error) {
|
|
608
|
+
if (gitBaseNote) throw new Error(`${error instanceof Error ? error.message : String(error)}${gitBaseNote}`);
|
|
609
|
+
throw error;
|
|
597
610
|
}
|
|
598
|
-
return enrollCanaryTask(this.cwd, input, this.enrollmentRegistry);
|
|
599
611
|
}
|
|
600
612
|
|
|
601
613
|
async advance(taskId: string, signal?: AbortSignal) {
|
|
@@ -378,6 +378,7 @@ export function elicitationParams(input: NativeConfirmationInput) {
|
|
|
378
378
|
input.intentRevision !== undefined ? `Intent revision: ${input.intentRevision}` : null,
|
|
379
379
|
input.intentContentHash ? `Intent hash: ${input.intentContentHash}` : null,
|
|
380
380
|
input.bindingDigest ? `Binding digest: ${input.bindingDigest}` : null,
|
|
381
|
+
input.gitBaseNotice,
|
|
381
382
|
].filter(Boolean);
|
|
382
383
|
return {
|
|
383
384
|
mode: "form",
|
|
@@ -40,6 +40,7 @@ import { projectLegacyAudit } from "../kernel/legacy_audit";
|
|
|
40
40
|
import { inspectStorageLayout } from "../kernel/storage_paths";
|
|
41
41
|
import { migrateLegacyLayout } from "../kernel/storage_layout_migration";
|
|
42
42
|
import { readBackendClaim } from "../kernel/backend_claim";
|
|
43
|
+
import { inspectEnrollmentGitBase, type EnrollmentGitBase } from "../assurance/enrollment_git_base";
|
|
43
44
|
import { probeKernelStore } from "../kernel";
|
|
44
45
|
|
|
45
46
|
export interface KernelCommandResult {
|
|
@@ -1134,8 +1135,11 @@ function runIntentValidate(args: string[], root: string): KernelExecution {
|
|
|
1134
1135
|
gitTracked = false;
|
|
1135
1136
|
}
|
|
1136
1137
|
|
|
1138
|
+
let gitBase: EnrollmentGitBase | { state: "invalid"; reason: string };
|
|
1139
|
+
try { gitBase = inspectEnrollmentGitBase(canonicalRoot); }
|
|
1140
|
+
catch (error) { gitBase = { state: "invalid", reason: error instanceof Error ? error.message : String(error) }; }
|
|
1137
1141
|
const contentHash = canonicalIntentHash(intent);
|
|
1138
|
-
const enrollmentReady = gitTracked && allEligible;
|
|
1142
|
+
const enrollmentReady = gitTracked && allEligible && gitBase.state !== "invalid";
|
|
1139
1143
|
return {
|
|
1140
1144
|
result: jsonResult(
|
|
1141
1145
|
{
|
|
@@ -1148,6 +1152,8 @@ function runIntentValidate(args: string[], root: string): KernelExecution {
|
|
|
1148
1152
|
acceptance_ids: intent.acceptance.map((item) => item.id),
|
|
1149
1153
|
verification: verification,
|
|
1150
1154
|
git_ownership: gitTracked ? "tracked" : "untracked",
|
|
1155
|
+
git_base: gitBase,
|
|
1156
|
+
git_base_initialization_required: gitBase.state === "unborn",
|
|
1151
1157
|
enrollment_ready: enrollmentReady,
|
|
1152
1158
|
},
|
|
1153
1159
|
0,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by scripts/plugin_versioning.ts from the root package.json.
|
|
2
|
-
export const PLUGIN_VERSION = "4.
|
|
2
|
+
export const PLUGIN_VERSION = "4.3.0" as const;
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
from `dist/`; nested modes, examples, recovery, and references load on demand.
|
|
7
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
8
|
- Keep edits inside the user-requested Direct scope or the enrolled TaskIntent acceptance and `scope_hint`.
|
|
9
|
-
- Stage only explicit task-owned paths.
|
|
9
|
+
- Stage only explicit task-owned paths. This staging authority does not grant
|
|
10
|
+
commit, push, broad staging, or authority over pre-existing user changes.
|
|
11
|
+
Never use `git add .` or `git add -A` in a dirty worktree.
|
|
10
12
|
- Do not create, switch, or delete Git worktrees; operate only in the Host launch directory.
|
|
11
13
|
- Record reproducible evidence before reporting closure.
|
|
12
14
|
- 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.
|
|
@@ -46,7 +48,9 @@ routing. A new Managed workflow starts only from explicit `imm-brainstorm`,
|
|
|
46
48
|
Managed owner remains authoritative; the user resumes it with `imm-loop`.
|
|
47
49
|
2. **Start explicitly**: the selected Immune-Brain Skill owns its planning or
|
|
48
50
|
coordination work. It creates only requested artifacts and their required
|
|
49
|
-
parent directories
|
|
51
|
+
parent directories. Explicit Planner entry also owns absent routing-policy
|
|
52
|
+
activation under Planner's Kernel TaskIntent Routing section;
|
|
53
|
+
it does not otherwise install project-wide contract files.
|
|
50
54
|
3. **Preserve authority**: Planner output is a candidate for later literal-user
|
|
51
55
|
Enrollment, and Fast-Track preserves TaskIntent scope, Enrollment, QA,
|
|
52
56
|
Review, authorization, and completion boundaries.
|
|
@@ -89,6 +93,8 @@ Privileged effects include:
|
|
|
89
93
|
|
|
90
94
|
Routine Managed enrollment uses one current-Host native confirmation bound to the TaskIntent content hash after Planner validation. Explicit Plan-only requests stop with candidate artifacts and do not invoke Enrollment; execution-bearing requests open the native gate directly without chat pre-confirmation. Enrollment validates intent, Git ownership, scope, workspace claim, and final authority preconditions without executing acceptance descriptors; deterministic QA executes them after implementation. The routine task proceeds from that single confirmation through enrollment, execution, and QA without a second human stop. Do not request confirmation for local in-scope edits, local verification, ordinary Direct rework, scoped diff review, or completion reporting. Managed evidence, QA, Review, and completion authority remain governed by their Managed contracts; R2 does not weaken them. Managed native-authority failures fail closed with one stable reason and exactly one same-Host recovery action; never offer a Pi, Direct Path, cross-Host/worktree, unmanaged, or automatic-retry fallback.
|
|
91
95
|
|
|
96
|
+
For an unborn symbolic Git HEAD, the same Enrollment confirmation discloses an empty root commit. After approval, the Host creates that commit without staging project content or changing the index/worktree, then revalidates ownership and rehearses Enrollment against the new base. Git identity uses existing environment/config values with an explicit automation fallback, never config writes. Decline or pre-initialization cancellation leaves HEAD unborn; if later Enrollment fails or is cancelled, report the remaining commit. Invalid Git refs are errors, not initialization candidates.
|
|
97
|
+
|
|
92
98
|
## Parallel Read-Only Dispatch
|
|
93
99
|
|
|
94
100
|
State mutations, step activations, QA decisions, and plan switches remain
|