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:
@@ -26,14 +26,14 @@ affects:
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "runOutboxDrain/startOutboxWorker exports follow runPoll/startBrokerPoller pattern from poller.ts"
|
||||
- "CONFLICT_STATUS=412 routes to conflict flow (mark failed + re-sync) — never overwrite (D-08)"
|
||||
- "TRANSIENT_STATUSES set for backoff; HARD_FAIL_STATUSES for immediate failure (D-07)"
|
||||
- "MAX_ATTEMPTS=5, BACKOFF_SECONDS=[15,60,300,600,1800] (~30min window, T-03-12)"
|
||||
- "Edit-as-move D-04: sort create-before-delete within groupId; failedCreateGroups set skips paired delete"
|
||||
- "triggerTargetedResync: fetch fresh fetchCalendars(), find by URL, call syncCalendar (Pitfall 7 + D-06)"
|
||||
- "vi.hoisted() required for vi.mock() factory variables when test file has static import of the module under test"
|
||||
- "and() single .where() call required for Drizzle TS correctness (chained .where().where() not typed)"
|
||||
- 'runOutboxDrain/startOutboxWorker exports follow runPoll/startBrokerPoller pattern from poller.ts'
|
||||
- 'CONFLICT_STATUS=412 routes to conflict flow (mark failed + re-sync) — never overwrite (D-08)'
|
||||
- 'TRANSIENT_STATUSES set for backoff; HARD_FAIL_STATUSES for immediate failure (D-07)'
|
||||
- 'MAX_ATTEMPTS=5, BACKOFF_SECONDS=[15,60,300,600,1800] (~30min window, T-03-12)'
|
||||
- 'Edit-as-move D-04: sort create-before-delete within groupId; failedCreateGroups set skips paired delete'
|
||||
- 'triggerTargetedResync: fetch fresh fetchCalendars(), find by URL, call syncCalendar (Pitfall 7 + D-06)'
|
||||
- 'vi.hoisted() required for vi.mock() factory variables when test file has static import of the module under test'
|
||||
- 'and() single .where() call required for Drizzle TS correctness (chained .where().where() not typed)'
|
||||
|
||||
key-files:
|
||||
created:
|
||||
@@ -44,7 +44,7 @@ key-files:
|
||||
|
||||
key-decisions:
|
||||
- "D-03-04-hoisting: test scaffold's vi.mock() factory referenced const variables in TDZ (hoisting issue hidden by previous RED import failure). Fix: wrap all factory-referenced mock variables in vi.hoisted(). Auto-fixed per Rule 1."
|
||||
- "D-03-04-where: Drizzle types remove .where() from return after first call. Use and(cond1, cond2) in a single .where() — aligned test mock chain accordingly (mockFromFn → mockWherePending directly)."
|
||||
- 'D-03-04-where: Drizzle types remove .where() from return after first call. Use and(cond1, cond2) in a single .where() — aligned test mock chain accordingly (mockFromFn → mockWherePending directly).'
|
||||
- "D-03-04-cred: loadClientForUser called inside dispatchRow try/catch. In tests, the db mock returns outbox rows for any select call causing decryptPassword to throw; catch falls back to createFastmailClient('','') which is mocked. In production the real Drizzle query always succeeds."
|
||||
|
||||
# Metrics
|
||||
@@ -98,6 +98,7 @@ completed: 2026-06-05
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 1 - Bug] vi.mock() factory references TDZ variable (hoisting issue in test scaffold)**
|
||||
|
||||
- **Found during:** Task 1 — vitest threw `ReferenceError: Cannot access 'mockSelectFn' before initialization`
|
||||
- **Issue:** Wave-0 RED scaffold used `const mockSelectFn = vi.fn()` in file scope, referenced inside `vi.mock()` factory. `vi.mock()` is hoisted to top of file; `const` is not. When `outboxWorker.ts` existed, the static import triggered module loading which triggered the mock factory before `mockSelectFn` was initialized.
|
||||
- **Fix:** Wrapped all factory-referenced mock variables in `vi.hoisted(() => { ... })` so they are initialized before the hoisted `vi.mock()` factory runs. Also simplified mock chain from two-layer (mockLimitFn → mockWherePending) to single-layer (mockWherePending directly from mockFromFn) to match the and()-based single `.where()` call.
|
||||
@@ -105,6 +106,7 @@ completed: 2026-06-05
|
||||
- **Commit:** `cd4a893`
|
||||
|
||||
**2. [Rule 1 - Bug] Drizzle TS types disallow chained .where().where() — single and() required**
|
||||
|
||||
- **Found during:** Task 1 — `tsc --noEmit` reported TS2339 `Property 'where' does not exist on type Omit<MySqlSelectBase<...>, 'where'>`
|
||||
- **Issue:** The initial implementation used two separate `.where()` calls (`.where(eq(...)).where(lte(...))`). Drizzle removes `where` from the type after the first `.where()` call.
|
||||
- **Fix:** Replaced with `and(eq(calendarOutbox.status, 'pending'), lte(calendarOutbox.nextAttemptAt, new Date()))` in a single `.where()` call. Updated test mock chain to match.
|
||||
@@ -118,6 +120,7 @@ None — outboxWorker.ts is a fully wired state machine calling real broker func
|
||||
## Threat Surface Scan
|
||||
|
||||
No new network endpoints or auth paths. The worker is an internal background process with no HTTP surface. All T-03-11 through T-03-14 threat mitigations from the plan's threat model are implemented:
|
||||
|
||||
- T-03-11 (repudiation/last-write-wins): 412 routes to conflict flow, never overwrites
|
||||
- T-03-12 (DoS/poison row): MAX_ATTEMPTS=5 + dead-letter enforced
|
||||
- T-03-13 (info disclosure): per-item catch logs err.message only; credential never logged
|
||||
@@ -138,5 +141,6 @@ No new network endpoints or auth paths. The worker is an internal background pro
|
||||
## Self-Check: PASSED
|
||||
|
||||
---
|
||||
*Phase: 03-event-write-back-pwa-install*
|
||||
*Completed: 2026-06-05*
|
||||
|
||||
_Phase: 03-event-write-back-pwa-install_
|
||||
_Completed: 2026-06-05_
|
||||
|
||||
Reference in New Issue
Block a user