diff --git a/packages/engine/src/__tests__/pipeline-smoke/_pipeline-drivers.ts b/packages/engine/src/__tests__/pipeline-smoke/_pipeline-drivers.ts index 536a1602ba..3c311a4b4b 100644 --- a/packages/engine/src/__tests__/pipeline-smoke/_pipeline-drivers.ts +++ b/packages/engine/src/__tests__/pipeline-smoke/_pipeline-drivers.ts @@ -179,8 +179,27 @@ export const PIPELINE_SCENARIO_DRIVERS = { } throw new Error("S07 did not persist its real unactionable Code Review rejection."); }), - s07Recovery: driver("provide an actionable approval through the restored graph session", async (context) => { + /* + FNXC:PipelineSmoke 2026-08-24-22:40: + The declared recovery for a park is "operator retry, or the cause disappears". Named remediation + parks an unactionable rejection as `awaiting-approval` with `paused: true` — deliberately, because + there is no actionable finding to derive work from, so a human must decide. A drive alone cannot + move a paused card, so the recovery must first perform the operator's half of that contract. + Releasing an EXPLICIT awaiting-approval park is the operator action under test; it is not a way to + make an unrelated failure pass, and the merge that follows is still fully asserted. + */ + s07Recovery: driver("release the operator park, then approve through the restored graph session", async (context) => { const parked = context.result; + const task = taskFor(context); + const live = await context.harness.freshTask(task.id); + if (live.paused === true || live.status === "awaiting-approval") { + await context.harness.store.updateTask(task.id, { + paused: false, + pausedReason: undefined, + status: undefined, + awaitingApprovalReason: undefined, + } as never); + } await driveMerged(context, { planReviewModes: ["approve"], codeReviewModes: ["approve"] }); context.result = parked; }), diff --git a/packages/engine/src/__tests__/pipeline-smoke/_pipeline-harness.ts b/packages/engine/src/__tests__/pipeline-smoke/_pipeline-harness.ts index 2827e4afb9..9b98e9134a 100644 --- a/packages/engine/src/__tests__/pipeline-smoke/_pipeline-harness.ts +++ b/packages/engine/src/__tests__/pipeline-smoke/_pipeline-harness.ts @@ -881,7 +881,7 @@ export class PipelineSmokeHarness { take before it is called wedged. A review-column workflow adds verification, documentation and summary nodes to every rework cycle, so S05 ("REVISE twice, then approve") needs roughly nine more dispatches than the same scenario on the base graph. Raising it does not weaken any - assertion � the declared terminal and the wedge detectors are unchanged. + assertion: the declared terminal and the wedge detectors are unchanged. */ maxIterations: 32, signature: (state) => JSON.stringify({ diff --git a/packages/engine/src/__tests__/pipeline-smoke/_pipeline-scenarios.ts b/packages/engine/src/__tests__/pipeline-smoke/_pipeline-scenarios.ts index b71ed314cd..1b015acb12 100644 --- a/packages/engine/src/__tests__/pipeline-smoke/_pipeline-scenarios.ts +++ b/packages/engine/src/__tests__/pipeline-smoke/_pipeline-scenarios.ts @@ -112,7 +112,7 @@ export const PIPELINE_SCENARIOS: readonly PipelineScenario[] = [ { id: "S07", title: "Unactionable review rejection parks then recovers", - workflows: ["builtin:coding-ideas"], + workflows: ["builtin:coding-ideas", "builtin:coding-ideas-v2"], expectedTerminal: "parked", arrange: PIPELINE_SCENARIO_DRIVERS.s07Arrange, act: PIPELINE_SCENARIO_DRIVERS.s07Act,