## Summary
Restores the non-blocking full suite on `main` after a multi-package
failure cluster (latest red run:
[30777132347](https://github.com/Runfusion/Fusion/actions/runs/30777132347)).
### Product fixes
- **MissionManager**: move `handleDiscardInterviewSession` /
`handleConfirmDelete` **above** `if (!isActive) return null` so hiding
the inline Missions tab does not drop hooks (`Rendered fewer hooks than
expected`).
- **task-update dependency re-spec**: emit `task:moved` only when the
column actually changes, with resolved endpoints (not hardcoded
`todo`→`triage`); fixes `laneCache.set is not a function` harness
failures and deleted-column announcements.
### Bookkeeping / suite alignment
- **Schema applier tests**: baseline `0042`, project table count `104`
(+4 FN-8685 consumer tables), historical `0000` fixture includes
`mission_validator_runs` for 0042 upgrades, version lists include
0041/0042.
- **Ledgers**: archived-gate TS inventory (lifecycle-ops), legacy
collection ledger (`LEGACY_PLANNER_WAKE_COLUMNS`), worktree capacity
audited bounds + two admission readers (scheduler + triage).
- **Desktop**: pin `actions/setup-java@v5.6.0` after Dependabot bump.
- **Dashboard tests**: FN-8701 ToolCallDetails nested `<pre>`;
CreateRoomModal re-pins agent mock after empty-once.
## Test plan
- [x] `@fusion/core` task-update + ledger tests
- [x] `@fusion/core` schema-applier subset (table count,
0000/0001/0002/0003 upgrades, concurrent)
- [x] `@fusion/dashboard` AgentLogViewer / CreateRoomModal /
MissionManager overview tests
- [x] `@fusion/desktop` release-workflow tests
- [ ] CI full-suite green on this PR
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Bug Fixes**
- Dependency re-specification now moves held tasks to the resolved
workflow intake lane when available.
- Task move events are emitted only when a task’s column changes.
- Improved mission draft deletion handling for locked, missing, and
failed operations.
- Prevented mission management issues when inline Missions are shown or
hidden.
- Updated database migration handling for lifecycle-related tables.
- **Tests**
- Expanded coverage for workflow lanes, database upgrades, worktree
limits, and release workflows.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
- Local `fusion/*` branches for **done** tasks kept unique tip SHAs
after squash/AI merge, so self-healing logged
`stale-active-branch-rescue-needed` on every maintenance sweep without
ever deleting them.
- **Completion fan-out** now force-deletes the task branch even when
unique commits remain (squash-safe).
- **`reclaim-stale-active-branches`** force-deletes complete-lane
leftovers (`reason=complete-column-unique-commits-force`) and no longer
emits rescue-needed for those lanes; non-complete columns still warn and
preserve unmerged work. Archived lanes still skip reclaim entirely.
Also cleaned up 116 leftover local fusion branches on this machine
(done/orphan only; 9 active kept).
## Test plan
- [x] `pnpm --filter @fusion/engine exec vitest run
src/__tests__/self-healing-completion-fanout.test.ts
src/__tests__/self-healing.test.ts -t "SelfHealingManager
reclaimStaleActiveBranches|self-healing completion
fan-out|force-deletes"`
- [ ] After merge/restart engine: confirm logs no longer spam
rescue-needed for done tasks
- [ ] Confirm active todo/in-progress fusion branches still get
rescue-needed when unique and no worktree
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved cleanup of stale task branches after completion, including
branches with unique commits remaining after squash or AI-assisted
merges.
* Completed tasks now reliably remove residual branches and worktree
metadata.
* Non-completed tasks continue to preserve recoverable branches and
display rescue warnings.
* Added clearer recovery logging and audit records for forced branch
cleanup.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Keep the terminal close control last in the non-embedded terminal header across responsive layouts.
- Render one shared close control after terminal tabs, workspace picker, and status.
- Preserve the mobile corner ordering and prevent close-control shrinkage.
- Add ordering coverage for desktop, mobile, workspace, and status states.
- Add a patch changeset for the toolbar fix.
Files changed:
.changeset/fn-8729-terminal-toolbar.md | 7 +++
.../dashboard/app/components/TerminalModal.css | 15 +++---
.../dashboard/app/components/TerminalModal.tsx | 56 ++++++++--------------
.../components/__tests__/TerminalModal.test.tsx | 51 ++++++++++++++++++++
4 files changed, 83 insertions(+), 46 deletions(-)
Fusion-Task-Id: FN-8729
Fusion-Task-Lineage: ba9b039c-557d-4692-8203-bf764388d039
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
FN-8656 moved the recentEngineTodoRequeues / dispatch-oscillation reset behind
await resolveTaskParkedColumns, racing sync delete/update handlers. A hold
requeue then delete in the same tick could re-set the settle guard after the
clear and leave the card undispatchable. Consume the sync parked lanes in the
emitter prologue again.
Tablet-class devices at ≤768 CSS px were mode=tablet (left sidebar on, no
MobileNavBar) while pure max-width:768 rules hid the sidebar and elevated the
footer for a phantom tab bar. Publish data-viewport-mode and key shell CSS off
it so tablet keeps the left sidebar and a true bottom footer.
Remove the FN-8700 PR/file-claim blocking mechanism end to end (operator
decision after FN-8728 parked on unrelated PR #2398):
- Drop the AGENTS.md claim-check rule and scripts/check-file-claimed.mjs
- Executor prompt + fn_task_done no longer accept pr:N refs or treat open
PRs as blocked-exit reasons
- execution-block-classifier classifies on Fusion task dependencies only;
legacy pr refs are discarded, reason prose never makes a block durable
- Remove the session-log BLOCKED promotion and the gh-backed
reconcile-external-pr-blockers self-healing sweep
- Legacy file-claim parks are no longer honored, so previously PR-blocked
rows recover via normal paths
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Make the useTasks hydration freshness coverage deterministic and restore it to the dashboard suite.
- Control the system clock for hydration fixtures and flush async updates without advancing time.
- Remove the rescued test from the dashboard exclusion list and quarantine ledger.
Files changed:
.../__tests__/useTasks-hydration-freshness.test.ts | 30 ++++++++++++++--------
packages/dashboard/vitest.config.ts | 8 ------
scripts/lib/test-quarantine.json | 5 ----
3 files changed, 19 insertions(+), 24 deletions(-)
Fusion-Task-Id: FN-8724
Fusion-Task-Lineage: 1d764e2c-0975-4d26-92c6-187a6a94caee
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
## Summary
- add reverted-task resolution keys to every secondary app catalog
- restore structural locale parity after the reverted-task dashboard UI
landed
- include labeled patch release metadata
## Test plan
- `pnpm --filter @fusion/i18n test`
- `pnpm i18n:status`
- `pnpm check:changesets -- --strict`
- `pnpm build`
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Localization**
* Added localized labels for reverted tasks, resolution actions,
revision actions, and related task titles in French, Korean, Simplified
Chinese, and Traditional Chinese.
* Added Spanish locale entries for consistent support of these task
actions.
* Improved terminology coverage across supported secondary locales.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Classify blocked exits so check-file-claimed / open-PR collisions never
auto-replan. Park failed with externalBlockers metadata (pr:N supported),
promote BLOCKED session logs instead of incomplete-step requeue, thrash-
exhaust after 3 identical durable blocks, and clear parks when gh reports
blocking PRs merged or closed.
Scope stuck-requeue merge-base failure to the task-branch proof so setup
still reaches the session; loosen MCP coverage to allow let session
rebinding; mock getRootDir for stranded-hold capacity; and expect the
scheduler parked-role site to use awaited resolveTaskParkedColumns after
FN-8656.
After one free needs-replan clear of an inactive DUPLICATE marker, a
re-emit of the same dismissed canonical parks status failed
(DUPLICATE_REPLAN_EXHAUSTED) so triage no longer re-admits the card.
Tracks clear count in sourceMetadata; self-healing mirrors triage.
Convert three real-timer 400ms wall waits in the unmapped-workflow forced-refetch
negative-assertion tests to deterministic vi.useFakeTimers()/advanceTimersByTimeAsync
advances, removing ~1.2s of dead wall-time while preserving the REVERT CHECK semantics
(a regression that armed a RETRY_DELAY_MS retry would still fire and fail).
Fusion-Task-Id: FN-slow
FN-8704 failed at the graph parse node because PROMPT.md was only
"DUPLICATE: FN-8676". Filesystem validation treated non-empty as planned
and admitted the card into WIP, which then looped on parse failure.
Treat a sole DUPLICATE redirect as unplanned: block dispatch and hold
release, badge as awaiting planning, and if parse still sees that shape
rebound to needs-replan with feedback instead of parking failed.
Failed parks left in the WIP column still counted as running agents and
file-scope lease holders, so they consumed maxWorktrees/maxConcurrent and
could serialize unrelated todos. Match review-lane semantics: status
failed is never a live top-level holder.
Clearing a DUPLICATE marker for an inactive or kept canonical left
status:null without PROMPT.md. The scheduler treats planning→null as
"finished planning" and re-dispatched the card; FS validation rebounded
to needs-replan with no ceiling, and triage re-planned with empty
feedback so the planner could re-emit the same inactive marker forever
(FN-8704 / FN-8676).
Leave needs-replan + dismissal metadata + replan feedback instead, share
the clear contract across triage and self-healing, and bound scheduler
filesystem-validation rebounds with the shared recovery budget.
Session setup, track bookkeeping, intentional skill exclusions, token-cache
metrics, zero-count recovery summaries, and expected-missing PROMPT seed reads
were flooding the default log pane. Gate them behind FUSION_DEBUG so only
state transitions and operator-actionable warnings remain visible.
Operators summing the lane-header executing counts saw 10 active cards
under a 9-slot concurrency cap and read it as a capacity breach. The
header unioned the shared Running predicate with the card activity-chrome
predicate, which glowed needs-replan parks (FN-8494) and fresh
planner-log windows (FN-8300) that hold no concurrency slot.
isTaskAgentActive's positive arm now delegates to the shared
isRunningAgentTask predicate (footer/admission truth) and Column headers
count only that predicate, so glow and counts are a strict subset of the
live-agent population. Idle replans render the existing "Queued to
revise" waiting label instead of activity chrome.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add regression coverage for independently retained task popups across Board and List views.
- Exercise popup identity, refresh, visibility, and close behavior for the same task.
- Cover real desktop and mobile Board/List interaction paths.
Files changed:
.../app/__tests__/App.taskPopupViewGating.test.tsx | 69 ++++++++++++-
.../app/components/__tests__/App.test.tsx | 113 ++++++++++++++++++++-
2 files changed, 176 insertions(+), 6 deletions(-)
Fusion-Task-Id: FN-8698
Fusion-Task-Lineage: 857db4cb-0dd5-45ea-a7b7-9cb95f6f5fef
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>