docs(18-03): complete broker rewire plan
This commit is contained in:
+136
@@ -0,0 +1,136 @@
|
||||
---
|
||||
phase: 18-auto-timezone-detection-and-ability-to-change-timezone
|
||||
plan: "03"
|
||||
subsystem: api
|
||||
tags: [timezone, broker, reminder-scheduler, outbox-worker, tdd, drizzle]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 18-auto-timezone-detection-and-ability-to-change-timezone
|
||||
plan: "01"
|
||||
provides: getHouseholdTimezone(db) — the accessor imported at all three rewired sites
|
||||
provides:
|
||||
- reminderScheduler.ts all-day branch reads stored household_timezone via getHouseholdTimezone(db)
|
||||
- outboxWorker.ts UPDATE all-day branch reads stored household_timezone via getHouseholdTimezone(db)
|
||||
- outboxWorker.ts CREATE all-day branch reads stored household_timezone via getHouseholdTimezone(db)
|
||||
|
||||
affects:
|
||||
- 18-04-PLAN (PWA settings UI — all three rewired sites now respect the timezone set via Plan 18-02 admin API)
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- getHouseholdTimezone(db) imported and awaited at three all-day broker sites (replacing bare process.env.TZ ?? Intl)
|
||||
- Mock chain extension: makeAppConfigSelectMock for where().limit() chain (different from makeSelectMock which handles innerJoin chains)
|
||||
- mockTwoQueries updated to mock the new third db.select() call, keeping existing tests green via D-06 fallback
|
||||
- wireMockChain() extended in outboxWorker.test.ts to handle app_config table with where().limit() returning []
|
||||
|
||||
key-files:
|
||||
created: []
|
||||
modified:
|
||||
- apps/api/src/broker/reminderScheduler.ts
|
||||
- apps/api/src/broker/outboxWorker.ts
|
||||
- apps/api/tests/broker/reminderScheduler.test.ts
|
||||
- apps/api/tests/broker/outboxWorker.test.ts
|
||||
|
||||
key-decisions:
|
||||
- "D-05 wired: three all-day sites replaced bare process.env.TZ ?? Intl with await getHouseholdTimezone(db)"
|
||||
- "D-06 preserved: getHouseholdTimezone falls back to process.env.TZ → Intl when no app_config row exists; existing tests pin process.env.TZ and pass unchanged"
|
||||
- "D-07 enforced: eventDateTime.ts and hydrateEvents.ts not modified (verified via git diff)"
|
||||
- "mockTwoQueries extended to emit a third mockReturnValueOnce for the new app_config SELECT (no-row → D-06 fallback)"
|
||||
- "mockReset() added in mockTwoQueries/mockThreeQueries to clear unconsumed once-queue entries across vi.resetModules() cycles (Vitest caches mock factory instances)"
|
||||
|
||||
requirements-completed: [D-05, D-06, D-07]
|
||||
|
||||
# Metrics
|
||||
duration: 28min
|
||||
completed: 2026-06-15
|
||||
---
|
||||
|
||||
# Phase 18 Plan 03: Broker Rewire — All-Day TZ Sites Summary
|
||||
|
||||
**Three all-day "9 AM local" reminder call sites in reminderScheduler.ts and outboxWorker.ts now route through `getHouseholdTimezone(db)` instead of the bare `process.env.TZ ?? Intl` expression, making the stored household_timezone the source of truth for all-day reminder fire times (D-05/D-06/D-07)**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 28 min
|
||||
- **Started:** 2026-06-15T02:04:00Z
|
||||
- **Completed:** 2026-06-15T02:32:01Z
|
||||
- **Tasks:** 2 (TDD RED + GREEN)
|
||||
- **Files modified:** 4
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- Rewired `reminderScheduler.ts` line 247: `const serverTz = await getHouseholdTimezone(db);`
|
||||
- Rewired `outboxWorker.ts` UPDATE branch (~line 501): `const tz = await getHouseholdTimezone(db);`
|
||||
- Rewired `outboxWorker.ts` CREATE branch (~line 607): `const tz = await getHouseholdTimezone(db);`
|
||||
- Added 4 new RED tests (2 scheduler + 2 outbox) verifying stored 'America/Chicago' drives the 9 AM alert instant; all correctly FAIL before the rewire
|
||||
- Extended test mock infrastructure: `makeAppConfigSelectMock`, `mockThreeQueries`, updated `mockTwoQueries` to add third call for D-06 fallback path, updated `wireMockChain()` in outboxWorker.test.ts for app_config table
|
||||
- All 76 broker tests pass after GREEN commit; TypeScript typecheck (`tsc --noEmit`) clean
|
||||
- D-07 boundary confirmed: `eventDateTime.ts` and `hydrateEvents.ts` not in changed-files list
|
||||
|
||||
## Task Commits
|
||||
|
||||
1. **Task 1: RED — failing stored-TZ all-day tests** - `94daca3` (test)
|
||||
2. **Task 2: GREEN — rewire all three all-day TZ call sites** - `c80845c` (feat)
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `apps/api/src/broker/reminderScheduler.ts` — import added + line 247 rewired to `await getHouseholdTimezone(db)`
|
||||
- `apps/api/src/broker/outboxWorker.ts` — import added + lines ~501 and ~607 rewired to `await getHouseholdTimezone(db)`
|
||||
- `apps/api/tests/broker/reminderScheduler.test.ts` — `makeAppConfigSelectMock`, `mockThreeQueries` helpers added; `mockTwoQueries` extended to mock the new third db.select(); Plan 18-03 describe block with 2 stored-TZ tests
|
||||
- `apps/api/tests/broker/outboxWorker.test.ts` — `wireMockChain()` extended for app_config table; `wireMockChainWithTz()` helper for D-05 stored-TZ tests; Plan 18-03 describe block with 2 stored-TZ tests (create + update branch)
|
||||
|
||||
## Decisions Made
|
||||
|
||||
- `mockTwoQueries` was extended (not renamed) to avoid updating 20+ call sites. The third mock call returns an empty app_config row (no stored TZ → D-06 fallback), which is transparent to all existing tests that pin `process.env.TZ`.
|
||||
- `mockReset()` added inside `mockTwoQueries` and `mockThreeQueries` to flush any unconsumed `mockReturnValueOnce` entries. Vitest caches mock factory instances across `vi.resetModules()` cycles, so the pending third entry from one test bleeds into the next test's queue without an explicit reset.
|
||||
- The outbox UPDATE branch test uses `mockWhereCalEvents.mockResolvedValue([{etag: 'W/"abc"'}])` after `wireMockChainWithTz` to drive the freshEtagRows path into the all-day VALARM branch (no rawVevent → falls through to the explicit-reminder/allDay condition).
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 1 - Bug] vi.fn() queue contamination across tests with vi.resetModules()**
|
||||
- **Found during:** Task 1 (RED) — second scheduler test crashed with "innerJoin is not a function"
|
||||
- **Issue:** `vi.clearAllMocks()` does not flush `mockReturnValueOnce` queues. Vitest's mock factory for `vi.mock()` returns the SAME `vi.fn()` instance across module resets, so an unconsumed third entry from the first test bled into the first call slot of the second test — causing `makeAppConfigSelectMock` to be returned where `makeSelectMock` was expected.
|
||||
- **Fix:** Added `db.select.mockReset()` at the start of both `mockTwoQueries` and `mockThreeQueries` to explicitly clear the queue before configuring new once-values.
|
||||
- **Files modified:** `apps/api/tests/broker/reminderScheduler.test.ts`
|
||||
|
||||
**2. [Rule 2 - Missing critical functionality] wireMockChain() in outboxWorker.test.ts didn't handle app_config**
|
||||
- **Found during:** Task 2 (GREEN) — the existing CAL-13 all-day test would have broken after the rewire because `app_config` fell through to `{ where: mockWherePending }`, and `mockWherePending(...)` returns a Promise; calling `.limit(1)` on a Promise throws "limit is not a function"
|
||||
- **Fix:** Extended `wireMockChain()` to handle `app_config` table with a `{ where: fn → {limit: fn} }` chain returning empty rows (D-06 fallback), matching the `getHouseholdTimezone` SELECT chain
|
||||
- **Files modified:** `apps/api/tests/broker/outboxWorker.test.ts`
|
||||
|
||||
**3. [Rule 2 - Missing critical functionality] mockTwoQueries needed a third mock for the new db.select() call**
|
||||
- **Found during:** Task 2 (GREEN) — all 20 existing scheduler tests that call `mockTwoQueries` started failing because `runReminderCheck` now issues a third `db.select()` for `getHouseholdTimezone`; the undefined return caused crashes
|
||||
- **Fix:** Updated `mockTwoQueries` to add a third `mockReturnValueOnce(makeAppConfigSelectMock(null))` returning no row, keeping the D-06 fallback path for all existing tests
|
||||
- **Files modified:** `apps/api/tests/broker/reminderScheduler.test.ts`
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None — all three rewired sites now read from the actual DB through `getHouseholdTimezone(db)`. No placeholder values.
|
||||
|
||||
## Threat Flags
|
||||
|
||||
None — no new network endpoints, auth paths, file access patterns, or schema changes. The three rewired sites are read-only DB lookups within the trusted server process (T-18-08 disposition: mitigate → validated values only reach computeAlertInstantUtc via the Plan 01 accessor that enforces the D-06 fallback chain).
|
||||
|
||||
## TDD Gate Compliance
|
||||
|
||||
- RED gate: `94daca3` — `test(18-03): add failing stored-TZ all-day tests for scheduler + outbox`
|
||||
- GREEN gate: `c80845c` — `feat(18-03): route all-day reminder TZ through stored household_timezone`
|
||||
- REFACTOR gate: N/A (implementation was clean on first pass; deviations were auto-fixed inline)
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- `apps/api/src/broker/reminderScheduler.ts` — FOUND
|
||||
- `apps/api/src/broker/outboxWorker.ts` — FOUND
|
||||
- `apps/api/tests/broker/reminderScheduler.test.ts` — FOUND
|
||||
- `apps/api/tests/broker/outboxWorker.test.ts` — FOUND
|
||||
- Commit `94daca3` — FOUND
|
||||
- Commit `c80845c` — FOUND
|
||||
|
||||
---
|
||||
*Phase: 18-auto-timezone-detection-and-ability-to-change-timezone*
|
||||
*Completed: 2026-06-15*
|
||||
Reference in New Issue
Block a user