2e4fcfcaea09b9dcbccd4443e2f67eb6fed04487
3227 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2e4fcfcaea |
fix(FN-7952): establish PostgreSQL core authority (#2108)
## Summary Fusion’s core runtime now treats PostgreSQL as the authoritative metadata store without leaving current CLI, dashboard, desktop, or engine composition roots uncompilable between stack layers. This is the 99-file foundation for the larger cutover: subsequent PRs migrate the remaining consumers, plugins, and operator surfaces. ## Design decisions - Runtime store construction fails closed when an asynchronous PostgreSQL layer is unavailable; SQLite remains readable only at explicit migration and identity-recovery boundaries. - Project ownership is enforced across active, archived, workflow, mission, analytics, and plugin-schema data. - The small set of cross-package files in this layer are compatibility-critical call sites required for a green intermediate commit, not the complete consumer migration. - Schema migration 0008 remains assigned to session-advisor state from current `main`; mission lineage idempotency advances to 0009 so neither invariant can be skipped. ## Validation - All affected package typechecks pass: Core, Engine, Dashboard, CLI, and Desktop. - `pnpm test:gate` passes: 478 tests across the engine gate, PostgreSQL core gate, and CLI workflow shape. - The PR changes exactly 99 files. ## Stack This is the base PR. Engine/dashboard, CLI/desktop/ops, plugins, and docs/release follow as stacked PRs, each below 100 changed files. Related: #2105 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * PostgreSQL is now the standard runtime backend, with embedded PostgreSQL enabled by default. * Added project-scoped storage for tasks, archives, chat sessions, missions, knowledge pages, and operational data. * Improved archived-task search, filtering, pagination, and restoration. * Added safer plugin schema initialization with validation and project isolation. * Added PostgreSQL-backed workflow, mission, validator, and dashboard capabilities. * **Bug Fixes** * Improved startup timeout cancellation and resource cleanup. * Prevented cross-project data access and phantom reservation cleanup errors. * Ensured archived tasks remain read-only and asynchronous writes complete reliably. * Retired SQLite opt-out settings with clear startup errors. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
e97081fb77 |
fix: stop agents exceeding the global concurrency cap (#2107)
## Summary - Operators could see more agents running than Global Max Concurrent (e.g. 5 running with cap 4: 4 planners + 1 executor). - Scheduler now `tryAcquire`s a shared semaphore slot before todo→in-progress and hands that pre-held slot to the executor/graph run. - Triage admits planners against the live top-level running-agent claim (planning + in-progress + active in-review), not only `semaphore.availableCount`. - Executor claims the pre-held slot for the full run and avoids a second top-level acquire on step/seam re-entry (deadlock under a full cap). ## Test plan - [x] `pnpm --filter @fusion/engine exec vitest run src/__tests__/concurrency.test.ts src/__tests__/triage.test.ts` - [x] Regression: triage leaves room when 1 in-progress agent is live under global cap 4 - [x] Regression: pre-held executor slot register/take/drop handoff - [ ] Manual: set Global Max Concurrent and Max triage concurrent to 4, fill Planning + run 1 In Progress; footer should not show 5 running under a full steady state <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Bug Fixes** - Improved global concurrency enforcement so the scheduler and executor never start more agents than the configured limit, including tighter top-level “claimed capacity” accounting. - Updated triage admission control to consider global top-level utilization, factoring processing tasks and agents already running to prevent over-admitting planners. - Added safer pre-held concurrency-slot handoff behavior to avoid capacity leaks and drift during graph routing, step execution, and legacy fallback. - Ensured reserved capacity is reliably released on early exits, failed dispatches, and other aborted paths (with idempotent cleanup). - Refreshed concurrency diagnostics to better explain whether throttling is due to project or global limits, with clearer claimed/processing visibility. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
51859148a7 |
fix(engine): implementation-incomplete merge failures fail-closed/resumable (#1991) (#2091)
## What & why Workflow graph merge failures classified `implementation-incomplete` (i.e. the merge node reports there is no implementation proof — no branch / no committed work) could still be routed to the no-op merge requester and false-complete the task as **done**. This hides genuinely unlanded work behind a green "merge" and is the merge-side sibling of the "(no feedback captured)" no-verdict dispatch defect. Closes the truthfulness gap: an `implementation-incomplete` merge-graph failure now **fails closed** when there is no executable proof to resume, or **requeues resumable parsed steps** back to `todo` for execution — it is never handed to a no-branch no-op merge requester. Refs #1991 (no-op merge truthfulness). Sibling of #1946 (no-verdict "(no feedback captured)" dispatch defect). ## Change - New classifier `routeImplementationIncompleteMergeGraphFailure(live, failedNode)`: - clears paused-aborted state + active worktree, - requeues resumable parsed steps via the existing execution-resume router when the task still has non-terminal workflow steps, - otherwise fails closed (`status: "failed"` with a logged, explicit reason). - Defense-in-depth: `isRetryableBenignMergePauseAbort` and the merge-requester route both short-circuit (`return false`) for `implementation-incomplete`, so this value can never reach the no-op merge requester. - `handleGraphFailure` routes genuine (non-global-pause, non-completion-finalize, non-user-paused) `implementation-incomplete` merge-graph failures through the new classifier. - Resume-eligibility predicate treats an `implementation-incomplete` merge failure with **no** incomplete steps as fail-closed, and keeps the premature-merge-with-incomplete-steps requeue path. Legitimate `noCommitsExpected` no-op merges are explicitly preserved (regression test included). ## Tests New regression coverage in: - `packages/engine/src/__tests__/reliability-interactions/merge-node-paused-abort-retryable.test.ts` — parametrized across merge node ids: (a) no-proof `implementation-incomplete` fails closed without requesting a no-op merge; (b) resumable parsed steps are requeued to `todo` for execution resume, not no-op-merged. - `packages/engine/src/__tests__/executor-fast-mode-workflows.test.ts` — a legitimate `noCommitsExpected` builtin:coding merge is still allowed (guard does not over-block). Verification (engine package): pnpm --filter @fusion/engine exec vitest run \ src/__tests__/executor-fast-mode-workflows.test.ts \ src/__tests__/reliability-interactions/merge-node-paused-abort-retryable.test.ts # => 2 files, 69 tests, 0 failures pnpm check:changesets # pass pnpm --filter @fusion/engine typecheck # 0 errors A `patch` changeset for `@runfusion/fusion` is included. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Prevented “implementation-incomplete” workflow merge failures from being treated as successful no-op merges. * Ensured tasks with resumable implementation steps move back to execution to continue where they left off. * Ensured tasks without sufficient implementation evidence fail safely rather than entering misleading retry/no-op paths. * Improved paused/aborted merge-failure handling to avoid incorrect completion states. * **Tests** * Added/expanded coverage for fast-mode coding merges and implementation-incomplete pause/abort retry classification. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Fusion <noreply@runfusion.ai> Co-authored-by: gsxdsm <gsxdsm@users.noreply.github.com> |
||
|
|
4f037679ad |
feat: planner overseer session advisor (OMP advisor parity) (#2082)
## Summary Adds a **session advisor** to the planner overseer so Fusion can review live executor transcripts the way [oh-my-pi’s advisor](https://github.com/can1357/oh-my-pi/tree/main/packages/coding-agent/src/advisor) does — without replacing the existing lifecycle supervisor (stage watch, retry, merge confirmation, human-control withhold). ### What ships - **Emission guard** (`OverseerEmissionGuard`) — content-free phrase filter, session dedupe with severity-rank escalation, one accept per advisor update - **Session delta runtime** — queues agent-log deltas, drains through an advisor agent, drops backlog after 3 failures - **Session advisor service** — model gate, level matrix (`observe` / `steer` / `autonomous`), human-control re-check at inject, `[session-advisor]` steering comments - **OVERSEER.md / WATCHDOG.md** discovery for project review priorities - **AgentLogger `onEntriesFlushed`** + poll-backed agent-log cursor for durable deltas - Workflow settings: `plannerOverseerAdvisorProvider` + `plannerOverseerAdvisorModelId` (both required; empty = soft-disabled for cost safety) - Docs + changeset ### What does not ship (deferred) - Multi-advisor YAML roster, mutating advisor tools, reviewer/merger shadowing, true tool-abort interrupt ### Plan `docs/plans/2026-07-13-001-feat-overseer-advisor-parity-plan.md` ## Enablement 1. Set workflow **Session advisor model provider** + **Session advisor model id** 2. Oversight level `observe` (log only), `steer`, or `autonomous` (inject) 3. Optional: add `OVERSEER.md` or `WATCHDOG.md` in the project ## Test plan - [x] `pnpm --filter @fusion/core exec vitest run src/__tests__/overseer-emission-guard.test.ts` - [x] `pnpm --filter @fusion/engine exec vitest run` overseer-* unit tests (21 tests) - [x] Related planner-overseer / intervention regression tests - [x] `@fusion/engine` + `@fusion/core` typecheck - [ ] Manual: configure advisor model, run an executor task, confirm `[session-advisor]` inject + timeline metadata when concern is raised ## Residual Review Findings None from autofix pass (log-cursor ordering fix already committed). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added an off-by-default “session advisor” that can review live execution activity and provide severity-based guidance. * Added project and per-task controls to enable it, including a default enable switch and Quick Add / Task Detail toggles. * Enhanced advisor prompting by discovering and incorporating `OVERSEER.md`/`WATCHDOG.md` review files. * **Documentation** * Added architecture and settings documentation for the new session-advisor parity behavior. * **Bug Fixes** * Improved fail-soft handling so advisor behavior won’t disrupt execution. * Fixed concurrent PostgreSQL migration startup failures. * **Tests** * Added coverage for advice parsing, emission guarding, runtime behavior, and watchdog discovery. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
6aff4958ad |
fix(FN-7952): finish async workflow selection cutover
Use PostgreSQL workflow selections in the dashboard TUI, authoritative driver, and graph-runner adapter so migrated tasks cannot silently fall back to the coding workflow. |
||
|
|
2d61976df0 |
fix(FN-7952): restore runtime state after PostgreSQL migration
Route workflow selections, model lanes, goals, skills, and reliability reads through project-scoped async stores. Recover heartbeat agents parked against an unrelated project model and preserve workflow JSONB patches atomically. |
||
|
|
278ede9dfa |
fix(FN-7952): recover provider failures without retry loops
Preserve authenticated CLI usage after migration, surface OAuth remediation, and use a single distinct model fallback before parking permanent failures. Keep transient credential errors retryable and confirm each OAuth expiry notification independently. Fusion-Task-Id: FN-7952 |
||
|
|
79d4299be2 |
fix: preserve provider and workflow behavior after migration
Use canonical Anthropic OAuth refresh, keep CLI-backed providers out of API-key auth rows, parse Grok's omitted zero usage, and carry board workflow context into task creation. |
||
|
|
7677ab07dc |
fix: add chat_sessions columns to schema baseline + fix remaining PG auth bugs (shard 4) (#2096)
## Summary Fixes shard 4 full-suite failures: chat_sessions schema baseline gap + two remaining PG auth bugs missed by PR #2086. **Scope: shard 4 only.** Shards 1/2 (engine timeouts) and shard 3 (compound-engineering CI-only failure) are separate issues not addressed here. ## Changes ### Schema baseline gap — `chat_sessions` missing columns (42703 error) - **`0000_initial.sql`**: Added `validator_thinking_level` and `planning_thinking_level` columns to `CREATE TABLE project.chat_sessions`. These exist in the Drizzle schema (`project.ts:1492-1493`) but were missing from the SQL baseline, causing `column does not exist` on all chat_sessions inserts in fresh test databases. - **`postgres-health.ts`**: Added both columns to `EXPECTED_PROJECT_COLUMNS` self-heal list so existing databases also get them via ALTER TABLE. **Fixes**: `chat-store-content-search-edit.pg.test.ts` (5 tests), `satellite-db-injected-stores.test.ts` (2 tests) ### Remaining auth bugs (password auth failed for user "runner") - **`allocator-cross-project.test.ts`**: Still had `process.env.USER` in inline adminExec — missed by PR #2086's batch fix. Replaced with `PG_TEST_URL_BASE` connection string. - **`connection.test.ts`**: Used `FUSION_PG_TEST_URL` (not set on CI) with a bare default URL lacking credentials. `postgres.js` fell back to OS user `runner`. Changed to derive from `FUSION_PG_TEST_URL_BASE` which includes credentials. **Fixes**: `allocator-cross-project.test.ts` (2 tests), `connection.test.ts` (3 tests) ## Verification | Check | Result | |---|---| | Merge gate (`pnpm test:gate`) | ✅ 294 + 114 + 63 = 471 passed | | chat-store-content-search-edit | ✅ 5 passed | | satellite-db-injected-stores | ✅ 10 passed | | allocator-cross-project | ✅ 2 passed | | connection | ✅ 13 passed | | Lint | ✅ exit 0 | | Typecheck | ✅ clean | ## Not in scope - **Shards 1/2**: Engine test suite timeouts with `getAsyncLayer`/`updateSettings` mock warnings. Pre-existing. - **Shard 3**: `compound-engineering stage-skill-loading.test.ts` — 14 tests fail on CI (`TypeError: Cannot read properties of undefined (reading 'close')`), pass locally. Likely CI-specific teardown issue. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added separate `validator_thinking_level` and `planning_thinking_level` fields to chat session data, including database schema and health-check recognition. * **Bug Fixes** * Improved PostgreSQL test connectivity by using configured connection URL settings instead of hardcoded local defaults. * Made Postgres-related test teardown null-safe to avoid failures when setup doesn’t complete. * **Tests** * Updated automated test quarantine/exclusions for known failing engine and reliability-interaction cases. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
945d629e3b |
fix(core): make SQLite cutover lossless and project-local
Preserve legacy-only tables, recover partial migration ownership, and enforce project-local keys, relationships, agents, merge queues, task IDs, archives, and monitor state with PostgreSQL RLS. Report successful cutovers once in the dashboard and system inbox with retained SQLite paths and Discord support details. |
||
|
|
dff864e098 |
feat: harden permanent-agent heartbeat instructions (#2081)
## Summary Hardens permanent-agent operating law while keeping the heartbeat/executor split: - **Critical Rules** in task-scoped and no-task heartbeat system prompts (survive custom `HEARTBEAT.md`) - Stronger default procedures: disposition checklist, scoped-wake, blocked dedup, progress note style - **Wake Delta multi-assign inventory** (ranked, cap 8, coordination-only framing) + `checkout_conflict` regression test - Standing instructions six-section template for blank custom create / empty detail insert - Onboarding interview guidance to prefer structured `instructionsText` - Playbooks, CONCEPTS, agents.md accuracy; remove stale agent gap-analysis doc Plan: `docs/plans/2026-07-12-001-feat-permanent-agent-heartbeat-instructions-plan.md` ## Test plan - [x] `pnpm --filter @fusion/core exec vitest run src/__tests__/assigned-task-ranking.test.ts` - [x] `pnpm --filter @fusion/engine exec vitest run src/__tests__/agent-heartbeat-procedures.test.ts src/__tests__/heartbeat-executor.test.ts -u` - [x] `pnpm --filter @fusion/dashboard exec vitest run app/components/__tests__/standing-instructions-template.test.ts` - [ ] CI gate green on PR ## Residual Review Findings None recorded at open (inline review; no residual sink). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added ranked multi-assignment context to agent heartbeat wake-ups, including task status, ownership, and lease details. * Added standing-instructions templates for creating and editing permanent agents. * Improved onboarding guidance with a consistent six-section instruction structure. * Added clearer heartbeat handling for blocked tasks, no-task runs, and checkout conflicts. * **Documentation** * Added permanent-agent heartbeat playbooks and expanded coordination glossary entries. * Updated documentation indexes and heartbeat behavior guidance. * **Tests** * Added coverage for task ranking, instruction templates, wake-up context, and conflict handling. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
30a83f21fc |
fix(engine): requeue stale assistant continuations (#2095)
## Summary - detect persisted executor sessions that cannot continue from an assistant message - clear the stale session pointer after the executor lock is released - requeue the task with workflow progress preserved instead of marking it failed ## Test plan - `pnpm --filter @fusion/engine exec vitest run src/__tests__/executor-step-session.test.ts -t "clears a stale assistant-continuation resume session and requeues without marking the task failed" --project=engine-default --silent=passed-only --reporter=dot` - `pnpm --filter @fusion/engine typecheck` - `pnpm build` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved recovery when an assistant continuation session becomes stale by restarting a fresh session with bounded retries, preserving overall task progress. * Clears invalid persisted session/continuation state and defers requeue until coordination cleanup is safe. * When retries are exhausted, tasks are marked failed and the error callback runs (without routing to review). * **Tests** * Added coverage for stale-session recovery, repeated-stale behavior, correct (or skipped) requeue decisions, and progress/error handling paths. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
b563b12662 |
feat: add Oh My Pi (omp) ACP runtime plugin (#2083)
## Summary - Add `fusion-plugin-omp-runtime` so Fusion agents can run through operator-installed **Oh My Pi (`omp`)** over the [Agent Client Protocol](https://omp.sh/docs/acp) (`omp acp`). - Wire staged/bundled install, Settings → Authentication card (enable + binary path), model discovery (`omp models` → `omp-cli/*`), and MCP eligibility for runtime id `omp`. - Forward Fusion `systemPrompt` via ACP `session/new` `_meta.systemPromptOverride`. ## How operators use it 1. Install/auth `omp` (credentials under `~/.omp`). 2. Enable **Oh My Pi — via omp ACP** in Settings → Authentication (optional binary path). 3. Set agent **Runtime Source → OMP Runtime** (`runtimeHint: "omp"`), or pick an `omp-cli/*` model when enabled. ## Known v1 gaps - No Grok-style Fusion `fn_*` loopback tool bridge yet (operator MCP is forwarded; in-process custom tools are not). - Model is fixed at spawn (`omp --model … acp`); no mid-session Fusion model switch. ## Test plan - [x] `pnpm --filter @fusion-plugin-examples/omp-runtime test` (unit + live ACP when `omp` is on PATH) - [x] Auth routes: `POST /api/auth/omp-cli`, `GET /api/providers/omp-cli/status` - [x] Engine `runtimeSupportsMcp("omp")` - [ ] Manual: enable card in dashboard, select OMP runtime on an agent, run a short chat turn <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added Oh My Pi (OMP) CLI support as an ACP-backed runtime and model provider, including model discovery and probing. * Added dashboard auth/status controls to enable OMP, check readiness, and configure the local binary path (with validation). * Exposed OMP custom `fn_*` tools via an MCP loopback bridge, plus optional filesystem capabilities and stricter tool permission gating. * **Documentation** * Added/expanded OMP runtime contract and integration docs (including the ACP session/handshake flow). * **Tests** * Added Vitest coverage for settings wiring, provider status, model discovery, runtime sessions, permissions, MCP bridging, and live connectivity. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d7e072a03c |
fix: add psql binary guard + delete expired quarantine tests (ratchet) (#2090)
## Summary Follow-up to PR #2086 addressing two Greptile review findings. ## P2 — Missing `psql` binary guard (Greptile P2) `hasPg` in `_helpers.ts` previously checked only TCP connectivity to PostgreSQL. But `adminExecAsync()` shells out to the `psql` CLI for DDL (`CREATE/DROP DATABASE`). On a runner where Postgres is reachable but `psql` isn't installed, tests would fail with `spawn psql ENOENT` instead of skipping cleanly. **Fix**: Added `hasPsql = spawnSync("psql", ["--version"]).status === 0` to the `hasPg` guard, so tests skip when either Postgres is unreachable OR `psql` is missing. ## P1 — Expired quarantine entries (Greptile P1) The 16 dashboard test files quarantined on 2026-06-25 were past the 14-day deletion ratchet (AGENTS.md: "DELETED after 14 days unless rescued"). Per the ratchet, the test files were deleted and all references removed: - **Deleted 16 test files** (CSS drift, mock drift, mobile-render regressions) - **Removed 16 entries** from `scripts/lib/test-quarantine.json` (only the CLI entry remains) - **Emptied `quarantinedDashboardTests` array** in `packages/dashboard/vitest.config.ts` ## Verification | Check | Result | |---|---| | Merge gate (`pnpm test:gate`) | ✅ 294 + 99 + 63 = 456 passed | | Dashboard curated-gate | ✅ passes (891 files, 892 executed, 1 skip-listed, 1 quarantined) | | Typecheck (engine) | ✅ clean | | Lint | ✅ exit 0 | <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Removed multiple outdated dashboard UI, CSS/token, theme contrast, and API/route test suites. * Updated dashboard test configuration to stop excluding quarantined tests and to prune the quality shard to the current set. * Updated the Vitest split/config guard to match the new test fixture set. * Improved PostgreSQL test detection by requiring the `psql` CLI before running database checks. * Adjusted quarantine tracking by adding a new CLI extension distribution ledger entry and removing obsolete dashboard quarantine entries. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d8f0b1a268 |
Restore PostgreSQL integration parity (#2089)
## Summary - add asynchronous PostgreSQL parity to research commands and engine execution paths - persist Roadmap, Compound Engineering sessions, and WhatsApp state in PostgreSQL - harden cancellation, concurrency, reconnect, replay-claim, and detached-promise behavior - bundle the PostgreSQL-backed integration implementations in the published CLI This is PR 2 of 2 and is intentionally stacked on #2088. It contains 44 changed files; merge #2088 first, then retarget this PR to `main` if GitHub does not do so automatically. ## Verification - `pnpm check:changesets --strict` - `pnpm lint` - `pnpm test:gate`: 463 tests passed - Compound Engineering plugin: 299 tests passed - Roadmap plugin: 144 tests passed - WhatsApp plugin: 27 tests passed - research CLI: 18 tests passed - `pnpm verify:fast`: all scoped typechecks, builds, CLI build, and boot smoke passed ## Post-Deploy Monitoring & Validation - deploy only after #2088 and verify schema migration `0002` is present - monitor research cancellation, automation claims, agent execution, plugin schema initialization, and unhandled rejections - validate Roadmap ownership, Compound Engineering session recovery, and WhatsApp reconnect/replay deduplication - compare per-project plugin and workflow counts after cutover - restore the pre-deploy backup for data rollback; avoid an in-place schema downgrade |
||
|
|
bc348345a4 |
fix(engine): break Plan Review REVISE replan loop (feedback + bounded cap) (#2078)
## Problem A task whose Plan Review step returns verdict `REVISE` can loop forever: plan → plan-review REVISE → `needs-replan` → re-plan → near-identical plan → REVISE → repeat. The triage **pre-execution** Plan Review gate (`runPlanReviewBeforeExecution`) sets `status: "needs-replan"` on REVISE with **no cap and no escape to `awaiting-approval`** — unlike the executor graph path, which already has `PLAN_REVIEW_REPLAN_HARD_CAP`. Under `planApprovalMode: require-all` there is also no human exit, because the task never reaches `awaiting-approval`. Separately, replan feedback (`triage.ts`) was derived only from `task.log` comment actions + the latest user comment; it never consulted the plan-review verdict stored in `task.workflowStepResults`. ## Fix 1. **Thread plan-review feedback into replan** — when re-planning with no comment-derived feedback, seed `buildSpecificationPrompt` from the most recent `plan-review` REVISE `output` in `workflowStepResults` (existing user/AI-comment precedence preserved). 2. **Bounded cap** — new `planReviewReplanCount` counter (`types.ts`, `store.ts` column + updateTask, `db.ts` migration 146, `manual-retry-reset.ts`). After `PLAN_REVIEW_GATE_REPLAN_CAP = 3` consecutive REVISE replans the task escalates to `awaiting-approval` (`awaitingApprovalReason: "plan-review-replan-cap"`) instead of replanning. Counter resets on APPROVE. ## Tests Adds `triage-replan-feedback-from-plan-review.test.ts` and `triage-plan-review-replan-cap.test.ts`. Merge gate green locally (`verify:fast`, `test:gate` 337+63, `lint`); changeset included. Made with Claude (see `Co-Authored-By` trailer). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Prevented Plan Review “REVISE” from looping indefinitely by enforcing a bounded replan cap. * After repeated Plan Review replans, tasks now escalate to an approval-hold state with a dedicated reason. * Improved replan feedback by seeding from the latest Plan Review output when no explicit feedback is available; the counter clears when Plan Review approves. * Manual retries now reset the Plan Review replan cap counter. * **Documentation** * Added release notes describing the Plan Review replan safeguards. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: gsxdsm <gsxdsm@users.noreply.github.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> |
||
|
|
8de0fbcd01 |
fix: repair full-suite failures after SQLite-to-PostgreSQL cutover (#2086)
## Summary
Fixes all deterministic full-suite (non-blocking) CI failures on `main`
caused by the SQLite-to-PostgreSQL cutover (VAL-REMOVAL-005).
## Changes
### i18n Key Parity (5 locale files)
- Added missing `taskPopupsBoardListOnly` +
`taskPopupsBoardListOnlyHelp` keys (empty strings per convention) to
zh-CN, zh-TW, fr, es, ko `app.json`
### Dashboard Curated-Gate Guard (`scripts/lib/test-quarantine.json`)
- Repaired "mirror drift": 16 dashboard test files were quarantined in
`vitest.config.ts` but never added to the quarantine ledger. Added all
16 with failing run URLs and `quarantinedAt` dates.
### Line-Count Audit CI Cache (`.github/workflows/full-suite.yml`)
- Removed `skip-install: "true"` from `line-count-audit` job —
`setup-node@v5` with `cache: pnpm` failed post-step because no
`node_modules` existed to cache.
### Engine Slow Tier — Full PG Migration
- **CI**: Added PostgreSQL service container to `test-slow` job (same
config as `test-shards`)
- **`_helpers.ts`**: Migrated `makeReliabilityFixture()` from removed
SQLite `Database.init()` to PG-backed `TaskStore`:
- Added `probeTcpReachable()` (TCP probe, copied from shared harness)
- Added `hasPg` export (uses TCP probe, not env-var guess)
- Added `adminExecAsync()` (`Promise.withResolvers`, psql via
`PG_TEST_URL_BASE`)
- Added `createPgLayer()` (fresh PG database + schema baseline +
`AsyncDataLayer`)
- Updated cleanup: `await store.close()`, close layer, drop database
- **Slow test**: Migrated 24 sync SQLite API calls to async PG APIs:
- `store.getRunAuditEvents()` → `await auditEvents(store, ...)` via
exported `queryRunAuditEvents`
- `store.getDatabase().prepare(...)` → Drizzle queries via
`store.getAsyncLayer()!.db`
- **Core exports**: Added `queryRunAuditEvents` from `async-audit.ts`
and `eq as drizzleEq` from `drizzle-orm`
- **22 reliability test files**: Added `hasPg` guards so tests skip
locally when PG is unavailable
### Shard 3 — PG Test Auth Bug (18 postgres test files)
- Replaced `psql -U ${process.env.USER ?? "postgres"}` with `psql
"${PG_TEST_URL_BASE}/postgres"` connection string. On GitHub Actions,
`process.env.USER` is `'runner'`, not `'postgres'`, causing auth
failure.
### Shard 3 — Removed Function Tests (`mesh-task-replication.test.ts`)
- Deleted 3 tests for functions intentionally removed in PostgresCutover
(`buildMeshReplicatedTaskCreatePayload`, `toReplicatedCreateInput`,
`taskMatchesReplicatedCreate`). Kept `buildBootstrapPrompt` test.
### Shard 3 — Store Thinking Levels (`store-thinking-levels.test.ts`)
- Migrated from removed SQLite path to PG-backed
`createTaskStoreForTest` + `pgDescribe`.
## Verification
| Check | Result |
|---|---|
| Merge gate (`pnpm test:gate`) | ✅ 294 + 99 + 63 = 456 passed |
| Engine slow tier (22 tests) | ✅ 22/22 passed |
| i18n parity tests | ✅ 7 passed |
| mesh-task-replication | ✅ 1 passed |
| PG data-layer | ✅ 14 passed |
| PG taskstore-lifecycle | ✅ 16 passed |
| store-thinking-levels | ✅ 1 passed |
| Dashboard curated-gate | ✅ passes |
| Typecheck (engine + core) | ✅ clean |
| Lint | ✅ exit 0 |
## Parked (not in scope)
- **Shards 1/2 timeout**: Engine test suite exceeds CI time budget.
Pre-existing, unrelated to these fixes.
- **2 latent PG files** (`chat-store-content-search-edit`,
`satellite-db-injected-stores`): Surface a separate pre-existing schema
baseline gap. Out of scope.
|
||
|
|
c15c78feeb |
feat: migrate storage from SQLite to PostgreSQL (#1793)
# Migrate storage from SQLite to PostgreSQL — full dashboard cutover Migrates Fusion's storage layer to the embedded PostgreSQL `AsyncDataLayer` (the default backend) and **completes the satellite-store + feature cutover** so every dashboard and Command Center surface works in PG mode. ## Status — every surface works in embedded-PG mode Verified live against a running embedded-Postgres dashboard (all **200**, zero 5xx) and gate-tested (**23 files / 99 tests** on embedded PG, plus engine-core 294 and ci-shape 63 in the blocking merge gate; core/engine/cli/dashboard typecheck clean). | Area | Surfaces | State | |---|---|---| | Satellite stores | workflows, todos, insights, research, missions, goals, mailbox | ✅ | | Views | artifacts, documents, evals | ✅ | | Command Center | activity, productivity, team, tokens, tools, **workflows**, **github**, **signals**, **plugin-activations**, **live** (all 10) | ✅ | | Run execution | insight generation, research run execution | ✅ (store-path; AI step needs a provider) | | Live updates | SSE push for mission/research/insight events | ✅ | | Workflow editing | create / update / delete / select (+ id counter) | ✅ | | Engine | mission autopilot, incident-signal ingestion, regression storm-guard, agent wake-on-message | ✅ | | Core | tasks, agents, secrets, automations, memory, chat, usage, PRs, git | ✅ | ## Approach Each satellite store gets an `Async<Store>` wrapper exposing the sync store's method names over the existing `async-*-store.ts` helpers; `get<Store>Store()` returns a `Sync | Async` union; consumers `await` (harmless on sync), and engine/CLI paths that can't convert use `instanceof Sync` graceful fallback. Analytics aggregators branch on `"ping" in dbOrLayer` to run schema-qualified raw SQL over `project.*` (snake_case) in PG. Executors/orchestrators/autopilot are await-converted to drive the union store; the async store wrappers extend `EventEmitter` so SSE live-push fires in both backends. Not-yet-ported capabilities degrade gracefully (never 500) and are individually called out in commits. ## Sync with main The branch is kept continuously merged with `main` (currently through FN-7845, 2026-07-12); the earlier "final rebase deferred" note no longer applies. Use **Create a merge commit** (or squash) to land it — GitHub's rebase-merge cannot replay a merge-maintained branch. ## Residual Review Findings Multi-agent code review of the PostgreSQL satellite-store ports (U1–U5) applied 3 safe fixes (see `fix(review): apply autofix feedback`). The following are **real but gated** — recorded here as follow-up work rather than auto-applied. All are SQLite→PostgreSQL **concurrency/atomicity regressions**: the sync stores were immune only by SQLite's single-writer, single-threaded-handler execution; the async ports open multi-await read-modify-write windows. **Reachability is low today** because the execution engines that generate concurrent same-run mutations (insight run executor, research orchestrator/dispatcher) are `instanceof`-gated to sync mode in PG. No process-crash class survived (all engine fallbacks correctly guard the sync store). - **[P1] Research `appendResearchEvent` dual-write is non-atomic** (`packages/core/src/async-research-store.ts`, corroborated: adversarial + reliability). The `research_run_events` insert (own transaction) and the `run.events` jsonb update are separate writes — a crash between them, or two concurrent appends, splits the table count from the jsonb array. **Fix:** perform the seq-insert and the jsonb update in one `layer.transactionImmediate`. - **[P1] Research run terminal-reversion via stale full-row persist** (`async-research-store.ts` `persistResearchRun`/`updateResearchStatus`). Concurrent `PATCH /runs/:id/status` + `POST /runs/:id/events` can revert a terminal run to `running` by overwriting the whole row, bypassing the transition guard. **Fix:** scoped column `UPDATE`s with a `WHERE status …` guard, or optimistic version column. - **[P2] `updateResearchRun`/`updateInsightRun` read-then-write TOCTOU** — concurrent PATCHes last-writer-wins on the lifecycle merge. **Fix:** `SELECT … FOR UPDATE` / enclosing transaction. - **[P2] `upsertRun`/`createRunOrThrowConflict` check-then-create race** (`async-insight-store.ts`) — two callers can each create an "active" run. **Fix:** partial unique index on `(projectId, trigger) WHERE status IN ('pending','running')`. - **[P3] `createResearchRetryRun` return-value divergence** — sync returns the pre-update `queued` snapshot; async returns the reloaded `retry_waiting` run (persisted state is identical). Pick one side for cross-backend parity. - **[P2/perf] Mission `getMissionWithHierarchy`/`getMissionHealth` N+1 fan-out** — O(milestones×slices) sequential round-trips hold one pool slot per request; can starve the pool for large hierarchies. **Fix:** batched/joined reads. - **Testing gaps:** no PG-mode concurrency tests (interleaved status/event mutations), no sync↔async parity assertion for the lifecycle-error codes, and no mission status/health rollup parity test vs the sync `MissionStore`. ~~Out of scope (deferred): AI run *execution* (insight/research) + mission autopilot + live SSE mission events remain sync-gated/degraded in PG mode.~~ **Since ported** — insight/research run execution, mission autopilot, and SSE live push all run on the async layer now, which also makes the concurrency findings above genuinely reachable; they remain open follow-ups. --- ## Update — 2026-07-12: production-readiness hardening & live acceptance Everything below landed on this branch since the description above was written: **Production blockers from review — fixed** - `recoverStaleTransitionPending` ported to the async layer (backend moves write + clear the crash-safe marker; startup/maintenance sweeps no longer throw). - Lost-update class fixed: `atomicWriteTaskJson`/`WithAudit` write changed columns only (full-row upserts silently resurrected stale fields across concurrent store instances — the "task stuck unplanned forever" bug). - First-boot **auto-migration**: booting the PG backend over a project with a legacy `fusion.db` migrates it automatically (loud failure, SQLite kept as backup), and the dashboard shows a one-time **"your data was migrated" banner** with the backup paths and a Need-help Discord link. - `pg_dump`/`pg_restore` discovered from common install locations for embedded-mode backups. - The PG suite is part of the blocking merge gate (`test:pg-gate`). **Multi-project isolation (PR #2007, merged into this branch)** - `project_id` partition key on tasks / archived tasks / config, `taskProjectScope` threaded through every scan/claim/count, per-project config rows, layer bound to the project at startup. - Review P1 follow-up: the shared cold-storage `archive.archived_tasks` table is also partitioned and all archived-board reads/counts/searches are scoped. - Schema drift self-heal generalized to schema-qualified columns so existing databases upgrade in place. **Other changes** - Node settings sync **removed** in PG mode (409 `settings-sync-disabled-postgres`) — nodes share state by connecting to the same database; auth sync kept (per-machine file). - Perf (review findings): `listTasks` pushes column filter + ORDER BY + LIMIT/OFFSET into SQL; `getConversation` capped to the most recent 200 messages. - Fixed a false "operator action required" pause-abort log fired on every successfully auto-merged task. **Live acceptance — PASSED (2026-07-12)** A sandboxed instance (isolated HOME, embedded PG, real Opus executor) ran a task through the complete cycle: create → triage (AI spec) → execute → in-review → AI squash-merge landed on the project's `main` → done. A write+read sweep of every data surface (settings, comments, documents, attachments + artifact bridge + artifact edit, chat with real generation, goals, missions, agent mail, secrets, workflows, memory, CC analytics) was green on embedded PG. **Known remaining work** - The per-project `config` PK re-key has no upgrade path for pre-isolation embedded-PG databases (needs a real `DROP CONSTRAINT`/re-key migration; fresh databases are fine). - `pg_dump`/`pg_restore` binaries are not yet bundled in release artifacts (PATH/common-location discovery only). - The satellite-store concurrency findings listed above. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Phil Larson <hello@phillarson.xyz> Co-authored-by: fusion-merge <fusion-merge@local> |
||
|
|
1ff83a2735 |
chore(release): v0.60.0
Version bump via changesets. |
||
|
|
d4001ab0ee |
feat: make merger AI model configurable under Global and Project Models
Add a dedicated merger model lane (project + global provider/model/thinking) so merge-agent sessions no longer share only the default model, without inheriting executor/planner/reviewer lanes. |
||
|
|
e35620c9aa |
FN-7939: supervise heartbeat timer-audit interval and bound non-advancing zombie re-arms
Fixes agents silently going stale for hours even though the heartbeat repair audit process was running. - HeartbeatTriggerScheduler now runs an independent watchdog (armTimerAuditWatchdog/checkTimerAuditLiveness) that tracks the audit loop's last-run timestamp and re-arms + immediately re-runs the 60s audit interval if it goes stale beyond a bounded multiple of the cadence, so a silently dropped audit driver self-heals instead of leaving active agents unrepaired for hours. - Tracks consecutive non-advancing zombie-timer re-arms per agent (nonAdvancingRearmState) and escalates once the count crosses a threshold, recording consecutiveNonAdvancingRearms/nonAdvancingEscalated in agent.metadata.heartbeatTimerRepair and logging reason=heartbeat-rearm-nonadvancing-escalated instead of silently churning the same zombie-timer-rearmed repair forever. - Clears non-advancing rearm state on unregister, non-eligible agents, paused settings, and stale-run-reap skip paths so tracking never leaks stale per-agent counters. - Watchdog and its interval handle are armed in start() and cleared in stop() alongside the existing audit interval. - Adds a changeset (patch) describing the fix, and updates docs/agents.md and docs/architecture.md to document the FN-7939 audit watchdog and non-advancing escalation behavior. - Adds heartbeat-scheduler.test.ts coverage for watchdog re-arm/liveness and non-advancing escalation. Files changed: .changeset/fn-7939-heartbeat-audit-supervision.md | 7 + docs/agents.md | 8 +- docs/architecture.md | 1 + .../src/__tests__/heartbeat-scheduler.test.ts | 209 +++++++++++++++++++++ packages/engine/src/agent-heartbeat.ts | 128 ++++++++++++- 5 files changed, 341 insertions(+), 12 deletions(-) Fusion-Task-Id: FN-7939 Fusion-Task-Lineage: 9fa90240-4333-4588-b595-aef3811b1524 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
316d4fa034 |
FN-7941: anchor execute-requeue loop guard to monotonic terminal-step progress
Hardens the FN-7863 execute-node self-requeue loop guard so residual execute_loop_stall cases (#2043/#2045/#2046/#2047) can no longer reset the loop counter forever via non-terminal signature drift. - Change buildExecuteRequeueLoopSignature to track terminal step count (done/skipped) plus total step count instead of raw currentStep + every step status, so pending/in-progress oscillation no longer produces a "new" signature each cycle. - Add buildExecuteRequeueLoopHighWaterSignature, which derives current terminal-step progress via the shared signature parser (parseExecuteRequeueLoopProgressSignature) and only resets the streak on monotonic forward progress, keeping a high-water mark across cycles so decreases/oscillation below the high-water still count toward exhaustion. - Update executor.ts's execute self-requeue dispatch path to use the new high-water helper when deciding whether to reset (1) or increment executeRequeueLoopCount, replacing the previous raw signature-equality check. - Extend execute-requeue-loop-guard.test.ts with regression coverage: a drifting-signature case that oscillates step order/status with no terminal progress (still terminalizes at MAX_EXECUTE_REQUEUE_LOOP_CYCLES), a done/in-progress oscillation case bounded after the high-water stops increasing, and an updated "real progress never terminalizes" case driven by genuine monotonic done-step advancement. - Update docs/architecture.md's FN-7863/FN-7926 self-healing notes to describe the new terminal-step high-water signature and cross-reference FN-7941. Files changed: docs/architecture.md | 4 +- .../execute-requeue-loop-guard.test.ts | 83 +++++++++++++++++++++- packages/engine/src/executor.ts | 54 ++++++++++++-- 3 files changed, 130 insertions(+), 11 deletions(-) Fusion-Task-Id: FN-7941 Fusion-Task-Lineage: cbf1e536-d29b-40da-bdd8-8c34d8d6b1ca Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
502c4c132f |
chore(release): v0.59.0
Version bump via changesets. |
||
|
|
9ba8a2e575 |
FN-7932: add per-lane Reviewer and Planning thinking-level overrides
Adds validatorThinkingLevel and planningThinkingLevel task fields so the Reviewer and Planning AI lanes can override reasoning effort independently of the shared task thinkingLevel, with dashboard UI, storage, and runtime fallback wiring. - Add validatorThinkingLevel and planningThinkingLevel to Task/TaskCreateInput types (packages/core/src/types.ts) - Persist the new fields in the SQLite schema and store read/write/replication paths (packages/core/src/db.ts, store.ts, mesh-task-replication.ts) - Wire executor and triage lanes to fall back per-lane thinking level -> task.thinkingLevel -> existing settings/lane fallback (packages/engine/src/executor.ts, triage.ts) - Add per-lane thinking-level selectors to the ModelSelectorTab UI, alongside the existing thinking-level control (packages/dashboard/app/components/ModelSelectorTab.tsx) - Expose the new fields through the legacy task API and task-workflow routes (packages/dashboard/app/api/legacy.ts, packages/dashboard/src/routes/register-task-workflow-routes.ts) - Document the new settings in dashboard-guide.md and settings-reference.md - Add a minor changeset and unit/integration test coverage for store persistence, routes, UI, and agent-session helpers Files changed: .changeset/per-lane-task-thinking.md | 7 ++ docs/dashboard-guide.md | 2 + docs/settings-reference.md | 2 +- .../src/__tests__/store-thinking-levels.test.ts | 43 +++++++ packages/core/src/db.ts | 15 ++- packages/core/src/mesh-task-replication.ts | 4 + packages/core/src/store.ts | 24 +++- packages/core/src/types.ts | 12 ++ packages/dashboard/app/api/legacy.ts | 2 + .../dashboard/app/components/ModelSelectorTab.tsx | 126 ++++++++++++++++++++- .../components/__tests__/ModelSelectorTab.test.tsx | 50 +++++++- .../src/__tests__/routes-tasks-ops.test.ts | 74 ++++++++++++ .../src/routes/register-task-workflow-routes.ts | 19 +++- .../src/__tests__/agent-session-helpers.test.ts | 15 +++ packages/engine/src/executor.ts | 16 ++- packages/engine/src/triage.ts | 8 +- 16 files changed, 395 insertions(+), 24 deletions(-) Fusion-Task-Id: FN-7932 Fusion-Task-Lineage: 4202f774-aab9-41d2-86a0-f5277dd0f848 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
f7e942e6f4 |
fix: resolve all full-suite failures + add structural mock-completeness gate check (round 10) (#2040)
## Summary
Fixes ALL failing shards from the latest full-suite run (29225946428)
AND adds a structural gate check to prevent the recurring mock-export
drift pattern that has caused every full-suite failure across rounds
1–9.
## What broke (run 29225946428, commit
|
||
|
|
6dcecb0c34 |
FN-7926: park completed-but-blocked tasks instead of looping execute-requeue
Stops the execute → pause-abort → re-queue-to-todo infinite loop for tasks whose implementation work is done but a dependency/blockedBy blocker is still live, by diverting them into a dedicated parked state instead of feeding the FN-7863 no-progress backstop or looping forever. - Add TaskExecutor.parkCompletedBlockedTask(): when work is complete but getTaskCompletionBlocker() still reports a blocker, park the task in todo with pausedReason:"completed-work-blocked", status:"queued", preserved worktree/branch/steps, and a cleared execute-requeue signature. - Replace shouldFinalizeCompletedTask's boolean with getCompletedTaskFinalizationDecision() returning "finalize" | "blocked" | "incomplete" so both the paused-after-completion and finalization call sites can react to the new "blocked" outcome without re-entering execution. - Divert completed-but-blocked tasks before the FN-7863 execute-requeue-loop counter increments, so waiting-on-dependency states are no longer misclassified as EXECUTION_DISPATCH_LOOP_EXHAUSTED. - Add SelfHealingManager.reconcileCompletedBlockedTasks(): a bounded sweep (wired into both startup/maintenance and periodic self-healing passes) that clears the park and advances the task to review once getTaskCompletionBlockerForStore() resolves, guarded by auto-merge eligibility, user-pause, and live-execution checks; failed advances re-park rather than strand the row. - Add run-audit mutation types task:completed-blocked-parked and task:completed-blocked-advanced (ids/counts/outcomes-only metadata) plus AGENTS.md/docs/architecture.md entries documenting the new lifecycle. - Extend execute-requeue-loop-guard.test.ts with coverage for the park/advance flow, including the zero-step task edge case. Files changed: AGENTS.md | 1 + docs/architecture.md | 2 + .../execute-requeue-loop-guard.test.ts | 256 ++++++++++++++++++++- packages/engine/src/executor.ts | 85 ++++++- packages/engine/src/run-audit.ts | 4 + packages/engine/src/self-healing.ts | 95 ++++++++ 6 files changed, 432 insertions(+), 11 deletions(-) Fusion-Task-Id: FN-7926 Fusion-Task-Lineage: e47945f4-a816-447e-9ea1-7c13105d0ba9 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
1ea185daa5 |
FN-7911: add workflow validate dry-run command, tool, and API route
Adds a non-mutating `fn workflow validate` dry-run path across CLI, agent tools, and dashboard API so custom workflow IR can be checked before create/update. - Add `packages/cli/src/commands/workflow.ts` implementing `fn workflow validate <id> | --file <path>` with JSON/text output, wired into `bin.ts`. - Add `fn_workflow_validate` agent tool (`agent-tools.ts`, `index.ts`) reusing the existing parseWorkflowIr/trait/code-node/column-agent validation used by create/update, performing no persistence. - Add `POST /api/workflows/validate` route in `register-workflow-routes.ts` plus dashboard route test coverage. - Extend heartbeat tool-gating/exposure tests and gating classifications to include `fn_workflow_validate` alongside the other workflow tools. - Update CLI/agent extension docs (`docs/cli-reference.md`, `docs/agents.md`, `docs/workflow-steps.md`, fusion skill references) to document the new command/tool. - Add changeset `.changeset/fn-7911-workflow-validate.md` (minor) describing the new capability. Files changed: .changeset/fn-7911-workflow-validate.md | 7 ++ docs/agents.md | 5 +- docs/cli-reference.md | 13 ++ docs/workflow-steps.md | 3 +- packages/cli/skill/fusion/SKILL.md | 2 +- .../cli/skill/fusion/references/extension-tools.md | 10 ++ .../skill/fusion/references/fusion-capabilities.md | 1 + .../src/__tests__/extension-workflow-tools.test.ts | 1 + packages/cli/src/__tests__/extension.test.ts | 1 + .../src/__tests__/workflow-docs-current.test.ts | 1 + packages/cli/src/bin.ts | 22 ++++ packages/cli/src/commands/workflow.ts | 80 ++++++++++++ packages/cli/src/extension.ts | 10 ++ .../dashboard/src/__tests__/chat-manager.test.ts | 1 + .../dashboard/src/__tests__/chat.rooms.test.ts | 1 + .../planning-document-tools-exposure.test.ts | 1 + .../__tests__/workflow-validate-route.test.ts | 101 +++++++++++++++ .../src/routes/register-workflow-routes.ts | 27 +++- .../engine/src/__tests__/agent-action-gate.test.ts | 2 +- .../agent-workflow-tools-exposure.test.ts | 70 ++++++++++- .../src/__tests__/gating-classifications.test.ts | 3 +- .../src/__tests__/heartbeat-executor.test.ts | 37 +++--- .../src/__tests__/heartbeat-session-prompt.test.ts | 5 +- .../src/__tests__/permanent-agent-gating.test.ts | 2 +- packages/engine/src/agent-heartbeat.ts | 5 +- packages/engine/src/agent-tools.ts | 140 ++++++++++++++++++++- packages/engine/src/executor.ts | 6 + packages/engine/src/gating-classifications.ts | 2 + packages/engine/src/index.ts | 4 + 29 files changed, 532 insertions(+), 31 deletions(-) Fusion-Task-Id: FN-7911 Fusion-Task-Lineage: 903d15fe-a7ec-458f-aa34-8f2e895a9603 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
9f8db7d1b5 |
FN-7903: wire thinkingLevel into AI session creation for automation steps
Threads the persisted per-step Thinking Level (from FN-7900) into runtime AI session creation and task spawning, so scheduled, routine, and manual automation runs actually apply the chosen reasoning effort instead of only storing it. - CronRunner passes step.thinkingLevel through AiPromptExecutor to createFnAgent's defaultThinkingLevel for scheduled AI-prompt steps - RoutineRunner forwards step.thinkingLevel to the shared AiPromptExecutor seam for routine AI-prompt steps - Cron/routine create-task steps map step.thinkingLevel onto TaskCreateInput.thinkingLevel so spawned tasks inherit the configured reasoning effort - Dashboard's inline/manual AI-prompt and create-task automation routes apply the same defaultThinkingLevel / TaskCreateInput.thinkingLevel behavior - Updated docs (dashboard-guide.md, settings-reference.md) to describe the now-active runtime behavior - Added a changeset for @runfusion/fusion (minor) and expanded cron-runner/routine-runner/routes-automation test coverage Files changed: .changeset/fn-7903-automation-thinking-level.md | 7 ++ docs/dashboard-guide.md | 5 +- docs/settings-reference.md | 2 +- .../src/__tests__/routes-automation.test.ts | 67 +++++++++++++++++++ packages/dashboard/src/routes.ts | 10 +++ packages/engine/src/__tests__/cron-runner.test.ts | 75 +++++++++++++++++++++- .../engine/src/__tests__/routine-runner.test.ts | 68 +++++++++++++++++++- packages/engine/src/cron-runner.ts | 21 +++++- packages/engine/src/routine-runner.ts | 11 +++- 9 files changed, 255 insertions(+), 11 deletions(-) Fusion-Task-Id: FN-7903 Fusion-Task-Lineage: c7eb4660-975d-4c5d-820e-0f1a3ac8b6a6 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
d4bbbcccc6 |
fix: stop Ideas-intake cards from auto-processing and keep replans in the workflow's own planner column
Root cause of the reported incident: store init ran the retired flag-off evacuation on every open, dumping Coding (Ideas) intake cards into triage where they were auto-planned and executed. Init now always runs the workflow-aware integrity pass (with a stale-selection mis-mapping guard and per-pass IR memoization) and evacuation remains toggle-only. Engine rebounds (Plan Review REVISE, stale-spec, fs-validation) resolve a workflow-aware replan column instead of hardcoding triage; needs-replan now counts as unplanned for hold-release dispatch so rejected plans cannot re-execute; triage rediscovers needs-replan todo cards and refinement seed prompts (shared buildRefinementSeedPrompt/isUnplannedSeedPrompt); the fs-validation rebound sets needs-replan so unreadable-prompt tasks re-spec instead of livelocking. Dashboard: the All-workflows board renders column-orphaned tasks instead of silently dropping them (hidden columns stay hidden), and the FN-7591 refetch also fires for present-but-unrepresentable workflow mappings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
7a51f95b38 |
FN-7901: persist thinkingLevel for insight model selection
Adds a persisted Thinking Level (reasoning-effort) selector to manual insight generation, threading the selection through the dashboard API, insight run metadata, and retries. - Add inline Thinking Level selector to the InsightsView model-config popover, persisted to localStorage (fusion-insight-thinking) - Thread thinkingLevel through triggerInsightRun (legacy API client) and useInsights.runInsights - Validate and store thinkingLevel in insight run inputMetadata.metadata on the POST /insights/run route; resolve it via resolvePlanningThinkingLevel for the actual generation call - Recover and reapply the original run's thinkingLevel on retry (retryInsightRunLifecycle) so retries reuse the same reasoning-effort setting - Export resolvePlanningThinkingLevel from @fusion/engine - Document the new Thinking Level selector in docs/dashboard-guide.md - Add a minor changeset for @runfusion/fusion Files changed: .changeset/fn-7901-insight-thinking-level.md | 7 ++ docs/dashboard-guide.md | 1 + .../app/__tests__/insight-model-selector.test.tsx | 41 ++++++++++- packages/dashboard/app/api/legacy.ts | 2 + packages/dashboard/app/components/InsightsView.tsx | 24 +++++- .../app/hooks/__tests__/useInsights.test.ts | 36 ++++++++- packages/dashboard/app/hooks/useInsights.ts | 6 +- .../src/__tests__/insights-routes.test.ts | 86 ++++++++++++++++++++++ packages/dashboard/src/insights-routes.ts | 36 ++++++++- packages/engine/src/index.ts | 1 + 10 files changed, 227 insertions(+), 13 deletions(-) Fusion-Task-Id: FN-7901 Fusion-Task-Lineage: a6249526-e97d-403e-b853-e497d16f425b Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
2e7fce21ae |
FN-7884: reset durable-agent error state on engine restart
Engine startup now treats itself as an implicit operator retry for durable heartbeat agents stuck in error, clearing eligible error states and re-arming heartbeats instead of waiting for the steady-state sweep's cooldown/exhaustion gates. - Add SelfHealingManager.resetDurableAgentErrorStateOnStartup(), run first in runStartupRecovery(), which resets shared heartbeatErrorRecovery/legacy durableErrorRecovery metadata, clears lastError/pauseReason, flips eligible error and error-retry-exhausted-parked durable agents to active, and re-arms their heartbeat - Preserve suppression for operator-actionable, stale worktree/module-resolution, user-paused, error-unrecoverable, ephemeral, disabled-runtime, and actively-executing agents - Add agent:reset-error-state-on-startup run-audit mutation type with ids/counts/outcomes-only metadata (agentId, priorState, priorPauseReason, source) - Add changeset FN-7884 (patch) documenting the operator-facing behavior - Update AGENTS.md and docs/agents.md, docs/architecture.md to describe the new startup reset path alongside existing FN-7835/FN-7844/FN-7859/FN-7878 recovery docs - Extend self-healing.test.ts with coverage for the new startup reset behavior and its exclusions Files changed: .changeset/fn-7884-restart-error-reset.md | 7 ++ AGENTS.md | 1 + docs/agents.md | 4 +- docs/architecture.md | 2 +- packages/engine/src/__tests__/self-healing.test.ts | 127 ++++++++++++++++++++- packages/engine/src/run-audit.ts | 1 + packages/engine/src/self-healing.ts | 88 +++++++++++++- 7 files changed, 223 insertions(+), 7 deletions(-) Fusion-Task-Id: FN-7884 Fusion-Task-Lineage: fe64f6af-3ff3-4876-8308-8a75591c45f1 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
c745990aa2 |
FN-7879: deliver one-time Postgres-migration inbox notice on first 0.59 startup
Adds a best-effort, idempotent dashboard inbox notice announcing the upcoming embedded-Postgres storage migration, delivered once per project on the first engine start under the Fusion 0.59.x release line. - New `deliverPostgresMigrationNoticeIfNeeded` in `@fusion/engine` (`postgres-migration-notice.ts`) builds and sends a `system` -> `user` inbox message via `MessageStore`, gated to version `0.59.x` by `isPostgresMigrationNoticeVersion` - Idempotency via existing inbox message `metadata.kind = "postgres-migration-notice"` marker (no new settings key or table), so restarts never duplicate the notice - Delivery is fully best-effort: any `MessageStore` failure is caught, logged as a warning, and never blocks or fails `ProjectEngine.start()` - `ProjectEngine.start()` invokes the notice after runtime start, using an injected `cliPackageVersion` threaded from the CLI layer through `EngineManagerOptions` / `ProjectEngineOptions` so the engine never imports CLI/dashboard code directly - `daemon.ts`, `dashboard.ts`, and `serve.ts` resolve the published `@runfusion/fusion` version via `getCliPackageVersion` / `isUnresolvedCliPackageVersion` and pass it into `ProjectEngineManager` - Exported new symbols (`POSTGRES_MIGRATION_HELP_URL`, `POSTGRES_MIGRATION_NOTICE_KIND`, `deliverPostgresMigrationNoticeIfNeeded`, `isPostgresMigrationNoticeVersion`, related types) from `@fusion/engine`, and `isUnresolvedCliPackageVersion` from `@fusion/dashboard` - New unit tests covering version matching and single-delivery/idempotency behavior - Docs updated (`docs/agents.md`, `docs/dashboard-guide.md`) to describe the one-time notice and its dedup key - Changeset added for `@runfusion/fusion` (minor, feature) Files changed: .changeset/fn-7879-postgres-migration-inbox-notice.md | 7 ++ docs/agents.md | 1 + docs/dashboard-guide.md | 1 + packages/cli/src/commands/daemon.ts | 6 +- packages/cli/src/commands/dashboard.ts | 5 + packages/cli/src/commands/serve.ts | 6 +- packages/dashboard/src/index.ts | 2 +- packages/engine/src/__tests__/postgres-migration-notice.test.ts | 140 +++++++++++++++++++++ packages/engine/src/index.ts | 9 ++ packages/engine/src/postgres-migration-notice.ts | 107 ++++++++++++++++ packages/engine/src/project-engine-manager.ts | 6 + packages/engine/src/project-engine.ts | 12 ++ 12 files changed, 299 insertions(+), 3 deletions(-) Fusion-Task-Id: FN-7879 Fusion-Task-Lineage: 201877e5-6bdc-4168-a8ac-ae0e50ec8308 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
504dc69f02 |
FN-7878: default heartbeat error recovery to recoverable for generic durable-agent failures
Durable agents were parking as error-unrecoverable on any non-transient-pattern failure, even generic/unknown blips that manual Retry immediately fixed; this changes the default to recoverable and reserves immediate unrecoverable parking for operator-actionable errors. - isHeartbeatErrorRecoverable now returns true unless the error is operator-actionable (auth/model/billing/scope) or a stale worktree/module-resolution error, instead of requiring a transient-pattern match via classifyError - Add OAuth scope-requirement and insufficient-scope patterns to the operator-actionable error detector so those still park immediately - Update heartbeat-error-recovery, heartbeat-executor, self-healing, and transient-error-detector tests to cover the new default-recoverable behavior - Update AGENTS.md and docs/architecture.md durable-agent error recovery notes to describe the new recoverable-by-default policy - Add changeset documenting the fix Files changed: .changeset/fn-7878-recoverable-default.md | 7 ++ AGENTS.md | 2 +- docs/architecture.md | 4 +- .../src/__tests__/heartbeat-error-recovery.test.ts | 90 +++++++++++++++++++--- .../src/__tests__/heartbeat-executor.test.ts | 17 ++-- packages/engine/src/__tests__/self-healing.test.ts | 45 ++++++----- .../src/__tests__/transient-error-detector.test.ts | 7 +- packages/engine/src/agent-heartbeat.ts | 8 +- packages/engine/src/transient-error-detector.ts | 2 + 9 files changed, 137 insertions(+), 45 deletions(-) Fusion-Task-Id: FN-7878 Fusion-Task-Lineage: 6f929af9-ceef-404f-95c9-98f26478f020 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
cbe07ee86b |
fix(engine): address PR #2027 review — tighten auth exclusions, accurate park accounting
- Exclude revoked/suspended/disabled/deactivated keys, inactive subscriptions, and locked accounts from the transient-auth classifier: no retry fixes those, so they stay operator-actionable even inside an authentication_error envelope. - Self-healing sweep logs unrecoverable-error parks separately from recovered-to-active agents (return value still counts actions taken). - Document same-session retry continuation semantics at the heartbeat withRateLimitRetry call site (side-effect replay concern). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c4fad2d793 |
fix(engine): auto-recover agents from transient OAuth token-rotation 401s
A routine Claude Max OAuth token rotation (~8h) fails the in-flight call with 401 authentication_error "Invalid authentication credentials" even though refreshed credentials already exist on disk. Three compounding defects turned that into a fleet-wide operator-action park: - The heartbeat prompt path never ran under withRateLimitRetry (executor/ triage/merger all do), so the 401 immediately failed the run. Now wrapped. - The 401 matched the operator-actionable /credential/ pattern and defaulted to "permanent", so FN-7859 parked agents paused/error-unrecoverable. A new shared isTransientAuthCredentialError classifier (also used by rate-limit-retry) classifies rotation 401s transient + not operator- actionable; OAuth scope-grant and API-key failures still park. - Heartbeat failure classification ran on the stack-bearing error detail; stack frames like "at withRateLimitRetry (.../rate-limit-retry.ts)" match the usage-limit /rate[_\s]?limit/ pattern. Classification and agent.lastError now use the message; stderrExcerpt keeps the full detail. Self-healing additionally un-parks agents previously paused with error-unrecoverable whose lastError now classifies recoverable, bounded by the shared heartbeat error-recovery budget. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
ee7af2513f |
fix(MAIN-008): address PR review feedback (#2020)
- Label namespaced mcp__* tools as resourceType "mcp" (not "research") so approvals/audit/dedupe keys describe external MCP actions - Guard getTask in resumeApprovalAfterUnwindIfNeeded so deferred resume cannot mask execute() finally outcomes |
||
|
|
b688266a02 |
test(MAIN-008): complete Step 4 — validate shared MCP lifecycle surfaces
Agent: engineer Fusion-Task-Id: MAIN-008 Co-authored-by: Fusion <noreply@runfusion.ai> |
||
|
|
555f916ebb |
fix(MAIN-008): complete Step 3 — resume approved MCP calls once
Agent: engineer Fusion-Task-Id: MAIN-008 Co-authored-by: Fusion <noreply@runfusion.ai> |
||
|
|
e977fadda9 |
fix(MAIN-008): complete Step 2 — stabilize MCP executor bootstrap
Agent: engineer Fusion-Task-Id: MAIN-008 Co-authored-by: Fusion <noreply@runfusion.ai> |
||
|
|
bc30ce8aa1 |
FN-7857: deliver plugin skill bodies to agent sessions and the Skills view
Plugin-contributed skills previously registered only a name for sessions and the dashboard, so their SKILL.md bodies were never actually loaded — fix threads real body paths through to both session creation and the Skills UI. - Resolve each enabled plugin skill's body path via @fusion/core's resolvePluginSkillBodyPath and thread its body dir (plus parent dir) into every session-creating lane (executor primary/retry/verification-fix/step/child-agent, triage, reviewer, merger, agent-heartbeat, cron-runner) as additionalSkillPaths, unioned with existing CE skill dirs. - Add collectPluginSkillNames/mergePluginSkills additionalSkillPaths plumbing in session-skill-context.ts so plugin skill discovery paths flow the same way as native/role-fallback skills. - Update dashboard skills-adapter.ts to read plugin skill SKILL.md and reference files from disk (via the traversal-guarded reader) instead of returning a runtime-placeholder/"not found" response for plugin-sourced skills. - Document the plugin skill body delivery mechanism in docs/PLUGIN_AUTHORING.md. - Add regression coverage: plugin-skill-body-delivery.test.ts, expanded session-skill-context.test.ts and skills-adapter.test.ts. - Add changeset fn-7857-plugin-skill-body-delivery.md (minor, fix). Files changed: .changeset/fn-7857-plugin-skill-body-delivery.md | 7 ++ docs/PLUGIN_AUTHORING.md | 3 + .../dashboard/src/__tests__/skills-adapter.test.ts | 92 ++++++++++++++++------ packages/dashboard/src/skills-adapter.ts | 33 ++------ .../__tests__/plugin-skill-body-delivery.test.ts | 75 ++++++++++++++++++ .../src/__tests__/session-skill-context.test.ts | 84 +++++++++++++++++++- packages/engine/src/agent-heartbeat.ts | 3 +- packages/engine/src/cron-runner.ts | 2 + packages/engine/src/executor.ts | 25 ++++-- packages/engine/src/merger.ts | 10 ++- packages/engine/src/reviewer.ts | 2 + packages/engine/src/session-skill-context.ts | 43 ++++++++-- packages/engine/src/step-session-executor.ts | 5 +- packages/engine/src/triage.ts | 3 +- 14 files changed, 318 insertions(+), 69 deletions(-) Fusion-Task-Id: FN-7857 Fusion-Task-Lineage: 9ba4c305-8b38-4ae8-85b3-4c87205ef767 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
7fccd73d84 | test(engine): update moveTask 3rd-arg assertion undefined -> {} (executor pause-abort always passes options object) | ||
|
|
73172bb45c | test(engine): update heartbeat expectations for FN-7835/FN-7859 error-unrecoverable reason + paused state transitions | ||
|
|
8d59df4531 | test(engine): add wrapToolsWithRtkRewrite/PermanentAgentGating/ActionGate to pi.js mocks (openclaw + reviewer) | ||
|
|
95a808af6e |
FN-7864: add inline artifact preview/link to artifact-registered mail messages
Artifact-registration mailbox notifications now render a shared inline preview and open-artifact link instead of plain text metadata. - Add MailboxArtifactAttachment component rendering an inline image/document preview plus an "open artifact" link from message.metadata (artifactId/artifactType/mimeType) via artifactMediaUrl - Wire MailboxModal and MailboxView to render the new attachment for artifact-registered messages, with supporting CSS - Emit metadata.mimeType from notifyArtifactRegistered in agent-tools.ts so mailbox surfaces can pick the right preview affordance without an extra artifact fetch - Add/extend tests for the new component and for MailboxView/agent-artifact-tools coverage - Update dashboard guide docs and add a changeset for the feature Files changed: .changeset/fn-7864-artifact-mail-link.md | 7 ++ docs/dashboard-guide.md | 2 +- .../app/components/MailboxArtifactAttachment.tsx | 103 +++++++++++++++++++++ packages/dashboard/app/components/MailboxModal.css | 74 +++++++++++++++ packages/dashboard/app/components/MailboxModal.tsx | 15 +++ packages/dashboard/app/components/MailboxView.tsx | 15 +++ .../__tests__/MailboxArtifactAttachment.test.tsx | 65 +++++++++++++ .../app/components/__tests__/MailboxView.test.tsx | 93 +++++++++++++++++++ .../src/__tests__/agent-artifact-tools.test.ts | 32 ++++++- packages/engine/src/agent-tools.ts | 5 + 10 files changed, 409 insertions(+), 2 deletions(-) Fusion-Task-Id: FN-7864 Fusion-Task-Lineage: a6502e18-5f7f-4c67-80fb-a709e4a52c50 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
9cfb40e137 |
FN-7863: add bounded execute-node self-requeue loop guard
Bounds the execute->pause-abort->todo dispatch loop so a task can no longer requeue forever with no visible signal or terminal state. - Track a progress-anchored `executeRequeueLoopCount`/`executeRequeueLoopSignature` pair on the task row (current step + step statuses) so slow no-progress requeue cycles are counted independently of the scheduler's wall-clock `dispatchStormCount` guard. - Warn visibly in the task log at `EXECUTE_REQUEUE_LOOP_VISIBLE_THRESHOLD` (3) and terminalize non-paused, non-terminal tasks at `MAX_EXECUTE_REQUEUE_LOOP_CYCLES` (6) with `status:"failed"` and an `EXECUTION_DISPATCH_LOOP_EXHAUSTED:` error, preserving worktree/branch/step progress. - Emit a new `task:execution-dispatch-loop-terminalized` run-audit mutation type with ids/counts/outcomes-only metadata. - Reset the loop counters on real progress, manual retry, forward moves (in-review/done/archived), and unpause, in both the executor and scheduler. - Add DB migration 142 (`executeRequeueLoopCount`, `executeRequeueLoopSignature` columns) plus store read/write/reset plumbing. - Add reliability-interactions coverage for the new loop guard and extend store-persistence tests for the new columns. - Document the new behavior in AGENTS.md and docs/architecture.md. Files changed: AGENTS.md | 1 + docs/architecture.md | 2 + packages/core/src/__tests__/store-persistence.test.ts | 45 +++++ packages/core/src/db.ts | 17 +- packages/core/src/manual-retry-reset.ts | 1 + packages/core/src/store.ts | 22 ++- packages/core/src/types.ts | 11 ++ .../execute-requeue-loop-guard.test.ts | 188 +++++++++++++++ packages/engine/src/executor.ts | 67 +++++++- packages/engine/src/run-audit.ts | 2 + packages/engine/src/scheduler.ts | 8 +- 11 files changed, 355 insertions(+), 9 deletions(-) Fusion-Task-Id: FN-7863 Fusion-Task-Lineage: db40507f-5851-435e-8854-c1ed695b4154 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
0c97c161ee |
FN-7860: honor plugin skillFiles paths for skill body resolution
Plugin skills declared with PluginSkillContribution.skillFiles were silently ignored by the host, forcing plugin authors into a flat skills/<name>/SKILL.md layout instead of category subdirectories. - Add packages/core/src/plugin-skill-paths.ts with resolvePluginSkillBodyPath (honors skillFiles[0] relative to plugin root, falls back to skills/<name>/SKILL.md, rejects path traversal) and resolvePluginRootFromEntryPath - Track per-plugin absolute roots in PluginLoader and expose pluginRoot alongside each getPluginSkills() contribution - Thread pluginRoot/skillFiles through PluginRunner, dashboard server/chat structural types, and skills-adapter so discovered plugin skill path/relativePath resolve via the new traversal-guarded resolver when a pluginRoot is available, keeping the old name-derived path for backward compatibility otherwise - Export resolvePluginSkillBodyPath/resolvePluginRootFromEntryPath/PluginSkillBodyPath from @fusion/core - Update docs/PLUGIN_AUTHORING.md and add unit tests covering the new resolver and updated plugin-loader/skills-adapter/plugin-runner behavior - Add changeset (@runfusion/fusion: minor, category: fix) Files changed: .changeset/fn-7860-plugin-skillfiles.md | 7 ++ docs/PLUGIN_AUTHORING.md | 4 +- packages/core/src/__tests__/plugin-loader.test.ts | 23 +++++++ .../core/src/__tests__/plugin-skill-paths.test.ts | 75 ++++++++++++++++++++++ packages/core/src/index.ts | 5 ++ packages/core/src/plugin-loader.ts | 20 +++++- packages/core/src/plugin-skill-paths.ts | 58 +++++++++++++++++ .../dashboard/src/__tests__/skills-adapter.test.ts | 75 +++++++++++++++++++++- packages/dashboard/src/chat.ts | 2 +- packages/dashboard/src/server.ts | 2 +- packages/dashboard/src/skills-adapter.ts | 19 ++++-- .../engine/src/__tests__/plugin-runner.test.ts | 2 +- packages/engine/src/plugin-runner.ts | 4 +- 13 files changed, 280 insertions(+), 16 deletions(-) Fusion-Task-Id: FN-7860 Fusion-Task-Lineage: 720cf527-9c6f-4877-838e-5fb64bd86556 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
67cc025562 |
FN-7859: park non-recoverable durable heartbeat errors instead of stalling in bare error
Debug org agents error state recovery regression: durable heartbeat-managed agents with a non-recoverable error (permanent/credential/model-access/ config, not stale-worktree/module-resolution) were previously left indefinitely in bare `state:"error"` with no operator-visible reason, and CLI agent inspection tools did not surface error/pause diagnostics. - Timer path (`HeartbeatMonitor`) and run-entry recovery now classify non-recoverable durable heartbeat errors and park the agent `paused` with `pauseReason:"error-unrecoverable"` instead of restart-looping or sitting in `error` forever. - `SelfHealingManager` mirrors the same non-recoverable classification in its recovery sweep, parking with the same reason/metadata and skipping the exhausted/next-retry gates for that terminal bucket. - New `agent:error-parked-unrecoverable` run-audit event type emitted by both the heartbeat and self-healing paths (ids/counts/outcomes-only metadata). - `fn_agent_show` now prints `Last Error`, `Pause Reason`, and a compact `Error Recovery` counter line; `fn_list_agents` prints the same diagnostics only for agents currently in `error`/`paused`. - Updated `AGENTS.md`, `docs/agents.md`, and `docs/architecture.md` to document the new terminal-park behavior and CLI diagnostics surface. - Added a changeset (`@runfusion/fusion` patch) describing the operator-facing fix. Files changed: .changeset/fn-7859-org-agent-error-diagnostics.md | 7 ++ AGENTS.md | 2 +- docs/agents.md | 3 +- docs/architecture.md | 4 +- packages/cli/src/__tests__/extension.test.ts | 68 ++++++++++++++++ packages/cli/src/extension.ts | 64 +++++++++++++++ .../src/__tests__/heartbeat-error-recovery.test.ts | 47 ++++++++++- packages/engine/src/__tests__/self-healing.test.ts | 94 ++++++++++++++++++---- packages/engine/src/agent-heartbeat.ts | 71 +++++++++++++++- packages/engine/src/run-audit.ts | 1 + packages/engine/src/self-healing.ts | 46 +++++++++-- 11 files changed, 375 insertions(+), 32 deletions(-) Fusion-Task-Id: FN-7859 Fusion-Task-Lineage: 09b2035d-e8a0-438f-b1ab-1b0048b35c76 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
c13d2ee9c2 |
FN-7858: honor per-project plugin-skill toggles in session merging
Session skill merging (collectPluginSkillNames) previously ignored per-project Skills view enable/disable toggles and only consulted each plugin's static default, so a user disabling a plugin skill in the Skills view would still see it merged into live agent sessions. Extracted the effective-enablement resolver shared by dashboard discovery and engine session assembly into @fusion/core so both surfaces stay in sync. - Added packages/core/src/skill-settings.ts with computeSkillId/parseSkillId/ normalizeStoredSkillPath/getSkillSettingState/resolvePluginSkillEnabled, exported from @fusion/core's index. - packages/dashboard/src/skills-adapter.ts now re-exports and delegates to the shared @fusion/core resolver instead of duplicating its own getSkillSettingState/computeSkillId/parseSkillId implementations. - packages/engine/src/session-skill-context.ts: collectPluginSkillNames now accepts a projectRootDir, reads project settings via skill-resolver's newly exported readProjectSettings/resolveProjectRoot, and calls resolvePluginSkillEnabled instead of only checking the plugin's static skill.enabled flag; mergePluginSkills passes projectRootDir through. - packages/engine/src/skill-resolver.ts: exported readProjectSettings and ProjectSkillSettings for reuse by session-skill-context. - Updated docs/plugin-management.md to document that per-project Skills view toggles now apply to runtime agent sessions, not just discovery. - Added unit tests for the new core resolver and updated dashboard/engine tests to cover per-project toggle overrides in session merging. - Added a patch changeset for @runfusion/fusion. Files changed: .changeset/fn-7858-plugin-skill-session-toggle.md | 7 ++ docs/plugin-management.md | 4 +- packages/core/src/__tests__/skill-settings.test.ts | 62 +++++++++ packages/core/src/index.ts | 8 ++ packages/core/src/skill-settings.ts | 102 +++++++++++++++ .../dashboard/src/__tests__/skills-adapter.test.ts | 60 ++++++++- packages/dashboard/src/skills-adapter.ts | 107 +++------------- .../src/__tests__/session-skill-context.test.ts | 140 ++++++++++++++++++++- packages/engine/src/session-skill-context.ts | 23 +++- packages/engine/src/skill-resolver.ts | 4 +- 10 files changed, 409 insertions(+), 108 deletions(-) Fusion-Task-Id: FN-7858 Fusion-Task-Lineage: 90e44d24-e385-4a74-b8e4-3c864ec39a95 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
8b601810e0 |
fix(FN-7851): enforce per-agent assignment policy across all task-routing binding primitives
Issue #2015: product-code executor tasks were repeatedly routed to a liaison-only agent because every routing path gated only on the coarse role field, and several binding primitives had no guard at all. - Add runtimeConfig.assignmentPolicy ("auto" | "explicit-only" | "none"); "none" can never be bound to implementation tasks by ANY path — no override bypasses it (the liaison guarantee) - Route every binding surface through one shared evaluator (evaluateImplementationTaskBind): claimTaskForAgent, the previously unguarded checkoutTask/assignTask primitives, selectNextTaskForAgent (including the in-progress re-selection loop), scheduler auto-assign pool, heartbeat inbox/auto-claim, fn_delegate_task, CLI agent-id validation, and dashboard assign/checkout/inbox routes - Lock project isolation with a regression test: a foreign-project agent id is rejected by every binding primitive - Expose Assignment Policy in Agent Detail settings; document in docs/agents.md; add changeset Fusion-Task-Id: FN-7851 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
f23619c2d4 |
fix: preserve user pause across executor pause teardown (FN-7851 pause-bounce loop)
Pausing an in-progress task never stuck: the pause teardown re-queued the row to todo with a plain engine move, and the reopen block wiped paused/pausedByAgentId/pausedReason. The graph-failure classifier then saw an unpaused row, misread the hard-cancel as an engine-internal abort, and auto-continued the session (graphResumeRetryCount 1/2, 2/2); once the budget was exhausted the benign re-queue left the row dispatchable and the scheduler re-dispatched it seconds later — an indefinite pause/resume bounce, burning a fresh worktree + pnpm install per cycle. - store: new moveTask option `preservePause` keeps the pause park across a reopen-to-todo/triage move (flag-ON trait hook + flag-OFF legacy inline, kept in sync). It never SETS a pause, only prevents clearing one. - executor teardown: when the pause that caused the abort is still in force, move with preservePause so the row lands in todo still parked (scheduler skips paused/userPaused rows until explicit unpause). - classifier: a live task pause is labeled operator intent, never "engine abort during pause/resume"; the benign log now says "parked … awaiting explicit unpause" instead of the contradictory "cleared for normal scheduling" for parked rows. Surfaces covered by tests: flag-ON hook (preserve + never-set + default clear), classifier no-auto-continue for task-pause/user-pause/global-pause rows in todo, provenance labels. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |