FN-5743: cut over merge dequeue authority to merge-request queue

Shift merge dequeue enforcement to merge-request queue/marker authority with reliability coverage updates.

- Enforce merge eligibility and dequeue ownership via merge-request queue/marker checks in engine and scheduler paths.
- Add hard-cancel behavior coverage to ensure queued merge requests are canceled when tasks are user-canceled.
- Extend core merge-request record/store tests and reliability interaction suites for dual-observe and cancel-on-hard-cancel seams.
- Document the FN-5741/FN-5743 reliability backstop updates in AGENTS.md and architecture docs.

Files changed:
 AGENTS.md                                          |  2 +
 docs/architecture.md                               |  2 +
 packages/core/src/__tests__/merge-request-record.test.ts     | 18 ++++
 packages/core/src/store.ts                         | 13 +++
 packages/engine/src/__tests__/reliability-interactions/dual-observe-merge-seam.test.ts                | 57 +++++++++++++
 packages/engine/src/__tests__/reliability-interactions/merge-request-cancel-on-hard-cancel.test.ts    | 87 +++++++++++++++++++
 packages/engine/src/project-engine.ts              | 98 +++++++++++++++++++++-
 packages/engine/src/scheduler.ts                   | 12 ++-
 8 files changed, 284 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-5743

Fusion-Task-Lineage: b9a49aeb-ed73-42fe-924d-25c7097d1bb9
This commit is contained in:
gsxdsm
2026-05-30 20:48:16 -07:00
parent 8609669a56
commit c9b159f4e5
8 changed files with 284 additions and 5 deletions

View File

@@ -94,4 +94,22 @@ describe("TaskStore merge request record + completion handoff marker", () => {
store.clearCompletionHandoffAcceptedMarker(taskId);
expect(store.getCompletionHandoffAcceptedMarker(taskId)).toBeNull();
});
it("cancels merge request and clears handoff marker on user hard-cancel from in-review to todo", async () => {
const taskId = await createTask();
await store.moveTask(taskId, "todo");
await store.moveTask(taskId, "in-progress");
await store.handoffToReview(taskId, {
ownerAgentId: "agent-test",
evidence: { reason: "fn_task_done", runId: "run-1", agentId: "agent-test" },
});
store.upsertMergeRequestRecord(taskId, { state: "queued", attemptCount: 1, lastError: "pending" });
store.setCompletionHandoffAcceptedMarker(taskId, { source: "executor:fn_task_done" });
await store.moveTask(taskId, "todo", { moveSource: "user" });
expect(store.getMergeRequestRecord(taskId)?.state).toBe("cancelled");
expect(store.getCompletionHandoffAcceptedMarker(taskId)).toBeNull();
});
});

View File

@@ -5544,6 +5544,19 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
}
await this.writeTaskJsonFile(dir, task);
if (fromColumn === "in-review" && toColumn === "todo" && moveSource === "user") {
const handoffAccepted = this.getCompletionHandoffAcceptedMarker(id);
const mergeRequest = this.getMergeRequestRecord(id);
if (handoffAccepted && mergeRequest && mergeRequest.state !== "succeeded" && mergeRequest.state !== "cancelled") {
if (mergeRequest.state === "queued" || mergeRequest.state === "running" || mergeRequest.state === "retrying" || mergeRequest.state === "manual-required") {
this.transitionMergeRequestState(id, "cancelled", {
attemptCount: mergeRequest.attemptCount,
lastError: mergeRequest.lastError ?? "cancelled-by-user-hard-cancel",
});
}
}
this.clearCompletionHandoffAcceptedMarker(id);
}
if (toColumn === "done") {
this.clearLinkedAgentTaskIds(id, task.updatedAt);
}