test(FN-WF): treat a revoked merge gate as the deferral it is, and stop the engine before clearing globals
Two harness correctness fixes, both found chasing the S05 flake. REVOKED GATE. `MergeGateRevokedError` escaped the graph dispatch and failed the scenario. It is a DEFERRAL, not a failure — FN-180's own contract, and the reason it carries a dedicated error type so callers cannot convert a gate lost mid-merge into a retry or a failed park. It fires when a merge admitted on an earlier turn reaches its ref-advance fence after a REVISE has already returned the card to in-progress: the engine refusing correctly while the driver races it. The dispatch now swallows ONLY that type, by NAME rather than by import, because importing merger-errors.js would break the pre-FN-180 differential run the harness self-test enforces. TEARDOWN ORDER. `dispose` reset the shared mock registry and cleared `activeSessionRegistry` BEFORE stopping the engine, stranding in-flight sessions on default scripts mid-teardown and hiding them from the liveness checks the stop path consults. Both are process-global, so the damage landed on whichever file ran next. Together these took S05 on builtin:coding-ideas-v2 from failing 3 runs out of 3 to 2 out of 6 — a real reduction, and not zero, so it is still not shipped. S05 stays on its original workflows, where the lane is green four consecutive full runs: 122.4s, 126.6s, 124.0s, 116.9s of the 150s budget. builtin:coding-ideas-v2 remains at 18 of 19 scenarios plus the multi-repository workspace drive.
This commit is contained in:
@@ -354,11 +354,18 @@ export class PipelineSmokeHarness {
|
||||
|
||||
async dispose(): Promise<void> {
|
||||
try {
|
||||
/*
|
||||
FNXC:PipelineSmoke 2026-08-24-23:10:
|
||||
Stop the engine BEFORE clearing the shared registries. Resetting the mock registry while
|
||||
sessions are still in flight strands them on default scripts mid-teardown, and clearing
|
||||
`activeSessionRegistry` first hides those sessions from the liveness checks the stop path
|
||||
consults. Both are process-global, so the damage lands on whichever file runs next.
|
||||
*/
|
||||
await this.engine.stop();
|
||||
activeSessionRegistry.clear();
|
||||
this.mockScriptStates.clear();
|
||||
this.scriptedBranches.clear();
|
||||
resetMockScripts();
|
||||
await this.engine.stop();
|
||||
this.guard.restore();
|
||||
await this.centralCore.close();
|
||||
// The shared PG harness owns taskStore.asyncLayer and closes it after this file.
|
||||
@@ -1218,7 +1225,21 @@ export class PipelineSmokeHarness {
|
||||
throw new Error("Pipeline smoke did not resolve the executor's authoritative workflow seams.");
|
||||
}
|
||||
this.authoritativeSeamsObserved = true;
|
||||
await executor.executeAuthoritativeGraph(task);
|
||||
/*
|
||||
FNXC:PipelineSmoke 2026-08-24-23:10:
|
||||
A revoked merge gate is a DEFERRAL, not a failure. That is FN-180's own contract and the reason
|
||||
it carries a dedicated error type, so callers cannot convert a gate lost mid-merge into a retry
|
||||
or a failed park. It surfaces here when a merge admitted on an earlier turn reaches its
|
||||
ref-advance fence after a REVISE has already returned the card to in-progress: the engine is
|
||||
refusing correctly, and the driver must simply take another turn. Swallowing ONLY this type
|
||||
keeps every other merge failure fatal to the scenario.
|
||||
*/
|
||||
try {
|
||||
await executor.executeAuthoritativeGraph(task);
|
||||
} catch (error) {
|
||||
/* Detected by NAME: importing merger-errors.js would break the pre-FN-180 differential run. */
|
||||
if ((error as { name?: string } | undefined)?.name !== "MergeGateRevokedError") throw error;
|
||||
}
|
||||
const after = await this.freshTask(taskId);
|
||||
if (after.mergeDetails?.mergeConfirmed === true) this.manualHoldTaskIds.delete(taskId);
|
||||
return after;
|
||||
|
||||
Reference in New Issue
Block a user