Files
stack/extensions/goal/test/runtime.test.ts
T

721 lines
34 KiB
TypeScript

import assert from "node:assert/strict";
import { cpSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { test } from "node:test";
import { fencedStateFilePath } from "../lib/store.ts";
import {
publishGoalPolicy,
registerGoalTrackedItemResolver,
resetGoalPolicyRegistryForTest,
} from "../../mosaic-core/lib/goal-policy.ts";
interface SentMessage {
content: string;
options?: { deliverAs?: "steer" | "followUp" };
}
const GOAL_ROOT = dirname(fileURLToPath(new URL("../index.ts", import.meta.url)));
const INCARNATION_SOURCE = join(GOAL_ROOT, "..", "mosaic-core", "lib", "incarnation.ts");
const EXECUTIVE_UPDATE_FORMAT = "structured progress in the ms-executive-update format (Just Completed / Next Step / Blocked)";
const PROACTIVE_LOOP_DIRECTIVE =
"Before reporting, run the ms-proactive-agent loop: reconcile records, perform the next authorized ready task, and verify its result. If no task can proceed, report a concrete wait or blocker. This extension owns goal lifecycle; use skills for task tracking, not a second goal loop.";
async function loadGoalExtension(root: string): Promise<(pi: any) => void> {
const extensionRoot = join(root, "extensions", "goal-runtime");
cpSync(join(GOAL_ROOT, "lib"), join(extensionRoot, "lib"), { recursive: true });
mkdirSync(join(root, "extensions", "mosaic-core", "lib"), { recursive: true });
cpSync(INCARNATION_SOURCE, join(root, "extensions", "mosaic-core", "lib", "incarnation.ts"));
cpSync(join(GOAL_ROOT, "..", "mosaic-core", "lib", "goal-policy.ts"), join(root, "extensions", "mosaic-core", "lib", "goal-policy.ts"));
const source = readFileSync(join(GOAL_ROOT, "index.ts"), "utf8");
const withoutTypebox = source.replace(
'import { Type } from "typebox";',
'const Type = { Object: (properties: unknown) => ({ type: "object", properties }), Optional: (schema: unknown) => schema, String: (options: unknown = {}) => ({ type: "string", ...(options as object) }) };',
);
const selfContained = withoutTypebox.replace(
'import { StringEnum } from "@earendil-works/pi-ai";',
'const StringEnum = (values: readonly string[]) => ({ type: "string", enum: values });',
);
assert.notEqual(withoutTypebox, source, "headless harness must replace TypeBox runtime import");
assert.notEqual(selfContained, withoutTypebox, "headless harness must replace pi-ai runtime import");
writeFileSync(join(extensionRoot, "index.ts"), selfContained);
return (await import(`${pathToFileURL(join(extensionRoot, "index.ts")).href}?runtime=${Date.now()}`)).default;
}
async function createHeadlessHarness(root: string, incarnation: string) {
const agentDir = join(root, "state", "goal");
const handlers = new Map<string, Array<(event: any, ctx: any) => any>>();
const commands = new Map<string, any>();
const tools = new Map<string, any>();
const sent: SentMessage[] = [];
const observedChecks = new Set<string>();
const notifications: Array<{ message: string; level: string }> = [];
const widgets: unknown[] = [];
const statuses: string[] = [];
const shortcuts = new Map<string, any>();
const previousAgentDir = process.env.PI_CODING_AGENT_DIR;
const previousIncarnation = process.env.MOSAIC_LAUNCH_INCARNATION;
process.env.PI_CODING_AGENT_DIR = agentDir;
process.env.MOSAIC_LAUNCH_INCARNATION = incarnation;
const pi: any = {
on(name: string, handler: (event: any, ctx: any) => any) {
handlers.set(name, [...(handlers.get(name) ?? []), handler]);
},
registerCommand(name: string, command: any) {
commands.set(name, command);
},
registerShortcut(key: string, shortcut: any) { shortcuts.set(key, shortcut); },
registerTool(tool: any) {
// Reports execute inside a model turn. Deliver its queued check's start
// rather than bypassing before_agent_start as the old fixture did.
tools.set(tool.name, { ...tool, execute: async (...args: any[]) => {
const queued = sent.at(-1)?.content;
if (queued && !observedChecks.has(queued)) {
observedChecks.add(queued);
for (const handler of handlers.get("before_agent_start") ?? []) {
await handler({ prompt: queued, systemPrompt: "base" }, ctx);
}
}
return tool.execute(...args);
} });
},
sendUserMessage(content: string, options?: SentMessage["options"]) {
sent.push({ content, options });
},
};
let idle = false;
const ctx: any = {
mode: "interactive",
hasUI: true,
isIdle: () => idle,
ui: {
theme: { fg: (color: string, text: string) => `[${color}]${text}` },
setStatus(_id: string, text: string) { statuses.push(text); },
notify(message: string, level: string) {
notifications.push({ message, level });
},
setWidget(_id: string, value: unknown) {
widgets.push(value);
},
},
sessionManager: {
getBranch: () => [{ type: "message", message: { role: "assistant", stopReason: "stop" } }],
},
};
const goalExtension = await loadGoalExtension(root);
goalExtension(pi);
return {
commands,
tools,
sent,
notifications,
widgets,
statuses,
shortcuts,
ctx,
setIdle(value: boolean) {
idle = value;
},
async emit(name: string, event: any = { type: name }) {
if (name === "before_agent_start") observedChecks.add(event.prompt);
for (const handler of handlers.get(name) ?? []) await handler(event, ctx);
},
state() {
return JSON.parse(readFileSync(fencedStateFilePath(agentDir, incarnation), "utf8"));
},
restoreEnv() {
if (previousAgentDir === undefined) delete process.env.PI_CODING_AGENT_DIR;
else process.env.PI_CODING_AGENT_DIR = previousAgentDir;
if (previousIncarnation === undefined) delete process.env.MOSAIC_LAUNCH_INCARNATION;
else process.env.MOSAIC_LAUNCH_INCARNATION = previousIncarnation;
},
};
}
test("goal reporting instructions name the executive-update format and proactive loop", () => {
const source = readFileSync(join(GOAL_ROOT, "index.ts"), "utf8");
const checkPrompt = source.slice(source.indexOf("function checkPrompt(): string"), source.indexOf("/** Inject one check prompt"));
const goalReport = source.slice(source.indexOf('name: "goal_report"'), source.indexOf("promptSnippet:", source.indexOf('name: "goal_report"')));
const beforeAgentStart = source.slice(source.indexOf('pi.on("before_agent_start"'), source.indexOf('pi.on("tool_result"'));
for (const [section, text] of Object.entries({ checkPrompt, goalReport, beforeAgentStart })) {
assert.ok(text.includes(EXECUTIVE_UPDATE_FORMAT), `${section} must name the executive-update format`);
assert.ok(text.includes(PROACTIVE_LOOP_DIRECTIVE), `${section} must name the proactive loop`);
}
});
test("headless runtime exercises goal_report, agent_settled, follow-up injection, and pause", async () => {
const dir = mkdtempSync(join(tmpdir(), "goal-ng8-runtime-"));
const harness = await createHeadlessHarness(dir, "ng8-headless-runtime");
try {
const goal = harness.commands.get("goal");
const report = harness.tools.get("goal_report");
assert.ok(goal);
assert.ok(report);
await goal.handler("ship safely", harness.ctx);
assert.equal(harness.sent.length, 1);
assert.equal(harness.sent[0].options?.deliverAs, "followUp");
assert.match(harness.sent[0].content, /no-progress 0\/3/);
for (let cycle = 1; cycle <= 3; cycle++) {
const result = await report.execute(`report-${cycle}`, { status: "in_progress" }, undefined, undefined, harness.ctx);
await harness.emit("tool_result", {
type: "tool_result",
toolCallId: `report-${cycle}`,
toolName: "goal_report",
input: { status: "in_progress" },
content: result.content,
isError: false,
});
await harness.emit("agent_settled");
if (cycle < 3) assert.equal(harness.sent.length, cycle + 1);
}
assert.equal(harness.sent.length, 3, "paused loop injects no fourth check");
assert.equal(harness.state().status, "paused");
assert.equal(harness.state().noProgressReports, 3);
assert.ok(harness.notifications.some((notice) => notice.level === "warning" && /no substantive progress/.test(notice.message)));
} finally {
harness.restoreEnv();
rmSync(dir, { recursive: true, force: true });
}
});
test("C7/C8: attested parser and resolver reject before Goal state changes", async () => {
resetGoalPolicyRegistryForTest();
const dir = mkdtempSync(join(tmpdir(), "goal-v4-policy-"));
const incarnation = "inc-goal-v4";
const harness = await createHeadlessHarness(dir, incarnation);
try {
assert.equal(registerGoalTrackedItemResolver(incarnation, async () => Object.freeze({ outcome: "zero" as const })).ok, true);
const journalReasons: string[] = [];
const publication = publishGoalPolicy({
schemaVersion: 1,
role: "plan-ng",
roleRevision: 4,
manifestSha256: "a".repeat(64),
format: "ms-executive-update/v1",
contractPath: "skills-local/ms-executive-update/SKILL.md",
contractSection: "Machine contract (for `goal_report` payloads and any parser)",
contractBlob: "df30c6fbb54b4a65a298c9e51c07f742610d171c",
contractSha256: "bbea48a46b1f8da7bc759f86856fb52830b7dde456b826317163c6dc6ccab319",
enforcement: "pre-state-change-fail-closed",
identifierResolution: "consumer-fail-closed",
launchGeneration: 1,
incarnationId: incarnation,
}, (reason) => journalReasons.push(reason));
assert.equal(publication.ok, true);
const goal = harness.commands.get("goal");
const report = harness.tools.get("goal_report");
await goal.handler("attested policy", harness.ctx);
const before = harness.state();
const update = [
"Just Completed:", "", "* T165: contracts added", "", "Next Step:", "", "* T165: run tests", "", "Blocked:", "", "* T165: none \u2014 nothing from you", "",
].join("\n");
await assert.rejects(
() => report.execute("attested-reject", { status: "satisfied", evidence: update }, undefined, undefined, harness.ctx),
/resolver-zero/,
);
const after = harness.state();
assert.equal(after.status, "active");
assert.equal(after.checks, before.checks);
assert.equal(after.noProgressReports, before.noProgressReports);
const noChange = "No change since T165; still waiting on T165.";
for (const status of ["satisfied", "blocked"] as const) {
await assert.rejects(
() => report.execute(`no-change-${status}`, { status, evidence: noChange }, undefined, undefined, harness.ctx),
/no-change-status/,
);
}
const terminalAfter = harness.state();
assert.equal(terminalAfter.status, "active", "unchanged form cannot settle or pause the goal");
assert.equal(terminalAfter.checks, before.checks);
assert.equal(terminalAfter.noProgressReports, before.noProgressReports);
assert.deepEqual(
journalReasons,
["resolver-zero", "no-change-status", "no-change-status"],
"all denials journal stable codes without report payload text",
);
} finally {
resetGoalPolicyRegistryForTest();
harness.restoreEnv();
rmSync(dir, { recursive: true, force: true });
}
});
test("headless runtime accepts a tool-backed measurement and preserves terminal behavior", async () => {
const dir = mkdtempSync(join(tmpdir(), "goal-ng8-runtime-work-"));
const harness = await createHeadlessHarness(dir, "ng8-headless-work");
try {
const goal = harness.commands.get("goal");
const report = harness.tools.get("goal_report");
await goal.handler("measure", harness.ctx);
await harness.emit("tool_result", {
type: "tool_result",
toolCallId: "read-error",
toolName: "read",
input: { path: "/tmp/missing" },
content: [{ type: "text", text: "missing" }],
isError: true,
});
assert.equal(harness.state().workEventSinceReport, false, "failed tools are not progress events");
await harness.emit("tool_result", {
type: "tool_result",
toolCallId: "read-1",
toolName: "read",
input: { path: "/tmp/status" },
content: [{ type: "text", text: "measured" }],
isError: false,
});
assert.equal(harness.state().workEventSinceReport, true);
const progress = {
kind: "measurement",
gate: "review",
owner: "reviewer",
lastMeasurement: "head abc remains pending at 2026-08-31T15:00:00Z",
nextAction: "dispatch reviewer",
};
const accepted = await report.execute(
"progress-1",
{ status: "in_progress", evidence: "measured exact head", progress },
undefined,
undefined,
harness.ctx,
);
assert.match(accepted.content[0].text, /Recorded substantive progress/);
assert.equal(harness.state().noProgressReports, 0);
assert.equal(harness.state().workEventSinceReport, false);
await goal.handler("done goal", harness.ctx);
await assert.rejects(
() => report.execute("satisfied-empty", { status: "satisfied" }, undefined, undefined, harness.ctx),
/requires non-empty evidence/,
);
const satisfied = await report.execute(
"satisfied",
{ status: "satisfied", evidence: "acceptance evidence" },
undefined,
undefined,
harness.ctx,
);
assert.match(satisfied.content[0].text, /SATISFIED/);
assert.equal(harness.state().status, "none");
await goal.handler("blocked goal", harness.ctx);
const blocked = await report.execute(
"blocked",
{ status: "blocked", evidence: "missing credential" },
undefined,
undefined,
harness.ctx,
);
assert.match(blocked.content[0].text, /BLOCKED/);
assert.equal(harness.state().status, "blocked");
} finally {
harness.restoreEnv();
rmSync(dir, { recursive: true, force: true });
}
});
const waitReport = {
status: "in_progress", evidence: "Input is pending",
progress: { kind: "wait", gate: "input", owner: "operator", lastMeasurement: "input absent",
nextAction: "Read input and finish output", nextCheck: "input file available" },
};
test("queued check latch deduplicates lifecycle events until the matching start", async () => {
const dir = mkdtempSync(join(tmpdir(), "goal-check-latch-"));
const harness = await createHeadlessHarness(dir, "check-latch");
try {
await harness.commands.get("goal").handler("ready work", harness.ctx);
const first = harness.sent[0].content;
for (let i = 0; i < 10; i++) {
await harness.emit("session_start");
await harness.emit("agent_settled");
}
assert.equal(harness.sent.length, 1);
await harness.emit("before_agent_start", { prompt: "unrelated incoming question", systemPrompt: "base" });
await harness.emit("agent_settled");
assert.equal(harness.sent.length, 1, "unrelated input does not release a pending check");
await harness.emit("before_agent_start", { prompt: first, systemPrompt: "base" });
await harness.emit("agent_settled");
assert.equal(harness.sent.length, 2, "a completed check can continue ready work");
await harness.emit("before_agent_start", { prompt: first, systemPrompt: "base" });
await harness.emit("agent_settled");
assert.equal(harness.sent.length, 2, "duplicate old start cannot release a newer check");
await harness.commands.get("goal").handler("replacement", harness.ctx);
assert.equal(harness.sent.length, 3, "explicit replacement may schedule its new goal");
await harness.commands.get("goal").handler("stop", harness.ctx);
await harness.commands.get("goal").handler("resume", harness.ctx);
assert.equal(harness.sent.length, 4);
} finally {
await harness.emit("session_shutdown"); harness.restoreEnv(); rmSync(dir, { recursive: true, force: true });
}
});
test("untimed wait: settle and duplicate reports never inject a heartbeat", async (t) => {
t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 100000 });
const dir = mkdtempSync(join(tmpdir(), "goal-untimed-"));
const harness = await createHeadlessHarness(dir, "untimed");
try {
await harness.commands.get("goal").handler("wait for coordinator", harness.ctx);
const report = harness.tools.get("goal_report");
await report.execute("wait", waitReport, undefined, undefined, harness.ctx);
const before = harness.sent.length;
for (let i = 0; i < 100; i++) {
await harness.emit("agent_settled");
await report.execute(`repeat-${i}`, waitReport, undefined, undefined, harness.ctx);
}
t.mock.timers.tick(7 * 86400000);
assert.equal(harness.sent.length, before, "accepted waits must not generate model turns");
assert.equal(harness.state().checks, 0);
assert.equal(harness.state().noProgressReports, 0);
assert.equal(harness.state().activeWait.deadlineAt, undefined);
} finally {
await harness.emit("session_shutdown"); harness.restoreEnv(); rmSync(dir, { recursive: true, force: true });
}
});
test("untimed wait: reload, unrelated input and tool work preserve suspension", async () => {
const dir = mkdtempSync(join(tmpdir(), "goal-untimed-reload-"));
const harness = await createHeadlessHarness(dir, "untimed-reload");
try {
await harness.commands.get("goal").handler("wait for coordinator", harness.ctx);
const report = harness.tools.get("goal_report");
await report.execute("wait", waitReport, undefined, undefined, harness.ctx);
const wait = harness.state().activeWait;
const before = harness.sent.length;
await harness.emit("session_shutdown");
await harness.emit("session_start");
await harness.emit("session_start");
assert.equal(harness.sent.length, before, "startup must preserve even an untimed wait");
await harness.emit("before_agent_start", { prompt: "unrelated question", systemPrompt: "base" });
await harness.emit("tool_result", { toolName: "read", isError: false });
await harness.emit("agent_settled");
assert.deepEqual(harness.state().activeWait, wait);
assert.equal(harness.sent.length, before);
await harness.emit("before_agent_start", { prompt: "dependency result arrived", systemPrompt: "base" });
await report.execute("progress", { status: "in_progress", evidence: "dependency verified", progress: { ...waitReport.progress, kind: "measurement", lastMeasurement: "verified input" } }, undefined, undefined, harness.ctx);
assert.equal(harness.state().activeWait, undefined);
await harness.emit("agent_settled");
assert.equal(harness.sent.length, before + 1, "verified progress allows continuation");
} finally {
await harness.emit("session_shutdown"); harness.restoreEnv(); rmSync(dir, { recursive: true, force: true });
}
});
test("untimed wait: explicit resume reconciles once, paused waits remain owner-controlled", async () => {
const dir = mkdtempSync(join(tmpdir(), "goal-untimed-resume-"));
const harness = await createHeadlessHarness(dir, "untimed-resume");
try {
const goal = harness.commands.get("goal");
const report = harness.tools.get("goal_report");
await goal.handler("wait for coordinator", harness.ctx);
await report.execute("wait", waitReport, undefined, undefined, harness.ctx);
await goal.handler("resume", harness.ctx);
assert.equal(harness.sent.length, 2, "resume must work for an active waiting goal");
assert.equal(harness.state().activeWait, undefined);
await report.execute("still-waiting", waitReport, undefined, undefined, harness.ctx);
await harness.emit("agent_settled");
assert.equal(harness.sent.length, 2);
await goal.handler("stop", harness.ctx);
await harness.emit("before_agent_start", { prompt: "dependency result", systemPrompt: "base" });
await harness.emit("agent_settled");
assert.equal(harness.state().status, "paused");
assert.equal(harness.sent.length, 2);
await goal.handler("resume", harness.ctx);
assert.equal(harness.sent.length, 3);
assert.equal(harness.state().activeWait, undefined);
} finally {
await harness.emit("session_shutdown"); harness.restoreEnv(); rmSync(dir, { recursive: true, force: true });
}
});
test("quiet wait: no heartbeats, one deadline wake, unresolved dependency pauses", async (t) => {
t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 100000 });
const dir = mkdtempSync(join(tmpdir(), "goal-quiet-runtime-"));
const harness = await createHeadlessHarness(dir, "quiet-runtime");
try {
harness.setIdle(true);
const goal = harness.commands.get("goal");
const report = harness.tools.get("goal_report");
await goal.handler("--wait-timeout 60 write output", harness.ctx);
await report.execute("wait-1", waitReport, undefined, undefined, harness.ctx);
const deadline = harness.state().activeWait.deadlineAt;
for (let i = 0; i < 100; i++) await harness.emit("agent_settled");
assert.equal(harness.sent.length, 1, "settle events cannot generate idle heartbeats");
t.mock.timers.tick(30000);
await report.execute("wait-2", { ...waitReport, evidence: "Still pending, differently worded" }, undefined, undefined, harness.ctx);
assert.equal(harness.state().activeWait.deadlineAt, deadline, "unchanged waits never extend deadline");
t.mock.timers.tick(29999);
assert.equal(harness.sent.length, 1);
t.mock.timers.tick(1);
assert.equal(harness.sent.length, 2);
assert.match(harness.sent[1].content, /Wait deadline reached/);
assert.equal(harness.state().waitWakeUsed, true);
const result = await report.execute("wait-3", waitReport, undefined, undefined, harness.ctx);
assert.equal(result.details.goalStatus, "paused");
t.mock.timers.tick(86400000);
await harness.emit("agent_settled");
assert.equal(harness.sent.length, 2, "unresolved deadline never re-arms itself");
await assert.rejects(() => report.execute("late-satisfied", { status: "satisfied", evidence: "late result" }, undefined, undefined, harness.ctx), /paused/);
} finally {
await harness.emit("session_shutdown");
harness.restoreEnv();
rmSync(dir, { recursive: true, force: true });
}
});
test("quiet wait: persisted deadline survives reload without an immediate check", async (t) => {
t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 100000 });
const dir = mkdtempSync(join(tmpdir(), "goal-quiet-reload-"));
const harness = await createHeadlessHarness(dir, "quiet-reload");
try {
harness.setIdle(true);
await harness.commands.get("goal").handler("--wait-timeout 60 write output", harness.ctx);
await harness.tools.get("goal_report").execute("wait", waitReport, undefined, undefined, harness.ctx);
await harness.emit("session_shutdown");
t.mock.timers.tick(30000);
await harness.emit("session_start");
assert.equal(harness.sent.length, 1);
t.mock.timers.tick(30000);
assert.equal(harness.sent.length, 2);
assert.match(harness.sent[1].content, /Wait deadline reached/);
} finally {
await harness.emit("session_shutdown");
harness.restoreEnv();
rmSync(dir, { recursive: true, force: true });
}
});
test("quiet wait: stop, clear, replacement, and completion cancel the timer", async (t) => {
t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 100000 });
const dir = mkdtempSync(join(tmpdir(), "goal-quiet-cancel-"));
const harness = await createHeadlessHarness(dir, "quiet-cancel");
try {
harness.setIdle(true);
const goal = harness.commands.get("goal");
const report = harness.tools.get("goal_report");
for (const operation of ["stop", "clear", "replacement", "satisfied"]) {
await goal.handler("--wait-timeout 60 write output", harness.ctx);
await report.execute("wait", waitReport, undefined, undefined, harness.ctx);
if (operation === "satisfied") {
await report.execute("done", { status: "satisfied", evidence: "Output verified" }, undefined, undefined, harness.ctx);
} else {
await goal.handler(operation, harness.ctx);
}
const before = harness.sent.length;
t.mock.timers.tick(61000);
assert.equal(harness.sent.length, before, `${operation} leaves no deadline wake`);
}
} finally {
await harness.emit("session_shutdown");
harness.restoreEnv();
rmSync(dir, { recursive: true, force: true });
}
});
test("quiet wait: a busy turn is allowed to settle before deadline injection", async (t) => {
t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 100000 });
const dir = mkdtempSync(join(tmpdir(), "goal-quiet-busy-"));
const harness = await createHeadlessHarness(dir, "quiet-busy");
try {
await harness.commands.get("goal").handler("--wait-timeout 60 write output", harness.ctx);
await harness.tools.get("goal_report").execute("wait", waitReport, undefined, undefined, harness.ctx);
t.mock.timers.tick(60000);
assert.equal(harness.sent.length, 1, "no deadline queued during a running turn");
await harness.commands.get("goal").handler("stop", harness.ctx);
await harness.emit("agent_settled");
assert.equal(harness.sent.length, 1, "stop cancels deferred deadline");
await harness.commands.get("goal").handler("resume", harness.ctx);
assert.equal(harness.state().activeWait, undefined);
await harness.tools.get("goal_report").execute("wait-again", waitReport, undefined, undefined, harness.ctx);
t.mock.timers.tick(60000);
const before = harness.sent.length;
await harness.emit("agent_settled");
assert.equal(harness.sent.length, before + 1);
} finally {
await harness.emit("session_shutdown");
harness.restoreEnv();
rmSync(dir, { recursive: true, force: true });
}
});
test("quiet wait: relevant progress cancels the wait; print mode has no timer wake", async (t) => {
t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 100000 });
const dir = mkdtempSync(join(tmpdir(), "goal-quiet-progress-"));
const harness = await createHeadlessHarness(dir, "quiet-progress");
try {
harness.setIdle(true);
const goal = harness.commands.get("goal");
const report = harness.tools.get("goal_report");
await goal.handler("--wait-timeout 60 write output", harness.ctx);
await report.execute("wait", waitReport, undefined, undefined, harness.ctx);
await harness.emit("tool_result", { toolName: "read", isError: false });
await report.execute("progress", { status: "in_progress", evidence: "Input arrived and was verified", progress: { ...waitReport.progress, kind: "measurement", lastMeasurement: "Input present" } }, undefined, undefined, harness.ctx);
assert.equal(harness.state().activeWait, undefined);
t.mock.timers.tick(60000);
assert.equal(harness.sent.length, 1);
await harness.emit("agent_settled");
assert.equal(harness.sent.length, 2, "ready work continues after wait is resolved");
harness.ctx.mode = "print";
await goal.handler("--wait-timeout 60 write output", harness.ctx);
await report.execute("wait-print", waitReport, undefined, undefined, harness.ctx);
t.mock.timers.tick(60000);
await harness.emit("agent_settled");
assert.equal(harness.sent.length, 2, "print mode never schedules a model wake");
} finally {
await harness.emit("session_shutdown");
harness.restoreEnv();
rmSync(dir, { recursive: true, force: true });
}
});
test("deadline readiness recovers after compaction without agent_settled", async (t) => {
t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 100000 });
const dir = mkdtempSync(join(tmpdir(), "goal-compaction-"));
const harness = await createHeadlessHarness(dir, "quiet-compaction");
try {
await harness.commands.get("goal").handler("--wait-timeout 60 output", harness.ctx);
await harness.tools.get("goal_report").execute("wait", waitReport, undefined, undefined, harness.ctx);
t.mock.timers.tick(60000);
assert.equal(harness.sent.length, 1);
harness.setIdle(true);
t.mock.timers.tick(1000);
assert.equal(harness.sent.length, 2, "runtime readiness alone releases the deferred wake");
} finally {
await harness.emit("session_shutdown"); harness.restoreEnv(); rmSync(dir, { recursive: true, force: true });
}
});
test("unobserved deadline dispatch pauses once; observed start cancels watchdog", async (t) => {
t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 100000 });
const dir = mkdtempSync(join(tmpdir(), "goal-dispatch-"));
const harness = await createHeadlessHarness(dir, "quiet-dispatch");
try {
harness.setIdle(true);
const goal = harness.commands.get("goal");
const report = harness.tools.get("goal_report");
await goal.handler("--wait-timeout 60 output", harness.ctx);
await report.execute("wait", waitReport, undefined, undefined, harness.ctx);
t.mock.timers.tick(60000);
const sent = harness.sent.length;
// Ordinary Pi sendUserMessage returns void; a rejected async delivery may never start.
t.mock.timers.tick(30000);
assert.equal(harness.state().status, "paused");
assert.match(harness.state().pausedReason, /not observed/);
assert.equal(harness.sent.length, sent, "watchdog never retries a potentially delivered request");
await goal.handler("resume", harness.ctx);
await report.execute("wait-again", waitReport, undefined, undefined, harness.ctx);
t.mock.timers.tick(60000);
await harness.emit("before_agent_start", { prompt: harness.sent.at(-1)!.content, systemPrompt: "base" });
assert.equal(harness.state().activeWait.wakeObserved, true);
t.mock.timers.tick(30000);
assert.equal(harness.state().status, "active", "observed model start cancels the acknowledgment timer");
} finally {
await harness.emit("session_shutdown"); harness.restoreEnv(); rmSync(dir, { recursive: true, force: true });
}
});
test("continuously busy runtime pauses after bounded readiness checks", async (t) => {
t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 100000 });
const dir = mkdtempSync(join(tmpdir(), "goal-busy-limit-"));
const harness = await createHeadlessHarness(dir, "quiet-busy-limit");
try {
await harness.commands.get("goal").handler("--wait-timeout 60 output", harness.ctx);
await harness.tools.get("goal_report").execute("wait", waitReport, undefined, undefined, harness.ctx);
t.mock.timers.tick(60000);
for (let i = 0; i < 60; i++) t.mock.timers.tick(1000);
assert.equal(harness.state().status, "paused");
assert.match(harness.state().pausedReason, /remained busy/);
assert.equal(harness.sent.length, 1);
} finally {
await harness.emit("session_shutdown"); harness.restoreEnv(); rmSync(dir, { recursive: true, force: true });
}
});
test("footer and both recall paths cover lifecycle without adding widget content", async () => {
const dir = mkdtempSync(join(tmpdir(), "goal-footer-"));
const harness = await createHeadlessHarness(dir, "footer");
const previousNoColor = process.env.NO_COLOR;
delete process.env.NO_COLOR;
try {
const goal = harness.commands.get("goal");
const report = harness.tools.get("goal_report");
const text = "Full goal " + "acceptance criteria ".repeat(100) + " END-OF-GOAL";
await harness.emit("session_start");
assert.match(harness.statuses.at(-1)!, /\[muted\]Goal: None/);
await goal.handler(text, harness.ctx);
assert.match(harness.statuses.at(-1)!, /\[accent\]Goal: Active/);
const sent = harness.sent.length;
await goal.handler("", harness.ctx);
const recall = harness.notifications.at(-1)!.message;
assert.ok(recall.includes(text));
await harness.shortcuts.get("alt+g").handler(harness.ctx);
assert.equal(harness.notifications.at(-1)!.message, recall);
assert.equal(harness.sent.length, sent, "recall never starts a turn");
assert.equal(harness.shortcuts.has("tab"), false);
await report.execute("wait", waitReport, undefined, undefined, harness.ctx);
assert.match(harness.statuses.at(-1)!, /\[warning\]Goal: Waiting/);
await goal.handler("stop", harness.ctx);
assert.match(harness.statuses.at(-1)!, /\[warning\]Goal: Paused/);
await goal.handler("resume", harness.ctx);
await report.execute("blocked", { status: "blocked", evidence: "permission needed" }, undefined, undefined, harness.ctx);
assert.match(harness.statuses.at(-1)!, /\[error\]Goal: Blocked/);
await goal.handler("resume", harness.ctx);
await report.execute("done", { status: "satisfied", evidence: "verified" }, undefined, undefined, harness.ctx);
assert.match(harness.statuses.at(-1)!, /\[success\]Goal: Complete/);
assert.equal(harness.state().lastOutcome.text, text);
const finishedSent = harness.sent.length;
await harness.emit("agent_settled");
await harness.emit("session_start");
await goal.handler("resume", harness.ctx);
assert.equal(harness.sent.length, finishedSent);
await goal.handler("", harness.ctx);
assert.ok(harness.notifications.at(-1)!.message.includes(text));
process.env.NO_COLOR = "1";
await harness.emit("session_start");
assert.equal(harness.statuses.at(-1), "Goal: Complete (/goal, Alt+G)");
await goal.handler("clear", harness.ctx);
assert.equal(harness.state().lastOutcome, undefined);
assert.equal(harness.statuses.at(-1), "Goal: None (/goal, Alt+G)");
assert.ok(harness.widgets.every(value => value === undefined));
} finally {
if (previousNoColor === undefined) delete process.env.NO_COLOR;
else process.env.NO_COLOR = previousNoColor;
await harness.emit("session_shutdown"); harness.restoreEnv(); rmSync(dir, { recursive: true, force: true });
}
});
test("state-write failure cannot report goal completion or inject another check", async () => {
const dir = mkdtempSync(join(tmpdir(), "goal-save-failure-"));
const incarnation = "quiet-save-failure";
const harness = await createHeadlessHarness(dir, incarnation);
try {
await harness.commands.get("goal").handler("--wait-timeout 60 output", harness.ctx);
const statePath = fencedStateFilePath(join(dir, "state", "goal"), incarnation);
rmSync(statePath);
mkdirSync(statePath); // force atomic replacement failure without mocking away filesystem behavior
await assert.rejects(() => harness.tools.get("goal_report").execute("done", { status: "satisfied", evidence: "done" }, undefined, undefined, harness.ctx), /could not be saved/);
await harness.emit("agent_settled");
assert.equal(harness.sent.length, 1);
assert.equal(harness.notifications.some((n) => n.message.includes("satisfied and cleared")), false);
} finally {
await harness.emit("session_shutdown"); harness.restoreEnv(); rmSync(dir, { recursive: true, force: true });
}
});