## What & why
FN-8141 (\"Update pi SDK to latest and verify Kimi K3 end to end\") was
**laundered into `done` despite producing zero net changes**. The pi SDK
bump kept breaking `verify:fast`, the work was reverted 5×, and the
agent used the sanctioned skip affordance to mark **Testing &
Verification** and **Documentation & Delivery** `skipped`.
`isTaskComplete()` counts `skipped` as complete, so:
1. self-healing `recoverStrandedCompletedTodoTasks` promoted the todo
task to in-review (all steps done/skipped),
2. the AI merger saw an empty diff vs main → \"finalizing as no-op\" →
`done` with `mergeConfirmed:true`,
3. no reviewer ever saw it (skipped steps request no review; the
merge-review pass reviews an empty diff).
The only existing guard, `evaluateNoCommitsNoOpFinalize` (FN-6461),
missed it **twice**: it only fired when `noCommitsExpected === true`
(FN-8141 was commit-expected — the branch was empty because work was
*reverted*), and even then only blocked when `incomplete >= done`
(FN-8141 had 3 done vs 2 skipped).
## The fix
Generalize the guard (same exported name/shape — every finalize lane
keeps working) so a **zero-diff/no-op finalize is blocked whenever ANY
step is `skipped`**:
- a **verification-flavored** skipped step (name matching
`/test|verif|qa|review/i`) blocks **unconditionally**;
- any **other** skipped step blocks **unless** every non-skipped step is
`done` **AND** the task is the legacy `noCommitsExpected` ops shape;
- the legacy FN-6461 ratio rule (`noCommitsExpected` + `incomplete >=
done`) is preserved for pending/in-progress incomplete work;
- blocked evaluations return a precise `reason` naming the skipped
steps.
Legitimate shapes still pass: all-done no-skip empty diffs (left to the
lineage-proof work), zero-step tasks, and `noCommitsExpected` ops tasks
with a minor non-verification skipped tail.
## Surface enumeration
The guard is the single chokepoint used at every zero-diff finalize
lane; all already honor `.blocked`/`.reason`, so the core change fixes
each surface:
- `packages/engine/src/merger-ai.ts` ~1116 — AI empty-merge lane
- `packages/engine/src/merger.ts` ~6261 / ~7354 / ~7658 — merger
empty-own-diff + no-op lanes
- `packages/engine/src/self-healing.ts` ~2851 — stranded-todo promoter
pre-check; ~6335 — no-op review finalize
Behavior on block is unchanged (error set, durable log entry,
`task:no-commits-finalize-blocked-incomplete-steps` run-audit event,
move back to todo with progress preserved).
## Test evidence
- **Core** `pnpm --filter @fusion/core exec vitest run
src/__tests__/no-commits-finalize-guard.test.ts` → **9 passed**. Covers
FN-8141 shape (3 done + 2 skipped, not noCommitsExpected → blocked),
verification-skip blocks regardless of ratio/`noCommitsExpected`, legacy
`noCommitsExpected` shapes, all-done no-skip → not blocked, zero steps →
not blocked.
- **Engine lanes** — one test per finalize-lane family, all green:
- `merger-ai.test.ts` (AI empty lane, incl. new FN-8141
reverted-commit-expected case) → **36 passed**
- `merger-finalize-unproven.real-git.test.ts` (merger lanes) → passing
- `self-healing.test.ts` (stranded-todo promoter + no-op review
finalize, incl. new FN-8141 promoter case) → **394 passed**
### `pnpm verify:fast` — pre-existing engine build breakage (not this
PR)
`verify:fast` fails at the workspace-dist bootstrap because
`@fusion/engine` does **not** typecheck on `main`:
`src/auth-storage.ts`, `src/pi.ts`, `src/provider-registration.ts`
reference `ModelRuntime` / `AuthInteraction` / `CredentialInfo` /
private `ModelRegistry` members removed by pi 0.80.9/0.80.10 (the
FN-8142 migration that motivated this incident; upstream fix is
FN-8145). Verified this failure reproduces with my changes **stashed**
(13 identical tsc errors at clean HEAD). This PR touches only
`@fusion/core` (builds clean, `tsc` exit 0) and engine **test** files —
no engine source — so it neither causes nor can resolve that breakage.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Prevented empty or no-op finalization when verification, QA, review,
or other required steps are skipped.
* Ensured tasks with skipped work are not incorrectly marked complete,
merged, or promoted during recovery.
* Improved error messages to identify skipped verification steps
blocking completion.
* **Tests**
* Added regression coverage across finalization, merge, and self-healing
workflows.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Claude Opus <noreply@anthropic.com>