Files
buzz/desktop
Duncan 0d7fe32a9e fix(unread): centralize allocateGeneration, fix rebase boundary, add finally to drainPendingIntents
Round-8 fixes for #3966:

1. allocateGeneration() primitive (pendingOverrideIntents.ts)
   Preflights BOTH the emitted gen AND _nextGen+1 before any mutation.
   If either is unsafe, throws without touching any queue/transaction map.
   Replaces both post-increment isSafeInteger guards in enqueue() and
   promoteDeferred(). promoteDeferred() now allocates FIRST, then mutates
   deferredEnqueues/promotedDeferredPayloads — so an allocation failure
   leaves the deferred payload untouched and abortTransaction can safely
   re-buffer it.

2. Hydration rebase boundary (readStateStorage.ts)
   Condition order swapped: rebase checked before clamp. New trigger:
   !isSafeInteger(requiredNextGen) || requiredNextGen >= MAX_SAFE_INTEGER
   This catches maxObservedGen = MAX_SAFE_INTEGER-1 (requiredNextGen =
   MAX_SAFE_INTEGER), which previously passed the isSafeInteger check and
   took the clamp path, leaving nextGen=MAX_SAFE_INTEGER and one tick from
   poisoning _nextGen. Added isSafeInteger guard to ng serialization.

3. Promotion allocation failure → total-closure exit (readStateDrain.ts)
   promoteDeferred() call in step-3 is now wrapped in try-catch. If
   allocateGeneration throws, the catch calls abortTransaction +
   scheduleAbortRetry and continues, same as other non-success exits.

4. drainPendingIntents finally (readStateManager.ts)
   Wrapped in try-finally so drainScheduled=false always clears, even on
   an escaped exception from the impl. Condensed JSDoc for scheduleDrain
   to stay within the 1000-line ratchet.

5. Two new witnesses (Tests 60, 61):
   - Test 60: pi.gen=MAX-1, ng=MAX-1 → hydrate → rebase fires → two
     enqueues get safe distinct gens, neither throws, persisted ng safe,
     both intents survive fresh-manager hydration.
   - Test 61: _nextGen forced to MAX_SAFE_INTEGER via restoreFromStorage
     with deferred gen2 mid-transaction → drain → allocation throws in
     promoteDeferred → catch routes to abortTransaction+scheduleAbortRetry
     → drainScheduled false, drainRetryTimer set, gen1 live, deferred
     payload preserved → hydrateFromLocalStorage normalizes _nextGen to 2
     → retry drain completes gen1+gen2, frontier ≥ 999.

Optional MINOR (explicit typed pass outcome): skipped. The change would
require threading a return value through drainPendingIntentsImpl and its
caller, adding several lines to files already near the ratchet. The current
drainRetryTimer === null discrimination is sound for the synchronous impl.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
2026-08-08 18:40:08 -04:00
..
2026-08-03 21:51:17 -04:00
2026-03-09 13:02:11 -07:00
2026-06-11 15:06:24 +00:00
2026-03-09 13:02:11 -07:00

Buzz

Desktop chat shell with:

  • Tauri + React + TypeScript + Vite
  • Tailwind CSS
  • shadcn/ui-ready shared components
  • Biome (lint/format/check)
  • Feature-driven frontend structure

Scripts

  • pnpm dev - run the web frontend
  • pnpm tauri dev - run the desktop app
  • pnpm build - typecheck and build frontend
  • pnpm typecheck - TypeScript checks
  • pnpm lint - Biome lint
  • pnpm format - Biome format (write)
  • pnpm check - Biome check

Structure

  • src/shared - reusable app-wide code (ui, lib, styles)
  • src/features - feature modules (vertical slices)
  • src/app - top-level app composition