Fixes two classes of task failures found while investigating stuck in-review
tasks FN-2165 (worktree base ref missing) and FN-2152 (stray .tmp-fn-2152
gitlink accidentally committed via merger amend).
FN-2165 — stale baseBranch:
- resolveWorktreeStartPoint now returns null instead of throwing
NonRetryableWorktreeError when the stored baseBranch is gone. Caller clears
task.baseBranch and falls back to branching from the default base (HEAD) so
the task self-heals instead of failing permanently.
- New TaskStore.clearStaleBaseBranchReferences() nulls baseBranch on any
dependent task when its upstream branch is deleted. Wired into
cleanupBranchForTask (archive/delete), merger branch cleanup, self-healing
orphan-branch sweep, executor dep-abort and conflict-cleanup paths, and
stale-branch recovery.
Nested worktrees:
- assertWorktreePathNotNested guard in tryCreateWorktree refuses to create a
worktree inside another registered worktree (previously produced pathological
paths like .worktrees/green-finch/.worktrees/amber-panda when rootDir pointed
at a worktree instead of the main repo).
Context-overflow recovery (FN-2182 class):
- Reduced-prompt retry budget raised from 1 → 3 within the same session.
- Adds a fresh-session requeue path when same-session retries still overflow:
task moves back to todo with worktree retained, bounded by
computeRecoveryDecision / MAX_RECOVERY_RETRIES. Prevents late-step context
exhaustion from becoming terminal.
Gitlink prevention (FN-2152 class):
- .gitignore now excludes .tmp-fn-* and .tmp-kb-* so stray worktrees at the
repo root cannot be captured by git add -A.
- Merger amend flow now scans staged entries for 160000 gitlinks and unstages
them with a loud warning; the project uses no submodules, so any such entry
is a bug (this is how f8f90f26 landed in HEAD as .tmp-fn-2152).
Tests: new coverage for baseBranch fallback, nested-worktree guard, and
clearStaleBaseBranchReferences. Full engine + core + dashboard + cli suites
pass (15349 tests).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root cause: during a triage split the AI could set a child task's
`dependencies` to the parent id. The parent is hard-deleted after the split,
and the scheduler's dep check treats a missing id as unmet — permanently
blocking the dependent. This stranded FN-2164 behind the deleted FN-2163.
- core/store.deleteTask: refuse to delete when any live task still has the id
in its `dependencies` array. Throws TaskHasDependentsError listing dependents
so callers can rewrite or recover. Covers the triage-split path and any
future caller.
- engine/triage task_create: validate each proposed dependency before creating
a child — reject the parent id, reject unknown task ids, allow siblings
created earlier in the same split or pre-existing tasks.
- engine/triage split cleanup: wrap the parent deleteTask in try/catch that
keeps the parent alive (safer than stranding dependents) and logs the reason.
- engine/triage prompts: both the mandatory-split and proactive-split prompts
now explicitly state that subtask deps must never reference the parent.
- dashboard/routes /subtasks/create-tasks: reject parent-id deps, drop unknown
deps with an audit log entry, surface parentTaskCloseError + droppedDependencies
in the response instead of silently swallowing them.
- engine/executor: on execute entry, detect the drift state (in-progress task
with no worktree) and emit a loud log + task log entry; the existing
fresh-worktree path then recovers. Prevents silent "operating without a
worktree" behavior that we saw on FN-2152.
Tests:
core: 2907/2907 pass (+5 new, incl. deleteTask guard regression)
engine: 2554/2554 pass (+17 new, incl. task_create dep validation)
dashboard: 9064/9064 pass (+2 new for /subtasks/create-tasks).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add defensive cleanup for in-memory task tracking when tasks move state or agents pause
- Improve stuck-detection and self-healing flow to reduce leaked state and missed recovery paths
- Add logging around previously swallowed errors and tighten executor cleanup behavior
- Expand restart and self-healing reliability tests to cover regression scenarios
Adds a SelfHealingManager scan that finds tasks parked in in-review with
a failed pre-merge workflow step and no active session, and sends them
back through the existing sendTaskBackForFix flow (PROMPT.md injection,
step reset, todo → in-progress). Bounded by a new maxPostReviewFixes
setting (default 1) and a per-task postReviewFixCount so a persistently-
failing verifier cannot ping-pong a task indefinitely.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add self-healing for stale in-review tasks left in merging status after the merge commit lands. Recovery uses taskStuckTimeoutMs, records merge details, moves confirmed merges to done, and clears stale merge status for retry when no landed commit is found.
- Add MailboxView as a full-page navigation view replacing the modal-based approach
- Migrate MessageStore from filesystem to SQLite backend for message persistence
- Implement conversation grouping for inbox display with unread badge state
- Remove modal plumbing (useModalManager, AppModals exports) and simplify App.tsx
- Add evictStaleProcessing() to TriageProcessor for self-healing hung triage sessions
- Add comprehensive MailboxView tests and Header mailbox tests
- Update README documentation with MailboxView features
- Add CSS styles for MailboxView component
- Fix MobileNavBar tests for mailbox tab visibility
- executor.test.ts: remove unused imports (Column, StuckTaskDetector),
replace Function type with EventListener, add MockTaskStore interface
- restart.integration.test.ts: replace require() with ESM import,
replace Function types with proper function signatures
- All tests pass
- Remove unused imports across 25 files in engine package
- Remove unused variable declarations in ipc-worker.ts, child-process-runtime.ts, and mission-autopilot.ts
- Clean up unnecessary imports in agent-instructions.ts, agent-tools.ts, cron-runner.ts, executor.ts, and other modules
- Minor cleanup in notifier.ts, peer-exchange-service.ts, pi.ts, plugin-runner.ts, and other files
- Improves code quality and reduces potential confusion from unused code
Tasks stuck in triage with status "specifying" had no recovery path when the
agent session crashed mid-specification (before producing an approved spec).
The stuck task detector only monitors tracked sessions, and
recoverApprovedTriageTasks only handles tasks with an approved spec — leaving
unapproved specifying tasks stranded indefinitely.
Add recoverOrphanedSpecifyingTasks to clear status back to null so the next
triage poll picks them up for a fresh specification attempt.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace blocking execSync calls with async execAsync in executor.ts for user-configured commands
- Convert self-healing.ts worktree status checks to async to avoid blocking the event loop
- Update step-session-executor.ts to use async worktree operations
- Refactor worktree-pool.ts for fully async worktree creation, cleanup, and listing
- Convert pi.ts agent session handling to async execution
- Update all corresponding tests with async/await patterns
- Add changeset for @gsxdsm/fusion patch release
- Convert hasRecoverableGitWork from sync execSync to async execAsync
- Update recoverNoProgressNoTaskDoneFailures caller to await the method
- Update self-healing tests to work with async method and execAsync mock
- Add exec and promisify imports to self-healing.ts
- Fix mock to include exec export for promisify compatibility
Bundles staged work-in-progress modifications across multiple packages
(routes, store, agent-instructions, self-healing, QuickEntryBox, etc.)
plus the dashboard theme-data.css preload fix.
Note: an unstaged 621-line deletion in .fusion/memory.md was deliberately
NOT committed — it appears to be an accidental overwrite of architecture
notes and is left in the working tree for review.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GET /api/tasks was returning ~69 MB of JSON per call (67.9 MB of agent
logs across 1199 tasks), causing the dashboard to hang for 2+ minutes.
- core: extend listTasks() with slim and includeArchived options
- dashboard: GET /api/tasks now uses slim mode and excludes archived
by default; ?includeArchived=1 opts in
- frontend: lazy-load archived tasks when the archived column is first
expanded via new useTasks.loadArchivedTasks()
- engine: self-healing maintenance now auto-archives done tasks older
than 48h (data stays in SQLite, column flips done -> archived)
- tests: slim mode + includeArchived coverage in store.test.ts;
routes.test.ts assertion updated for new args
Also bundles in-progress test-setup noise filters and pre-existing
QuickEntryBox/routes test work that was already modified locally.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add /missions/health endpoint handling to MissionManager test mocks
- Add listMissionsWithSummaries to mission-e2e test mock
- Add planState to Slice type and mock factories
- Add stuckKillCount to retry task test assertions
- Update log message for stuck-killed retry
Previously, recoverOrphanedExecutions() skipped tasks whose worktree
directory still existed, assuming an active session. After engine crashes
where resumeOrphaned() failed, these tasks were stuck forever. Now uses
a tiered grace period: 60s for missing worktrees, 5min for existing ones
to avoid racing with startup recovery.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When context overflow or compaction causes an agent to lose awareness of
the task_done tool, the executor now checks if all steps are complete
before failing — treating it as an implicit task_done. Also adds
self-healing recovery for tasks that already slipped through as
misclassified failures in in-review.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move single-session and step-session executor failure paths to in-review after marking tasks failed
- Route exhausted transient recovery retries to in-review instead of leaving tasks outside review flow
- Move stuck-kill budget exhaustion failures in self-healing to in-review and update failure log wording
- Add regression tests in executor and self-healing suites to verify in-review transitions on these failure states
- Add optional chaining (?.) on task.description.slice() to prevent null-reference crash
- Fallback to '(untitled)' when both title and description are absent
- Add changeset for @fusion/engine patch
- Add scanOrphanedBranches utility to worktree-pool for detecting fusion/* branches with no matching task
- Add cleanupOrphanedBranches to SelfHealingManager with dry-run support and task re-registration
- Wire branch cleanup into deleteTask and archiveTask so branches are removed when tasks are deleted or archived
- Add comprehensive tests for scanning, cleanup, and integration with delete/archive flows