HapiProtocol/Window/ — pure port of web/src/lib/message-window-store.ts +
messages.ts, mirroring the Android reference port 1:1:
- MessageWindowState: constants (400/600/800/800/200), MessagePosition,
OlderLoadOutcome, full InternalState fields, persisted v2 snapshot shape
- MessageWindowLogic: every transition (merge/trim preserving queued rows,
latest replace with request-baseline identity preservation, tail sync
begin/apply/finish, older pages + epoch-mismatch reset, enterTailMode
that deliberately keeps requiresLatestReset, activate, SSE ingest with
hidden-row cursor advance, markConsumed stamping server rows to 'sent',
optimistic lifecycle, queued reconcile, hydrate/persist, seededState)
- MessageMerge: position comparator (ASCII tie-break), localId echo
replacement preserving status/invokedAt, 10s sent-dedup fallback
- MessageRetention: calls the fixtures-green chat pipeline's
normalizeDecryptedMessage directly (no hand-mirrored tree to drift)
- WindowMessage: identity-carrying final class (web's !== baseline
classification), tri-state invokedAt, buildOptimisticMessage
HapiClient/Stores/ — async half:
- MessagesProviding seam (three-variant MessagesPageQuery; APIClient
conforms via its existing endpoints)
- MessageWindowController actor: single-flight tail controller with
trailing drain and a synchronous generation bump before the first await
(the web runs to its first suspension; Android used UNDISPATCHED),
fetchOlder with onBeforeApply veto, SSE hooks, optimistic append/status/
cancel-invoked, queued-state reconciliation in 1000-id batches, seedFrom
- WindowSnapshotStore: per-session JSON snapshots, LRU 10 (dedup TODO with
the session-list package's cache) + MessageWindowControllers registry
Tests (swift-testing):
- PaginationFixtureTests: parameterized replay of shared/fixtures/
pagination/*.json against the real controller via a scripted provider;
asserts expectedRequests (canonical JSON incl. explicit-null untils),
expectedOutcome, expectedCandidates, and the final expectedState
projection with per-op labels and first-differing-line diffs
- MessageWindowControllerTests: tail-sync coalescing + trailing drain,
concurrent-SSE preservation across a reset replace, cursor-no-advance
guard, snapshot round-trip/LRU, seedFrom
All 11 fixtures verified green against a line-by-line Python mirror of
these exact algorithms (no local Swift toolchain; CI runs the real suite).