Commit Graph

11707 Commits

Author SHA1 Message Date
gsxdsm
7bf83bb458 fix(desktop,dashboard): open OAuth URLs via activation-free IPC on desktop
window.open after awaiting /auth/login can outlive Chromium's transient
user activation and get silently popup-blocked in the desktop app — the
OpenAI Codex flow (method select + localhost callback server) crossed
that threshold while Anthropic's faster flow usually didn't, so Codex
login never opened the browser. Add a shell:openExternal IPC bridge
(http/https only), expose it in preload, and route every dashboard
auth-URL open through an openExternalUrl helper that falls back to
window.open on the web.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 00:03:48 -07:00
gsxdsm
26054de697 feat(dashboard): OpenAI Codex subscription card in onboarding quick start
Placed directly after the Anthropic subscription and before the API-key
options; previously reachable only under Advanced.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 23:59:58 -07:00
gsxdsm
924e0df5ab fix(core): find git installed mid-session despite the stale PATH snapshot
A git installed DURING first-run setup stayed invisible (spawn git
ENOENT on project creation; onboarding indicator stuck on missing)
because the server's PATH snapshot predates the install. New resolver
probes well-known install locations on PATH ENOENT with cache
invalidation, wired into project git init/workspace detection, the
onboarding git status probe, and the dashboard clone route.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 23:56:34 -07:00
gsxdsm
38c6fdc60d fix: green full-suite after mock and stacking drift (#2287)
## Summary
Restacks onto latest main after #2285 and clears the remaining Full
Suite red classes from run
[29633869887](https://github.com/Runfusion/Fusion/actions/runs/29633869887)
(post-#2285):

- **Shard 1:** `agent-skills-flow` vitest TDZ — hoist `mockFiles` via
`vi.hoisted` (same class as skill-resolver in #2285)
- **Shard 2/3:** incomplete mocks after product drift
- `isFullScreenSheetViewport` / `isShortViewport` on viewport mocks
(without overriding dynamic mobile helpers)
  - `fetchCodebaseMetrics` on Command Center `api/legacy` mocks
  - `fetchSettings` on `agent-modals-mobile` api mock
- **Shard 3:** PlanningMode `ui-interactions` race — sync-settle
`fetchGlobalSettings` (FN-8245 pattern from planning-flow)
- **Shard 3:** settings search drift guard — inventory
`SettingsFieldRow` `htmlFor` keys (`mobileNavPrimaryItems`)
- **Shard 2:** FloatingWindow shared-stack product bug — only reclaim
z-index on hidden→visible (not every mount effect), so last-mounted
utility stays on top
- **Shard 4:** grok process-lifecycle timeout under shard load — prove
bound with 5 reimports instead of 15

## Test plan
- [x] `agent-skills-flow.test.ts` green
- [x] `process-lifecycle.test.ts` green
- [x] FileBrowserModal, FloatingWindowStack.cross-type,
agent-modals-mobile, settings-search-index, SystemControlsArea,
PlanningModeModal.ui-interactions + planning-flow (210 tests) green
- [ ] PR merge gate (Lint/Typecheck/Build/Gate)
- [ ] Post-merge Full Suite on `main` green

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved floating-window stacking so reopened or interacted windows
appear in the correct order.
* Restored consistent layering between floating windows and expanded
dock modals.
* **Tests**
* Updated automated coverage for viewport behavior, codebase metrics,
settings search indexing, and process lifecycle scenarios.
* Improved test reliability and consistency across responsive layouts
and modal interactions.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-17 23:53:50 -07:00
gsxdsm
b60833c419 fix(dashboard): browse panel follows a newly created folder in project setup
selectCreatedDirectory set the input value but left the panel on the
PARENT directory, whose footer Select button commits currentPath — the
natural next click overwrote the just-created folder with its parent.
Navigate the panel into the created directory so input, panel, and
Select agree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 23:51:55 -07:00
gsxdsm
6cdebe1d61 fix(dashboard): theme-aware links on the onboarding GitHub setup step
GitHub-step anchors had layout-only CSS and rendered the user-agent
default blue, which ignores the dashboard theme. Use var(--color-info)
with hover underline; .btn anchors keep button styling.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 23:51:55 -07:00
gsxdsm
1afce9532a fix: green full-suite after product and CI PG drift (#2285)
## Summary
Main Full Suite was red again after release/desktop workflow drift,
engine mock gaps, mission landed-SHA gating, and compound-engineering PG
admin auth on GHA (`USER=runner`).

## Fixes
| Area | Failure | Fix |
|------|---------|-----|
| desktop `release-workflow` | expected old `find artifacts -type f` |
assert pruned collect + `release-files/*` |
| `step-session-executor` | missing
`resolveExecutorFallbackThinkingLevel` | mock export |
| tool-availability tests | empty tools (cascade from above) | fixed by
mock |
| `skill-resolver` | TDZ on `mockFiles` during import | `vi.hoisted`
filesystem state |
| `merge-error-recovery` | enqueue no-op when not started | set
`started=true` |
| mission behavioral posture | `blocked` (no landed SHA / git probe) |
`mergeDetails.commitSha` + staleness stub |
| GraphTaskNode | missing `useOptionalToast` | mock both toast exports |
| CE `pipeline-store.pg` | psql as `runner` | admin via
`FUSION_PG_TEST_URL_BASE` |

## Test plan
- [x] step-session-executor, skill-resolver, merge-error-recovery,
mission-validator-behavioral-posture (203)
- [x] release-workflow (10)
- [x] `pnpm --filter @fusion/engine test:core` (294)
- [ ] Full Suite (non-blocking) after merge

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Bug Fixes**
- Improved desktop release artifact collection by pruning nested
`runtime` and `migrations` directories and consistently staging release
uploads via a dedicated `release-files` mapping.

- **Tests**
- Enhanced engine merge error-recovery coverage and mission validator
behavioral posture setup.
- Improved test reliability by synchronizing mocked filesystem state,
executor fallbacks, and toast hook variants.
- Updated Postgres test harness/admin commands to use a configurable
base URL; refined related Windows changeset description.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-17 23:22:04 -07:00
gsxdsm
95e011f890 fix(core): auto-repair empty non-UTF-8 embedded Postgres clusters on boot (#2286)
Users whose embedded cluster was initdb'd with an OS-locale encoding by
a pre-fix version now self-heal with zero manual steps: on the
encoding-conversion schema failure the startup factory proves the
cluster is non-UTF-8 AND empty (the baseline transaction never applied,
so no schema or migrated data can exist) and that this process owns the
postmaster, then deletes the data dir and reboots once with the UTF-8
initdb defaults. Joined instances and unproven states keep the manual
re-init hint; one retry ever, so no loops.

Verified on the elevated windows-latest runner: CI seeds a real WIN1252
cluster via initdb and proves a stock 'fn serve' auto-recovers it to a
healthy /api/health (run 29633351848, all jobs green). Also caps the
desktop-windows embedded-PG smoke at 30 min and adds a skip input.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 23:18:40 -07:00
gsxdsm
d4ee80a818 fix(core): Windows embedded Postgres — no local user account, UTF-8 clusters, diagnosable boot errors
Squash of feature/win-elevated-no-user, verified end-to-end on the
elevated windows-latest runner (restricted-token double boot + full
'fn serve' /api/health smoke, both green).

- Elevated Windows boots embedded PostgreSQL via pg_ctl's built-in
  restricted-token re-exec instead of creating a 'fusion-pg' local user
  (operator requirement: Fusion must never create accounts). Removes
  the credential launcher, icacls grants, and cmd/PowerShell wrapper —
  and with them the 'directory name is invalid' and wrapper-log EBUSY
  field failures. Leftover fusion-pg accounts are deleted on start.
- Embedded clusters are always initdb'd --encoding=UTF8 --locale=C
  (GitHub issue #2286: OS-locale WIN1252/WIN1254 clusters could not
  store the UTF-8 schema and crash-looped the dashboard). Existing
  non-UTF-8 clusters get an actionable re-init hint at boot.
- Schema-backend boot failures now surface the full error cause chain
  (DrizzleQueryError hid the real PostgresError behind the SQL text).
- Elevated stop() waits until the port closes and postmaster.pid is
  gone before resolving.
- CI: branch verification workflow (restricted-token proof + elevated
  boot smoke + account-absence assertions); boot-smoke stderr tail
  widened for diagnosability.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 22:45:57 -07:00
gsxdsm
fd87c3f23f fix(core): pin non-admin postgres launcher working directory on elevated Windows
Start-Process -Credential (CreateProcessWithLogonW) validates the working
directory as the TARGET user. The launcher inherited the desktop app's cwd
(admin profile / install dir), which the dedicated fusion-pg user cannot
read, so elevated desktop boots died with "The directory name is invalid"
before postgres ever started. launch.ps1 now pins -WorkingDirectory to the
.pgrunner run dir inside the data dir the user was just granted full
control on. CI never caught it because runner cwds are world-traversable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 21:01:29 -07:00
gsxdsm
7dda1aa3f5 chore(release): v0.71.0
Version bump via changesets.
2026-07-17 20:13:12 -07:00
gsxdsm
0b6c4cd4ca feat(dashboard,desktop): show live database-migration progress during boot
The one-time SQLite→PostgreSQL migration runs inside createTaskStoreForBackend
before any HTTP server listens, so browsers saw "connection refused" and open
tabs failed silently for minutes. Now:

- CLI: a temporary holding server binds the dashboard port for the boot window,
  serving an auto-reloading "Database migration in progress" page and an
  /api/health payload with status "migrating" + structured progress; the port
  is handed off (awaited) to the real app.listen().
- Dashboard SPA: already-open tabs render the new MigrationInProgressBanner
  from the 15s health poll when status is "migrating".
- Desktop: LocalRuntimeManager publishes migration progress on
  DesktopRuntimeStatus via the new core onMigrationProgress option;
  DesktopLaunchGate shows the live label and extends its 30s startup timeout
  while progress advances (2min stall cap), in both boot and first-run flows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 20:09:56 -07:00
gsxdsm
48b0d04322 fix(core): sanitize NUL (u0000) characters in SQLite-to-PostgreSQL migration
Legacy SQLite databases can hold U+0000 in TEXT cells and inside stored
JSON, which PostgreSQL rejects in text and jsonb columns and which
aborted the first-boot auto-migration. Strip NUL from plain text cells,
JSON string values and object keys, malformed-JSON scalars, and opaque
legacy-preservation cells; content-checksum verification compares the
sanitized source against the sanitized target so migrations still verify.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 20:04:22 -07:00
gsxdsm
e31223c25f chore(release): v0.70.2
Version bump via changesets.
2026-07-17 19:17:17 -07:00
gsxdsm
8517a5d3ba fix(core): make embedded Postgres shared_memory_type default platform-aware
shared_memory_type=mmap (defaulted 2026-07-16 for SysV shm exhaustion)
is invalid on Windows — PostgreSQL only accepts "windows" there and
dies with FATAL invalid value for parameter before opening the port.
Every Windows embedded start broke, failing the Windows release smoke
in both the v0.70.0 and v0.70.1 tag runs. Default flags now come from
defaultEmbeddedPostgresFlagsFor(platform): empty on win32 (no override
needed; SysV exhaustion cannot occur there), mmap elsewhere. Regression
test asserts the per-platform flag invariant.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 19:09:03 -07:00
gsxdsm
6b893f78ec fix(cli): make the standalone fn binary boot PostgreSQL in both modes
The bun-compiled exe has been unbootable since the PG cutover: bun
standalone binaries do no node_modules resolution, so the deliberately
out-of-graph require("embedded-postgres") failed from /$bunfs, and
readFile'd migration .sql files were never embedded, so even external
DATABASE_URL mode died at schema init.

- schema-applier: resolveMigrationsDir() — FUSION_MIGRATIONS_DIR env >
  module-relative dist/migrations (npm/desktop, unchanged) >
  execPath-relative migrations/ (standalone exe), probe-based.
- embedded-lifecycle: require("embedded-postgres") first (npm/desktop
  untouched), falling back to a self-contained staged bundle at
  <execDir>/runtime/<platform>/embedded-postgres/dist/index.cjs
  (FUSION_EMBEDDED_PG_RUNTIME_DIR override) with the native
  initdb/pg_ctl/postgres payload beside it.
- build.ts: stage dist/migrations plus the per-target embedded-postgres
  bundle + native payload (warn when a cross-target payload is absent on
  the host, mirroring desktop's verifyEmbeddedPostgresPayloads).
- release.yml: package fn-cli-<os>-<arch>.tar.gz (binary + migrations +
  runtime + client) with sha256 per leg; prune staged payload files from
  the release-collection globs; bare fn-cli-* binaries still uploaded.

E2E-verified on the compiled binary: embedded mode initdb→/api/health
200 database healthy; DATABASE_URL mode applied migrations 0000–0019
(109 tables). Core typecheck clean; schema-applier 58/58 and
embedded-lifecycle 44/44 tests pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 18:45:47 -07:00
gsxdsm
90a1a4b157 fix(cli): emit child-process runtime worker in the published package
engine's child-process-runtime forks dist/child-process-worker.js as a
sibling of the bundled bin.js, but the CLI build never emitted it, so
isolationMode: "child-process" could not spawn its runtime worker from
any published install. Add a named tsup entry bundling the engine worker
with bin.js's exact externals; verified via fork() with the runtime's
spawn options (IPC handlers register, no module-resolution errors) and
npm pack --dry-run listing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 18:34:38 -07:00
gsxdsm
c831ccb366 fix(cli): ship registry manifest and pi-llama-cpp extension in npm package
Tarball-completeness audit found two more assets stripped from the
published package: dist/pi-llama-cpp (staged by tsup, matched no files
glob — useLlamaCpp silently reported not-installed) and the dashboard's
registry-manifest.json (resolved beside the bundled bin.js by
plugin-routes but never staged into cli dist — published installs served
an empty plugin registry). Stage the manifest in tsup onSuccess and add
both to files; npm pack --dry-run now lists them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 18:30:00 -07:00
gsxdsm
4970465364 fix(cli): ship PostgreSQL migrations in the published npm package
The files globs (dist/**/*.js, *.d.ts, maps, named dirs) matched no .sql
file, so npm pack stripped dist/migrations from every published tarball.
npm-installed CLIs crashed schema init (ENOENT dist/migrations/
0000_initial.sql) and the dashboard supervisor crash-looped on boot.
Add dist/migrations/** to files; npm pack --dry-run now lists all 21
migration files. Sibling of the desktop staging fix 6e5bb5d3d.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 18:21:02 -07:00
gsxdsm
eccb115c7e chore(release): v0.70.1
Version bump via changesets.
2026-07-17 18:17:15 -07:00
gsxdsm
09e519e3b8 chore(changesets): add changeset for desktop PG migrations packaging fix
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 18:15:25 -07:00
gsxdsm
d94fd0e61b FN-8257: retain quick chat state when closed
Keep Quick Chat mounted after its first opening so closing and reopening preserves its session and scroll state.

- Add an opt-in hidden state for FloatingWindow that suspends invisible-window effects.
- Retain Quick Chat per project while resetting its React identity on project changes.
- Cover persistent close/reopen behavior and hidden floating-window semantics.

Files changed:
 packages/dashboard/app/App.tsx                     |  25 ++++-
 .../dashboard/app/components/FloatingWindow.css    |  10 ++
 .../dashboard/app/components/FloatingWindow.tsx    |  38 +++++--
 .../components/__tests__/FloatingWindow.test.tsx   |  90 +++++++++++++++-
 .../__tests__/QuickChat.persist.test.tsx           | 120 +++++++++++++++++++++
 5 files changed, 274 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-8257

Fusion-Task-Lineage: 6b0cd41c-32e8-4cd4-8c0c-82d0254aa1e4

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 18:12:47 -07:00
gsxdsm
dbf52886ca FN-8256: preserve task detail tabs during column changes
Preserve a task detail view's selected tab and related state through live task column updates.

- Reinitialize tabs only when the caller changes initialTab
- Retain dedicated guards for unavailable PR, Summary, and Session tabs
- Cover modal and embedded task-detail tab persistence

Files changed:
 .../dashboard/app/components/TaskDetailModal.tsx   |  20 +-
 .../TaskDetailModal.tab-persistence.test.tsx       | 244 +++++++++++++++++++++
 2 files changed, 261 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-8256

Fusion-Task-Lineage: 86620e72-65b2-4c2f-b0e9-04ecce4d951c

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 18:06:14 -07:00
gsxdsm
6e5bb5d3d5 fix(desktop): stage @fusion/core PG migrations into packaged builds
Bare tsc never copies .sql files into core's dist, and the desktop staging
had no equivalent of the CLI's tsup migrations hook, so every packaged
desktop build shipped without dist/postgres/migrations and Local mode
crashed schema init (ENOENT 0000_initial.sql) after embedded Postgres
started. buildCore() now stages the migrations beside the compiled output,
stageDesktopDeploy() re-stages them into the deployed closure, and
verifyCoreMigrationsStaged() fails the build if the baseline migration is
missing from the stage.

Verified end to end: packed mac-arm64 app boots with isolated home,
embedded PG 15.18 initializes from packaged migrations, /api/health 200.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 18:00:52 -07:00
gsxdsm
12e0e3987b FN-8254: standardize task-card header badge heights
Standardize TaskCard header badge geometry across text and icon-only variants.

- Align planner oversight, fast-mode, mission, PR, and existing header chips with shared badge padding, borders, line height, and icon sizing.
- Cover populated desktop header chips and shared mobile chip declarations with regression tests.

Files changed:
 packages/dashboard/app/components/TaskCard.css     | 75 ++++++++++++++++------
 .../__tests__/TaskCard.badge-height.test.tsx       | 69 ++++++++++++++++++--
 .../__tests__/TaskCard.badge-wrap.test.tsx         | 26 ++++++--
 3 files changed, 142 insertions(+), 28 deletions(-)

Fusion-Task-Id: FN-8254

Fusion-Task-Lineage: bd5e4cce-8641-47ac-8745-6465d5cbbc1a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 17:52:08 -07:00
gsxdsm
d4de9ebf30 Update roadmap 2026-07-17 17:41:09 -07:00
gsxdsm
204bf8afa8 FN-8253: align task size badge with header badges
Align task-card size badge geometry with its sibling header badges.

- Center the size badge and inherit shared header-badge height.
- Cover desktop and mobile badge-height behavior with CSS assertions.

Files changed:
 packages/dashboard/app/components/TaskCard.css                | 11 +++++------
 .../app/components/__tests__/TaskCard.badge-wrap.test.tsx     | 11 +++++++++--
 2 files changed, 14 insertions(+), 8 deletions(-)

Fusion-Task-Id: FN-8253

Fusion-Task-Lineage: 63a64d62-12b3-4b53-a05e-1df7406ab222

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 17:33:19 -07:00
gsxdsm
e24f765495 FN-8252: rescue quarantined engine tests
Restore non-mechanical engine coverage with PostgreSQL-safe test fixtures and awaited overseer audit writes.

- migrate eligible engine tests to shared PostgreSQL harnesses and restore their Vitest coverage
- harden mission and advisory reporting paths for async persistence and observable failures
- await the production planner-overseer audit callback and verify the start() wiring preserves persistence

Files changed:
 .../__tests__/mission-autopilot-end-to-end.test.ts |  27 ++--
 .../engine/src/__tests__/mission-autopilot.test.ts |   4 +-
 .../planner-overseer-intervention-wiring.test.ts   |  39 +++---
 .../engine/src/__tests__/project-engine.test.ts    | 138 ++++++++++++++++-----
 .../unlinked-missions-advisory-reporter.pg.test.ts |  51 ++++++++
 .../unlinked-missions-advisory-reporter.test.ts    |  20 ++-
 packages/engine/src/mission-execution-loop.ts      |  27 ++--
 packages/engine/src/project-engine.ts              |  41 +++---
 .../src/unlinked-missions-advisory-reporter.ts     |  23 ++--
 packages/engine/vitest.config.ts                   |   6 +-
 scripts/lib/test-quarantine.json                   |  27 +---
 11 files changed, 260 insertions(+), 143 deletions(-)

Fusion-Task-Id: FN-8252
Fusion-Task-Lineage: 4f86ce7e-11a2-4704-a5d1-00e0a8c1448e
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 17:28:36 -07:00
Victor Canô
9cafa045df fix(pr-merge): resolve repo from the project checkout, not process.cwd(), in PR-mode auto-merge (#2281)
## Summary

In a centrally-installed, multi-project Fusion server (one process
serving several repos, `process.cwd()` = the install dir, not any repo),
every task under `mergeStrategy: "pull-request"` fails at the auto-merge
stage with:

```
Could not determine repository. Specify owner/repo in params or run from a git repository with a GitHub remote.
```

PR creation from the dashboard and status polling work; only the
engine's automatic PR path fails. This is the **non-workspace sibling of
#1924** (FN-7610 routed workspace-mode tasks to direct merge but does
not cover regular multi-project tasks) and the completion of
#1797/FN-7133 (which fixed only the `getPrMergeStatus` arguments).

## Root cause

`GitHubClient.resolveRepo()` (`packages/dashboard/src/github.ts`) falls
back to a cwd-less `getCurrentRepo()` — i.e. `git remote get-url origin`
in `process.cwd()` — whenever a PR method is called without explicit
`owner`/`repo`. The engine merge path already resolves the correct repo
from the per-project cwd (`prRepo = getCurrentRepo(cwd)`, FN-7133) but
only threaded it into `getPrMergeStatus`. Every other GitHub call
omitted it:

- `processPullRequestMergeTask`: `findPrForBranch` / `createPr` /
`mergePr` on both the per-task and shared-branch-group paths
- `createGroupPrCallback` (group-PR promotion): `findPrForBranch` /
`createPr`
- `createPrNodeGithubOps` (`pr-create`/`pr-merge` workflow nodes):
cwd-less `getCurrentRepo()` persisted `entity.repo` as `""` (poisoning
the downstream `splitRepoSlug` consumers), and the git
push/`createPr`/`mergePr` ran against `process.cwd()`
- the engine's review-response run (`buildRespondCallback`):
`respondOps.getCwd` collapses to `process.cwd()` because no CLI
composition site wires `getTaskWorktree`, so its git ops and response
agent ran outside the project repo

In a central install the fallback throws; worse, if `process.cwd()`
happens to be inside some *other* git repo, it silently targets the
**wrong repository**.

## What changed

- `fix(pr-merge): thread repo identity into PR auto-merge GitHub calls`
— widens the CLI-local `GitHubOperations` interface (optional
`owner`/`repo`, already accepted by `GitHubClient`'s
`FindPrParams`/`CreatePrParams`/`MergePrParams`) and passes `prRepo` at
all six call sites in `processPullRequestMergeTask`.
- `fix(pr-merge): resolve group-PR repo from project cwd in
createGroupPrCallback` — resolves via `getCurrentRepo(cwd)` from the
callback input (same T4 pattern as `syncGroupPrCallback`) with a loud
failure instead of a silent wrong-repo fallback.
- `fix(pr-merge): resolve PR-node repo from task worktree instead of
process cwd` — `resolvePrSource` resolves from `task.worktree`, git ops
run in `getTaskWorktree(...) ?? task.worktree ?? process.cwd()`, and
`createPr`/`mergePr` pass `owner`/`repo` parsed from `entity.repo`.
- `fix(pr-merge): resolve review-response run cwd from the task
worktree` — the engine owns the store, so `buildRespondCallback` prefers
the task's recorded `worktree` for the response run's git ops + agent,
keeping `ops.getCwd` as the single-project fallback (defensive against
structural `PrNodeStore`s without `getTask`).
- Changeset (`@runfusion/fusion` patch, structured body) included.

Deliberately **not** done: a constructor-scoped default repo on
`GitHubClient` — one client instance is shared across all projects in a
central install (`serve.ts`/`daemon.ts`/`dashboard.ts`), so per-call
`owner`/`repo` is the only correct scope.

## Testing

- New regression tests simulate the central-install topology
(`getCurrentRepo` mocked as `(cwd?) => cwd ? repo : null`, exactly the
failing environment) and drive the merge flow end-to-end on the per-task
path, the shared-branch-group path, `createGroupPrCallback`, and all
three `createPrNodeGithubOps` ops, asserting every GitHub call carries
explicit `owner`/`repo` (45 tests in
`packages/cli/src/commands/__tests__/task-lifecycle.test.ts`, all
green).
- `packages/engine/src/__tests__/pr-respond-cwd-resolution.test.ts`
covers the respond-run cwd: worktree preferred, `ops.getCwd` fallback
when the task has no worktree, when the lookup fails, and when a
structural store has no `getTask`.
- Existing exact-argument assertions were extended to the new call
contract (no assertions weakened or removed).
- `pnpm lint`, `pnpm typecheck`, and `pnpm build` green locally; `pnpm
test:gate`'s engine-core suite green (294/294) — its PostgreSQL-backend
lane needs local PG credentials this environment lacks, so that lane
defers to CI. `pnpm verify:fast` (scoped typecheck/build + CLI build +
boot smoke) also passes.

## Repro

1. Install the CLI centrally; run the server from a dir that is not a
git repo, serving ≥1 project with a GitHub `origin` and `mergeStrategy:
"pull-request"`.
2. Run a task to completion and let it reach the merge stage.
3. Before this fix: the auto-merger throws `Could not determine
repository …` (tasks with a persisted PR poll fine but never merge).
Merging the same task from the Pull Requests tab succeeds, because the
dashboard route resolves the repo explicitly (`parseBadgeUrl(...) ??
getCurrentRepo(rootDir)`).

Full analysis: https://github.com/Tchori-Labs/Fusion/issues/4

---

Developed with Claude (co-authored on all commits).

https://claude.ai/code/session_01ChEa8SHFYNAzjCdFbwFMfh


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Bug Fixes**
- Resolved pull request auto-merge failures in centrally installed,
multi-project deployments.
- Ensured explicit repository context (`owner/repo`) is used for pull
request lookup, creation, and merging throughout the merge workflow.
- Improved pull request response handling to prefer the task worktree
for working-directory resolution, with safe error behavior when task
details are unavailable.
- **Tests**
- Expanded coverage for multi-repository merge workflows and
worktree-based repository/cwd resolution in PR response handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-17 17:28:09 -07:00
gsxdsm
3fcab9fc1d fix: green full-suite after main product drift (#2275)
## Summary
Follow-up after #2266: full suite on latest `main` still failed on i18n
parity and engine product-drift tests (duplicate flagging, mission
validator signature, worktree path reservation, pi ModelRuntime,
assigned-agent PG layer).

## Changes
- **i18n**: add `listView/tasks.statusReplan` and mobile-nav settings
keys to es/fr/ko/zh-CN/zh-TW
- **triage**: opt-in `triageDuplicateResolution: "delete"` coverage +
default prompt/flag path; stub `recordActivity`
- **MCP PR response**: stub `getTask` for merger model resolution
- **pi-layers**: mock `ModelRuntime.create` (FN-8142)
- **assigned-agent**: stub `getAsyncLayer` for authoritative AgentStore
fallback
- **mission validation**: `startValidatorRun(..., taskId)` +
`runValidation` `{ result, inspection }` shape
- **worktree acquisition**: real temp roots for path reservation;
probe-aware worktrunk failure fixture
- **useBlockerFanout**: read `MAX_AUTO_MERGE_RETRIES` from
`self-healing-constants.ts` (wave-8 peel)

## Test plan
- [x] Targeted engine suites above (48 tests)
- [x] i18n parity + gate coverage
- [x] useBlockerFanout
- [x] `pnpm test:gate`
- [ ] Full Suite (non-blocking) on PR

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Localization**
* Added “Replan”/replanning status labels across Spanish, French,
Korean, Simplified Chinese, and Traditional Chinese.
* Completed settings mobile navigation translations, including primary
items controls and reordering options.

* **Tests**
* Expanded coverage for validation recovery and task forwarding
behavior.
* Improved duplicate-resolution scenarios (including activity recording
and lineage deletion behavior).
* Increased test reliability for worktree acquisition by using temporary
filesystem roots.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-17 17:27:04 -07:00
gsxdsm
f5538e6253 chore(release): v0.70.0
Version bump via changesets.
2026-07-17 17:12:42 -07:00
gsxdsm
dc4a8dfadf chore(changesets): downgrade postgres cutover bump from major to minor
Next release should be 0.x, not 1.0.0 (which also already exists on npm
as a deprecated erroneous April publish). Keeps category: breaking so
release notes still flag the SQLite→PostgreSQL cutover.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 17:10:00 -07:00
gsxdsm
d8396c3273 fix(changesets): correct invalid release bump types 2026-07-17 17:03:57 -07:00
gsxdsm
d8735b3dbe FN-8249: persist GitHub translations and show status
Persist legacy GitHub translation cache entries and expose background translation progress to import operators.

- Backfill historic unscoped translation cache partitions during schema migration.
- Display accessible translating and failure status in the GitHub issues import list.
- Add migration, service, and UI coverage plus operator documentation.

Files changed:
 .../fn-8249-github-import-translation-status.md    |  7 ++
 docs/dashboard-guide.md                            |  2 +-
 .../postgres/import-translation-cache.pg.test.ts   | 13 +++-
 .../src/__tests__/postgres/schema-applier.test.ts  | 48 ++++++++++++
 ...translation_cache_legacy_partition_backfill.sql | 31 ++++++++
 packages/core/src/postgres/schema-applier.ts       | 29 ++++++-
 .../dashboard/app/components/GitHubImportModal.css | 42 ++++++++++
 .../dashboard/app/components/GitHubImportModal.tsx | 29 +++++++
 .../__tests__/GitHubImportModal.test.tsx           | 90 ++++++++++++++++++++++
 .../src/__tests__/import-translate-service.test.ts | 62 +++++++++++++++
 10 files changed, 346 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-8249

Fusion-Task-Lineage: 79c26d85-50f1-4d01-9341-a17db5e57f8f

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 16:46:42 -07:00
gsxdsm
b0654031bc FN-8251: hide overseer eye when oversight is off
Resolve inherited workflow oversight before rendering task-card overseer indicators.

- Resolve selected-workflow oversight using the planning workflow identity
- Fail closed for unknown, pending, malformed, and failed inherited settings
- Cover workflow changes and mobile suppression, and document the behavior
- Add a patch changeset for the corrected card indicator

Files changed:
 .changeset/fn-8251-card-eye-effective-oversight.md |   7 +
 docs/dashboard-guide.md                            |   4 +-
 packages/dashboard/app/components/TaskCard.tsx     | 116 ++++++++-------
 .../__tests__/TaskCard.oversight.test.tsx          | 161 ++++++++++++++++++++-
 .../app/components/__tests__/TaskCard.test.tsx     |   6 +-
 5 files changed, 234 insertions(+), 60 deletions(-)

Fusion-Task-Id: FN-8251

Fusion-Task-Lineage: 72dfa67e-e6d5-4557-91b3-23aff6dcf9e7

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 16:38:29 -07:00
gsxdsm
eee04bc1a8 FN-8248: fix Quick Chat popup stacking
Make Quick Chat and task popups honor their most recent interaction order.

- Place Quick Chat in the task-detail peer stack while retaining higher utility windows.
- Raise Create Room dialogs above Chat on each open, including mobile sheets.
- Add stacking regression coverage and operator documentation with screenshots.

Files changed:
 docs/assets/fn-8248-chat-above-task.png            | Bin 0 -> 55108 bytes
 docs/assets/fn-8248-mobile-create-room.png         | Bin 0 -> 56699 bytes
 docs/assets/fn-8248-task-above-chat.png            | Bin 0 -> 74263 bytes
 docs/dashboard-guide.md                            |   5 +-
 packages/dashboard/app/App.tsx                     |  13 +++-
 .../dashboard/app/components/CreateRoomModal.tsx   |  15 ++++-
 .../dashboard/app/components/FloatingWindow.tsx    |  11 +++-
 .../components/__tests__/CreateRoomModal.test.tsx  |  72 +++++++++++++++++++++
 .../FloatingWindowStack.cross-type.test.tsx        |  37 +++++++----
 .../app/components/floatingWindowStack.ts          |  10 +--
 10 files changed, 139 insertions(+), 24 deletions(-)

Fusion-Task-Id: FN-8248

Fusion-Task-Lineage: 94ef20f1-96da-4249-9812-169f780c9451

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 16:34:16 -07:00
gsxdsm
703488f0f3 fix(FN-8142): restore Anthropic OAuth refresh
Use the Claude OAuth client identity issued by the login flow and lock the request contract down with a regression assertion.
2026-07-17 16:26:20 -07:00
gsxdsm
62f121e0c9 FN-8247: stop session advisor with oversight
Stop now persists session-advisor disablement and reflects inherited advisor state in task details.

- Persist an explicit advisor-off override and clear its live runtime when stopping oversight.
- Resolve workflow-level advisor defaults for task-detail icons and toggle behavior.
- Cover stop cleanup and desktop/mobile oversight state transitions with regression tests.
- Document the combined stop contract and add a patch changeset.

Files changed:
 .changeset/fn-8247-session-advisor-stop-and-icon.md       |   7 ++
 docs/dashboard-guide.md                            |   6 +-
 packages/dashboard/app/components/TaskDetailModal.tsx   |  86 +++++++++++------
 packages/dashboard/app/components/__tests__/TaskDetailModal.oversight-controls.test.tsx    | 104 +++++++++++++++++++++
 packages/dashboard/app/components/__tests__/TaskDetailModal.oversight-mobile.test.tsx      |  62 ++++++++++++
 packages/engine/src/__tests__/project-engine-stop-overseer-session-advisor.test.ts |  62 ++++++++++++
 packages/engine/src/project-engine.ts              |  13 ++-
 7 files changed, 310 insertions(+), 30 deletions(-)

Fusion-Task-Id: FN-8247

Fusion-Task-Lineage: dcb67af7-9a36-4b25-bafa-84722fe158a0

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 16:20:10 -07:00
gsxdsm
669cb7cc56 FN-8250: pin Settings at bottom of mobile More menu
Pin the omitted Settings destination beneath the mobile More-menu divider.

- Render Settings after the More-menu separator when omitted from primary tabs.
- Prevent duplicate Settings entries when it is a primary tab.
- Cover ordering and duplicate-prevention behavior with MobileNavBar tests.
- Add a patch changeset for the mobile navigation fix.

Files changed:
 .changeset/fn-8250-mobile-more-settings.md         |  7 +++++++
 packages/dashboard/app/components/MobileNavBar.tsx | 11 ++++++++++-
 .../app/components/__tests__/MobileNavBar.test.tsx | 22 ++++++++++++++++++++++
 3 files changed, 39 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-8250

Fusion-Task-Lineage: 4eea65d8-2e01-4fa4-986e-ffc15e906553

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 15:54:39 -07:00
gsxdsm
c43fdbb520 FN-8245: stabilize dashboard focus and planning tests
Make dashboard test execution deterministic and restore quarantined coverage.

- Defer oversight-menu autofocus until the opening frame and cover both breakpoints.
- Replace timing-dependent planning stream mocks with deterministic microtasks.
- Isolate QuickEntryBox focus state and re-admit restored dashboard tests.

Files changed:
 .../dashboard/app/components/TaskDetailModal.tsx   |  15 ++-
 .../PlanningModeModal.planning-flow.test.tsx       | 132 ++++++++++++++-------
 .../components/__tests__/QuickEntryBox.test.tsx    |  13 ++
 .../TaskDetailModal.oversight-mobile.test.tsx      |  19 +--
 packages/dashboard/vitest.config.ts                |  24 ++--
 scripts/lib/dashboard-curated-skiplist.json        |   4 +
 scripts/lib/test-quarantine.json                   |  20 ----
 7 files changed, 140 insertions(+), 87 deletions(-)

Fusion-Task-Id: FN-8245

Fusion-Task-Lineage: cd9b0638-0a6b-4dcf-980a-e90ba72b5db9

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 15:46:31 -07:00
gsxdsm
59815fd563 FN-8240: restore dashboard API test coverage
Restore quarantined dashboard API coverage and harden PostgreSQL template setup.

- Re-enable 18 dashboard API tests by clearing their quarantine ledger and Vitest exclusions.
- Preserve remote tunnel providers in route test mocks.
- Prevent PostgreSQL template cleanup races and terminate stale template sessions before copies.

Files changed:
 .../core/src/__test-utils__/pg-test-harness.ts     | 28 ++++---
 .../src/__tests__/routes-remote-access.test.ts     |  7 +-
 packages/dashboard/vitest.config.ts                | 25 ++----
 scripts/lib/test-quarantine.json                   | 90 ----------------------
 4 files changed, 30 insertions(+), 120 deletions(-)

Fusion-Task-Id: FN-8240

Fusion-Task-Lineage: 19269246-4eb7-418f-ab0d-bf90ba5dfb49

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 15:02:25 -07:00
gsxdsm
56773f691c FN-8244: fix PG template database isolation
Prevent same-process Vitest modules from racing over a shared PostgreSQL schema template.

- Assign each harness module instance a nonce-bearing template database.
- Clean up successful-worker templates and preserve live sibling templates during sweeps.
- Add isolated-module concurrency and template lifecycle regression coverage.

Files changed:
 .../core/src/__test-utils__/pg-test-harness.ts     | 100 +++++++++++++++-----
 ...pg-test-harness-template-concurrency.pg.test.ts | 101 +++++++++++++++++++++
 2 files changed, 177 insertions(+), 24 deletions(-)

Fusion-Task-Id: FN-8244

Fusion-Task-Lineage: 5a693232-6740-404f-a3da-763fecc5950f

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 14:50:59 -07:00
gsxdsm
c0441c96e4 FN-8243: restore priority select focus-visible coverage
Restore tokenized focus styling required by dashboard CSS hygiene checks.

- Add the missing `.detail-priority-select:focus-visible` selector.
- Reuse the shared strong focus-ring and radius tokens.

Files changed:
 packages/dashboard/app/components/TaskDetailModal.css | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

Fusion-Task-Id: FN-8243

Fusion-Task-Lineage: 35d6214e-a0de-48b1-8fd7-9eb4fca707ef

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 14:45:23 -07:00
gsxdsm
600e9c9ecc FN-8242: fix triage duplicate-finalization test mock
Make triage duplicate-finalization tests provide the activity recorder used by the implementation.

- Add an awaited recordActivity mock to the shared TaskStore fixture.
- Select delete resolution in the reviewer-outage retry scenario so it reaches deleteTask.

Files changed:
 packages/engine/src/__tests__/triage.test.ts | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-8242

Fusion-Task-Lineage: 8f9fd4b6-8071-47f3-8091-747884762ec9

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 14:40:48 -07:00
gsxdsm
7517f2eddf FN-8239: align task card oversight icon state
Keep task-card overseer indicators aligned with resolved oversight settings.

- Gate transient Eye badges on the resolved effective oversight level.
- Suppress stale snapshots and empty header wrappers while inherited workflow settings load.
- Add regression coverage and document the consistent off-state behavior.

Files changed:
 .changeset/fn-8239-oversight-icon-consistency.md   |  7 ++++
 docs/dashboard-guide.md                            |  3 +-
 packages/dashboard/app/components/TaskCard.tsx     | 29 ++++++++++++----
 .../__tests__/TaskCard.oversight.test.tsx          | 40 ++++++++++++++++++++++
 .../app/components/__tests__/TaskCard.test.tsx     | 23 +++++++++++++
 5 files changed, 94 insertions(+), 8 deletions(-)

Fusion-Task-Id: FN-8239

Fusion-Task-Lineage: 2857358c-7626-4b04-b1b5-fa51c3a71418

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 14:35:07 -07:00
gsxdsm
9152d8fa61 FN-8229: remove background AI tasks pill
Replace the redundant footer AI session control with progress and action visibility in the session notification banner.

- Delete the BackgroundTasksIndicator component, styles, footer wiring, and obsolete translations.
- Surface non-planning generating and retained error sessions through the notification banner while leaving Planning in its dedicated view.
- Update session lifecycle, localization, documentation, and regression coverage.

Files changed:
 .../fn-8229-remove-ai-background-tasks-pill.md     |   7 +
 docs/dashboard-guide.md                            |   4 +-
 packages/dashboard/README.md                       |   1 -
 packages/dashboard/app/App.tsx                     |  28 +--
 .../app/__tests__/css-hygiene-scan.test.ts         |   2 -
 .../dashboard-component-color-tokenization.test.ts |   1 -
 packages/dashboard/app/api/legacy.ts               |   2 +-
 .../app/components/BackgroundTasksIndicator.css    | 130 -------------
 .../app/components/BackgroundTasksIndicator.tsx    | 210 ---------------------
 .../dashboard/app/components/ExecutorStatusBar.css |   3 -
 .../dashboard/app/components/ExecutorStatusBar.tsx |  30 +--
 .../app/components/SessionNotificationBanner.css   |  10 +
 .../app/components/SessionNotificationBanner.tsx   |  52 ++++-
 .../app/components/SubtaskBreakdownModal.tsx       |   7 +-
 .../app/components/__tests__/App.test.tsx          |  11 +-
 .../__tests__/ExecutorStatusBar.test.tsx           |   1 -
 .../__tests__/SessionNotificationBanner.test.tsx   |  88 ++++-----
 .../components/__tests__/utility-mobile.test.tsx   | 191 +------------------
 .../app/components/dashboard/DashboardBanners.tsx  |   8 +-
 .../dashboard/__tests__/DashboardBanners.test.tsx  |  30 ++-
 .../hooks/__tests__/useBackgroundSessions.test.ts  |  21 ++-
 .../dashboard/app/hooks/useBackgroundSessions.ts   |  21 ++-
 .../app/utils/__tests__/appLifecycle.test.ts       |  61 ++----
 packages/dashboard/app/utils/appLifecycle.ts       |  16 +-
 packages/dashboard/src/routes.ts                   |   2 +-
 packages/i18n/locales/en/app.json                  |  33 +---
 packages/i18n/locales/es/app.json                  |  44 ++---
 packages/i18n/locales/fr/app.json                  |  44 ++---
 packages/i18n/locales/ko/app.json                  |  44 ++---
 packages/i18n/locales/zh-CN/app.json               |  44 ++---
 packages/i18n/locales/zh-TW/app.json               |  44 ++---
 packages/i18n/src/resources.d.ts                   |  48 ++---
 32 files changed, 316 insertions(+), 922 deletions(-)

Fusion-Task-Id: FN-8229

Fusion-Task-Lineage: a232fb04-08ff-4f0a-a440-e94545243e61

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 14:25:30 -07:00
gsxdsm
0b6957a1b2 FN-8241: log Plan Review revisions distinctly
Classify requested Plan Review changes as normal specification revision activity rather than workflow failures.

- Replace failure log actions for deterministic and reviewer-requested revisions
- Preserve failed workflow-result state for replan and recovery processing
- Cover revision logging across deterministic, reviewer, and retry paths

Files changed:
 .../triage-review-spec-external-integration.test.ts        |  5 ++++-
 packages/engine/src/__tests__/triage.test.ts               | 11 +++++++++++
 packages/engine/src/triage.ts                              | 14 ++++++++++++--
 3 files changed, 27 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-8241

Fusion-Task-Lineage: 316370ac-36c2-45b5-944f-602375167cdd

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 14:19:28 -07:00
gsxdsm
a746a02f3b FN-8236: group mobile Settings sections by topic
Group the mobile Settings picker by desktop navigation topics while preserving scoped section adjacency.

- Render mobile section choices in native topic optgroups
- Preserve Global-before-Project ordering and search-aware empty groups
- Cover grouped picker behavior and document the mobile navigation

Files changed:
docs/dashboard-guide.md                            |  2 +-
packages/dashboard/app/components/SettingsModal.tsx | 31 +++++++--
packages/dashboard/app/components/__tests__/settings-mobile.test.tsx | 80 ++++++++++++++++++++++
3 files changed, 107 insertions(+), 6 deletions(-)

Fusion-Task-Id: FN-8236

Fusion-Task-Lineage: 3a90bc72-2393-4b41-a7c3-2c9e30c94e01

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 14:13:41 -07:00
gsxdsm
eae8d9dabe FN-8238: tighten mobile mailbox header layout
Keep full-page mailbox actions and detail controls compact on mobile devices.

- Gate compact mailbox styles on the runtime mobile viewport mode
- Preserve header actions, tabs, and message controls in single mobile rows
- Add regression coverage for mobile layout gating and actions

Files changed:
 packages/dashboard/app/components/MailboxModal.css | 113 ++++++++++++++++++++-
 packages/dashboard/app/components/MailboxView.tsx  |  12 ++-
 .../app/components/__tests__/MailboxView.test.tsx  |  73 +++++++++++++
 3 files changed, 193 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-8238

Fusion-Task-Lineage: fce35577-4368-4cf6-a059-445550c98463

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 13:58:34 -07:00
gsxdsm
595c27ceae FN-8235: add mobile Kanban column snapping
Mobile Kanban now settles user swipes on the nearest column.

- add a mobile-only, user-driven scroll-end snapping hook
- wire snapping to every live Board rendering and cover interaction boundaries
- document the behavior and add a patch changeset

Files changed:
 .changeset/fn-8235-mobile-kanban-snap.md           |   7 +
 docs/dashboard-guide.md                            |   6 +
 packages/dashboard/app/components/Board.tsx        |  19 ++-
 .../app/components/__tests__/board-mobile.test.tsx |  14 +-
 .../hooks/__tests__/useColumnScrollSnap.test.ts    | 159 ++++++++++++++++++
 .../dashboard/app/hooks/useColumnScrollSnap.ts     | 179 +++++++++++++++++++++
 6 files changed, 380 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-8235

Fusion-Task-Lineage: 46881e93-59f2-49d6-b29e-fa6150420f2a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 13:53:13 -07:00