Block unverified external plan adoption without granting authority

This commit is contained in:
wassname2
2026-09-15 17:20:27 +08:00
parent 4599b5ad9f
commit ed050658e3
4 changed files with 45 additions and 35 deletions
+31 -21
View File
@@ -332,15 +332,14 @@ it("rejects an existing zero-byte evidence file", async () => {
expect(result.content[0].text).toContain("Empty evidence"); expect(readFileSync(f.path, "utf8")).toBe(before);
});
it("requires actual nonempty evidence, distinguishes manual ticks, and retains reviewed markers through Clear/reattach", async () => {
it("requires actual nonempty evidence, distinguishes manual ticks, and retains reviewed markers through same-context restoration", async () => {
const f = fixture(); await f.draft(); await f.command("ready");
const complete = (goal: string, evidence: string[], signal?: AbortSignal) => f.tools.get("CompleteGoal").execute("t", { goal, evidence, observation: "Inspected exact saved bytes" }, signal, undefined, f.ctx);
expect((await complete("first output", ["missing.log"])).content[0].text).toContain("Evidence unavailable");
mkdirSync(join(f.ctx.cwd, "evidence")); writeFileSync(join(f.ctx.cwd, "evidence/pass.log"), "actual fixture bytes\n");
expect((await complete("first output", ["evidence/pass.log"], AbortSignal.abort())).content[0].text).toContain("Cancelled");
await complete("first output", ["evidence/pass.log"]);
await f.command("clear");
f.ctx.ui.select.mockResolvedValueOnce("Previous supervisor confirmed stopped"); await f.command(`attach ${f.path}`); await f.command("ready");
await f.command(`attach ${f.path}`);
writeFileSync(f.path, readFileSync(f.path, "utf8").replace("[ ] goal: second", "[x] goal: second"));
f.hooks.get("session_start")({}, f.ctx);
expect(f.ctx.ui.setStatus).toHaveBeenLastCalledWith("goals", "👀 1/2 goals");
@@ -575,21 +574,22 @@ it("requires confirmed worker stop before solo takeover and never lets two write
expect(text).toContain("self-verification");
});
it("attaches an existing plan without restarting completed work, and restores its noted worker session", async () => {
it("leaves an unverified external plan and its noted worker untouched", async () => {
const f = fixture();
const existing = join(f.ctx.cwd, "existing.md");
writeFileSync(existing, "# Plan\n- preferred worker model: deepseek flash\n- worker session: /tmp/attach-child.jsonl\n- [ ] goal: attached goal\n\n## Log\n- previous progress kept\n");
f.ctx.ui.select.mockResolvedValueOnce("Previous supervisor confirmed stopped");
await f.command(`attach ${existing}`);
expect(f.entries.at(-1).data.mode).toBe("planning");
expect(f.entries.at(-1).data.plan).toBe(existing);
expect(f.messages.at(-1).message.content).toContain("without restarting completed work");
expect(f.messages.at(-1).message.content).toContain("/tmp/attach-child.jsonl");
expect(f.entries).toEqual([]);
expect(f.messages).toEqual([]);
expect(f.ctx.ui.select).not.toHaveBeenCalled();
expect(readFileSync(existing, "utf8")).toContain("previous progress kept");
expect(f.ctx.ui.notify).toHaveBeenLastCalledWith(expect.stringContaining("Original supervisor unknown"), "warning");
});
it("attaches directly into solo mode and reports the recorded session in status", async () => {
const f = fixture();
const existing = join(f.ctx.cwd, "existing.md");
it("retains same-current-plan solo recovery and reports the recorded session in status", async () => {
const f = fixture(); await f.draft();
const existing = f.path;
writeFileSync(existing, "# Plan\n- worker session: /tmp/attach-child.jsonl\n- [ ] goal: attached goal\n\n## Log\n");
f.ctx.ui.select.mockResolvedValueOnce("Worker confirmed stopped");
await f.command(`attach ${existing} solo`);
@@ -621,9 +621,10 @@ it.each(["exit", "quit", "clear", "menu"])("%s exits planning with the draft pre
expect(f.ctx.ui.setWidget).toHaveBeenLastCalledWith("goals", undefined);
expect(readFileSync(f.path, "utf8")).toContain("first output");
expect(f.messages.length).toBe(before); // notify only, no model turn started
f.ctx.ui.select.mockResolvedValueOnce("Previous supervisor confirmed stopped");
await f.command(`attach ${f.path}`);
expect(f.entries.at(-1).data.mode).toBe("planning");
expect(f.entries.at(-1).data.mode).toBe("chat");
expect(f.messages.length).toBe(before);
expect(f.ctx.ui.notify).toHaveBeenLastCalledWith(expect.stringContaining("Cannot verify ownership"), "warning");
});
it("records the preferred worker model as a visible plan preference", async () => {
@@ -647,7 +648,7 @@ it.each(["solo", "attach"])("%s takeover cannot bypass confirmation or survive a
expect(f.entries.at(-1).data.workerStopped).not.toBe(true);
});
it("attach solo requires stop confirmation for a noted worker even in a fresh session", async () => {
it("external attach solo cannot turn a noted worker or stop checkbox into ownership proof", async () => {
const f = fixture(); const path = join(f.ctx.cwd, "saved.md");
writeFileSync(path, `# Plan\n- worker session: /tmp/known.jsonl\n${f.plan}`);
f.ctx.ui.select.mockResolvedValueOnce("Cancel");
@@ -655,21 +656,27 @@ it("attach solo requires stop confirmation for a noted worker even in a fresh se
expect(f.entries).toHaveLength(0);
f.ctx.ui.select.mockResolvedValueOnce("Worker confirmed stopped");
await f.command(`attach ${path} solo`);
expect(f.entries.at(-1).data).toMatchObject({ mode: "solo", workerStopped: true, worker: { sessionFile: "/tmp/known.jsonl" } });
expect(f.entries).toHaveLength(0);
expect(f.ctx.ui.select).not.toHaveBeenCalled();
expect(f.messages).toEqual([]);
expect(readFileSync(path, "utf8")).toContain("worker session: /tmp/known.jsonl");
});
it("retains the stopped session reference across plan changes", async () => {
it("retains current solo authority and stopped-session reference when external adoption is blocked", async () => {
const f = fixture(); await f.draft(); await f.command("ready");
await f.launch({ id: "child", sessionFile: "/tmp/prior.jsonl" });
f.ctx.ui.select.mockResolvedValueOnce("Worker confirmed stopped"); await f.command("solo");
const other = join(f.ctx.cwd, "another.md"); writeFileSync(other, "- [ ] goal: next\n## Log\n");
const before = f.entries.at(-1), messageCount = f.messages.length;
f.ctx.ui.select.mockResolvedValueOnce("Previous supervisor confirmed stopped");
await f.command(`attach ${other}`);
expect(f.entries.at(-1).data).toMatchObject({ mode: "planning", plan: other, workerStopped: true, worker: { sessionFile: "/tmp/prior.jsonl" } });
await f.command("ready");
expect(f.entries.at(-1).data).toMatchObject({ mode: "solo", plan: f.path, workerStopped: true, worker: { sessionFile: "/tmp/prior.jsonl" } });
expect(f.entries.at(-1)).toBe(before); expect(f.messages).toHaveLength(messageCount);
expect(f.ctx.ui.notify).toHaveBeenLastCalledWith(expect.stringContaining('read({path:"/tmp/prior.jsonl"})'), "warning");
expect(f.ctx.ui.notify).toHaveBeenLastCalledWith(expect.stringContaining('herdr pane process-info --pane "native-pane"'), "warning");
expect(f.ctx.ui.notify).toHaveBeenLastCalledWith(expect.stringContaining("locate exact ID child"), "warning");
const response = await f.tools.get("OpenGoalWorker").execute("open", { task: "next task" }, undefined, undefined, f.ctx);
expect(response.content[0].text).toContain("already recorded");
expect(response.content[0].text).toContain("solo");
expect(f.entries.at(-1).data.workerStopped).toBe(true);
});
@@ -922,7 +929,7 @@ it("changed plan or shutdown during takeover never grants solo permission", asyn
expect(f.entries.at(-1).data.mode).toBe("planning");
});
it("requires explicit supervisor ownership confirmation when attaching an existing plan", async () => {
it("blocks unknown external ownership without offering an attestation or launching work", async () => {
const f = fixture(); const path = join(f.ctx.cwd, "shared.md");
writeFileSync(path, f.plan);
f.ctx.ui.select.mockResolvedValueOnce("Cancel");
@@ -930,7 +937,10 @@ it("requires explicit supervisor ownership confirmation when attaching an existi
expect(f.entries).toHaveLength(0);
f.ctx.ui.select.mockResolvedValueOnce("Previous supervisor confirmed stopped");
await f.command(`attach ${path}`);
expect(f.entries.at(-1).data).toMatchObject({ mode: "planning", plan: path });
expect(f.entries).toHaveLength(0);
expect(f.ctx.ui.select).not.toHaveBeenCalled();
expect(f.messages).toEqual([]);
expect(f.ctx.ui.notify).toHaveBeenLastCalledWith(expect.stringContaining("supported Intercom roster does not identify per-plan supervisors"), "warning");
});
it("does not approve cancelled goals or display current completion for an unavailable plan", async () => {