**Problem:** Scheduler writes assumed a full missionStore contract
(getSlice/getMilestone), aborting/pre-resolving mission reconciliation
when a minimal store or a genuine missing mission was present.
**Fix:** Resolve a missing `missionId` best-effort through
`missionStore.getSlice`/getMilestone when available, and make
reconciliation non-blocking — a partial missionStore must not gate the
completion advance. Includes scheduler + pre.json rebase resolution over
the latest origin.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Added Grok 4.6 to the model catalog.
- Added archive and restore views for mailbox messages and chat
conversations.
- Added manager evaluation tools for reviewing agents and follow-up
actions.
- Updated the bundled Pi runtime.
- **Bug Fixes**
- Improved Quick Add model searching and dropdown toggling.
- Refined Quick Add merger labels and spacing.
- Recommendations now appear only for completed tasks with valid
recommendations.
- Improved scheduler resilience during mission updates and
reconciliation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: gsxdsm <gsxdsm@users.noreply.github.com>
**Problem:** The FN-8953 pending-wedge-notification reconciliation
called getActiveNotificationService() unconditionally at its top (to
read the wedge settle window), even against a healthy/empty notification
service — leaving a narrow test wedge where the service getter was
expected never to be called.
**Fix:** Guard `reconcilePendingWedgeNotifications` so the wedge
settle-window read does not fire against a healthy/empty notification
service, closing the stub gap and making the reconciliation
side-effect-free when idle.
Co-authored-by: Fusion <noreply@runfusion.ai>
## Summary
- preserve the gridlock notification wall-clock cooldown across
transient detector clears
- add a regression test for clear-then-rediscover behavior during the
cooldown
- document the cooldown contract and add a patch changeset
## Test plan
- `corepack pnpm --filter @fusion/engine exec vitest run
src/__tests__/notifier.test.ts --project=engine-default
--reporter=verbose -t 'suppresses the same gridlock after a transient
resolution during cooldown'`
- `corepack pnpm --filter @fusion/engine typecheck`
- `corepack pnpm build`
- `corepack pnpm changeset status --output
/tmp/fusion-gridlock-changeset-status.json`
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Bug Fixes**
- Gridlock notifications now remain suppressed during the 15-minute
cooldown, even if the condition temporarily clears and reappears.
- Prevents repeated notifications caused by transient detector-state
changes.
- **Documentation**
- Updated gridlock notification behavior documentation to reflect the
persistent cooldown.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
createFnAgent now delegates to createResolvedAgentSession — deriving the CLI
runtime hint (cursor/claude/grok/omp/hermes), mock/test-mode forcing, and
session:runtime-resolved visibility — using a host-registered default
PluginRunner keyed by project root (published by InProcessRuntime at plugin
init). DefaultPiRuntime re-enters via a __rawPiSession marker so the seam's
own pi bridge cannot recurse, and the raw constructor survives as
createPiAgentSessionRaw for that bridge and pi-internal tests.
Mission and milestone/slice interviews additionally pass their request-scoped
pluginRunner through the seam and prompt via the engine promptWithFallback
dispatcher (plugin CLI runtime sessions have no session.prompt()). This fixes
"Configured model cursor-cli/auto ... was not found in the pi model registry"
in mission planning while chat on the same model worked, and closes the same
gap for every remaining bare createFnAgent lane.
Also updates the pi skill-filtering test that still asserted pre-FN-9114
allow-list narrowing; requested skill names are ensure-present since FN-9114.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Keep visible Planning Mode controls bound to the current turn during asynchronous refreshes.
- preserve active question and plan-review workspaces during same-session hydration
- submit from live session state and retain dirty answers across response identity changes
- add desktop and mobile regression coverage for deferred hydration and stale Stop polling
- document the ownership race and add a patch changeset
Files changed:
.changeset/fn-9117-planning-turn-ownership.md | 7 +
.../suite-only-flakes-observed-register.md | 24 ++++
.../dashboard/app/components/PlanningModeModal.tsx | 141 ++++++++++++---------
.../PlanningModeModal.planning-flow.test.tsx | 132 +++++++++++++++++++
.../PlanningModeModal.ui-interactions.test.tsx | 20 +++
5 files changed, 265 insertions(+), 59 deletions(-)
Fusion-Task-Id: FN-9117
Fusion-Task-Lineage: 18d63f63-b532-49eb-a6d1-241e31c5b2c7
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Second root cause of the browser-back flake: the board is a lazy chunk
behind Suspense fallback={null} and waitForAppShell only proves the
header, so a synchronous getByText raced chunk resolution under
sharded-lane load (failure DOM showed a header-only page). The first
board lookup in both back-nav tests is now the async finder — the
correct wait mechanism, no widened timeouts. Complements the
once-queue purge fix; 3/3 solo runs green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Local e2e runs regenerated the fn-8602/fn-8607 baselines with small rendering
deltas and produced the FN-8806 task-title-stable-modal baselines that were
never checked in.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The FN-8923 drift guard was red on main: the fixture predated the FN-9047-9062
workspace wave and regeneration was blocked by 18 unclassified workspace
TaskStore methods. Classify the FN-9059 workspace coordination surface (lease
acquire/renew/release/reclaim/reconcile, land-intent record/resolve, fence-ref
recording, mergeWorkspaceWorktreeEntry, withValidWorkspaceLease as writers; the
inspect/list/find/validate reads as non-writers), regenerate the manifest, and
supply lifecycle verdicts for the 13 new call sites: lease/intent writes in the
land path are already-fenced by FN-9059 store-seam fence-token validation, the
land-failure note is benign-unfenced bookkeeping, and the remaining sites carry
their enclosing symbols' out-of-frontier verdicts. Also drops the deleted
diff-volume gate module from scannedModules.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An SSE subscription with a nonexistent projectId (stale client tab, e2e fixture
page using projectId "fixture") surfaced the PG startup-factory construction
chain as a 500 on every poll, filling operator logs with alarming
"failed to construct TaskStore" errors. Map project-not-found to a clean 404,
matching the project routes' existing handling.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The gate blocked approved clean-room squashes on per-file shrinkage with no
override path ("AI merge diff-volume gate blocked the approved squash").
Removed by operator decision: delete checkDiffVolume/DiffVolumeRegressionError,
the merge:diff-volume-blocked audit event, the runDiffVolumeGate call sites in
every legacy squash finalizer, the AI-merge pre-land check, and the
mergeDiffVolume* settings. File scope remains the pre-land guard; the
post-squash audit policy remains the shrinkage backstop.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The mobile-styles guard forbids raw px anywhere in the stylesheet,
comments included; the FN-8866 token-fix comment mentioned the named
steps' pixel values and tripped it. Reworded — CSS rules unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Root-cause fix for the order-sensitive 'closes board-opened main-panel
task detail on one browser back' flake: vi.clearAllMocks() clears calls
but never drops unconsumed mockResolvedValueOnce entries, and a plain
mockResolvedValue default does not purge them either — the once-queue
wins first. A prior test's unconsumed auth/settings/health/plugin-views
Once value poisoned the next test's first fetch, rendering an
auto-opened modal surface instead of the board. The global beforeEach
now mockReset()s every once-queue-prone API mock before re-applying its
default (fetchPluginDashboardViews gains an explicit empty default
since its factory impl dies with the reset). 4/4 consecutive full-file
runs green (was ~1-in-3 failing); no assertions changed, no quarantine
needed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dashboard bare-run repair, mock-drift cluster. Six route suites'
inline @fusion/engine mocks predated FN-8902's
DEFAULT_MODEL_REGISTRY_REFRESH_TIMEOUT_MS import and now wrap the
canonical createEngineMock fallback proxy; App.test's useTasks mock
becomes an importOriginal spread so the real mergeTaskSnapshot reaches
components, its Todo/graph tests move to FN-8762's plugin-view
enablement invariants (with a mockReset fix for a stale
mockResolvedValueOnce queue the clearAllMocks reset never drops); the
Mailbox lucide mock learns FN-9014's Archive icon; and two source-scan
tests repoint files moved by the #2398 domain-folder refactor
(app/api/agents/agents.ts, engine healing/self-healing-constants.ts),
both verified via git log --follow. Verified 10 files / 252 tests green
under their standard lane projects; both dashboard typechecks clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dashboard bare-run repair, route/store cluster. Real product regression
fixed: the FNXC:IntakeOwnership boundary replaced the 'Workflow ... not
found' message with a typed TaskIntakeOwnerResolutionError, so the
mission triage routes' message-pattern mapping stopped firing and an
unknown workflowId leaked as a 500 — both feature and slice triage
handlers now match the typed error structurally and return 404 (patch
changeset included). Everything else was stale fixtures behind the PG
cutover and recent seams: sse's mock stores learn getAsyncLayer, the
retry fixtures learn FN-8908's resetTerminalFailureAutoRecoveryBudget,
approve-plan tests materialize a real on-disk PROMPT.md per the
SpecLockApproval 409 contract (fingerprint assertion strengthened to
the always-hash contract), and the MCP settings route body pins the new
host-dependent fusionMemoryMcpAvailable field. Verified 7 files / 213
tests green under their assigned lane projects, src typecheck clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dashboard bare-run repair, component-drift cluster. All nine suites
were stale expectations behind cited intentional commits — no UI
regressions found: FN-8826's always-on WIP lifecycle badge
(TaskCard.oversight now asserts no overseer element instead of an empty
header), FN-8762's Todo Lists plugin extraction (MobileNavBar,
MainContent.graph-popout, useAppSettings repurposed to the
pluginDashboardViews contract, with a regression pin that the removed
todosEnabled field never returns), FN-8796's clock-arbitrated
mergeTaskSnapshot, FN-8797's prompt-only planning refresh, FN-8702's
767.98px phone-sheet boundary, FN-8764's primary-role split, and
FN-8947's added touch-target selector. Every update carries an FNXC
comment citing the causing commit. Verified 9 files / 293 tests green,
tsconfig.app.json typecheck clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The browser-lane suite regenerates these PNGs when it runs locally; six
regenerated baselines were swept into 9673f15c11 from the shared index.
Restore the committed baselines — no intentional visual re-baseline
happened.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dashboard bare-run repair, census/token cluster. Real product bugs: the
Command Center activity panel (FN-8866) and structural-mail badge
(FN-8872) referenced undefined --space-* tokens, zeroing their
gaps/padding — mapped to the defined named scale; the settings search
index lagged FN-8829/FN-9021 additions and FN-8855's requiredChecks
entry had no scroll anchor (now a SettingsTextRow). Test-side: the
theme census learns FN-8730's intentional midnight theme, and the
Chromium touch-resize suite self-gates with describe.runIf per the
sibling browser-lane convention (CI/FUSION_BROWSER_SMOKE_REQUIRE still
fail loudly; all 62 tests still run where Chromium exists).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Gateway 502/503/504 non-JSON bodies (for example Traefik "no available server")
were dumped as content-type diagnostics into the Planning error banner.
## What
- Retry post-merge target pushes after recognized transient Git
transport failures.
- Use a bounded schedule: the initial attempt plus two retries after 2s
and 5s.
- Apply the same helper to the unified fast path and the shared push
path used by divergence recovery and the soft-deprecated merger.
- Keep retry sleeps and subsequent attempts cancellation-aware.
- Add a patch changeset and regression coverage, including a real bare
remote that rejects the first push.
## Why
Fusion already retries non-fast-forward races, and #1942 made terminal
push failures durable, but a temporary network failure still ended
post-merge delivery after one attempt. That can leave the local
integration branch ahead of the remote even though retrying seconds
later would succeed.
The retry is deliberately provider-neutral. It uses Git error
classification and normal Fusion logs only; it does not add Telegram,
OpenClaw, or any other notification-vendor dependency.
## Behavior and impact
- Retries only transient transport signatures such as connection resets,
DNS failures, unreachable networks, selected HTTP 429/5xx RPC failures,
and unexpected disconnects.
- Permission, authentication, configuration, and ref-rejection errors
keep their existing immediate handling.
- Exhausted retries remain non-fatal to the already-landed merge and
flow through the existing audit/task-log failure reporting.
- Existing non-fast-forward pull/rebase recovery is unchanged apart from
making its backoff cancellation-aware.
## Checks
- [x] `pnpm --filter @fusion/engine exec vitest run
src/__tests__/merger-ai-push-after-merge.test.ts
src/__tests__/merger-prompt-and-utils.test.ts --silent=passed-only
--reporter=dot` (48 tests)
- [x] `pnpm --filter @fusion/engine typecheck`
- [x] `pnpm lint` (0 errors; 2 pre-existing warnings)
- [x] `pnpm check:changesets --strict`
- [x] `pnpm check:fnxc-future-dates`
- [x] `pnpm test` (changed-test gate; static checks and 688 tests
passed)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved reliability of post-merge pushes by retrying temporary Git
transport failures.
* Added bounded backoff between retries to prevent excessive repeated
attempts.
* Push retries now stop promptly when an operation is canceled.
* Configuration, authentication, and ref-rejection errors continue to
fail immediately.
* Successful retries and canceled operations now report accurate
outcomes.
* **Tests**
* Added coverage for successful retries, cancellation, and non-retryable
failures.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: flexi767 <flexi767@users.noreply.github.com>
Co-authored-by: v <v@m5.speedport.ip>
Slow-test trim, DELETE + dashboard OPTIMIZE tiers. Deletions follow the
docs/testing.md taxonomy exactly — 40 tests removed across
TaskDetailModal.rendering (134→129), QuickEntryBox (300→280),
TerminalModal (247→240), ModelOnboardingModal (205→197), and
AgentDetailView.settings (27→25): byte-identical field-presence twins,
CSS-class permutation residue, and strict-subset interaction copies,
with every FN-tagged describe and user-noticeable behavior kept and
condensed matrices converted to it.each with all cases retained. The
real payoff is the FN-2707 latency pass: SettingsModal's real 500ms
auto-save debounce (and AgentDetailView's 700ms config debounce) now
flush under fake timers via a shared flushSettingsAutoSave harness
export — SettingsModal splits 102.3s→63.6s. Also fixed (not appeased) a
pre-existing race the speedup exposed: nav-button lookups now
findByRole after the settings promise resolves, file-wide. Verified:
1235 tests green across the touched set, tsconfig.app.json typecheck
clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Cursor provider card's Enable action only flips useCursorCli in
settings and never registers fusion-plugin-cursor-runtime, so
getRuntimeById("cursor") missed and every cursor-cli selection hit the
runtime-routed fail-fast error even with an authenticated cursor-agent.
Mirror the FN-7761 Grok eager bootstrap in serve, dashboard, and daemon,
guarded by the same source-scan regression test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Slow-test trim, OPTIMIZE tier (harness owner). Profiling showed 163ms
of the shared harness's 169ms per-test beforeEach was one TRUNCATE over
~110 tables (per-table catalog/fsync constants, row-independent). The
reset is now a single DO block: transaction-local
session_replication_role=replica, DELETE only from non-empty tables,
and sequence resets reproducing RESTART IDENTITY exactly — 169ms → 10ms
per test across every harness file, with the legacy TRUNCATE retained
as an automatic error fallback for non-superuser roles. sqlite-migrator
(the live SQLite→PG upgrade path; all 43 tests kept incl.
VAL-MIGRATE-001..006) now provisions targets from a golden-template
clone via new createBaselinedPgTestDatabase/createEmptyPgTestDatabase
exports — the dry-run test keeps a pristine empty DB so its
no-schemas-left-behind assertions stay meaningful — 148.8s → ~26s.
taskstore-lifecycle, data-layer, and taskstore-remaining migrate onto
the shared harness with byte-identical test bodies (187s → ~11s
combined); data-layer's close() test closes a private layer so the
shared pool survives. Seeding hoists were measured and deliberately
skipped: the harness fix already exceeded their projected savings and a
beforeAll seed would weaken the clean-DB-per-test contract.
Verified: 287 tests green across the touched files plus untouched
harness consumers (schema-applier 80/80, mission-store 62/62).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Slow-test trim, OPTIMIZE tier (mechanical sweep). These files each
created and baselined a fresh database per test (~3-4.6s/test); they now
use the shared golden-template harness (TRUNCATE per test) or, where a
private database is genuinely required (postgres-health drift/VACUUM
subjects, allocator-cross-project RLS connection sets), a per-test
template clone instead of raw DDL. Zero assertion lines changed
(verified), identical test counts, 110/110 green. Deliberately left
alone: startup-factory-integration and embedded-lifecycle (own-database
boot IS the subject) and schema-applier (real DDL is the subject).
Measured: ~195s serial → ~30s for these files.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Slow-test trim, CONDENSE tier. The three satellite-store files each
hand-rolled CREATE DATABASE + schema baseline per test (38 database
creations, ~75s serial); their describes now live verbatim — every it
name, assertion, and FNXC provenance comment preserved, 38/38 tests —
inside one shared-harness file with a single boot. The 3-test
custom-v1-workflow-dispatch characterization (13s alone) moved into the
adjacent no-selection-default-workflow-move harness file. Measured:
~92s serial → ~8s for the same coverage.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>