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.
6.4 KiB
phase, fixed_at, review_path, iteration, findings_in_scope, fixed, skipped, status
| phase | fixed_at | review_path | iteration | findings_in_scope | fixed | skipped | status |
|---|---|---|---|---|---|---|---|
| 03-event-write-back-pwa-install | 2026-06-09T15:06:11Z | .planning/phases/03-event-write-back-pwa-install/03-REVIEW.md | 2 | 8 | 8 | 0 | all_fixed |
Phase 3: Code Review Fix Report (Iteration 2)
Fixed at: 2026-06-09T15:06:11Z Source review: .planning/phases/03-event-write-back-pwa-install/03-REVIEW.md Iteration: 2
Summary:
- Findings in scope: 8 (fix_scope: all — Critical + Warning + Info)
- Fixed: 8
- Skipped: 0
All fixes verified with tsc --noEmit AND the full vitest suite in BOTH apps:
apps/api: 108 tests pass (was 103 baseline; +5 new regression tests)apps/pwa: 145 tests pass (was 141 baseline; +4 new regression tests)- Typecheck clean in both packages.
Fixed Issues
CR-01: Edit-as-move silently strips a recurring series' RRULE
Files modified: apps/api/src/routes/events.ts, apps/api/src/broker/outboxWorker.ts, apps/api/tests/routes/events.test.ts, apps/api/tests/broker/outboxWorker.test.ts
Commit: 5168920
Applied fix: Used the review's approach 1 (forward the RRULE from the route). The PATCH edit lookup now also selects calendarEvents.rawVevent. In the edit-as-move branch, when the edit payload carries no explicit recurrence, the route extracts the source RRULE via extractRruleString() and stashes it on the create outbox payload as _preservedRrule. The worker's create branch now mirrors the update branch's recurrence logic: it re-applies _preservedRrule when the payload omits recurrence, while an explicit recurrence (including 'none') still wins. Added two worker regression tests (moved event → emitted ICS contains RRULE:; explicit recurrence:'none' suppresses RRULE even when _preservedRrule present) and one route regression test (move stashes the source FREQ=WEEKLY;BYDAY=MO on the create row).
Note: Logic-sensitive fix. Backed by direct regression tests asserting the RRULE survives the move on both the route side (payload stash) and the worker side (ICS re-apply), so behavior is locked rather than relying on syntax verification alone.
WR-01: Edit form provides no indication recurrence is locked
Files modified: apps/pwa/src/components/EventForm.tsx, apps/pwa/src/components/EventForm.test.tsx
Commit: eed178f
Applied fix: Additive helper text only (no logic change). In edit mode, explanatory copy renders beneath the disabled recurrence select: "Repeat can't be changed yet — edits keep the existing schedule." Added two tests (text present in edit mode; absent in create mode).
WR-02: handleAllDayToggle can leave end-date inconsistent
Files modified: apps/pwa/src/components/EventForm.tsx, apps/pwa/src/components/EventForm.test.tsx
Commit: eed178f
Applied fix: On toggle-on, endDate is clamped to max(startDate, endDate) deterministically (snaps a behind-end up to the start day) and any stale end-time error from the timed view is cleared. Added a test toggling all-day ON with end behind start, asserting the clamp and clean validation. Per the review's prescribed max(startDate, endDate) fix, a genuinely midnight-spanning event (end day after start day) still yields a 2-day all-day span — the clamp only repairs the behind-case, matching the review's suggested fix exactly.
WR-03: Missing cached etag becomes an unconditional PUT/DELETE
Files modified: apps/api/src/broker/write.ts
Commit: 5b720ff
Applied fix: Took the review's minimum (observability). updateCalendarEvent and deleteCalendarEvent now console.warn when dispatched with a null/empty etag, making the unconditional-write (conflict-detection-disabled) path observable instead of silent. The write is not blocked (blocking would strand the user's edit).
WR-04: sync-status masks an earlier failure behind the newest row
Files modified: apps/api/src/routes/events.ts, apps/api/tests/routes/events.test.ts
Commit: fd13852
Applied fix: The sync-status query now orders by a status-priority CASE (failed/dead rank 0, pending rank 1, done rank 2) before createdAt DESC, so any failed/dead row for the uid is surfaced ahead of a later done row. Added a test seeding a dead row, asserting the handler returns dead + its error and that the ORDER BY contains the priority CASE expression (scanned via the Drizzle sql queryChunks to avoid the circular-structure JSON.stringify pitfall).
IN-01: RRULE_PRESETS round-trip is lossy for parameterized RRULEs
Files modified: apps/api/src/broker/vevent.ts
Commit: f95760e
Applied fix: Documentation only. Added a v1-limitation note at RRULE_PRESETS explaining that applying a bare preset to a previously-rich rule drops BYDAY/INTERVAL/UNTIL/COUNT, and that recurrence editing must modify the parsed RECUR in place rather than replacing it with a preset.
IN-02: parseDateTime silently rewrites a malformed edit value to today/09:00
Files modified: apps/pwa/src/components/EventForm.tsx, apps/pwa/src/components/EventForm.test.tsx
Commit: eed178f
Applied fix: parseDateTime now returns an ok flag. A new initFormDateTime() helper falls back to today/09:00 only on the CREATE path (benign default for a new event); in EDIT mode a parse failure leaves the field blank. validate() blocks submit when start/end (or time for non-all-day) is blank, surfacing "Couldn't read this event's date — re-open it from the calendar." Added a test: edit mode with an unparseable start leaves the date blank and blocks updateEvent.
Note: Logic-sensitive (changes validation flow). Backed by a regression test asserting the blank field + blocked submit; CREATE-mode defaults remain covered by existing tests.
IN-03: Unchecked as casts on JSON-parsed outbox payload fields
Files modified: apps/api/src/broker/outboxWorker.ts, apps/api/tests/broker/outboxWorker.test.ts
Commit: b8c1864
Applied fix: Added a worker-local zod schema (outboxPayloadSchema, mirroring eventFieldsSchema and .passthrough()-ing the CR-01 _preservedRrule field). Both the update and create branches now safeParse the JSON payload after parsing and hard-fail the row (no retry) on validation error, so a schema-invalid row can never dispatch SUMMARY:undefined/Invalid Date. Added a test: a create row missing title is hard-failed and never dispatched.
Fixed: 2026-06-09T15:06:11Z Fixer: Claude (gsd-code-fixer) Iteration: 2