- Align dashboard prefix validation to 1-5 chars (was 1-10) matching CLI cap
- Fix distributed-task-id.ts fallback from KB to FN (3 occurrences)
- Move taskPrefix/defaultWorkflowId persistence outside interactive-only block
so non-interactive CLI registration also gets defaults
- Wrap both TaskStore lifecycles in try/finally to guarantee close() on error
Hardens task ID collision guards across distributed instances by adding `isAllocated` checks in `store.ts` and rewriting `distributed-task-id.ts` with deterministic collision-safe allocation logic, backed by a new `store-create-collision.test.ts` suite reproducing the race path. Updates architecture
Fusion-Task-Id: FN-4044
Unifies task ID allocation under a single store-owned distributed allocator, removing redundant ID-generation logic from dashboard route handlers and simplifying the overall flow; Step 1 merges the allocation authority into the store, Step 3 removes the now-unnecessary mixed-path routing, and tests
Fusion-Task-Id: FN-4053
Adds retry logic for distributed task ID overlap conflicts across the cluster, hardening the ID allocator with exponential-backoff recovery, wiring the retry into task workflow registration, and documenting the behavior in architecture docs. Minor CSS tokenization on the Mailbox and Plugin Manager m
Fusion-Task-Id: FN-3710
The dashboard task-create route now uses the distributed task ID allocator
(FN-3450). On projects whose tasks had been allocated through the legacy
config.nextId counter, the allocator's `ensureStateRow` was seeding a fresh
prefix at sequence 1, so new tasks restarted at FN-001 even when FN-3700
already existed. ensureStateRow now seeds past:
- the legacy config.nextId counter (when configured taskPrefix matches), and
- one past the highest numeric suffix on any existing tasks/archivedTasks row
for the prefix.
A regression test seeds FN-3700 in a fresh DB and asserts the next reservation
returns FN-3701, not FN-001.
Plugin dashboard view contracts are now exposed via a slim type-only module
(`@fusion/dashboard/app/plugins/types`). External plugin tsc builds previously
imported `pluginViewRegistry`, transitively pulling in dashboard runtime
sources (React components, CSS, lucide-react). The dependency-graph plugin's
import + path mapping is updated to use the new module.
Schema housekeeping: drop unused scaffolding tables left over from an earlier
migration via a new idempotent migration (v67). Fresh DBs see no change;
existing DBs that ran the older migration get the orphan tables dropped on
next init.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
iOS fires visualViewport scroll events at 60fps during a pan with the
keyboard up. Routing those through React state and into the .chat-thread
translateY(--vv-offset-top) transform amplified the pan into a visible
judder + ~300px shift + body background exposure.
useMobileKeyboard now uses two listeners: a full update (resize +
focusin/focusout) that re-snapshots all metrics including offsetTop, and
a scroll-only update that updates only height/keyboardOpen. offsetTop
is therefore frozen between keyboard open/close events — the transform
correctly compensates for iOS's initial visualViewport shift on focus
without following pan-time movement.
Restores the translateY anchor (so the thread isn't off-screen on
first focus) while keeping the swipe-jitter fix.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>