From d866617f4083d8404658029fe2f7fd7632449202 Mon Sep 17 00:00:00 2001 From: Fusion Agent Date: Tue, 25 Aug 2026 01:30:20 +0000 Subject: [PATCH] test(FN-WF): complete every pending step in the smoke executor mock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mock marked only step 0 done. A review gate that appends named remediation work (`review-remediation-steps`) adds steps beyond the first, and a workflow whose parse node disables trailing-step reopening depends on exactly that mechanism to give a bounced card something to execute — so those steps stayed pending forever. The mock now completes every pending step, as a real executor does. This is necessary but not sufficient for S05 on builtin:coding-ideas-v2: the remediation step IS appended and still ends pending (`["Implement deterministic pipeline output:done", "Fix: The disposable fixture needs the scripted remediation commit.:pending"]`), so the bounced card is not re-dispatched through an executor session that can complete it. S05 and S07 therefore stay on their proven workflows rather than shipping red. Lane green: 6 files, 81 tests, 19/19 scenarios. --- .../pipeline-smoke/_pipeline-harness.ts | 1 + .../pipeline-smoke/_pipeline-mock-scripts.ts | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/engine/src/__tests__/pipeline-smoke/_pipeline-harness.ts b/packages/engine/src/__tests__/pipeline-smoke/_pipeline-harness.ts index 2f27620630..9da8024ef4 100644 --- a/packages/engine/src/__tests__/pipeline-smoke/_pipeline-harness.ts +++ b/packages/engine/src/__tests__/pipeline-smoke/_pipeline-harness.ts @@ -640,6 +640,7 @@ export class PipelineSmokeHarness { behavior, state: entry.state, observeMockRuntime: () => this.guard.assertMockRuntime("mock/scripted"), + readTaskSteps: async () => (await this.freshTask(taskId).catch(() => undefined))?.steps?.map((step) => step.status) ?? [], }); } diff --git a/packages/engine/src/__tests__/pipeline-smoke/_pipeline-mock-scripts.ts b/packages/engine/src/__tests__/pipeline-smoke/_pipeline-mock-scripts.ts index 94624e6397..8301373cea 100644 --- a/packages/engine/src/__tests__/pipeline-smoke/_pipeline-mock-scripts.ts +++ b/packages/engine/src/__tests__/pipeline-smoke/_pipeline-mock-scripts.ts @@ -95,6 +95,8 @@ export function installPipelineMockScripts(input: { readonly behavior?: PipelineScriptedMergeBehavior; readonly state?: PipelineMockScriptState; readonly observeMockRuntime: () => void; + /** Current step statuses, read live so appended remediation work is completed too. */ + readonly readTaskSteps: () => Promise; }): void { const behavior = input.behavior ?? {}; const state = input.state ?? { planReviewIndex: 0, codeReviewIndex: 0, implementationCommitted: false }; @@ -268,7 +270,22 @@ export function installPipelineMockScripts(input: { state.implementationCommitted = true; } if (hasTaskUpdateTool) { - await context.invokeTool("fn_task_update", { step: 0, status: "done" }); + /* + FNXC:PipelineSmoke 2026-08-24-19:00: + Complete EVERY pending step, not only step 0. A review gate that appends named remediation + work (`review-remediation-steps`) adds steps beyond the first, and a workflow whose parse + node disables trailing-step reopening depends on exactly that mechanism to give the bounced + card something to execute. Marking only step 0 left those remediation steps pending forever, + so the card could never satisfy the completed-implementation projection and S05 + ("REVISE twice, then approve") stalled with + "did not persist completed implementation-step projection". A real executor finishes the + steps it was handed; the mock must too. + */ + const live = await input.readTaskSteps(); + for (let index = 0; index < Math.max(live.length, 1); index += 1) { + if (live[index] && live[index] !== "pending" && live[index] !== "in-progress") continue; + await context.invokeTool("fn_task_update", { step: index, status: "done" }); + } } /* FNXC:PipelineSmoke 2026-08-23-20:23: