Files
fusion/packages
gsxdsm 632d10a9b4 fix(engine): a completed-blocked guard was inert on renamed boards — plus one owner for the terminal pair (#2568)
Two commits: a behaviour-preserving extraction, then the behaviour
change.

## ⚠️ Stack note worth acting on

**#2550 and #2554 both report MERGED, but their content is not on
`main`.** They merged into their *base branches*, and the bottom of that
stack (**#2544**) is still open. Nothing in this chain has reached
`main` yet.

Nothing is lost — everything is in
`origin/feature/workflow-e2e-merge-rebound`, which is why this PR
targets it. But "merged" reads as "landed" and here it doesn't.
**Merging #2544 flows the whole chain down.**

## The bug

`parkCompletedBlockedTask` opens with *"is this card already finished?"*
and answered it with:

```ts
if (task.column === "done" || task.column === "archived") return false;
```

On a renamed board neither matches, so **the guard was inert** — and the
very next branch (`if (task.column !== "todo")`) would then have **moved
a completed card back out of its own terminal column**.

A guard that never fires does not fail a test. This one was found by
tracing the last ledger site, not by anything going red.

## Why a shared owner, not a local fix

`merger-ai`'s `isAlreadyFinalizedColumn` held the **only** copy of the
per-role terminal-pair rule — a P1 learned the hard way (PR #2471
review): a per-**set** fallback collapses to one element for a workflow
declaring `complete` but no `archived`, silently dropping the archived
half of every already-finished check.

Executor's guard was the raw literal pair, so **whoever converted it
next would have re-made exactly that mistake** — the lesson lived in a
comment in another file. Hence `resolveTerminalColumns(ir)` in core: one
owner, one place for the rule.

## Evidence, and its limits

**Commit 1 (extraction) is proven behaviour-preserving**:
`workflow-already-finalized-live-e2e` is unchanged and green through the
delegation, and the per-set mutation **still fails** through the shared
helper.

**Commit 2 (the fix) is unproven at the call site, and I'm labelling it
rather than implying otherwise.** `parkCompletedBlockedTask` is private
and reached only from inside executor dispatch — I could not drive it
end to end. So the shared helper gets its **own** tests, in both
partial-role directions, precisely because its other consumer can't
vouch for it. The call site is a one-line delegation to a tested
function.

Weaker evidence than the rest of this unit's work. Saying so, because
quietly counting it as proven is the exact failure this unit exists to
catch.

## Census

417 → 416. That ratchet (#2557) is a **ceiling**, so it stays green
without coordination; lower the pin when convenient.

## Verification

- E2E suites 10/10; helper unit tests 5/5
- core + engine `tsc --noEmit` clean
- `pnpm test:gate` green (414 + 10 + 71)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---

## Note on the conflict status (2026-07-31)

GitHub reports this PR `CONFLICTING / DIRTY`. **It is not.** Three
independent checks:

- `git rebase origin/main` on the pushed head reports *"up to date"* and
leaves the SHA unchanged — the branch is already on top of main.
- `git merge-tree` against the merge base produces **zero** conflict
markers.
- `origin/main` is unchanged at the commit this was rebased onto.

The remote SHA matches the local head, so the push landed. The
`mergeable` field is a **stale computation** — it goes stale after a
force-push and doesn't always recompute.

This branch has now been rebased and force-pushed four times against
that cached value. Worth guarding at the source: the auto-retry treats
`mergeable` as ground truth, so a stale value generates conflict notices
indefinitely. Confirming with a trial rebase or `git merge-tree` before
dispatching distinguishes "actually conflicting" from "GitHub hasn't
recomputed" — one command, and it ends the loop.

Verification on the current head: merge gate green (487 + 158 + 10),
engine + core tsc clean, lint clean, 20 tests in the affected suite,
zero unresolved threads.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 01:33:03 -07:00
..
2026-07-26 18:11:47 -07:00