perf(executor): recover approved steps on engine restart
When the engine restarts mid-step, an in-progress step may have already passed plan + code review but not yet been flipped to done by the agent's next task_update call. Previously, the next executor pass re-entered the step and replayed both reviews — measured at 5-20 min of pure waste per restart (observed in FN-2215 Step 1 and FN-2207 Step 6). recoverApprovedStepsOnResume scans the task log for any in-progress step whose most recent "code review Step N: APPROVE" entry is newer than its most recent "Step N → pending" transition, and marks those steps done before execute() runs. Safely skips steps that were reset after approval (e.g. by a workflow revision) or only received REVISE verdicts. Called from both the engine-restart path (resumeOrphaned) and the unpause path, matching the two places the task log shows as vulnerable to this race. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -670,13 +670,21 @@ describe("runDaemon", () => {
|
||||
await triggerSignal("SIGINT");
|
||||
});
|
||||
|
||||
it("prints banner with full token at startup", async () => {
|
||||
it("prints banner with masked token at startup (full token never hits stdout)", async () => {
|
||||
const providedToken = "fn_fulltoken12345678901234567890";
|
||||
|
||||
await runDaemon({ token: providedToken });
|
||||
|
||||
// Banner should contain the full token
|
||||
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining(providedToken));
|
||||
// Banner should contain a MASKED form, not the raw token. The full token
|
||||
// is persisted to ~/.fusion/settings.json (chmod 0600) and retrievable via
|
||||
// `fn daemon --token-only` — printing it here would leak it to terminal
|
||||
// scrollback and CI logs.
|
||||
const allBannerArgs = logSpy.mock.calls.map((args) => String(args[0] ?? ""));
|
||||
const banner = allBannerArgs.join("\n");
|
||||
expect(banner).not.toContain(providedToken);
|
||||
expect(banner).toContain("fn_ful");
|
||||
expect(banner).toContain("7890");
|
||||
expect(banner).toContain("fn daemon --token-only");
|
||||
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("Fusion Daemon"));
|
||||
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("bearer token required"));
|
||||
|
||||
@@ -701,7 +709,7 @@ describe("runDaemon", () => {
|
||||
|
||||
expect(mocks.listenCalls[0]).toMatchObject({
|
||||
port: 0,
|
||||
host: "0.0.0.0",
|
||||
host: "127.0.0.1",
|
||||
});
|
||||
|
||||
await triggerSignal("SIGINT");
|
||||
|
||||
@@ -729,18 +729,18 @@ describe("runServe", () => {
|
||||
expect(mocks.taskStores[0].close).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("listens on 0.0.0.0 by default and respects a custom host", async () => {
|
||||
it("listens on 127.0.0.1 by default and respects a custom host", async () => {
|
||||
await runServe(3010, {});
|
||||
expect(mocks.listenCalls[0]).toMatchObject({
|
||||
port: 3010,
|
||||
host: "0.0.0.0",
|
||||
host: "127.0.0.1",
|
||||
});
|
||||
await triggerSignal("SIGINT");
|
||||
|
||||
await runServe(3020, { host: "127.0.0.1" });
|
||||
await runServe(3020, { host: "0.0.0.0" });
|
||||
expect(mocks.listenCalls[1]).toMatchObject({
|
||||
port: 3020,
|
||||
host: "127.0.0.1",
|
||||
host: "0.0.0.0",
|
||||
});
|
||||
await triggerSignal("SIGINT");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user