diff --git a/packages/engine/src/__tests__/executor-task-done-invariant.test.ts b/packages/engine/src/__tests__/executor-task-done-invariant.test.ts index 7088c41f05..a939af9e56 100644 --- a/packages/engine/src/__tests__/executor-task-done-invariant.test.ts +++ b/packages/engine/src/__tests__/executor-task-done-invariant.test.ts @@ -206,6 +206,23 @@ describe("FN-4114 fn_task_done invariants", () => { expect(result.content[0].text).toContain("fn_task_done refused: wrong_branch"); expect(store.moveTask).toHaveBeenCalledWith("FN-4114", "todo", { preserveProgress: true }); }); + it("FN-4114 allows no-commit completion when noCommitsExpected audit logging fails", async () => { + const { store, tool } = await setup({ noCommitsExpected: true }); + mockedExecSync.mockImplementation((cmd: string) => { + if (cmd.includes("rev-parse --show-toplevel")) return Buffer.from("/repo/.worktrees/swift-falcon\n"); + if (cmd.includes("rev-parse --abbrev-ref HEAD")) return Buffer.from("fusion/fn-4114\n"); + if (cmd.includes("rev-list --count")) return Buffer.from("0\n"); + if (cmd.includes("rev-parse HEAD")) return Buffer.from("def456\n"); + return Buffer.from(""); + }); + store.logEntry.mockImplementation(async (_id: string, message: string) => { + if (message.includes("no_commits guard skipped")) throw new Error("audit unavailable"); + }); + + const result = await tool.execute("id", {}); + expect(result.content[0].text).toContain("Task marked complete"); + expect(store.updateStep).toHaveBeenCalled(); + }); it("FN-416 allows plan-only operational no-source completion with zero commits when the explicit flag is missing", async () => { diff --git a/packages/engine/src/executor.ts b/packages/engine/src/executor.ts index 56ecd1895f..00dc22c2b7 100644 --- a/packages/engine/src/executor.ts +++ b/packages/engine/src/executor.ts @@ -9530,12 +9530,18 @@ export class TaskExecutor { : evaluatePromptDerivedNoCommitEligibility(task, typeof promptContent === "string" ? promptContent : ""); if (noCommitEligibility.eligible) { executorLog.log(`${task.id}: fn_task_done no_commits guard skipped (${noCommitEligibility.reason})`); - await this.store.logEntry( - task.id, - `fn_task_done no_commits guard skipped (${noCommitEligibility.reason})`, - undefined, - this.getRunContextFor(task.id), - ); + try { + await this.store.logEntry( + task.id, + `fn_task_done no_commits guard skipped (${noCommitEligibility.reason})`, + undefined, + this.getRunContextFor(task.id), + ); + } catch (error) { + executorLog.warn( + `${task.id}: failed to write no_commits guard skip audit log: ${error instanceof Error ? error.message : String(error)}`, + ); + } return { ok: true }; }