fix(dashboard): pin --vv-offset-top to resize/focus, ignore pan scrolls
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>
This commit is contained in:
@@ -471,6 +471,12 @@ Implemented in `agent-heartbeat.ts`:
|
||||
- Canonical replication/write-coordination contract: [`docs/shared-mesh-protocol.md`](./shared-mesh-protocol.md)
|
||||
- Defines protocol versioning, write classes, quorum/ack semantics, lease epochs/fencing, offline queue/replay, reconciliation outcomes, restart recovery hooks, and degraded-read staleness metadata.
|
||||
- Existing `/api/mesh/sync` and settings-sync payloads remain the active exchange primitives while follow-on runtime tasks implement full v1 coordinator/quorum behavior.
|
||||
- Distributed task-ID allocation (`packages/core/src/distributed-task-id.ts`) is the first mesh-aware coordinated write primitive.
|
||||
- Durable state lives in SQLite tables `distributed_task_id_state` (prefix sequence + authoritative committed count) and `distributed_task_id_reservations` (reservation lifecycle rows).
|
||||
- Reserve/commit/abort execute under a process-local lock and a single SQLite transaction. Lazy reservation expiry cleanup runs inside those same transactions.
|
||||
- Default reservation TTL is `15 * 60 * 1000` ms (15 minutes). Expired/aborted reservations are **burned IDs** and are never reissued.
|
||||
- `committedClusterTaskCount` from allocator state is the only authoritative cluster-wide committed-task count. Local task-row counts and ID suffix math are not authoritative.
|
||||
- Mesh allocator write routes (`/api/mesh/task-ids/reserve|commit|abort`) return `503` when the coordinator node is unreachable; they never fall back to local-only cluster ID issuance.
|
||||
- Process lifecycle ownership:
|
||||
- `fn serve` / `fn dashboard` start a single process-level `PeerExchangeService` and stop it during shutdown.
|
||||
- `CentralCore.startDiscovery()` is invoked from CLI startup only after HTTP bind completes so discovery advertises the actual listening port.
|
||||
|
||||
Reference in New Issue
Block a user