style(13-03): apply Prettier formatting across repo

Mechanical reformat — no logic changes. 398 files changed, 19125
insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc
(singleQuote:true, semi:true, tabWidth:2, trailingComma:all,
printWidth:100). Isolated per D-13-08 for reviewability.
This commit is contained in:
Lucas Berger
2026-06-11 20:35:18 -04:00
parent 4bc0445173
commit 982438dc10
398 changed files with 19050 additions and 16382 deletions
@@ -1,6 +1,6 @@
---
phase: 03-event-write-back-pwa-install
plan: "11"
plan: '11'
subsystem: api-broker
tags: [tdd, gap-closure, outbox-worker, concurrency-guard, etag, durability, calDAV]
dependency_graph:
@@ -16,25 +16,25 @@ dependency_graph:
tech_stack:
added: []
patterns:
- "TDD RED→GREEN per task"
- "DB sibling-status query pattern for durable inter-row ordering"
- "Module-level boolean drain guard for single-process deployment"
- 'TDD RED→GREEN per task'
- 'DB sibling-status query pattern for durable inter-row ordering'
- 'Module-level boolean drain guard for single-process deployment'
- "Symbol.for('drizzle:Name') for safe Drizzle table identification in tests (JSON.stringify circular)"
- "vi.resetAllMocks() instead of vi.clearAllMocks() when mockImplementationOnce queues must be purged"
- "Per-table mockWhere functions (mockWherePending vs mockWhereCalEvents) to isolate select mocks"
- 'vi.resetAllMocks() instead of vi.clearAllMocks() when mockImplementationOnce queues must be purged'
- 'Per-table mockWhere functions (mockWherePending vs mockWhereCalEvents) to isolate select mocks'
key_files:
modified:
- apps/api/src/broker/outboxWorker.ts
- apps/api/tests/broker/outboxWorker.test.ts
key_decisions:
- "CR-04 durable gate uses DB sibling-status query (not in-memory Set) so create-before-delete ordering holds across drain cycles; in-batch fast path retained as optimization"
- 'CR-04 durable gate uses DB sibling-status query (not in-memory Set) so create-before-delete ordering holds across drain cycles; in-batch fast path retained as optimization'
- "CR-05 isDraining guard is explicitly documented as single-process-only; multi-replica deployments would need DB row-claim (UPDATE WHERE status='pending' with affected-rows check)"
- "WR-02 fresh etag reads calendarEvents at dispatch time, not calendarOutbox enqueue time; D-08 conflict detection preserved — genuine external changes update calendarEvents.etag differently from any queued row"
- 'WR-02 fresh etag reads calendarEvents at dispatch time, not calendarOutbox enqueue time; D-08 conflict detection preserved — genuine external changes update calendarEvents.etag differently from any queued row'
- "mockFromFn updated to use Symbol.for('drizzle:Name') to identify Drizzle tables — JSON.stringify throws CircularReference on all MySqlTable instances"
- "All beforeEach blocks switched to vi.resetAllMocks() to prevent unconsumed mockImplementationOnce calls bleeding into subsequent tests"
- 'All beforeEach blocks switched to vi.resetAllMocks() to prevent unconsumed mockImplementationOnce calls bleeding into subsequent tests'
requirements-completed: [CAL-05, CAL-06]
duration: 30min
completed: "2026-06-05"
completed: '2026-06-05'
---
# Phase 03 Plan 11: Outbox Durability and Etag Fix Summary
@@ -81,6 +81,7 @@ Each task was committed atomically:
### Auto-fixed Issues
**1. [Rule 1 - Bug] Drizzle table identification using JSON.stringify throws CircularReference**
- **Found during:** Task 1 GREEN — when running tests after implementing the sibling-status DB select
- **Issue:** `wireMockChain`'s `mockFromFn` used `JSON.stringify(table).includes('member_credentials')` to identify the credential table. `JSON.stringify` on a Drizzle `MySqlTable` object throws `TypeError: Converting circular structure to JSON` (MySqlInt columns hold a back-reference to their parent table). The `catch` block silently set `isCred = false`, making ALL `db.select().from(...)` calls route to `mockWherePending` — including credential lookups. Prior tests "worked" accidentally because `mockDecryptPassword` was mocked to succeed regardless of input, but the new sibling-status select consumed `mockWherePending` calls out of order, breaking the D-04 ordering test and the CR-04 drain 2 test.
- **Fix:** Replaced with `(table as Record<symbol, string>)[Symbol.for('drizzle:Name')]` which reads the table name property Drizzle attaches as a Symbol. Added separate `mockWhereCalEvents` for `calendarEvents` table selects. Switched all `beforeEach` to `vi.resetAllMocks()`.
@@ -106,10 +107,10 @@ None beyond the mock infrastructure deviation above.
## Issues Closed
| ID | Description |
|----|-------------|
| CR-04 | Create-before-delete ordering relied on in-memory Set, broke across drain batches — DB sibling-status gate now authoritative |
| CR-05 | No concurrency guard — overlapping drain cycles could double-dispatch same row — isDraining guard prevents it (single-process) |
| ID | Description |
| ----- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| CR-04 | Create-before-delete ordering relied on in-memory Set, broke across drain batches — DB sibling-status gate now authoritative |
| CR-05 | No concurrency guard — overlapping drain cycles could double-dispatch same row — isDraining guard prevents it (single-process) |
| WR-02 | Update dispatch used stale enqueue-time etag — rapid successive edits guaranteed 412 — fresh calendarEvents.etag re-read at dispatch time |
## Known Stubs