## Why this exists
#2757 merged as `9a2a033b9e`, but **the third of its three fixes is not
on main**:
```
$ git show origin/main:packages/engine/src/executor.ts | grep -c wipDeclared
0
```
The merge captured my branch *before* commit `68381db72f`, so the
no-wip-lane fix was dropped while the other two landed.
`executor-execution-policy-renamed-columns` → *"a workflow with no wip
column terminalizes visibly instead of claiming the card advanced"* is
still red on main, still returning `status: null, error: null`.
This is that commit, cherry-picked cleanly onto current main. No new
work — the review discussion is in #2757.
## What it fixes (recap)
`resolveResumeLanes` defaulted `wip: lifecycle?.wip ?? "in-progress"`,
collapsing two different states:
1. **the IR failed to resolve** — defaulting is right; the `catch` arm
wants exactly this
2. **the IR resolved and declares NO wip column** — defaulting *invents
a lane the workflow does not have*
`routeGraphFailureToExecutionResume` then admitted a card resting in
that workflow's **hold** lane with incomplete steps, rehomed it,
returned `true` — and the terminalize branch never ran. Resuming into a
workflow with no implementation lane *is* "claiming the card advanced"
when nothing did.
The fix adds `wipDeclared` (declared, as opposed to defaulted) and
declines the resume when it is false — the same fail-closed rule the
sibling branch already applies with `wipColumn !== undefined` before
calling a card "already advanced". That path failed closed; this one
failed open.
IR-unavailable deliberately keeps today's behaviour (`catch` reports
`wipDeclared: true`), so an infrastructure error does not start refusing
legitimate resumes.
## Verification on current main
| check | result |
|---|---|
| the three affected files | **23 passed** |
| `pnpm test:gate` | **726** |
| engine `tsc --noEmit`, `pnpm lint` | clean |
| remove the guard | 1 failed — the fail-closed case goes red again |
| always decline | 1 failed — a legitimate resume breaks |
Full-suite blast radius was measured on #2757 before it merged: 834
files / 10,845 tests, 5 failures, both files pre-existing
(`executor-prompt`'s pause-guard 3 and `executor-abort-provenance`'s 2,
byte-identical to baseline). Zero new failures.
## Note
Worth checking whether other PRs merged in that window lost their final
commits the same way — I only noticed because I re-verified main after
the merge rather than assuming a merged PR contains what the branch
held.