13bdf63bfcffc3ef70aae7589ae2274d2ae2e644
11602 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
13bdf63bfc |
fix: resolve Anthropic subscription auth through getApiKey for pi ModelRuntime.getAuth
pi >=0.80.8 moved session request auth to ModelRuntime.getAuth -> pi-ai
resolveProviderAuth, which reads credentials.read("anthropic") and refreshes an
OAuth credential via credentials.modify("anthropic"). Fusion stores the
subscription login under `anthropic-subscription` with no raw `anthropic` row,
so the refresh callback saw current===undefined, bailed, and auth resolved to
undefined -> "Provider is not configured: anthropic" (then fell back).
Resolve read("anthropic") through fusion's getApiKey (refresh + raw/legacy/
subscription/fallback precedence) and hand pi-ai a ready api_key credential;
pi-ai routes it as OAuth by the sk-ant-oat token prefix. Supersedes the prior
read-alias, which fixed lookup but not the broken OAuth refresh-via-modify path.
Verified end-to-end: ModelRuntime.getAuth(anthropic/opus) now resolves the
subscription token instead of returning undefined.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
4b150e2280 |
fix: resolve Anthropic subscription auth under pi-ai >=0.80 read() contract
pi-ai >=0.80 resolves provider auth via credentials.read(provider.id) and
performs OAuth refresh/derivation itself, bypassing fusion's getApiKey()
where the anthropic-subscription -> anthropic alias lived. A subscription-only
login surfaced as "Provider is not configured: anthropic" at prompt time even
though the status card showed connected.
- Alias the subscription OAuth credential into read("anthropic") at the
credential-store layer (createFusionCredentialStore); raw/legacy rows still win.
- Match "not configured" in isRetryableModelSelectionError so an unresolved
provider triggers the configured fallback model instead of hard-failing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
00cca460fc |
fix(engine): reclaim leaked semaphore slots when the system is busy, not only at total idle (#2265)
## fix(engine): reclaim leaked semaphore slots when the system is busy, not only at total idle ### The bug `recoverIdleSemaphoreLeakCandidate` only reclaims stale `AgentSemaphore` slots when the system is **completely** idle (`persistedActive === 0 && inFlightCount === 0` → reconcile to 0). If even one in-progress row persists — e.g. a zombie task whose agent session died without its `finally` release — the valve never opens, and slots leaked by abnormal teardown accumulate monotonically until `activeCount` pins the limit. At that point the engine deadlocks in a distinctive way: - every hold/release sweep logs `Hold release for <task> deferred — no reservable slot for in-progress` - triage/plan report `planning=0 … processing=0, semaphore active=<limit>/<limit>, available=0` - the merge queue grows unboundedly (merges also need a slot) - only a process restart recovers `reapLeakedConcurrencySlots` (FN-6782) doesn't help — it reconciles **worktree** slots, not the shared semaphore. ### Production evidence Observed twice on a 6-project embedded-PG deployment driving a local model: - After ~5 days of continuous operation: `semaphore active=24/24`, `planning=0/24, processing=0`, 5 persisted in-progress rows (dead sessions), merge queue at 88, **zero merges for >24h**. Restart immediately restored merging. - Same signature earlier at `active=40/40` with both LLM backends idle (`kvcache≈0`). The handful of zombie in-progress rows kept `persistedActive` nonzero indefinitely, so the idle-only valve could never fire. ### The fix Generalize the valve: clamp `activeCount` down to the **persisted + in-flight bound** whenever the semaphore over-holds **continuously** for a repair window. - The strict-idle case (`bound === 0`) keeps its existing fast 5s window — behavior unchanged, existing tests pass as-is. - The non-idle case uses a deliberately conservative new window (`STALE_SEMAPHORE_EXCESS_REPAIR_MS = 600_000`, 10 min): nested helper agents (`runNested`) legitimately push `activeCount` above the persisted top-level count for the duration of a nested run, so the excess must outlive any plausible nested session before it is treated as leaked. The candidate timestamp resets the moment the excess clears. - `reconcileActiveCount` only ever lowers the count, so the clamp cannot inflate capacity; a late release from a genuinely live agent after a (worst-case, mis-timed) clamp is absorbed by the existing excess-release guard (FN-6423). Call-site changes are limited to the two log messages (the old parenthetical claimed "no persisted … agent work", which is no longer the only repair case). ### Tests - existing idle-valve tests pass unchanged (same window, same reconcile-to-0) - new: stale excess above a nonzero persisted bound is repaired only after the long window, and clamps exactly to the bound - new: candidate resets when the excess clears (nested overshoot ending) - new: caller in-flight sessions count into the bound (no false candidate) ### Files - `packages/engine/src/concurrency.ts` — generalized valve + `STALE_SEMAPHORE_EXCESS_REPAIR_MS` - `packages/engine/src/scheduler.ts`, `packages/engine/src/triage.ts` — log message accuracy - `packages/engine/src/__tests__/concurrency.test.ts` — 3 new tests <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved stale “semaphore excess” recovery by using a configurable repair window when excess persists. * Prevented premature capacity corrections by accounting for in-flight top-level work during reconciliation. * Correctly handles nested helper activity so only leaked excess is reclaimed, preserving legitimate nested runs. * Updated reconciliation to clamp excess to the appropriate reclaim floor instead of waiting indefinitely. * **Improvements** * Refreshed diagnostic warning text to clarify the over-held vs persisted+in-flight work comparison. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: TrinaryCompute <fusion-merge@trinarycompute.dev> Co-authored-by: gsxdsm <gsxdsm@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
d1e9b563f7 |
fix(FN-8141): add forward migration for tasks.bulk_completion_refusal_at
PR #2260 added project.tasks.bulk_completion_refusal_at to the Drizzle model and the 0000 baseline but shipped no forward migration. Databases created before #2260 already carry the 0000 marker, so the applier skips the baseline and they never gained the column — every such cluster crashed on the first TaskStore SELECT ("column bulk_completion_refusal_at does not exist"), taking down dashboard/app boot. Adds forward migration 0018 (wired via BULK_COMPLETION_REFUSAL_AT_VERSION; SCHEMA_BASELINE_VERSION -> "0018") so existing clusters heal on next startup. Prevention: - Per-column upgrade regression test reproducing the exact existing-DB failure. - Migration-wiring-integrity guard (no PostgreSQL): SCHEMA_BASELINE_VERSION must equal the highest migration file, and every .sql must be registered in the applier so none silently never runs. - Repairs 6 pre-existing schema-applier tests left stale by the 0017 addition (baseline-marker identity + version-list enumerations). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
da7c68c1dc |
refactor: package code organization wave 8 (#2252)
## Summary Wave 8 of package code organization (plan: `docs/plans/2026-07-14-001-refactor-package-code-organization-plan.md`), after #2166. ### Peels | New module | Parent | |---|---| | `app/api/board-workflows.ts` | `legacy.ts` | | `app/api/remote.ts` | `legacy.ts` | | `app/api/memory.ts` | `legacy.ts` | | `types/docker-nodes.ts` | `types.ts` | | `task-store/task-store-helpers.ts` | `remaining-ops-10.ts` (rename) | ### CI fix (main unblocker) FN-8142 requires pi SDK **0.80.8+** (`ModelRuntime`, `CredentialStore.list`). Floored `@earendil-works/pi-*` to `^0.80.8` so lockfile resolves past 0.80.6. Public import paths stay stable via re-exports. ### LOC - `legacy.ts` ~10975 → ~10561 - `types.ts` ~7349 → ~6928 ## Test plan - [x] core / dashboard typecheck + eslint on peels - [x] api-tasks (66) - [x] CI merge gate (Lint / Typecheck / Build / Gate) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added dashboard support for multi-lane board workflows, including workflow metadata retrieval and task custom-field updates. * Added dashboard memory client capabilities for reading/writing memory, managing memory files, compaction/dreaming, insights, auditing, backend status, and retrieval testing. * Added remote connectivity controls, including tunnel start/stop, provider activation, token generation, URL sharing, and QR generation. * Added Docker node configuration validation plus secure redaction for sensitive fields in responses. * **Improvements** * Consolidated dashboard API exports into dedicated modules and preserved the legacy API surface via re-exports. * **Chores** * Updated related agent dependency versions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
daa34fbc38 |
fix: refineTask/duplicateTask fail in backend (PostgreSQL) mode (#2253)
## Summary Eliminates the remaining backend/PostgreSQL-mode sync-SQLite (`store.db`) call sites — both the crashing ones and the try/catch-masked ones that silently degraded features. Found via a full audit of `store.db`/`archiveDb` residue after the PG cutover's per-site routing missed them. **Crashes fixed:** 1. **refineTask / duplicateTask** threw `TaskStore.db: SQLite Database is not available in backend mode`. Both create rows through `createTaskWithId` callbacks calling `store.atomicCreateTaskJson()` directly, bypassing `_createTaskInternal`'s backend routing. The shared helper now routes itself (soft-delete conflict check + non-destructive insert in one AsyncDataLayer transaction). 2. **Merger verification cache**: `getVerificationCacheHit` ran sync SQLite unguarded *outside* any try/catch in `runDeterministicVerification`; `recordVerificationCachePass` was swallowed so the cache never warmed. Both are now async with a PG branch. **Silent degradations fixed (features that were dead on PG):** - Workflow run-branch + foreach step-instance persistence (`saveWorkflowRunBranch`, `loadWorkflowRunBranches`, `clearWorkflowRunBranches`, `saveWorkflowRunStepInstance`, `loadWorkflowRunStepInstances`, `clearWorkflowRunStepInstances`) — executor crash-resume checkpoints were silently never persisted. - `getBranchProgressByTask` — returned an empty map, dropping `branchProgress` from task payloads. - `runPluginColumnTransitionHooks` — plugin `onEnter`/`onExit` column-transition hooks never fired (marker bookkeeping + non-locking task read now async). - `getTaskColumns` — dashboard treated all agent-linked tasks as non-terminal. - `getWorkflowStep` / `listWorkflowSteps` — stored workflow-step rows now read from `project.workflow_steps` (listing previously returned plugin steps only); `getLegacyWorkflowStepSnapshot` returns `undefined` on PG (legacy snapshot exists only in pre-migration SQLite). - `readRawProjectSettings` / `listWorkflowPromptOverridesForProject` — now read via the async layer. These store methods became **async**; engine/dashboard callers await them (the workflow persistence interfaces already accepted `Promise`-returning impls). **PG gotcha encoded in the fixes:** migration `0006_project_ownership` rebuilds every project-schema PK to lead with `project_id`, so column-list `ON CONFLICT` inference fails (42P10) — upserts target the PK by constraint name. ## Surface Enumeration - Creators through `atomicCreateTaskJson`: `refineTaskImpl`, `duplicateTaskImpl` (fixed); `_createTaskInternalImpl` unaffected (already routed). - Verification-cache callers (all merger, all 3 sites now awaited). - Run-branch/step-instance callers: executor persistence adapters, parse-steps foreach probe, integration-queue flip, crash-resume reconcile, graph-reset cleanup; triage replan cleanup; dashboard spec-rebuild pin clears; agent-reflection rework summing — all awaited. - Audit classified everything else as guarded or sync-mode-only (dead in production — every entry point constructs stores via `createTaskStoreForBackend`). ## Symptom Verification - **Original symptoms:** refinement/duplicate creation threw; merge verification threw; workflow checkpoints/branch progress/plugin hooks/task-column lookups silently no-oped on PostgreSQL. - **Exact reproduction:** `refine-duplicate-task.pg.test.ts`, `verification-cache.pg.test.ts`, and `sync-db-residue-backend.pg.test.ts` exercise each surface against embedded-PostgreSQL backend-mode TaskStores. - **Assertion it is gone:** all suites pass (14 + 5 tests), plus `transition-pending-and-status-clear.pg.test.ts`, `create-task-reserved-id.pg.test.ts`, dashboard `routes-github.test.ts` (123), engine `triage.test.ts` (221) and `agent-reflection.test.ts` (31). Core/engine/dashboard typecheck fully clean: the 13 errors from the FN-8142 pi SDK migration are fixed by bumping @earendil-works/pi-ai/pi-coding-agent to ^0.80.10 (FN-8142 used APIs absent from the previously locked 0.80.6). Locally green: `pnpm verify:fast` (scoped typecheck + build + CLI build + boot smoke), `pnpm test:gate`, and `pnpm lint`. 🤖 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** * Fixed refinement/duplication task creation in PostgreSQL-backed backend mode. * Improved backend-mode persistence for workflow checkpoints, foreach-step instances, branch progress, and cleanup flows (including retries/resets/transitions), so stored data reliably round-trips. * Hardened backend-mode reads for workflow steps, task columns, project settings, and prompt overrides. * Made verification-cache reads/writes complete reliably, including command-specific cache behavior. * **Tests** * Added PostgreSQL integration/regression coverage for refinement/duplication, sync residue, and verification caching. * **Chores** * Bumped `@earendil-works/pi-ai` and `@earendil-works/pi-coding-agent` to `^0.80.10`. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c64c1014e2 |
test(FN-8146): speed up PG test harness with per-process schema template
Applying the full schema baseline on every fresh test database cost ~530ms per file and dominated PG gate wall-time under fork contention. Apply the schema once per worker process into a pid-keyed template database, then create each test DB via CREATE DATABASE ... TEMPLATE (fast server-side copy). Dead-pid templates from crashed/prior runs are swept before creating a new one; template copies are serialized since CREATE DATABASE ... TEMPLATE forbids concurrent access to the source. Removes the throwaway probe2 timing test. Fusion-Task-Id: FN-8146 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
5f70447a62 |
FN-8108: require resolution for triage duplicate tasks
Require explicit resolution for triage-detected duplicate tasks. - Add configurable prompt, keep, and delete handling for explicit duplicate markers. - Surface linked duplicate decisions in task details and scheduling settings. - Preserve task failure provenance and strengthen lifecycle recovery coverage. Files changed: .changeset/blocked-park-survives-graph-teardown.md | 7 + .changeset/failure-provenance-promoter-marker.md | 7 + .changeset/fn-8108-triage-duplicate-resolution.md | 7 + .changeset/veto-progressing-does-not-clear.md | 7 + docs/settings-reference.md | 2 + .../completed-promotion-failure-provenance.test.ts | 31 +++ .../core/src/__tests__/duplicate-intake.test.ts | 11 ++ .../src/completed-promotion-failure-provenance.ts | 38 +++- packages/core/src/duplicate-intake.ts | 29 +++ packages/core/src/index.gate.ts | 1 + packages/core/src/index.ts | 3 +- packages/core/src/settings-schema.ts | 1 + packages/core/src/types.ts | 6 + .../dashboard/app/components/TaskDetailModal.tsx | 38 +++- .../__tests__/TaskDetailModal.rendering.test.tsx | 26 +++ .../settings/sections/SchedulingSection.search.ts | 9 + .../settings/sections/SchedulingSection.tsx | 15 ++ .../__tests__/routes-tasks-near-duplicate.test.ts | 31 +++ .../src/routes/register-task-workflow-routes.ts | 19 ++ .../__tests__/executor-task-done-blocked.test.ts | 212 ++++++++++++++++++++- packages/engine/src/__tests__/merger-ai.test.ts | 56 +++++- .../__tests__/overseer-noop-finalize-veto.test.ts | 64 ++++++- .../explicit-duplicate-marker-sweep.test.ts | 19 +- packages/engine/src/__tests__/self-healing.test.ts | 53 ++++++ .../triage-explicit-duplicate-marker.test.ts | 22 ++- packages/engine/src/executor.ts | 30 +++ packages/engine/src/merger-ai.ts | 5 +- packages/engine/src/overseer-noop-finalize-veto.ts | 148 ++++++++++---- packages/engine/src/self-healing.ts | 29 ++- packages/engine/src/triage.ts | 58 +++--- packages/i18n/locales/en/app.json | 15 +- packages/i18n/src/resources.d.ts | 13 +- 32 files changed, 897 insertions(+), 115 deletions(-) Fusion-Task-Id: FN-8108 Fusion-Task-Lineage: 8e732bad-d418-426e-85e1-903a7f990fba Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
0753476c0a |
fix(engine): no-op finalize veto no longer cleared by mid-execution progressing — only accepted-completion evidence supersedes a failure park (#2263)
## What
FN-8141 follow-up 3. Tightens `deriveExecutorSignalMemory`
(packages/engine/src/overseer-noop-finalize-veto.ts) so a mid-execution
`progressing` overseer observation can no longer clear the executor
no-op-finalize veto.
## Why
The prior derivation took the **newest** executor `observe` entry and
cleared `incompleteWork` whenever it was anything but the canonical
failed reason. But the planner overseer emits a `progressing`
observation ("Task is actively executing in-progress work") the
**moment** a task re-enters execution — long before that execution
finishes. The defeating shape:
> task parks failed-incomplete → requeued → re-execution starts
(overseer observes `progressing`) → execution dies or reverts again
**without** a newer failed observation → newest observation is
`progressing` → `incompleteWork:false` → an empty no-op finalize is
**not** vetoed → the reverted branch launders into `done`.
`progressing` is not "completed green" — the veto's own contract says
the failure must be superseded by a green completion.
## Change
The executor stage in `planner-overseer.ts` emits only
`progressing`/`failed`/`stuck`/`blocked` — **no** green-completion
observation — so the timeline alone cannot distinguish progressing from
completed. Per the follow-up spec, the derivation now:
1. Scans the executor `observe` timeline for the newest
**failed-with-incomplete-work** observation.
2. Keeps `incompleteWork` TRUE unless a durable **clean-completion
task-log marker** is **strictly newer** than that failure park. Reuses
the shared `CLEAN_COMPLETION_MARKERS` set (now exported from
`@fusion/core`, single-sourced with
`evaluateCompletedPromotionFailureProvenance`) so it automatically
tracks sibling follow-up F2's removal of the promotion-output marker.
3. Fails safe on a malformed failure timestamp (stays vetoed).
4. `merger-ai.ts` threads `task.log` into the derivation.
All existing precedence rules are preserved: non-empty merges are never
vetoed; human-control deferral (user-paused / autoMerge:false) still
defers; a missing task fails open.
## Test evidence
- `pnpm --filter @fusion/engine exec vitest run
src/__tests__/overseer-noop-finalize-veto.test.ts
src/__tests__/merger-ai.test.ts` → **59 passed**. New/updated cases:
failed→progressing (no completion) ⇒ still vetoed (the regression this
fixes); progressing between two failed parks (FN-8141 timeline) ⇒
vetoed; clean-completion marker newer than failure ⇒ not vetoed; older
completion marker ⇒ still vetoed; no failure park ⇒ not vetoed; bounded
tail-scan preserved. Integration: empty lane with
failed-then-progressing timeline blocks the finalize; genuinely
re-executed green task finalizes to done.
- `pnpm --filter @fusion/core exec vitest run
src/__tests__/completed-promotion-failure-provenance.test.ts` → 9
passed.
- `pnpm --filter @fusion/engine exec tsc --noEmit` → clean. `pnpm
--filter @fusion/core exec tsc --noEmit` → clean.
- `pnpm verify:fast` → PASS (3 steps green).
🤖 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**
* Improved empty-merge finalization safeguards so an in-progress task
cannot incorrectly clear a previously detected incomplete-work failure.
* Finalization can now proceed when a newer clean-completion record
confirms successful completion.
* Added bounded task-history evaluation to ensure completion records are
interpreted safely and consistently.
* **Tests**
* Expanded coverage for progressing, failed, and clean-completion task
timelines.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Claude Opus <noreply@anthropic.com>
|
||
|
|
46866a5c5a |
fix(core): promoter recovery output no longer counts as clean-completion evidence in the failure-provenance guard (#2262)
## What FN-8141 follow-up 2. Removes `"Auto-recovered: task work was complete but stranded"` from `CLEAN_COMPLETION_MARKERS` in `packages/core/src/completed-promotion-failure-provenance.ts`. Clean-completion evidence is now **execution outcomes only**: `"Task marked done by agent"` (accepted explicit fn_task_done, also covers the PREMISE STALE skip-then-done flow) and `"All steps complete — implicit fn_task_done"` (implicit-completion success). ## Why That string is the PROMOTER'S OWN OUTPUT — self-healing's `recoverCompletedTasks` (executor.ts:4594) narrating "I promoted this task" — not evidence of a clean execution outcome. Any task whose durable log contains a promotion written by the pre-#2257 buggy sweep (the real FN-8141 row, or any pre-guard history) carried a permanent "clean" marker: the tail scan hit the promotion line before the older failure park and returned not-blocked, re-enabling the exact laundering the guard exists to stop. Audit confirmed no other genuine execution-outcome success markers are missing — the PREMISE STALE accepted `fn_task_done` writes the already-listed `"Task marked done by agent"` line (executor.ts:14939), and the honest-blocked exit (`BLOCKED: ...`) is correctly NOT counted. `grep` confirmed the removed string has only one other consumer: its writer at executor.ts:4594. A task already promoted to in-review/done is out of the promoters' todo/in-progress scan scope, so legitimately-recovered old tasks are not wedged (verified by test rather than assumed). ## Test evidence - Core `completed-promotion-failure-provenance.test.ts`: **11 passed** — added pre-fix-history shape (failure park → promoter recovery line → blocked), promoter-line-alone → blocked, and positive coverage of each remaining marker. - Engine `self-healing.test.ts`: **405 passed** — added promoter withholds on the pre-fix-history shape and emits the existing `task:reconcile-stranded-completed-no-action` (reason `failure-provenance`) event. - `pnpm --filter @fusion/engine exec tsc --noEmit`: clean. - `pnpm verify:fast`: PASS (3 steps green, no tests run). 🤖 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 failed tasks with prior failure history from being automatically promoted. - Ensured recovery messages cannot override authoritative failure records or be mistaken for successful completion. - Preserved the existing no-action behavior and audit event when promotion is blocked by failure provenance. - **Tests** - Added regression coverage for failed-task promotion and stranded-task recovery scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus <noreply@anthropic.com> |
||
|
|
f116d05c41 |
fix(engine): honest BLOCKED park survives pause-abort and workflow-graph teardown (#2264)
## What Follow-up 1 to the FN-8141 guard series (#2254–#2260). Makes the honest `fn_task_done(outcome="blocked")` park (`status:"failed"`, `error:"BLOCKED: <reason>"`, blockedBy → dependencies, added in #2256) **survive the graph-teardown machinery** that bounced FN-8141's failed park back to `todo`. ## Why In the original FN-8141 incident, the executor's parked-failed state did not stick: the pause-abort classifier and the workflow-graph failure handler either rehomed the task to `todo` (clearing `status`/`error`) or overwrote the distinctive `BLOCKED:` error with a generic "Workflow graph terminated with failure" string. #2256 added the blocked exit but nobody proved the park survives that bounce. Any path that clears/overwrites the marker re-opens the laundering hole, because self-healing (#2257/#2260) and dependency-gated scheduling key off exactly that `BLOCKED:` error plus the recorded `blockedBy` dependencies. `handleGraphFailure` now detects a live blocked park (`status === "failed" && error.startsWith("BLOCKED:")`) **before every other classifier** and honors it, following the existing non-graph honor-park precedent (executor `~12163`): - no requeue to `todo`, no engine-internal auto-continue, no `BLOCKED:` error overwrite; - clears the in-memory pause-abort marker so `recoverPausedAbortFailures` has nothing to chase; - **releases the worktree / `maxWorktrees` slot** (FN-6782 leaked-holder precedent — the graph `finally` does not delete `activeWorktrees`); - leaves `status`/`error`/`column`/`dependencies`/steps untouched. Unblocking still works: the operator requeue (`moveTask` in-progress→todo, `moves.ts ~628`) and `buildManualRetryResetPatch` clear the `BLOCKED:` error; the guard keys off the **live** error, so a cleared row is never re-wedged, and dependency-gated scheduling leaves the parked row untouched while `blockedBy` deps are unmet. ## Surfaces covered Pause-abort classifier (hard-cancel), engine-internal auto-continue, and the plain terminal graph-failure sink — all routed through `handleGraphFailure`, so a single top-of-method guard composes across them. ## Test evidence Extended `executor-task-done-blocked.test.ts` (drives `handleGraphFailure` against a live blocked park): - honors the park under a hard-cancel pause-abort bounce (no requeue / clear / auto-continue); - honors it under a plain terminal graph failure (sink never overwrites `BLOCKED:`); - releases the worktree/concurrency slot + clears the pause-abort marker; - NON-blocked failed park keeps existing behavior (guard scoped to `BLOCKED:`); - a cleared (unblocked) row is NOT re-honor-parked. ``` pnpm --filter @fusion/engine exec vitest run src/__tests__/executor-task-done-blocked.test.ts → 13 passed pnpm --filter @fusion/engine exec vitest run executor-paused-abort-todo-benign + executor-graph-requeue-gate → 53 passed pnpm --filter @fusion/engine exec tsc --noEmit → clean pnpm verify:fast → PASS (3 steps green) ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus <noreply@anthropic.com> |
||
|
|
bc7dfe4bbf |
FN-8178: fix task-card context menu autofocus dismissal
Prevent portaled task-card menus from closing when autofocus creates a scroll event. - Focus the first menu action with preventScroll while preserving keyboard access. - Cover all card menu entry points and intentional dismissal paths. - Document the interaction lifecycle fix and publish a patch changeset. Files changed: .changeset/fn-8178-context-menu-flash-dismiss.md | 7 +++ docs/dashboard-guide.md | 2 +- .../task-card-context-menu-flash-dismiss-layers.md | 35 +++++++++++ .../dashboard/app/components/TaskContextMenu.tsx | 9 ++- .../app/components/__tests__/TaskCard.test.tsx | 69 ++++++++++++++++++++++ 5 files changed, 120 insertions(+), 2 deletions(-) Fusion-Task-Id: FN-8178 Fusion-Task-Lineage: 2eb94ffd-e922-497d-8904-1aea8bf760b1 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
e72629c251 |
FN-8126: add per-task merger model controls
Enable Quick Add and task editing to select merger models and thinking levels. - Persist merger model and thinking overrides through task APIs, storage, and PostgreSQL migrations. - Add merger-lane selection controls to Quick Add and model settings interfaces. - Apply task merger settings to merger and PR fallback sessions, with regression coverage. - Document the merger lane and include a release changeset. Files changed: .changeset/fn-8126-quick-add-merger-lane.md | 7 ++ docs/dashboard-guide.md | 2 + docs/settings-reference.md | 7 +- .../core/src/__tests__/model-resolution.test.ts | 9 ++ packages/core/src/index.gate.ts | 1 + packages/core/src/index.ts | 1 + packages/core/src/model-resolution.ts | 20 ++++ .../core/src/postgres/migrations/0000_initial.sql | 3 + .../migrations/0017_task_merger_model_lane.sql | 4 + packages/core/src/postgres/schema-applier.ts | 14 ++- packages/core/src/postgres/schema/project.ts | 3 + packages/core/src/store.ts | 2 +- .../core/src/task-store/archive-lifecycle-2.ts | 6 ++ packages/core/src/task-store/persistence.ts | 6 ++ packages/core/src/task-store/remaining-ops-2.ts | 4 +- packages/core/src/task-store/remaining-ops-6.ts | 2 +- packages/core/src/task-store/serialization.ts | 6 ++ packages/core/src/task-store/task-creation.ts | 6 ++ packages/core/src/task-store/task-row-mappers.ts | 4 +- packages/core/src/task-store/task-update.ts | 6 ++ packages/core/src/types.ts | 18 ++++ packages/dashboard/app/api/tasks.ts | 13 +++ .../dashboard/app/components/InlineCreateCard.tsx | 33 ++++++- .../app/components/ModelSelectionModal.tsx | 29 ++++++ .../dashboard/app/components/ModelSelectorTab.tsx | 101 +++++++++++++++++++-- .../dashboard/app/components/QuickEntryBox.tsx | 44 +++++++-- .../__tests__/ModelSelectionModal.test.tsx | 20 ++++ .../components/__tests__/ModelSelectorTab.test.tsx | 37 +++++++- .../src/routes/register-task-workflow-routes.ts | 27 +++++- .../src/__tests__/agent-session-helpers.test.ts | 8 ++ packages/engine/src/agent-session-helpers.ts | 16 +++- packages/engine/src/merger-ai.ts | 14 +-- packages/engine/src/merger.ts | 35 ++++--- packages/engine/src/pr-response-run-ops.ts | 7 +- 34 files changed, 451 insertions(+), 64 deletions(-) Fusion-Task-Id: FN-8126 Fusion-Task-Lineage: 3fc81801-6d77-4e11-9cf0-3af37313930e Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
b747f51f8b |
FN-8185: use async persistence for reflection rework reads
Resolve workflow rework metrics from the persisted production run. - Resolve workflow selections to definition-backed run IDs - Prefer asynchronous step-instance reads with legacy-store compatibility - Cover PostgreSQL, fallback, and degraded reflection metrics Files changed: .../engine/src/__tests__/agent-reflection.test.ts | 51 +++++++++++++++++++--- packages/engine/src/agent-reflection.ts | 50 ++++++++++++++------- 2 files changed, 80 insertions(+), 21 deletions(-) Fusion-Task-Id: FN-8185 Fusion-Task-Lineage: 2554d5f1-62b7-47a6-bad0-c00a7d649a2d Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
30aaab209c |
FN-8170: suppress stale planning status badges
Hide stale planning badges from Todo and In Progress task surfaces. - Centralize the planning badge suppression predicate. - Apply it to board cards and desktop/mobile list views. - Cover suppressed and preserved status badge behavior. Files changed: packages/dashboard/app/components/ListView.tsx | 11 +++-- packages/dashboard/app/components/TaskCard.tsx | 16 +++++-- .../app/components/__tests__/ListView.test.tsx | 53 ++++++++++++++++++++++ .../app/components/__tests__/TaskCard.test.tsx | 40 ++++++++++++++++ .../utils/__tests__/taskStatusBadgeLabel.test.ts | 21 ++++++++- .../dashboard/app/utils/taskStatusBadgeLabel.ts | 14 ++++++ 6 files changed, 147 insertions(+), 8 deletions(-) Fusion-Task-Id: FN-8170 Fusion-Task-Lineage: e2a00154-8537-4eb3-aadb-45b42f13f15b Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
a136535f15 |
fix(engine): taint steps skipped after a bulk-completion refusal so they cannot auto-promote (#2260)
## What & why
**FN-8141 laundered a failed task into `done` with zero net changes and
no sign-off.** After the executor's
`bulk-step-completion-without-review` refusal fired (steps had no
APPROVE verdicts), the agent used the sanctioned skip affordance
(`fn_task_update status="skipped"`) on the remaining unreviewed steps.
Because every completion check counts `skipped` as complete, the task
then satisfied the exact condition the refusal was protecting, and
downstream **automatic** promotion (implicit `fn_task_done`,
self-healing `recoverStrandedCompletedTodoTasks`) moved it to in-review
— where the AI merger found an empty diff and finalized it as a no-op
`done`.
This PR restores the invariant: **steps skipped while a
bulk-step-completion refusal marker is active on the task are "tainted"
and cannot carry the task to review through any automatic path.** The
taint clears on an honest exit — an accepted `fn_task_done` (explicit or
non-tainted implicit) or an operator manual retry — so the legitimate
`PREMISE STALE` skip-then-done flow is unaffected.
## Design
- **Persisted marker**: new nullable `Task.bulkCompletionRefusalAt` (ISO
timestamp), stamped when the `bulk-step-completion-without-review`
refusal fires (explicit `fn_task_done` handler + implicit
`handleImplicitTaskDoneRefusal`). Survives requeue so a refusal on
attempt N taints attempt N+1's promotion. Full store plumbing (types,
descriptors, serialization, SQLite/PG schema + health self-heal).
- **Pure evaluator** `evaluateSkipBypassTaint(task)` in `@fusion/core`
(next to `evaluateNoCommitsNoOpFinalize`): `blocked` iff the marker is
set AND ≥1 step is `skipped`. Single rule every AUTO-promotion check
calls.
- **Clearing**: accepted explicit `fn_task_done`, accepted
implicit/retry completion (the success-reset `updateTask`s), and
`buildManualRetryResetPatch` (operator retry). A fresh lifecycle that
genuinely re-does the work leaves zero skipped steps, so it is never
blocked even if a marker lingers.
## Surface enumeration (every consumer of "all steps done/skipped" that
gates AUTO-promotion)
- **executor.ts**: `getCompletedTaskFinalizationDecision` (gated on the
`isTaskWorkComplete` branch only, never on an accepted `taskDone`);
`recoverCompletedTask` (shared chokepoint for unpause resume,
completed-task watchdog, orphan resume);
`evaluateImplicitCompletionRefusal` (both implicit-completion loops);
`isTaskAlreadyCompleteForNonContinuableSession`; graph merge-boundary
`getWorkflowMergeImplementationProofFailure`.
- **self-healing.ts**: `recoverCompletedTasks` (stuck in-progress) and
`recoverStrandedCompletedTodoTasks` (the exact FN-8141 promoter).
- **Verified-safe, left as-is**: per-step graph node projections
(executor ~6274/6298) and progress-render checks — they don't gate
whole-task auto-promotion.
## Test evidence
Scoped runs (all green):
```
CORE: pnpm --filter @fusion/core exec vitest run \
src/__tests__/skip-bypass-taint-guard.test.ts \
src/__tests__/skip-bypass-taint-persistence.test.ts \
src/__tests__/manual-retry-reset.test.ts
→ 17 passed
ENGINE: pnpm --filter @fusion/engine exec vitest run \
src/__tests__/executor-skip-bypass-taint.test.ts \
src/__tests__/self-healing.test.ts
→ 401 passed
```
Coverage: pure-evaluator (skip-before-refusal counts, skip-after-refusal
doesn't, taint-clearing, empty-marker/empty-steps edges); store
round-trip of the marker (set→read→clear); executor white-box (implicit
completion refused when tainted, allowed when clean or fully re-done,
graph merge-boundary reports missing proof, and the **explicit
`fn_task_done` PREMISE-STALE honest exit stays accepted**); self-healing
(FN-8141 sequence does not promote from either recovery path; a clean
legitimately-skipped task still promotes); manual-retry clears the
marker.
## Note on `pnpm verify:fast`
`verify:fast` currently fails at the workspace-artifact bootstrap on
**pre-existing** pi-SDK type errors in
`packages/engine/src/{auth-storage,pi,provider-registration}.ts` — the
FN-8145 upstream migration breakage (pi 0.80.x removed
`AuthStorage`/`ModelRegistry.create`). **None of those files are in this
diff.** `@fusion/core` builds clean (`packages/core build: Done`), and
`@fusion/engine` `tsc` reports **no errors in the files this PR
touches** (`executor.ts`, `self-healing.ts`); the only engine build
errors are the FN-8145 files. This base failure is the same condition
FN-8141 describes and is out of scope for this task.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus <noreply@anthropic.com>
|
||
|
|
29543a0aac |
FN-8157: add PostgreSQL workflow step-instance persistence
Persist workflow foreach step-instance state through async PostgreSQL store APIs. - Add async save, load, and stale-run pruning operations backed by Drizzle. - Route executor persistence, recovery, and integration projection through async APIs. - Cover PostgreSQL persistence and migrate foreach wiring coverage to the PG harness. - Quarantine unrelated flaky route and triage tests per the test ledger. Files changed: .../workflow-run-step-instances.pg.test.ts | 100 +++++++++++++++++++ packages/core/src/store.ts | 14 ++- packages/core/src/task-store/remaining-ops-6.ts | 109 ++++++++++++++++++++- .../dashboard/src/__tests__/routes-github.test.ts | 14 +-- .../src/routes/register-task-workflow-routes.ts | 18 ++-- packages/engine/src/__tests__/triage.test.ts | 6 +- .../src/__tests__/workflow-foreach-wiring.test.ts | 59 +++++------ packages/engine/src/executor.ts | 57 ++++++++--- packages/engine/src/triage.ts | 4 +- packages/engine/vitest.config.ts | 2 +- scripts/lib/test-quarantine.json | 7 +- 11 files changed, 315 insertions(+), 75 deletions(-) Fusion-Task-Id: FN-8157 Fusion-Task-Lineage: c359f0d3-9191-4d27-aaed-9912419c5c27 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
aa1e250dd3 |
fix(engine): overseer vetoes no-op merge finalize when the last executor signal was failed-with-incomplete-work (#2258)
## What & why FN-8141 (\"Update pi SDK … verify Kimi K3 end to end\") was **laundered into `done`** despite producing zero net changes. The executor reverted the impossible work 5 times; the planner overseer emitted `stage=executor signal=failed` (\"Executor stage parked failed with work incomplete\") **twice**, then an hour later — because the overseer is **stage-scoped and memoryless** — classified the same task `stage=merger signal=progressing` and let the AI merger's **empty no-op finalize** promote it to `done`. No reviewer ever saw it (skipped steps request no review; the merge-review pass reviews an empty diff). This restores the invariant: **a task whose most-recent executor signal is failed-with-incomplete-work, with no subsequent green completion, must not reach `done` via a zero-diff no-op merge finalize.** ## Change Two pure, unit-testable, never-throw functions (`packages/engine/src/overseer-noop-finalize-veto.ts`), following the FN-7514 `evaluateOverseerHumanControl` precedent (pure predicate + ids/outcomes-only audit metadata): - **`deriveExecutorSignalMemory`** — reconstructs the most-recent executor signal from the **durable `overseer:intervention` timeline the overseer already writes** (no new persisted column / migration; \"the existing oversight state storage the controller uses\"). A later green executor observation supersedes an earlier failure, which is how \"no subsequent execution completed green\" is derived. Keys on the newly-exported `EXECUTOR_FAILED_INCOMPLETE_REASON` constant (already load-bearing for FN-7577 feed dedup) as the single source of truth. - **`evaluateNoOpFinalizeExecutorVeto`** — the veto decision. Wired into the AI **empty-merge lane** (`merger-ai.ts`), composed with (and independent of) the FN-6461 no-commits guard: on veto it sets `error`, writes a durable log entry, emits `overseer:no-op-finalize-vetoed-failed-executor`, and moves the task back to `todo` with progress preserved — mirroring the FN-6461 blocked lane. The move-to-todo transition takes the task out of the merge lane, so the event isn't re-emitted every poll (equivalent to the `overseer:oversight-withheld-human-control` per-(taskId, reason) dedup). Independent of the sibling Task 2 merger-layer lineage guard: both can fire; **either alone stops FN-8141**. ## Surface enumeration - **Empty (zero-diff) no-op merge** — vetoed when memory is failed-incomplete. ✅ - **Non-empty (real squash landed) merge** — **never** vetoed (reviewers/merge review cover real diffs). ✅ - **failed-incomplete then later green execution** — memory superseded → no veto. ✅ - **No executor memory / store lacks the async reader** — fail open (no veto); FN-6461 + sibling guard remain the safety net. ✅ - **user-paused / autoMerge:false / approval-blocked** — defers to FN-7514 human-control; never fights those semantics. ✅ - **Timeline entry filtering** — only `stage=executor` + `action=observe` entries count as signals (retry/escalate messages ignored). ✅ ## Test evidence `pnpm --filter @fusion/engine exec vitest run src/__tests__/overseer-noop-finalize-veto.test.ts src/__tests__/merger-ai.test.ts --silent=passed-only --reporter=dot` ``` Test Files 2 passed (2) Tests 48 passed (48) ``` Covers: derivation (failed→veto, failed-then-green→no-veto, non-executor/non-observe ignored, empty→null); evaluator (veto, green, no-memory, non-empty never-vetoed, user-paused defer, autoMerge:false defer, missing-task fail-open); and an engine integration test driving an **FN-8141-shaped** empty merge through `runAiMerge` → asserts move-to-todo + `overseer:no-op-finalize-vetoed-failed-executor` audit event + main untouched, plus the later-green case finalizing done. `@fusion/core` builds clean (`pnpm --filter @fusion/core build`). **Note on `pnpm verify:fast`:** it currently fails to build `@fusion/engine`, but **only** in `auth-storage.ts` / `pi.ts` / `provider-registration.ts` — the pre-existing pi-SDK breakage that *is* this incident (pi 0.80.x removed `AuthStorage`/`ModelRuntime`/`ModelRegistry`; tracked as FN-8145). Verified identical errors with my changes stashed; **my diff touches none of those files and adds zero new type errors** (tsc reports all program errors before failing — none were in my files). 🤖 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 zero-change tasks from being incorrectly finalized when the latest executor attempt failed with unfinished work. - Preserved task progress and returned affected tasks to **Todo** for continued processing. - Allowed finalization to proceed after a subsequent successful executor result. - Maintained existing human-control and non-empty merge behavior. - Added audit visibility for blocked finalization events. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus <noreply@anthropic.com> |
||
|
|
50179ed5eb |
FN-8167: suppress failed UI during automatic recovery
Prevent transient automatic-retry tasks from appearing as terminal failures. - Centralize pending-recovery and manual-retry presentation rules. - Suppress failed styling, failure alerts, and Retry actions across list, card, and detail views. - Cover recovery timing and desktop/mobile task surfaces with regression tests. Files changed: .changeset/fn-8167-transient-retry-affordance.md | 7 ++ packages/dashboard/app/components/ListView.tsx | 16 ++--- packages/dashboard/app/components/TaskCard.tsx | 13 ++-- .../dashboard/app/components/TaskDetailModal.tsx | 13 ++-- .../app/components/__tests__/ListView.test.tsx | 38 +++++++++++ .../app/components/__tests__/TaskCard.test.tsx | 22 +++++++ .../__tests__/TaskDetailModal.rendering.test.tsx | 26 ++++++++ .../app/utils/__tests__/taskRecovery.test.ts | 77 ++++++++++++++++++++++ packages/dashboard/app/utils/taskRecovery.ts | 32 +++++++++ 9 files changed, 215 insertions(+), 29 deletions(-) Fusion-Task-Id: FN-8167 Fusion-Task-Lineage: 60d599e2-2e0e-46e7-ad16-cc6a836b5ac7 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
f079245acc |
fix(engine): defensive getAuth guard on session routing seam + realign pi tests to ModelRuntime seam (#2261)
## What / Why **Reworked after FN-8179 (`fd43a57a4`) landed on `main`.** FN-8179 did most of what the original PR #2261 did — pinned `@earendil-works/pi-ai` / `pi-coding-agent` to `^0.80.10` everywhere, added the `createSessionOptions` `NonNullable` typing in `pi.ts`, and regenerated `pnpm-lock.yaml`. This PR was rebased onto current `origin/main` and reduced to **only the unique residual not covered by FN-8179**. ### Residual change 1 — defensive `getAuth` guard The FN-8142 migration rewrote `attachSessionRoutingHeaders` from the `ModelRegistry.getApiKeyAndHeaders` seam to `ModelRuntime.getAuth`, but dropped the pre-migration defensive invariant: a missing resolution method must **not** break session creation. On `main` the function now calls `modelRuntime.getAuth.bind(...)` unguarded, which throws if `getAuth` is ever absent. This restores the guard: no-op (warn) when `getAuth` is missing, so a future pi rename degrades to un-tagged requests instead of a hard failure at every agent start. ### Residual change 2 — test realignment (needed against current main) FN-8179 aligned the SDK but did **not** update the two `#1675` routing-header test suites, which still asserted the old `getApiKeyAndHeaders` seam. **Verified RED on current `main` before touching them:** - `pi-create-fn-agent.test.ts` — **60 / 104 failing** (mock had no `ModelRuntime` export; `createAgentSession` now receives `modelRuntime`). - `pi-session-routing-headers.test.ts` — **4 / 5 failing** (`attachSessionRoutingHeaders` signature is `getAuth`, not `getApiKeyAndHeaders`). Both are realigned to the `ModelRuntime.getAuth` seam (the mock gains the `ModelRuntime` export) → **109 / 109 green**. Assertions were strengthened to the new behavior, not weakened; the #1675 precedence invariant (taskId > pi session id > no-wrap), header merge, apiKey/provider-header passthrough, failed/undefined passthrough, and absent-method no-op are all still asserted. ## Surface enumeration - **Routing-header seam**: both the `createFnAgent` path and the `attachSessionRoutingHeaders` unit (taskId / pi-session-id / no-id precedence; header merge; apiKey + provider-header passthrough; failed/undefined resolution; absent-method no-op). - **Both mock forms** in `pi-create-fn-agent.test.ts`: the top-level `vi.mock` and all three `vi.doMock` skill-selection blocks now export `ModelRuntime`. ## Test evidence - `pnpm --filter @fusion/engine exec tsc --noEmit` → **exit 0**. - `pnpm --filter @fusion/engine exec vitest run` on both suites → **109/109 pass** (was 64 failing on main). - `pnpm verify:fast` → **PASS** (typecheck + build scoped to changed packages + CLI build + boot smoke `GET /api/health 200`; no tests run). Do not merge without CI. No release performed. 🤖 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** * Improved session creation reliability when authentication support is unavailable. * Preserved existing authentication details while adding session-routing headers when supported. * Prevented session creation from failing when authentication information cannot be resolved. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus <noreply@anthropic.com> |
||
|
|
ced0e84f5d |
FN-8184: unify heartbeat multiplier timing
Keep scheduler repair and reports health aligned with the effective heartbeat cadence. - Apply heartbeatMultiplier once through shared interval calculations. - Align scheduler repair and reports-health stale thresholds with scaled cadence. - Add multiplier regression coverage and document the effective timing rules. Files changed: .../fn-8184-heartbeat-multiplier-consistency.md | 7 ++ docs/agents.md | 8 +- .../src/__tests__/heartbeat-executor.test.ts | 43 +++++++++ .../src/__tests__/heartbeat-scheduler.test.ts | 46 ++++++++++ packages/engine/src/agent-heartbeat.ts | 101 ++++++++++++++++----- 5 files changed, 176 insertions(+), 29 deletions(-) Fusion-Task-Id: FN-8184 Fusion-Task-Lineage: 05b79c5e-444a-42c3-9073-9c8c05df5def Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
95dbf9558d |
FN-8150: expand mobile import issue lists
Allow mobile issue lists to fill the available import-sheet height. - Make the mobile import pane a constrained flex column with internal scrolling. - Remove the 50vh list cap while preserving pagination and action access. - Cover the responsive list sizing rules with a regression test. Files changed: .../dashboard/app/components/GitHubImportModal.css | 18 +++++++++++++++++- .../components/__tests__/GitHubImportModal.test.tsx | 17 +++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) Fusion-Task-Id: FN-8150 Fusion-Task-Lineage: 92841921-7769-4304-b1f3-8c91aa18efb6 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
e10ba2826f |
FN-8149: consolidate task-card move actions in three-dot menu
Consolidate task-card movement controls into the shared three-dot action menu. - Remove standalone Send back and Move dropdown controls and their styles. - Preserve all in-review move targets, including Triage and Done (no merge), in the action menu. - Update task-card desktop and mobile coverage for the consolidated menu. Files changed: packages/dashboard/app/components/TaskCard.css | 63 +-------- packages/dashboard/app/components/TaskCard.tsx | 150 +++------------------ .../__tests__/TaskCard.badge-wrap.test.tsx | 39 ++---- .../app/components/__tests__/TaskCard.test.tsx | 134 +++++------------- .../app/components/__tests__/board-mobile.test.tsx | 6 +- 5 files changed, 69 insertions(+), 323 deletions(-) Fusion-Task-Id: FN-8149 Fusion-Task-Lineage: 650e20f6-c660-4c29-aa65-eb156bed7a0e Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
aaa95305cb |
FN-8148: fix Respecify workflow replanning
Make Respecify reliably return tasks to their workflow's planning lane. - Resolve task-specific planner lanes with recovery rehoming for custom workflows - Return the persisted needs-replan task for in-place replans and cover legacy triage - Hide unsupported Respecify actions for archived tasks Files changed: .changeset/fn-8148-respecify-fix.md | 7 ++ .../dashboard/app/components/TaskContextMenu.tsx | 10 +- .../components/__tests__/TaskContextMenu.test.tsx | 6 +- .../dashboard/src/__tests__/routes-github.test.ts | 103 ++++++++++++++++++++- .../src/routes/register-task-workflow-routes.ts | 66 ++++++------- 5 files changed, 152 insertions(+), 40 deletions(-) Fusion-Task-Id: FN-8148 Fusion-Task-Lineage: 7184bd58-e841-4bb1-a7fa-c1c336d6270a Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
26cb0cc2e1 |
FN-8180: add Kimi K3 catalog and pricing support
Expose Kimi K3 throughout the native pi catalog and token-cost surfaces. - Add K3 pricing and normalized lookup coverage for Dashboard cost calculations. - Verify native K3 registry, API model route, and repeat-stop behavior end to end. - Add a minor release changeset for Kimi K3 model selection support. Files changed: .changeset/fn-8180-pi-sdk-kimi-k3.md | 7 +++ packages/core/src/__tests__/model-pricing.test.ts | 7 ++- packages/core/src/model-pricing.ts | 17 +++++- ...ister-model-routes-kimi-k3-supplemental.test.ts | 70 ++++++++++++++++++++++ .../pi-prompt-session-and-check-recursion.test.ts | 15 +++++ .../src/__tests__/provider-registration.test.ts | 17 ++++++ 6 files changed, 130 insertions(+), 3 deletions(-) Fusion-Task-Id: FN-8180 Fusion-Task-Lineage: 07598d73-c866-4329-b5cf-3aebc1c0a180 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
136958fc60 |
fix(engine): stranded-completed promoters withhold tasks whose last execution ended in a failure park (#2257)
## What & why
FN-8141 laundered a failed task into `done`. The executor correctly
parked the task `failed` ("task parked failed during no-fn_task_done
retry" / "fn_task_done refusal retry budget exhausted"), the pause-abort
machinery bounced it to `todo`, and ~12 minutes later
`recoverStrandedCompletedTodoTasks` promoted it to `in-review` because
every step was done/skipped — overriding the honest failure park. From
there the AI merger found an empty diff and finalized it as a no-op
`done`, with no reviewer ever seeing it.
Existing exclusions (`task.error`,
`evaluateNoCommitsNoOpFinalize().blocked`, active statuses, refreshing
review state) all missed it because the failure provenance lived **only
in the durable task log** by the time the promoter ran — status/error
had been cleared by the pause-abort bounce.
This PR restores the invariant: **a stranded-completed promoter must not
promote a task whose most recent execution lifecycle ended in a
failure/refusal park.**
## Change
- New pure, unit-testable evaluator
`evaluateCompletedPromotionFailureProvenance(task)` in `@fusion/core`
(next to `no-commits-finalize-guard.ts`). It scans the task-log **tail**
(bounded to 250 entries) and lets the **most-recent execution-outcome
marker** decide: a failure/refusal park → `{ blocked: true, reason:
"failure-provenance" }`; a fresh clean completion (`Task marked done by
agent` / `All steps complete — implicit fn_task_done`) that appears more
recently supersedes an earlier park; zero failure markers → not blocked.
Recency is by construction, so a failure that predates a newer clean
execution is never reached.
- Both self-healing sweeps (`recoverCompletedTasks` stuck-in-progress
**and** `recoverStrandedCompletedTodoTasks` stranded-todo) fetch the
full task for candidates that already cleared the cheap slim filters
(slim listings strip `log`) and skip when blocked, emitting a
**deduped** `task:reconcile-stranded-completed-no-action` run-audit
event (ids/outcomes-only: `taskId`, `reason`, `sweep`, `marker?`).
- Defense-in-depth: the shared executor `recoverCompletedTask`
chokepoint — which the sweeps AND the executor's own
unpause/`resumeOrphaned` fast-paths all funnel through — also refuses a
provenance-blocked promotion, so no route can launder a failed park.
**Escape hatch (documented in FNXC comments):** an operator
retrying/moving the task starts a fresh execution whose clean-completion
marker supersedes the failure park, clearing the block with no code
change.
## Surface enumeration
- `recoverCompletedTasks` (stuck-in-progress sweep, self-healing.ts) —
guarded + audited.
- `recoverStrandedCompletedTodoTasks` (stranded-todo sweep,
self-healing.ts) — guarded + audited. FN-8141 shows both columns can
launder.
- `recoverCompletedTask` executor callback (the route both sweeps +
unpause + `resumeOrphaned` share) — verified it did **not** check
log-based provenance; added the guard there as the final chokepoint.
## Test evidence
Pure-evaluator unit tests (`@fusion/core`) — marker detection,
most-recent-outcome recency, supersede-by-clean-completion,
empty/missing log, tail-scan bound:
```
pnpm --filter @fusion/core exec vitest run src/__tests__/completed-promotion-failure-provenance.test.ts
Test Files 1 passed (1) Tests 9 passed (9)
```
Self-healing integration tests (`@fusion/engine`) — FN-8141-shaped todo
(3 done + 2 skipped + refusal-exhaust/park marker) is NOT promoted and
emits the no-action event exactly once (deduped across a second cycle);
same task after a fresh clean execution IS promoted; stuck-in-progress
variant covered:
```
pnpm --filter @fusion/engine exec vitest run src/__tests__/self-healing.test.ts -t "recoverCompletedTasks|recoverStrandedCompletedTodoTasks|FN-8141"
Test Files 1 passed (1) Tests 14 passed | 382 skipped (396)
```
`@fusion/core` builds clean. My engine changes add **zero** new type
errors (verified: all 13 engine build errors are the pre-existing pi-SDK
cluster in `auth-storage.ts`/`pi.ts`/`provider-registration.ts`, none in
`self-healing.ts`/`run-audit.ts`/`executor.ts`/the new file).
## Known environmental blocker
`pnpm verify:fast` cannot go green on this branch: the `@fusion/engine`
build is **already broken at baseline** (confirmed by stashing all my
changes) by the pi 0.80.x SDK migration errors
(`ModelRegistry`/`AuthStorage`/`ModelRuntime`) — the exact FN-8145
upstream breakage described in the FN-8141 incident. That is out of
scope for this task and independent of this diff. Likewise, the 22
pre-existing
`restart.integration.test.ts`/`executor-fast-mode-workflows.test.ts`
failures are identical with and without my changes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus <noreply@anthropic.com>
|
||
|
|
1c4fdb7b59 |
fix(engine): require already-landed proof before finalizing an empty AI merge as done (#2259)
## What & why Task FN-8141 laundered a failed task into `done`: its branch had no net changes vs `main` **only because the executor reverted its own work five times**, and the AI empty-merge lane took the "empty means already-landed or nothing-to-do → finalize as no-op done" path, stamping `mergeConfirmed: true` with no reviewer or operator sign-off. This restores the invariant: **a commit-expected task that reaches the empty AI-merge outcome must not finalize `done` without positive evidence the work already landed.** `packages/engine/src/merger-ai.ts` empty-outcome lane now, for a commit-expected task (`noCommitsExpected !== true`), requires one of: 1. Durable recorded landing on the task (`mergeDetails.mergeConfirmed`/`commitSha`). 2. A prior AI no-op finalization proof pair in the task log (`hasPriorAiNoOpFinalizationProof`, FN-7261 shape). 3. The branch tip is an **ancestor of the integration branch** (fast-forwarded / zero-ahead / already-integrated). 4. The already-on-main classifier (`detectAlreadyLandedOnMain`) finds a distinct landing commit via a **strong** strategy (`trailer`/`ancestry`/`patch-id`). The classifier's weak `tree-equal`/`no-diff` strategies are **deliberately rejected**: a branch that committed work then reverted it back to base has a tree equal to `main` (main never advanced), which is exactly the FN-8141 shape and would false-positive. Absent proof, the task gets `task.error` set, emits run-audit `task:empty-merge-finalize-blocked-no-landed-proof` (ids/counts/outcomes-only), and is moved back to `todo` with progress preserved — mirroring the existing FN-6461 blocked lane. `noCommitsExpected === true` tasks are untouched (hardened separately in the sibling Task 1). The non-empty landed path, group/PR routing, and push-after-merge behavior are unchanged. ## Surface enumeration - **Single-repo empty-outcome finalize (primary lane)** — guarded in `runAiMerge`. - **Workspace/multi-repo caller** — `landWorkspaceTask`'s all-empty finalize is a second route. Already-landed sub-repos are proven up front by `findProvenLandedCommit` and marked `status:"landed"`; when `landedCount === 0` the guard re-checks each empty sub-repo's branch and blocks the FN-8141 reverted shape (tip not an ancestor / branch vanished) identically. (Note: the genuinely-integrated all-empty workspace case already throws `missing-merge-confirmation` on `mergeConfirmed:false`, so it never reached `done`; that pre-existing path is left intact.) - **Re-promotion ping-pong** — the blocked path sets `task.error`, and `recoverStrandedCompletedTodoTasks` excludes any task with `task.error`, so the promoter cannot re-promote the unchanged blocked task. Regression-tested. ## Test evidence Scoped tests (all green): ``` vitest run merger-ai.test.ts workspace-merger.test.ts → 46 passed vitest run self-healing.test.ts -t recoverStrandedCompletedTodoTasks → 4 passed vitest run merger.test.ts merger-finalize-unproven.real-git → 20 passed vitest run self-healing-workspace + workspace-merger-lease + workspace-merger-deps-resilient → 26 passed ``` New tests: - merger-ai.test.ts: commit-expected empty (reverted) → blocked to todo + error + audit event, NOT done; empty + prior no-op proof → still no-op done; empty + branch-ancestor-of-main → still no-op done; noCommitsExpected empty → unchanged done path. - workspace-merger.test.ts: all-empty (reverted) workspace → blocked to todo + error, not done / not `task:merged`. - self-healing.test.ts: a task blocked by this guard (all steps done/skipped, `task.error` set) is NOT re-promoted by `recoverStrandedCompletedTodoTasks`. **`pnpm verify:fast` is red on this branch due to the pre-existing pi SDK breakage** (`auth-storage.ts`/`pi.ts`/`provider-registration.ts` — the FN-8142/FN-8145 `AuthStorage`/`ModelRegistry` removal that is the root of the FN-8141 incident). Verified those identical build errors reproduce with my changes stashed; this PR adds **zero** new type errors (no build error is in `merger-ai.ts` or `run-audit.ts`). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus <noreply@anthropic.com> |
||
|
|
19eb179473 |
fix(core): block empty-diff finalize of tasks with skipped steps — generalized FN-6461 guard (#2254)
## 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> |
||
|
|
9a37415887 |
fix(engine): add honest blocked exit to fn_task_done so impossible tasks park failed instead of laundering to done (#2256)
## What & why
FN-8141 ("Update pi SDK to latest and verify Kimi K3 end to end") was
impossible as specced — pi 0.80.x removed `AuthStorage`/`ModelRegistry`
APIs, so every SDK bump broke the build. The executor correctly reverted
its work and filed follow-up FN-8145 — but had **no sanctioned way to
end the task in a blocked state**. `fn_task_done` only expressed
success: the bulk-completion gate refused it, the requeue budget re-ran
the doomed task 5 times, and the only remaining affordance (mark every
step `skipped`, then complete) made `isTaskComplete()` return true.
Self-healing then promoted the "complete" todo to in-review and the AI
merger finalized the empty diff as `done`. **The honest path must be
cheaper than the laundering path.**
This adds a first-class **blocked** outcome to the executor's
`fn_task_done` tool.
## Change
- `fn_task_done` gains `outcome: "completed" | "blocked"` (default
`"completed"`), optional `blockedBy: string[]`, and `reason` (required
when blocked).
- `outcome="blocked"` runs **before** every completion gate (completion
blocker, verdict providers, worktree invariants, bulk-completion
refusal) — blocked is not a completion claim, so none of those gates
apply.
- Parks the task `failed` with `error = "BLOCKED: <reason>"`, following
the FN-7863 `EXECUTION_DISPATCH_LOOP_EXHAUSTED` park convention: **steps
keep their true statuses** (no auto-done, no auto-skip), worktree/branch
preserved. It does **not** call `onDone()`, so the executor's existing
`status === "failed"` post-loop branch honors the park instead of
handing off to review.
- `blockedBy` is recorded as real `task.dependencies` edges (unioned
with existing) so the task requeues behind the blocker.
- Emits run-audit `task:execution-blocked-parked` with ids/outcomes-only
metadata (`taskId`, `blockedBy` ids, `hasReason` boolean — **never** the
reason prose).
- Executor + core prompt guidance and the
`bulk-step-completion-without-review` refusal message now name the
blocked exit as **the** correct action when work cannot proceed,
replacing skip-and-done. `PREMISE STALE:` skip guidance is preserved for
genuinely-stale premises.
## Surface enumeration
- **fn_task_done tool schema + handler**
(`packages/engine/src/executor.ts`): blocked branch added at the top of
`execute`, before all gates.
- **Refusal/requeue machinery**: `formatTaskDoneRefusal` for
`bulk-step-completion-without-review` now points at the blocked exit;
the requeue-budget path is untouched (blocked never enters it).
- **Executor prompt text**: turn-ending rules, the "Cannot proceed"
section, the preflight/stale-premise escape hatch (now explicitly
distinguishes stale-premise skip from blocked).
- **Core prompt mirror** (`packages/core/src/agent-prompts.ts`): same
turn-ending + cannot-proceed guidance.
- **Tool reference doc**
(`packages/cli/skill/fusion/references/engine-tools.md`): `fn_task_done`
params updated. (grep for `fn_task_done` confirmed the only executable
tool schema is in executor.ts; CLI/pi surfaces re-export it, no separate
schema copy.)
- **Self-healing**: verified a blocked-parked row is NOT auto-recovered
by `recoverStrandedCompletedTodoTasks` — its steps are not all
done/skipped and `task.error` is set (both are hard filters in the
sweep).
- **Run Audit inventory** (`AGENTS.md`): documented the new event.
## Test evidence
New `packages/engine/src/__tests__/executor-task-done-blocked.test.ts`
(8 tests) asserts the invariant across surfaces:
```
pnpm --filter @fusion/engine exec vitest run \
src/__tests__/executor-task-done-blocked.test.ts \
src/__tests__/executor-task-done-invariant.test.ts \
src/__tests__/gating-classifications.test.ts \
src/__tests__/reliability-interactions/execute-requeue-loop-guard.test.ts --reporter=dot
→ Test Files 3 passed | Tests 138 passed (0 failed)
```
Coverage: blocked parks failed with `BLOCKED:` error and does **not**
trip the bulk-completion refusal or requeue to todo; `blockedBy` unioned
into `dependencies`; `task:execution-blocked-parked` emitted with
metadata that excludes the reason prose; steps left untouched; empty
`reason` rejected without parking; `completed` outcome unchanged (still
marks steps done, no blocked audit); and
`recoverStrandedCompletedTodoTasks` never promotes a blocked-parked row.
### Note on `pnpm verify:fast`
`verify:fast` currently fails at the workspace build step due to
**pre-existing** type errors in `packages/engine/src/auth-storage.ts`,
`pi.ts`, and `provider-registration.ts` — the exact FN-8142 pi SDK API
break that FN-8145 will fix. These are present on the base branch and
untouched by this PR. Verified instead that this change introduces
**zero** new type errors (`tsc` diff before/after, engine and core both
clean) and that all scoped tests are green.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus <noreply@anthropic.com>
|
||
|
|
779cd2e030 |
FN-8175: preserve mobile session switcher title layout contract
Preserve the ChatView mobile session switcher styling contract for pinned session titles. - Assert full-width inline-flex title layout and indicator alignment - Retain wrapping and line-height coverage for long mobile session names Files changed: packages/dashboard/app/components/__tests__/ChatView.core-contracts.test.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) Fusion-Task-Id: FN-8175 Fusion-Task-Lineage: cbb349c8-f53d-4a88-ab44-32b1b0f2cb2e Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
fd43a57a41 |
FN-8179: align pi SDK versions with ModelRuntime API
Align workspace pi SDK dependencies with the ModelRuntime API required by the engine. - Pin pi AI and coding-agent packages to 0.80.10 across workspace consumers. - Keep session option typing compatible with the updated SDK contract. - Add a patch changeset and regenerate the dependency lockfile. Files changed: .changeset/fn-8179-pi-sdk-align.md | 7 + packages/cli/package.json | 4 +- packages/core/package.json | 2 +- packages/dashboard/package.json | 2 +- packages/engine/package.json | 4 +- packages/engine/src/pi.ts | 8 +- packages/pi-claude-cli/package.json | 8 +- .../src/thinking-config.ts | 9 +- pnpm-lock.yaml | 947 +++++++++++---------- pnpm-workspace.yaml | 5 + 10 files changed, 520 insertions(+), 476 deletions(-) Fusion-Task-Id: FN-8179 Fusion-Task-Lineage: aef45c2e-f353-4014-93de-44be91f43293 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
b687cc994e |
FN-8174: preserve live triage planning sessions
Keep active planning sessions protected from stale recovery while reclaiming genuinely hung triage work. - Retain stale processing entries that still have a live, non-aborted triage session. - Continue evicting no-session and stuck-aborted tasks so recovery can proceed. - Add triage and self-healing regression coverage, architecture guidance, and a patch changeset. Files changed: .changeset/fn-8174-planning-premature-todo.md | 7 ++ docs/architecture.md | 1 + packages/engine/src/__tests__/self-healing.test.ts | 102 +++++++++++++++++++++ packages/engine/src/__tests__/triage.test.ts | 37 +++++++- packages/engine/src/triage.ts | 48 +++++----- 5 files changed, 168 insertions(+), 27 deletions(-) Fusion-Task-Id: FN-8174 Fusion-Task-Lineage: f6811d72-95b4-4b5f-a71f-212f50e3ecdd Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
eab9977a42 |
FN-8173: consolidate chat session actions into overflow menu
Consolidate each chat session row's actions behind a shared three-dot menu. - Replace inline pin, rename, and delete buttons with an accessible overflow trigger - Preserve context-menu actions, pin-limit feedback, and desktop/mobile title clearance - Update chat session interaction, layout, and mobile coverage Files changed: packages/dashboard/app/components/ChatView.css | 30 +++----- packages/dashboard/app/components/ChatView.tsx | 66 +++++++---------- .../__tests__/ChatView.core-contracts.test.tsx | 83 ++++++++++++++-------- .../__tests__/ChatView.core-interactions.test.tsx | 12 ++-- .../components/__tests__/ChatView.mobile.test.tsx | 22 +++--- 5 files changed, 107 insertions(+), 106 deletions(-) Fusion-Task-Id: FN-8173 Fusion-Task-Lineage: 4fee30f2-b8af-470b-bedd-9691680b78fb Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
c449379d00 |
FN-8172: persist import translations across restarts
Persist GitHub and GitLab import translation caches across application restarts. - Normalize cache ownership scope for reads, writes, pruning, and PostgreSQL RLS - Add forward migration 0016 to repair existing cache table partitioning - Cover durable cache reuse and migration behavior with PostgreSQL and service tests Files changed: .changeset/github-translation-cache-persistence.md | 7 ++ docs/settings-reference.md | 2 +- .../postgres/import-translation-cache.pg.test.ts | 105 +++++++++++++++++++++ .../src/__tests__/postgres/schema-applier.test.ts | 84 +++++++++++++++-- .../migrations/0010_import_translation_cache.sql | 6 +- .../0016_import_translation_cache_scope_fix.sql | 50 ++++++++++ packages/core/src/postgres/schema-applier.ts | 29 +++++- packages/core/src/postgres/schema/project.ts | 8 +- packages/core/src/task-store/remaining-ops-8.ts | 21 +++-- .../src/__tests__/import-translate-service.test.ts | 32 ++++++- packages/dashboard/src/import-translate-service.ts | Bin 10392 -> 11109 bytes 11 files changed, 323 insertions(+), 21 deletions(-) Fusion-Task-Id: FN-8172 Fusion-Task-Lineage: b3d18f58-dc0b-47e4-a1bf-acb8b2360869 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
25df9bf4fd |
FN-8171: expand active task thinking by default
Show Activity Live reasoning immediately for active and review-stage tasks. - Default thinking blocks open for in-progress and in-review tasks. - Preserve collapsed, user-toggleable reasoning for all other task columns. - Document behavior and cover default state and user collapse interactions. Files changed: .changeset/fn-8171-thinking-default-open.md | 7 ++++ docs/dashboard-guide.md | 2 +- packages/dashboard/app/components/TaskChatTab.tsx | 20 +++++++--- .../app/components/__tests__/TaskChatTab.test.tsx | 43 ++++++++++++++++++++-- 4 files changed, 63 insertions(+), 9 deletions(-) Fusion-Task-Id: FN-8171 Fusion-Task-Lineage: 705d6ac8-0c43-47d3-84df-57e9ec55a3b5 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
5006e5543c |
FN-8169: group workflow fallback lanes with primary lanes
Keep fallback model lanes adjacent to their primary lanes throughout Settings. - Interleave planning, execution, and validator fallback lanes after their respective primary lanes. - Classify executor fallback settings in the Models group so the row remains visible. - Add ordering coverage for project and workflow Settings surfaces. Files changed: .changeset/fn-8169-group-fallback-lanes.md | 7 ++++ .../app/__tests__/settings-sections.test.tsx | 47 ++++++++++++++++++++++ .../app/components/WorkflowSettingsPanel.tsx | 31 +++++++------- .../__tests__/WorkflowSettingsPanel.test.tsx | 40 ++++++++++++++++++ .../settings/sections/ProjectModelsSection.tsx | 31 +++++++------- .../app/components/workflow-setting-display.ts | 12 ++++++ 6 files changed, 140 insertions(+), 28 deletions(-) Fusion-Task-Id: FN-8169 Fusion-Task-Lineage: 89402b95-1f42-46a7-8ad6-5182dc21f172 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
f4903d3db0 |
FN-8168: dismiss mobile More sheet on Back
Make the mobile More sheet participate in navigation history so Back dismisses it before changing views. - Register the open More sheet as a navigation modal and remove it on every close path - Cover browser, native, gesture, keyboard, action, and provider-less dismissal flows - Document mobile More-sheet Back behavior Files changed: docs/dashboard-guide.md | 2 + packages/dashboard/app/components/MobileNavBar.tsx | 48 ++++-- .../__tests__/MobileNavBar.swipe-back.test.tsx | 190 +++++++++++++++++++++ 3 files changed, 228 insertions(+), 12 deletions(-) Fusion-Task-Id: FN-8168 Fusion-Task-Lineage: 1c5652db-5f27-4671-b4b7-676753ca4cd0 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
c9aa3b465c |
FN-8166: fix mobile task-detail right padding
Remove the residual mobile Feed right inset so task details use balanced body padding. - Let the task-detail body provide the mobile right inset. - Retain first-row clearance for overlay controls. - Cover mobile Feed padding and attached tab behavior with regression tests. - Add a patch changeset for the dashboard fix. Files changed: .../fn-8166-task-detail-mobile-right-padding.md | 7 +++ .../dashboard/app/components/TaskDetailModal.css | 8 +-- .../TaskDetailModal.attachments-and-tabs.test.tsx | 2 +- ...etailModal.responsive-and-dependencies.test.tsx | 63 +++++++++++++++++++++- 4 files changed, 74 insertions(+), 6 deletions(-) Fusion-Task-Id: FN-8166 Fusion-Task-Lineage: ae58ae8b-4659-429f-8939-1d7e1a82d34c Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
76ec9334af |
FN-8164: enlarge mobile Quick Entry action icons
Make icon-forward Quick Entry mobile controls proportionate while preserving touch targets. - Increase only primary mobile action glyphs using spacing tokens - Compact mobile action group gaps without changing desktop sizing - Cover the mobile-only sizing contract and add a patch changeset Files changed: .changeset/fn-8164-quick-add-mobile-icon-sizing.md | 7 +++ .../quick-entry-action-row-height-parity.test.tsx | 59 ++++++++++++++++++++-- .../dashboard/app/components/QuickEntryBox.css | 18 +++++++ 3 files changed, 81 insertions(+), 3 deletions(-) Fusion-Task-Id: FN-8164 Fusion-Task-Lineage: 030688cd-880d-448c-a2ef-d6e967dab169 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
07e1ceb860 |
FN-8151: add Cobalt, Clay, and Moss themes
Add three synchronized color themes across dashboard and desktop surfaces. - Register Cobalt, Clay, and Moss theme IDs, token palettes, and light/dark swatches. - Keep dashboard and desktop bootstrap validators aligned with selector metadata. - Document and test the cross-surface theme registration invariant. Files changed: .changeset/fn-8151-new-themes.md | 7 + docs/dashboard-guide.md | 3 +- packages/core/src/types/execution-and-ui.ts | 4 + .../app/__tests__/new-color-themes.test.ts | 116 ++++++++++++ .../dashboard/app/components/ThemeSelector.css | 42 +++++ packages/dashboard/app/components/themeOptions.ts | 3 + packages/dashboard/app/index.html | 2 +- packages/dashboard/app/public/theme-data.css | 202 +++++++++++++++++++++ packages/desktop/src/renderer/index.html | 3 + 9 files changed, 380 insertions(+), 2 deletions(-) Fusion-Task-Id: FN-8151 Fusion-Task-Lineage: d97973a7-3387-4b98-b150-8ac2e838bfa9 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
5a60643c0a |
FN-8142: migrate auth storage and model runtime to pi SDK
Migrate Fusion's credential and model integrations to pi SDK 0.80.8+. - Replace legacy AuthStorage initialization with a locked Fusion credential store and ModelRuntime-backed registry. - Wire asynchronous model initialization and refresh through CLI, desktop, dashboard, executor, and provider paths. - Update provider, routing, and registry tests for the new SDK contracts. Files changed: packages/cli/src/commands/__tests__/daemon.test.ts | 2 +- .../cli/src/commands/__tests__/dashboard.test.ts | 9 +- .../cli/src/commands/__tests__/onboard.test.ts | 1 + packages/cli/src/commands/__tests__/serve.test.ts | 2 +- packages/cli/src/commands/daemon.ts | 19 +- packages/cli/src/commands/dashboard.ts | 20 +- packages/cli/src/commands/onboard.ts | 6 +- packages/cli/src/commands/serve.ts | 19 +- packages/cli/src/commands/startup-model-sync.ts | 4 +- packages/core/src/__tests__/openai-models.test.ts | 17 +- ...-model-routes-openai-codex-supplemental.test.ts | 17 +- ...register-model-routes-zai-real-registry.test.ts | 15 +- packages/dashboard/src/routes.ts | 12 +- .../dashboard/src/routes/register-model-routes.ts | 2 +- packages/desktop/src/local-runtime.ts | 2 +- packages/desktop/src/local-server.ts | 2 +- .../custom-providers-openai-completions.test.ts | 16 +- .../custom-providers-openai-responses.test.ts | 16 +- .../engine/src/__tests__/executor-test-helpers.ts | 2 +- .../src/__tests__/pi-create-fn-agent.test.ts | 8 +- .../engine/src/__tests__/pi-layers-wiring.test.ts | 2 +- packages/engine/src/__tests__/pi.test.ts | 47 ++--- .../src/__tests__/provider-registration.test.ts | 17 +- packages/engine/src/auth-storage.ts | 218 ++++++++++++++++++--- packages/engine/src/custom-provider-registry.ts | 14 +- packages/engine/src/executor.ts | 15 +- packages/engine/src/pi.ts | 50 +++-- packages/engine/src/provider-auth.ts | 58 +++--- packages/engine/src/provider-registration.ts | 16 +- 29 files changed, 421 insertions(+), 207 deletions(-) Fusion-Task-Id: FN-8142 Fusion-Task-Lineage: 8ae79064-7820-4976-9645-9431b5a3129e Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
d3544cfa99 |
FN-8160: remove multi-tab session lock prompts
Allow planning interview sessions to resume across tabs without legacy lock affordances. - Remove obsolete cross-tab session lock translations and generated resource keys. - Cover direct resumption for milestone, slice, and mobile background sessions. Files changed: .../MilestoneSliceInterviewModal.test.tsx | 37 +++++++++++++ .../components/__tests__/utility-mobile.test.tsx | 60 ++++++++++++++++++++++ packages/i18n/locales/en/app.json | 18 ------- packages/i18n/locales/es/app.json | 57 +++++++++++--------- packages/i18n/locales/fr/app.json | 57 +++++++++++--------- packages/i18n/locales/ko/app.json | 57 +++++++++++--------- packages/i18n/locales/zh-CN/app.json | 57 +++++++++++--------- packages/i18n/locales/zh-TW/app.json | 57 +++++++++++--------- packages/i18n/src/resources.d.ts | 51 +++++++++--------- 9 files changed, 290 insertions(+), 161 deletions(-) Fusion-Task-Id: FN-8160 Fusion-Task-Lineage: 8bf80297-8394-4e63-b689-6ab56f9a5088 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
ca7a5a7106 |
FN-8144: remove workspace worktrees on archive
Archive workspace task worktrees synchronously and safely across archive entry points. - Add store-scoped workspace disposal planning, reservations, and quarantine handling. - Install baseline and executor disposers that remove per-repository worktrees and branches without shell interpolation. - Cover disposal-plan deduplication and document the archive cleanup behavior. Files changed: .../fn-8144-archive-removes-workspace-worktrees.md | 7 ++ AGENTS.md | 1 + docs/task-management.md | 4 + .../archive-removes-workspace-worktrees.test.ts | 59 +++++++++++ packages/core/src/archive-worktree-disposer.ts | 52 ++++++++++ packages/core/src/index.gate.ts | 8 ++ packages/core/src/index.ts | 8 ++ .../core/src/task-store/archive-lifecycle-2.ts | 29 ++++-- packages/core/src/task-store/archive-lifecycle.ts | 114 ++++++++++++++++++++- .../src/archive-worktree-disposer-install.ts | 27 ++++- packages/engine/src/executor.ts | 25 ++++- 11 files changed, 319 insertions(+), 15 deletions(-) Fusion-Task-Id: FN-8144 Fusion-Task-Lineage: 1c4b65f3-a1d2-4a5c-a4b6-c263f9e6f61d Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
fd036665ae |
FN-8123: add agent clarification notifications
Add agent clarification notices with ntfy delivery and mailbox support. - Add configurable clarification ntfy topics and notification settings - Route agent clarification requests to ntfy and the planning mailbox - Update planning dialogs, translations, documentation, and regression tests Files changed: .changeset/fn-8123-agent-clarification.md | 7 + docs/dashboard-guide.md | 6 + docs/settings-reference.md | 1 + .../core/src/__tests__/global-settings.test.ts | 11 + packages/core/src/settings-schema.ts | 2 + packages/core/src/types.ts | 6 + .../app/__tests__/settings-save-split.test.ts | 13 ++ packages/dashboard/app/api/legacy.ts | 3 +- .../dashboard/app/components/PlanningModeModal.tsx | 29 ++- .../dashboard/app/components/SettingsModal.tsx | 1 + .../__tests__/PlanningModeModal.initial.test.tsx | 17 +- .../app/components/settings/save-split.ts | 1 + .../settings/sections/NotificationsSection.tsx | 11 + .../src/__tests__/routes-planning.test.ts | 7 +- packages/dashboard/src/planning.ts | 228 ++++++++++++++++----- .../src/routes/register-planning-subtask-routes.ts | 59 +++++- packages/i18n/locales/en/app.json | 4 + packages/i18n/src/resources.d.ts | 4 + 18 files changed, 346 insertions(+), 64 deletions(-) Fusion-Task-Id: FN-8123 Fusion-Task-Lineage: cf397749-01c6-44d6-8d12-8ce7f5627c29 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
bd8a6ae7bb |
FN-8154: fix mobile task-detail Feed padding
Narrow the mobile Feed inset while preserving clearance for its overlay control. - Restore full-width activity content on narrow task-detail surfaces. - Reserve overlay-toggle clearance only for first-row Feed elements. - Cover the responsive CSS contract and publish a patch changeset. Files changed: .changeset/fn-8154-task-detail-mobile-padding.md | 7 +++++++ .../dashboard/app/components/TaskDetailModal.css | 16 +++++++++++++++- .../TaskDetailModal.attachments-and-tabs.test.tsx | 2 +- .../__tests__/TaskDetailModal.css.test.ts | 22 ++++++++++++++++++++++ ...etailModal.responsive-and-dependencies.test.tsx | 2 +- 5 files changed, 46 insertions(+), 3 deletions(-) Fusion-Task-Id: FN-8154 Fusion-Task-Lineage: 9094d12d-0431-4f42-bec9-c573686c7d6f Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
ee28f5e45e |
FN-8155: test triage retry title handling
Cover blank-title behavior across retryable triage failures. - Verify deterministic validation retries retain blank task titles - Verify transient failures retain blank task titles while retries remain Files changed: packages/engine/src/__tests__/triage.test.ts | 81 ++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) Fusion-Task-Id: FN-8155 Fusion-Task-Lineage: d8b4414d-b105-4251-bc42-d02a6d84bf3a Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
c6be0b158b |
FN-8129: centralize database backup settings
Move database backup policy and scheduling to shared global configuration. - Split project memory backups from cluster-wide database backup settings. - Migrate legacy backup values and routines safely into central global storage. - Schedule and dispatch one shared PostgreSQL backup routine across project engines. Files changed: .changeset/fn-8129-backup-settings-scope-split.md | 7 + docs/dashboard-guide.md | 2 + docs/settings-reference.md | 10 +- packages/cli/src/commands/backup.ts | 3 +- .../__tests__/backup-settings-migration.test.ts | 50 ++++++ .../src/__tests__/backup-settings-scope.test.ts | 27 +++ packages/core/src/backup-settings-migration.ts | 188 +++++++++++++++++++++ packages/core/src/backup.ts | 77 +++++---- packages/core/src/global-routine-store.ts | 104 ++++++++++++ packages/core/src/index.gate.ts | 6 +- packages/core/src/index.ts | 6 +- .../core/src/postgres/migrations/0000_initial.sql | 19 +++ .../postgres/migrations/0015_global_routines.sql | 19 +++ packages/core/src/postgres/schema-applier.ts | 19 ++- packages/core/src/postgres/schema/central.ts | 21 ++- packages/core/src/postgres/startup-factory.ts | 11 ++ packages/core/src/settings-schema.ts | 14 +- packages/core/src/types.ts | 31 +++- .../dashboard/app/components/SettingsModal.tsx | 10 +- .../settings/__tests__/section-keys.test.ts | 1 + .../app/components/settings/save-split.ts | 2 + .../search/__tests__/settings-search-index.test.ts | 1 + .../settings/search/entries.ts | 2 + .../app/components/settings/section-keys.ts | 4 - .../settings/sections/BackupsSection.search.ts | 40 ----- .../settings/sections/BackupsSection.tsx | 112 +----------- .../sections/DatabaseBackupsSection.search.ts | 51 ++++++ .../settings/sections/DatabaseBackupsSection.tsx | 142 ++++++++++++++++ .../settings-default-descriptions.test.tsx | 1 + packages/dashboard/src/routes.ts | 12 +- .../src/routes/register-settings-memory-routes.ts | 41 ++--- .../engine/src/__tests__/routine-scheduler.test.ts | 55 +++++- packages/engine/src/cron-runner.ts | 4 +- packages/engine/src/routine-runner.ts | 67 +++++--- packages/engine/src/routine-scheduler.ts | 35 +++- 35 files changed, 929 insertions(+), 265 deletions(-) Fusion-Task-Id: FN-8129 Fusion-Task-Lineage: af17f39a-7f1c-40ff-8a4a-cd63895cd532 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
d8f9b44fc3 |
fix(build): move pnpm overrides to pnpm-workspace.yaml for pnpm 11 readiness (#2220)
pnpm 10.33 warns on every install and build: [WARN] The "pnpm" field in package.json is no longer read by pnpm. The following keys were ignored: "pnpm.onlyBuiltDependencies", "pnpm.overrides" The wording overstates it for the pinned version: on pnpm 10.33 the field is still honoured, so nothing is broken today. It is a forward-looking deprecation notice, and pnpm 11 makes it real — there the overrides silently stop applying. Reproduced on pnpm 11 with the workspace pins declared only in package.json: overrides block dropped from pnpm-lock.yaml @types/node ^25.5.2 -> ^22.0.0 (25.5.2 -> 22.20.1) zod 4.3.6 -> 3.25.76 @types/node fragments into 5 versions across the workspace pnpm-workspace.yaml is the supported home and is honoured by both 10.33 and 11, so moving `overrides` there is safe on the pinned version and correct for the next major. Verified on pnpm 10.33: `pnpm install --lockfile-only` leaves pnpm-lock.yaml byte-identical and its `overrides` block is now sourced from pnpm-workspace.yaml. Verified on a minimal repro that pnpm 10.33 applies yaml overrides (ms -> 2.0.0). Scope is deliberately limited to `overrides`. `ignoredBuiltDependencies` and `onlyBuiltDependencies` are left in place: they are also honoured on 10.33 and ignored on 11, but the workspace list is not a superset of the package.json one (it omits `electron`, removed in |
||
|
|
478f226a54 |
test: green full-suite CI after main drift (#2229)
## Summary Restores green **Full Suite (non-blocking)** runs on `main`. Recent main merges left i18n key parity, schema baseline bookkeeping (0011→0012), heartbeat tool inventory (FN-8058 `fn_task_logs_read`), and merger whitespace-classification mocks (execFile `git diff -p -w :2: :3:`) out of date, so all four test shards failed. ## Root causes observed on main - **Shard 4 / `@fusion/i18n`**: missing `skipConfirmationDialogs*` + `reviewBudgetExhausted` in non-en locales; orphan `awaitingApprovalPlanReviewReplanCap` - **Shard 3 / `@fusion/core`**: `SCHEMA_BASELINE_VERSION` advanced to `0012` while tests still equated it with `OWNER_PROJECT_ID_SPLIT_VERSION` (`0011`) and omitted `0012` from applied-migration lists - **Shards 1–2 / `@fusion/engine`**: tool count/snapshot drift for `fn_task_logs_read`; merger tests still mocked `git diff-tree` for trivial classification after the execFile `:2:`/`:3:` cutover; mock provider `updateTask` arity drift ## Changes - Locale catalogs: add missing keys, drop orphan key - Schema applier tests: immutable 0011 identity + baseline 0012 lists - Heartbeat + gating snapshots: include `fn_task_logs_read` - Merger unit mocks: recognize `git diff -p -w :2:path :3:path` - Mock provider: accept optional third `updateTask` arg ## Test plan - [x] `pnpm --filter @fusion/i18n exec vitest run` — 23/23 - [x] `pnpm --filter @fusion/core exec vitest run src/__tests__/postgres/schema-applier.test.ts` (immutable + automation upgrade) — pass - [x] `pnpm --filter @fusion/core exec vitest run` project-identity + satellite-fusiondir — pass - [x] Engine suites from failed CI shards (file-scoped, hermes/openclaw/paperclip/grok, reliability post-finalize/mission, heartbeat, gating, merger recovery/prompt, mock-provider, etc.) — pass - [ ] Full Suite workflow green on merge to main <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Improved project data isolation across backend operations. - Added safer optional toast handling when UI components render outside the full application shell. - Added support for reading task logs during agent heartbeat sessions. - **Bug Fixes** - Prevented runtime probes from hanging and avoided scanning large binary files. - Improved path handling for workspaces with missing descendants. - Corrected task retry state resets and GitHub import/issue-close behavior. - **Style** - Improved chat, terminal, and settings spacing. - Added clearer accessibility labeling for the auto-merge control. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
06a5fd813d |
refactor: package code organization waves 6–7 (#2166)
## Summary Waves 6–7 of package code organization (plan: `docs/plans/2026-07-14-001-refactor-package-code-organization-plan.md`), after #2148. ### Wave 6 | New module | Parent | |---|---| | `merger-autostash-labels.ts` | `merger.ts` | | `types/agent-state.ts` | `types.ts` | | `app/api/tasks-lifecycle.ts` | `legacy.ts` | | `task-store/task-row-mappers.ts` | `remaining-ops-3.ts` (rename) | ### Wave 7 | New module | Parent | |---|---| | `self-healing-optional-step-revision.ts` | `self-healing.ts` | | `self-healing-path-utils.ts` | `self-healing.ts` | | `merger-git-parse` (+ `quoteArg`, `getBranchChangedFiles`) | `merger.ts` | | `app/api/settings.ts` | `legacy.ts` | Public import paths stay stable via re-exports. ## Test plan - [x] engine + dashboard typecheck (incl. app) - [x] eslint on touched modules - [x] merger-autostash / parse-porcelain / getBranchChanged / api-tasks - [ ] CI merge gate <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a dedicated task lifecycle API client (task promotion, merge, retry/reset/duplicate, pause/unpause, archive/unarchive, revert, plan approve/reject) plus branch-group and planner oversight actions. * Added a settings/config API service (effective task settings, update check/refresh/install). * Introduced standardized agent lifecycle states with identity/ephemeral detection helpers. * **Bug Fixes** * Improved autostash label compatibility and NUL-delimited changed-file detection for branch diffs. * **Refactor** * Modularized merger labeling/parsing, self-healing helpers, and lifecycle/type wiring while keeping behavior consistent. * **Tests** * Updated merger verification tests for `git diff -z` output handling. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |