immune-brain 4.4.1 → 4.6.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 +3 -2
- 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 +0 -1
- package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +47 -2
- package/plugins/immune-brain/.pi-extension/imm-unattended-batch.ts +23 -18
- package/plugins/immune-brain/.pi-extension/runtime-stub.ts +0 -3
- package/plugins/immune-brain/dist/BASELINE.md +18 -1
- package/plugins/immune-brain/dist/claude/mcp-server.mjs +1401 -1101
- package/plugins/immune-brain/dist/docs/reference/subagent-dispatch-protocol.md +30 -0
- package/plugins/immune-brain/dist/imm-brainstorm.md +21 -0
- package/plugins/immune-brain/dist/imm-loop.md +52 -6
- package/plugins/immune-brain/dist/imm-planner.md +102 -13
- package/plugins/immune-brain/dist/role-prompts/code-review.md +19 -0
- package/plugins/immune-brain/dist/role-prompts/qa.md +13 -1
- package/plugins/immune-brain/runtime/assurance/coordinator.ts +55 -2
- package/plugins/immune-brain/runtime/assurance/review_evidence.ts +4 -0
- package/plugins/immune-brain/runtime/claude/interaction.ts +1 -2
- package/plugins/immune-brain/runtime/claude/kernel_ports.ts +73 -27
- package/plugins/immune-brain/runtime/claude/mcp_server.ts +3 -4
- package/plugins/immune-brain/runtime/claude/review_host.ts +15 -0
- package/plugins/immune-brain/runtime/github_issue_tracker.ts +956 -634
- package/plugins/immune-brain/runtime/kernel/application.ts +2 -5
- package/plugins/immune-brain/runtime/kernel/authority_port.ts +5 -14
- package/plugins/immune-brain/runtime/kernel/batch_authority.ts +30 -49
- package/plugins/immune-brain/runtime/kernel/canary_application.ts +1 -2
- package/plugins/immune-brain/runtime/kernel/canary_eligibility.ts +0 -1
- package/plugins/immune-brain/runtime/kernel/capability_registry.ts +7 -9
- package/plugins/immune-brain/runtime/kernel/enrollment.ts +21 -12
- package/plugins/immune-brain/runtime/kernel/enrollment_authority.ts +5 -11
- package/plugins/immune-brain/runtime/kernel/storage.ts +8 -3
- package/plugins/immune-brain/runtime/kernel/types.ts +2 -1
- package/plugins/immune-brain/runtime/kernel/validation.ts +3 -1
- package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
- package/plugins/immune-brain/runtime/prompts/code-review.md +19 -0
- package/plugins/immune-brain/runtime/prompts/qa.md +13 -1
- package/plugins/immune-brain/runtime/unattended/batch_git.ts +9 -1
- package/plugins/immune-brain/runtime/unattended/batch_plan.ts +3 -9
- package/plugins/immune-brain/runtime/unattended/batch_preflight.ts +152 -46
- package/plugins/immune-brain/runtime/unattended/batch_reasons.ts +0 -6
- package/plugins/immune-brain/runtime/unattended/batch_reconfirmation.ts +193 -0
- package/plugins/immune-brain/runtime/unattended/batch_runner.ts +112 -122
- package/plugins/immune-brain/runtime/unattended/batch_state.ts +57 -16
- package/plugins/immune-brain/runtime/unattended/types.ts +0 -2
- package/plugins/immune-brain/runtime/v4_runtime.ts +54 -0
- package/plugins/immune-brain/runtime/workspace_scope.ts +75 -12
- package/plugins/immune-brain/skills/BASELINE.md +18 -1
- package/plugins/immune-brain/skills/imm-brainstorm/SKILL.md +5 -0
- package/plugins/immune-brain/skills/imm-loop/SKILL.md +4 -2
- package/plugins/immune-brain/skills/imm-planner/SKILL.md +10 -1
- package/plugins/immune-brain/runtime/unattended/confirmation_deadline.ts +0 -33
package/README.md
CHANGED
|
@@ -301,7 +301,8 @@ When an Initiative has several ready children, you can run them as one serial ba
|
|
|
301
301
|
- **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.
|
|
302
302
|
- **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.
|
|
303
303
|
- **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.
|
|
304
|
-
- **
|
|
304
|
+
- **Closeout is automatic:** when a child reaches `done` in the foreground, the same call commits it and enrolls the next child, or marks the batch `completed`, with no new gate. A parked or stopped child is never committed for you, and a failed continuation is reported beside the result with `start_unattended_batch` as the retry. A fast-forward commit you add to the batch branch is adopted; any other HEAD movement still stops the run.
|
|
305
|
+
- **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, authorization, or commit failure stops it; the budget is a child count and a QA failure limit, and nothing expires with time, 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.
|
|
305
306
|
|
|
306
307
|
---
|
|
307
308
|
|
|
@@ -361,7 +362,7 @@ docs/specs/ # Living specs (updated in place)
|
|
|
361
362
|
|
|
362
363
|
**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.
|
|
363
364
|
|
|
364
|
-
**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,
|
|
365
|
+
**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, authorization, or commit failure. A parked run waits for you indefinitely: neither the confirmation dialog nor the authorization it grants times out. It never pushes, opens PRs, or settles user decisions for you.
|
|
365
366
|
|
|
366
367
|
**Can I switch between hosts (e.g. plan in Claude Code, code in Pi)?** Yes. Immune-Brain's contracts and state live entirely on disk in the repository, decoupled from conversation sessions. You can leverage Claude Code for deep architectural thinking and Spec planning, then switch to Pi to run `imm-loop` for code execution and deterministic QA. Interrupted tasks can be resumed in either host at any time.
|
|
367
368
|
|
package/package.json
CHANGED
|
@@ -557,7 +557,6 @@ async function executeForegroundEnrollment(
|
|
|
557
557
|
preparation_digest: preparation.digest,
|
|
558
558
|
actor_id: LITERAL_USER_ACTOR_ID,
|
|
559
559
|
confirmation_ref: `pi-confirm-${createHash("sha256").update(`${taskId}\0${now}\0${nonce}`).digest("hex").slice(0, 16)}`,
|
|
560
|
-
expires_at: new Date(Date.now() + 10 * 60 * 1000).toISOString(),
|
|
561
560
|
nonce,
|
|
562
561
|
};
|
|
563
562
|
const capability = registry.issue(binding);
|
|
@@ -21,6 +21,8 @@ import { join, resolve } from "node:path";
|
|
|
21
21
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
22
22
|
import { Type } from "typebox";
|
|
23
23
|
import { PLUGIN_VERSION } from "../runtime/plugin_version";
|
|
24
|
+
import { findResumableBatchSlugForTask } from "../runtime/unattended/batch_preflight";
|
|
25
|
+
import { executePiUnattendedBatch } from "./imm-unattended-batch";
|
|
24
26
|
import {
|
|
25
27
|
parseVerificationDescriptor,
|
|
26
28
|
type VerificationDescriptor,
|
|
@@ -581,7 +583,11 @@ export default function (
|
|
|
581
583
|
: action.op === "request_stop"
|
|
582
584
|
? await authorizeExactOperation(taskId, "stop", { ...ctx, signal: signal && ctx.signal ? AbortSignal.any([signal, ctx.signal]) : signal ?? ctx.signal })
|
|
583
585
|
: await requestAuthorization(taskId, ctx);
|
|
584
|
-
const enriched = await
|
|
586
|
+
const enriched = await closeOutBatchChild(
|
|
587
|
+
ctx,
|
|
588
|
+
taskId,
|
|
589
|
+
await enrichAssuranceResult(ctx, taskId, result as unknown as Record<string, unknown>),
|
|
590
|
+
);
|
|
585
591
|
presentTaskRailResult(ctx, taskId, enriched);
|
|
586
592
|
throwIfCanaryToolFailure(taskId, action.op, enriched);
|
|
587
593
|
return toolResult(JSON.stringify(enriched, null, 2), enriched);
|
|
@@ -1648,7 +1654,6 @@ async function mintCapability(
|
|
|
1648
1654
|
confirmation_ref: `pi-confirm-${createHash("sha256").update(
|
|
1649
1655
|
`${input.task_id}\0${now}\0${input.intent_revision}\0${input.intent_content_hash}\0${input.diff_hash}`,
|
|
1650
1656
|
).digest("hex").slice(0, 16)}`,
|
|
1651
|
-
expires_at: new Date(Date.now() + 10 * 60 * 1000).toISOString(),
|
|
1652
1657
|
findings_digest:
|
|
1653
1658
|
input.action_kind === "request_rework"
|
|
1654
1659
|
? await findingsDigestV2(input.findings as never[])
|
|
@@ -1732,6 +1737,46 @@ async function reconcileRefsQuietly(root: string): Promise<void> {
|
|
|
1732
1737
|
}
|
|
1733
1738
|
}
|
|
1734
1739
|
|
|
1740
|
+
/**
|
|
1741
|
+
* Gate-free closeout: a batch child that reached Kernel `done` in the foreground
|
|
1742
|
+
* re-enters the batch in the same call, reusing its authorization. Only `done`
|
|
1743
|
+
* continues; stopped, parked and Review-pending children end where they do
|
|
1744
|
+
* today. The continuation is transport: the Kernel result is returned
|
|
1745
|
+
* unchanged, and any failure is reported beside it with one retry action.
|
|
1746
|
+
*/
|
|
1747
|
+
async function closeOutBatchChild(
|
|
1748
|
+
ctx: ExtensionContext,
|
|
1749
|
+
taskId: string,
|
|
1750
|
+
enriched: Record<string, unknown>,
|
|
1751
|
+
): Promise<Record<string, unknown>> {
|
|
1752
|
+
const taskState = enriched.task_state as { lifecycle?: unknown } | undefined;
|
|
1753
|
+
if (taskState?.lifecycle !== "done") return enriched;
|
|
1754
|
+
let slug: string | null;
|
|
1755
|
+
try {
|
|
1756
|
+
slug = findResumableBatchSlugForTask(ctx.cwd, taskId);
|
|
1757
|
+
} catch {
|
|
1758
|
+
return enriched;
|
|
1759
|
+
}
|
|
1760
|
+
if (!slug) return enriched;
|
|
1761
|
+
try {
|
|
1762
|
+
// The batch commit takes exactly the scope envelope plus this task's own
|
|
1763
|
+
// audit evidence and refuses unstaged changes: stage only that evidence.
|
|
1764
|
+
if (existsSync(join(ctx.cwd, ".imm", "audit", taskId)))
|
|
1765
|
+
execFileSync("git", ["-C", ctx.cwd, "add", "--", `.imm/audit/${taskId}`], { stdio: "ignore" });
|
|
1766
|
+
const batch = await executePiUnattendedBatch({ root: ctx.cwd, initiativeSlug: slug, reuseOnly: true, signal: ctx.signal });
|
|
1767
|
+
return { ...enriched, batch };
|
|
1768
|
+
} catch (error) {
|
|
1769
|
+
return {
|
|
1770
|
+
...enriched,
|
|
1771
|
+
batch: {
|
|
1772
|
+
state: "rejected",
|
|
1773
|
+
reason: `batch continuation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
1774
|
+
recovery_action: "call start_unattended_batch with the same Initiative to continue the batch",
|
|
1775
|
+
},
|
|
1776
|
+
};
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1735
1780
|
async function enrichAssuranceResult(
|
|
1736
1781
|
ctx: ExtensionContext,
|
|
1737
1782
|
taskId: string,
|
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
type InitiativeObservationReader,
|
|
20
20
|
} from "./runtime-stub";
|
|
21
21
|
import { batchReason } from "../runtime/unattended/batch_reasons";
|
|
22
|
-
import { startConfirmationDeadline } from "../runtime/unattended/confirmation_deadline";
|
|
23
22
|
import {
|
|
24
23
|
authorizeBatch,
|
|
25
24
|
projectBatchPreflight,
|
|
@@ -69,12 +68,16 @@ export interface PiBatchExecutionOptions {
|
|
|
69
68
|
root: string;
|
|
70
69
|
initiativeSlug: string;
|
|
71
70
|
interactive?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Gate-free continuation after a foreground child: never opens the
|
|
73
|
+
* confirmation, and an authorization that cannot be reused is reported as a
|
|
74
|
+
* blocked result with the one action that reopens the gate.
|
|
75
|
+
*/
|
|
76
|
+
reuseOnly?: boolean;
|
|
72
77
|
signal?: AbortSignal;
|
|
73
78
|
batchKernel?: Partial<BatchRunnerKernelPort>;
|
|
74
79
|
batchGit?: BatchRunnerGitPort;
|
|
75
80
|
readInitiative?: InitiativeObservationReader;
|
|
76
|
-
/** Environment the confirmation deadline reads; production passes process.env. */
|
|
77
|
-
env?: Record<string, string | undefined>;
|
|
78
81
|
confirmBatch?: (details: {
|
|
79
82
|
title: string;
|
|
80
83
|
summary: string;
|
|
@@ -107,9 +110,10 @@ export async function executePiUnattendedBatch(
|
|
|
107
110
|
options: PiBatchExecutionOptions,
|
|
108
111
|
): Promise<PiBatchExecutionResult> {
|
|
109
112
|
const { root, initiativeSlug, signal } = options;
|
|
113
|
+
const reuseOnly = options.reuseOnly === true;
|
|
110
114
|
const interactive = options.interactive ?? true;
|
|
111
115
|
|
|
112
|
-
if (!interactive) return { state: "rejected", ...nonInteractiveRefusal() };
|
|
116
|
+
if (!reuseOnly && !interactive) return { state: "rejected", ...nonInteractiveRefusal() };
|
|
113
117
|
|
|
114
118
|
// 1. Host-independent batch preflight: claim ownership, branch availability,
|
|
115
119
|
// working-tree cleanliness against the authorized scope, recovery children,
|
|
@@ -132,7 +136,7 @@ export async function executePiUnattendedBatch(
|
|
|
132
136
|
const planDigest = preflight.projection.plan_digest;
|
|
133
137
|
const recoveryChildren = preflight.projection.recovery_children;
|
|
134
138
|
|
|
135
|
-
// 4. Literal-user gate plus the shared reuse
|
|
139
|
+
// 4. Literal-user gate plus the shared reuse decision, the post-gate
|
|
136
140
|
// claim/drift cascade, and the Batch Authorization binding. The Host supplies
|
|
137
141
|
// only its gate, its confirmation reference, and its binding nonce.
|
|
138
142
|
const authorization = await authorizeBatch<PiBatchExecutionResult>({
|
|
@@ -143,36 +147,40 @@ export async function executePiUnattendedBatch(
|
|
|
143
147
|
readInitiative: options.readInitiative,
|
|
144
148
|
nonce: randomUUID(),
|
|
145
149
|
gate: async (facts) => {
|
|
150
|
+
if (reuseOnly)
|
|
151
|
+
return {
|
|
152
|
+
kind: "host_rejection",
|
|
153
|
+
value: {
|
|
154
|
+
state: "blocked",
|
|
155
|
+
reason: `batch authorization cannot be reused (${facts.reuse_blockers.join(", ")})`,
|
|
156
|
+
recovery_action: "call start_unattended_batch with the same Initiative to confirm a fresh authorization",
|
|
157
|
+
},
|
|
158
|
+
};
|
|
146
159
|
// review-2: fail closed with zero writes when confirmation port is missing
|
|
147
160
|
if (!options.confirmBatch) {
|
|
148
161
|
return { kind: "host_rejection", value: batchReason("confirmation_port_unavailable") };
|
|
149
162
|
}
|
|
150
163
|
const confirmDetails = {
|
|
151
164
|
title: `Authorize Unattended Batch: ${facts.initiative_slug}`,
|
|
152
|
-
summary: `Initiative: ${facts.initiative_slug}\nBatch branch: ${facts.batch_branch}\nPlan digest: ${facts.plan_digest}\nBudget: max_children=${facts.budget.max_children},
|
|
165
|
+
summary: `Initiative: ${facts.initiative_slug}\nBatch branch: ${facts.batch_branch}\nPlan digest: ${facts.plan_digest}\nBudget: max_children=${facts.budget.max_children}, qa_failure_limit=${facts.budget.qa_failure_limit}`,
|
|
153
166
|
details: `Ordered children (${facts.children.length}):\n${facts.children.map((child) => ` - ${child.task_id} (${child.slice_id}) [risk: ${child.risk}] [status: ${child.status === "already_settled" ? "completed" : "pending execution"}]`).join("\n")}${facts.excluded.length > 0 ? `\n\nExcluded children:\n${facts.excluded.map((child) => ` - ${child.task_id} (${child.slice_id}): ${child.reason}`).join("\n")}` : ""}${facts.reuse_blockers.length > 0 ? `\n\nRe-confirmation required: ${facts.reuse_blockers.join(", ")}.\nRecovery: confirm to issue a fresh authorization bound to the current plan and HEAD.` : ""}`,
|
|
154
167
|
planDigest: facts.plan_digest,
|
|
155
168
|
signal,
|
|
156
169
|
};
|
|
157
170
|
|
|
158
|
-
// The
|
|
159
|
-
//
|
|
160
|
-
const deadline = startConfirmationDeadline({ env: options.env ?? process.env, signal });
|
|
171
|
+
// The gate settles only on the literal user's answer or the caller's
|
|
172
|
+
// cancellation signal.
|
|
161
173
|
let decision: "accept" | "decline" | "cancel";
|
|
162
174
|
try {
|
|
163
|
-
decision = await options.confirmBatch(
|
|
175
|
+
decision = await options.confirmBatch(confirmDetails);
|
|
164
176
|
} catch (err) {
|
|
165
|
-
if (deadline.timedOut()) return { kind: "host_rejection", value: batchReason("confirmation_timed_out") };
|
|
166
177
|
if (signal?.aborted) return { kind: "host_rejection", value: batchReason("confirmation_cancelled") };
|
|
167
178
|
return {
|
|
168
179
|
kind: "host_rejection",
|
|
169
180
|
value: batchReason("confirmation_failed", err instanceof Error ? err.message : String(err)),
|
|
170
181
|
};
|
|
171
|
-
} finally {
|
|
172
|
-
deadline.clear();
|
|
173
182
|
}
|
|
174
183
|
|
|
175
|
-
if (deadline.timedOut()) return { kind: "host_rejection", value: batchReason("confirmation_timed_out") };
|
|
176
184
|
if (decision === "cancel" || signal?.aborted) {
|
|
177
185
|
return { kind: "host_rejection", value: batchReason("confirmation_cancelled") };
|
|
178
186
|
}
|
|
@@ -195,7 +203,7 @@ export async function executePiUnattendedBatch(
|
|
|
195
203
|
});
|
|
196
204
|
if (authorization.outcome === "host_rejection") return authorization.value;
|
|
197
205
|
if (authorization.outcome === "rejected") return authorization.rejection;
|
|
198
|
-
const { binding, batch_id: batchId
|
|
206
|
+
const { binding, batch_id: batchId } = authorization;
|
|
199
207
|
|
|
200
208
|
// 6. Issue Batch Authorization through Kernel registry and startBatch
|
|
201
209
|
const batchRegistry: BatchAuthorityRegistry = await createBatchAuthorityRegistry();
|
|
@@ -205,8 +213,6 @@ export async function executePiUnattendedBatch(
|
|
|
205
213
|
if (signal?.aborted) return batchReason("cancelled_before_execution");
|
|
206
214
|
|
|
207
215
|
now = new Date().toISOString();
|
|
208
|
-
if (Date.parse(expiresAt) <= Date.parse(now))
|
|
209
|
-
return batchReason("confirmation_failed", "confirmed batch deadline expired before authorization issuance");
|
|
210
216
|
const capability = batchRegistry.issue(binding, recoveryChildren as any, now);
|
|
211
217
|
|
|
212
218
|
let activeReviewDispatch: { operation_id: string; agent_params: Record<string, unknown> } | null = null;
|
|
@@ -300,7 +306,6 @@ export async function executePiUnattendedBatch(
|
|
|
300
306
|
plan_digest: planDigest,
|
|
301
307
|
base_head: binding.base_head,
|
|
302
308
|
confirmation_time: now,
|
|
303
|
-
authorization_expires_at: expiresAt,
|
|
304
309
|
budget,
|
|
305
310
|
now,
|
|
306
311
|
kernel: kernelPort,
|
|
@@ -21,7 +21,6 @@ export interface EnrollmentCapabilityBinding {
|
|
|
21
21
|
preparation_digest: string;
|
|
22
22
|
actor_id: string;
|
|
23
23
|
confirmation_ref: string;
|
|
24
|
-
expires_at: string;
|
|
25
24
|
nonce: string;
|
|
26
25
|
}
|
|
27
26
|
export interface EnrollmentAuthorityRegistry {
|
|
@@ -36,7 +35,6 @@ export interface CanaryWaiver {
|
|
|
36
35
|
reason: string;
|
|
37
36
|
actor: string;
|
|
38
37
|
confirmation_ref: string;
|
|
39
|
-
expires_at: string;
|
|
40
38
|
nonce: string;
|
|
41
39
|
}
|
|
42
40
|
export interface PiCanaryPrepareInput {
|
|
@@ -66,7 +64,6 @@ export interface CapabilityBindingV2 {
|
|
|
66
64
|
diff_hash: string;
|
|
67
65
|
actor_id: string;
|
|
68
66
|
confirmation_ref: string;
|
|
69
|
-
expires_at: string;
|
|
70
67
|
findings_digest: string | null;
|
|
71
68
|
}
|
|
72
69
|
export interface MutationAuthorityRegistry {
|
|
@@ -9,6 +9,20 @@
|
|
|
9
9
|
- Stage only explicit task-owned paths. This staging authority does not grant
|
|
10
10
|
commit, push, broad staging, or authority over pre-existing user changes.
|
|
11
11
|
Never use `git add .` or `git add -A` in a dirty worktree.
|
|
12
|
+
- Grant effects separately: staging, commit, push, publication, and outbound
|
|
13
|
+
model/data calls are distinct operations. Recovering a stage-only instruction
|
|
14
|
+
restores staging and nothing more; commit, push, and publication each keep
|
|
15
|
+
their own existing grant. An explicit approval already covering the same
|
|
16
|
+
operation, target, and impact — including a valid batch capability — stays
|
|
17
|
+
usable without another gate.
|
|
18
|
+
- Before a new outbound effect, check the project's existing research channel and
|
|
19
|
+
data scope. A public article, a mock, a documentation example, or a local
|
|
20
|
+
read-only database gives no authority to call an arbitrary provider or send new
|
|
21
|
+
data; authorize only a genuinely new channel/data/effect delta. Distinguish
|
|
22
|
+
documentation, mock, real-channel, and model-quality evidence when reporting.
|
|
23
|
+
- These text rules are instruction contracts, not a hard bash sandbox. They
|
|
24
|
+
guide behavior and are checked as contracts; they do not technically prevent an
|
|
25
|
+
arbitrary shell command, so authority gates and review remain the real boundary.
|
|
12
26
|
- Do not create, switch, or delete Git worktrees; operate only in the Host launch directory.
|
|
13
27
|
- Record reproducible evidence before reporting closure.
|
|
14
28
|
- 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.
|
|
@@ -81,7 +95,6 @@ non-Kernel operations, an explicit user approval already covering the same
|
|
|
81
95
|
operation, target, and impact is sufficient; ask again only for a material delta.
|
|
82
96
|
A generic continuation or configured preference is not blanket authorization.
|
|
83
97
|
Mandatory native gates and hash-bound manifest approvals still apply.
|
|
84
|
-
|
|
85
98
|
Privileged effects include:
|
|
86
99
|
|
|
87
100
|
- publish, release, deployment, or remote-system mutation;
|
|
@@ -91,6 +104,10 @@ Privileged effects include:
|
|
|
91
104
|
override; and
|
|
92
105
|
- external writes whose target or impact cannot be safely reversed locally.
|
|
93
106
|
|
|
107
|
+
An existing grant for one of these never inherits another: a stage-only
|
|
108
|
+
instruction stays stage-only, a commit is not push or publication authority,
|
|
109
|
+
and a valid batch capability commits only its own scope-bounded child.
|
|
110
|
+
|
|
94
111
|
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.
|
|
95
112
|
|
|
96
113
|
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.
|