Skip to content

Commit 72c5be2

Browse files
committed
Scope Migrator shell to dry-run and scratch-copy execution
run_shell is dry-run/scratch-copy ONLY: never execute the forward migration against live state, no background shells (shell_collect unmounted; foreground with timeouts only). Scratch copies live under tmp/, are cleaned up afterwards, and the scratch path is reported in the delivery. Rename the registry leaf test to dry-run-scoped and raise the migrator prompt budgets to 12800 chars / 13900 bytes (measured-max + 2000/+3000, ceiling 100).
1 parent 4d45067 commit 72c5be2

4 files changed

Lines changed: 33 additions & 4 deletions

File tree

‎src/agent/directors/migrator/package.test.ts‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,29 @@ describe("migratorPackage", () => {
4343
expect(p).toMatch(/do not ship it/);
4444
});
4545

46+
test("systemPrompt scopes run_shell to dry-run/scratch-only, forbids live execution", () => {
47+
const p = migratorPackage.systemPrompt;
48+
expect(p).toMatch(/dry-run and scratch-copy execution ONLY/);
49+
expect(p).toMatch(/never execute the forward migration/);
50+
expect(p).toMatch(/live state/);
51+
});
52+
53+
test("systemPrompt forbids background shells — foreground with timeouts only", () => {
54+
const p = migratorPackage.systemPrompt;
55+
expect(p).toMatch(/Background shells are forbidden/);
56+
expect(p).toMatch(/background: true/);
57+
expect(p).toMatch(/shell_collect/);
58+
expect(p).toMatch(/foreground/);
59+
expect(p).toMatch(/timeouts only/);
60+
});
61+
62+
test("systemPrompt makes scratch auditable under tmp/ with reported path", () => {
63+
const p = migratorPackage.systemPrompt;
64+
expect(p).toMatch(/tmp\//);
65+
expect(p).toMatch(/clean them up afterwards/);
66+
expect(p).toMatch(/scratch path in the delivery/);
67+
});
68+
4669
test("systemPrompt states the report shape", () => {
4770
const p = migratorPackage.systemPrompt;
4871
expect(p).toMatch(

‎src/agent/directors/migrator/package.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,5 @@ export const migratorPackage: DirectorPackage = {
2626
modelRole: "plan",
2727
systemPrompt: `PRIMARY INTENT: Ship reversible data migrations with dry-run evidence and a tested rollback path.
2828
29-
You are Migrator, the reversible-migration leaf. You own settings-schema, config-key, run.json, and context-store-layout data changes ONLY — never bulk renames, never features. Every change ships three artifacts: (1) dry-run output showing exactly what would change, (2) the forward migration path, (3) the rollback path back to the prior shape. State what happens to in-flight sessions on both paths. Verify the rollback by executing it in a scratch copy (temporary test, cleaned up afterwards), not by inspection. If a change cannot be rolled back, say so plainly and stop — do not ship it. Report: dry-run output, forward path, rollback path, in-flight impact.`,
29+
You are Migrator, the reversible-migration leaf. You own settings-schema, config-key, run.json, and context-store-layout data changes ONLY — never bulk renames, never features. Every change ships three artifacts: (1) dry-run output showing exactly what would change, (2) the forward migration path, (3) the rollback path back to the prior shape. State what happens to in-flight sessions on both paths. Verify the rollback by executing it in a scratch copy (temporary test, cleaned up afterwards), not by inspection. run_shell is for dry-run and scratch-copy execution ONLY — never execute the forward migration (or anything else) against live state. Background shells are forbidden (background: true starts are uncollectable without shell_collect, which is deliberately not mounted) — use foreground calls with timeouts only. Keep scratch copies under tmp/, clean them up afterwards, and report the scratch path in the delivery. If a change cannot be rolled back, say so plainly and stop — do not ship it. Report: dry-run output, forward path, rollback path, in-flight impact.`,
3030
};

‎src/agent/directors/registry.test.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,16 @@ describe("director registry", () => {
133133
expect(packageToProfile(g).orchestrator).toBe(true);
134134
});
135135

136-
test("migrator is a read-only leaf with no fleet verbs (CL-7671)", () => {
136+
test("migrator is a dry-run-scoped leaf with no fleet verbs (CL-7671)", () => {
137137
const m = DIRECTOR_REGISTRY.migrator;
138138
expect(m.id).toBe("migrator");
139139
expect(m.tier).toBe("leaf");
140140
expect(m.spawn.maySpawn).toBe(false);
141141
expect(m.modelRole).toBe("plan");
142142
expect(m.tools?.allow).toEqual(["read_file", "grep", "lsp", "run_shell"]);
143143
expect(packageToProfile(m).orchestrator).toBe(false);
144+
expect(m.systemPrompt).toMatch(/dry-run and scratch-copy execution ONLY/);
145+
expect(m.systemPrompt).toMatch(/Background shells are forbidden/);
144146
const r = resolveDirector({ agentId: "migrator" });
145147
expect(r.ok).toBe(true);
146148
if (r.ok) expect(r.package.id).toBe("migrator");

‎src/agent/prompt-sizes.test.ts‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ const CHAR_BUDGET: Record<DirectorId, number> = {
3333
shakespeare: 54700,
3434
testsmith: 16200,
3535
tester: 13900,
36-
migrator: 12300,
36+
// CL-7671 scope-honesty sentences grew migrator past the 12300-char
37+
// placeholder: measured-max + 2000 allowance, ceiling to 100.
38+
migrator: 12800,
3739
};
3840

3941
const BYTE_BUDGET: Record<DirectorId, number> = {
@@ -55,7 +57,9 @@ const BYTE_BUDGET: Record<DirectorId, number> = {
5557
shakespeare: 55900,
5658
testsmith: 17200,
5759
tester: 15000,
58-
migrator: 13400,
60+
// CL-7671 scope-honesty sentences grew migrator past the 13400-byte
61+
// placeholder: measured-max + 3000 allowance, ceiling to 100.
62+
migrator: 13900,
5963
};
6064

6165
function budgetMessage(

0 commit comments

Comments
 (0)