# Phase 3: Event Write-Back + PWA Install - Discussion Log

> **Audit trail only.** Do not use as input to planning, research, or execution agents.
> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.

**Date:** 2026-06-05
**Phase:** 3-Event Write-Back + PWA Install
**Areas discussed:** Target calendar pick, Write feedback & sync

Areas offered but not selected (left to Claude's discretion): Event form & fields, iOS install onboarding.

---

## Target calendar pick

### Default target calendar for a new event

| Option             | Description                                                                                | Selected |
| ------------------ | ------------------------------------------------------------------------------------------ | -------- |
| Their own personal | New events default to the creator's own personal calendar                                  |          |
| Shared Family      | Default to the shared Family calendar; personal is opt-out (needs fallback, may not exist) |          |
| Remember last-used | Default to whatever calendar they last wrote to, persisted per member                      | ✓        |

**User's choice:** Remember last-used
**Notes:** Seed/first-time default set to creator's own personal (always exists; shared may not, per D-16).

### Calendar selector visibility

| Option                | Description                                                                        | Selected |
| --------------------- | ---------------------------------------------------------------------------------- | -------- |
| Only when >1 writable | Hide picker when only one writable calendar exists; show once shared Family exists | ✓        |
| Always show           | Always render the selector with default pre-selected                               |          |

**User's choice:** Only when >1 writable

### Move event between calendars on edit

| Option                | Description                                                      | Selected |
| --------------------- | ---------------------------------------------------------------- | -------- |
| Lock calendar on edit | Calendar fixed once created; defer cross-calendar move to v1.x   |          |
| Allow move            | Edit may change target calendar (CalDAV delete-old + create-new) | ✓        |

**User's choice:** Allow move
**Notes:** Researcher/planner must handle UID/etag and partial-failure safety.

### Writable calendar set

| Option                       | Description                                                                         | Selected |
| ---------------------------- | ----------------------------------------------------------------------------------- | -------- |
| Own personal + shared Family | Write to own personal + shared Family; other member's personal is read-only overlay | ✓        |
| Any visible calendar         | Allow writing to any aggregated calendar incl. other member's personal              |          |

**User's choice:** Own personal + shared Family

---

## Write feedback & sync

### How the member sees their own change after save (poll-based cache)

| Option                      | Description                                                         | Selected       |
| --------------------------- | ------------------------------------------------------------------- | -------------- |
| Optimistic + forced re-sync | Optimistic UI update + background targeted re-sync of that calendar | (evolved into) |
| Forced re-sync, then show   | Synchronously re-sync that calendar, then refresh; ~0.5–1s spinner  | ✓ (initial)    |
| Wait for poll               | Let the ctag poller pick it up next cycle; visibly laggy            |                |

**User's choice:** Forced re-sync, then show — subsequently evolved (via the failure-handling answer) into optimistic-accept + queued write + re-sync on confirm. Same authoritative-cache guarantee, async instead of blocking.

### Behavior when the CalDAV write fails

| Option                          | Description                                              | Selected |
| ------------------------------- | -------------------------------------------------------- | -------- |
| Inline error + retry, keep form | Keep form + input, show inline error, manual retry       |          |
| Toast + silent rollback         | Close form, roll back optimistic change, transient toast |          |

**User's choice:** Free-text — "accept the edit, queue it, keep a toast showing it isn't sync'd yet and keep retrying. Transient failures should be short; anything beyond that is a hard fail that won't auto-resolve."
**Notes:** Reframed the save path into an optimistic-accept + queued-write-with-retry model (outbox).

### Edit-conflict (etag mismatch / 412) handling

| Option                       | Description                                                    | Selected |
| ---------------------------- | -------------------------------------------------------------- | -------- |
| Detect + warn, reload latest | If-Match cached etag; on 412 abort, re-sync, warn before retry | ✓        |
| Last-write-wins              | No If-Match; overwrite whatever is on Fastmail                 |          |

**User's choice:** Detect + warn, reload latest

### Pending-write queue location

| Option                       | Description                                                                      | Selected |
| ---------------------------- | -------------------------------------------------------------------------------- | -------- |
| Server-side outbox (MariaDB) | API persists pending row; backend worker drains with backoff; survives app close | ✓        |
| Client-side queue (PWA)      | PWA holds + retries; stops when app closed unless persisted                      |          |

**User's choice:** Server-side outbox (MariaDB)

### Transient vs hard-failure classification

| Option                                   | Description                                                           | Selected |
| ---------------------------------------- | --------------------------------------------------------------------- | -------- |
| Backoff transient; fail-fast hard errors | Network/5xx/timeout → bounded backoff; 401/403/400/412 → stop/surface | ✓        |
| Let me refine the thresholds             | Operator specifies retry window/backoff/status codes                  |          |

**User's choice:** Backoff transient; fail-fast hard errors (412 routed to the conflict-reload flow)

---

## Claude's Discretion

- Event form & fields (field set, layout) — build into / alongside the reused `EventDetailPopover`.
- Recurrence creation UX (presets vs custom builder) — whole-series only for v1.
- iOS install onboarding (trigger + annotated walkthrough) and Android `beforeinstallprompt`.
- `vite-plugin-pwa` manifest + service worker config (keep SW conservative re: OIDC/iOS login).
- Outbox worker mechanics (interval/trigger, idempotency key, max attempts, dead-letter).

## Deferred Ideas

- Single-occurrence / "this-and-following" recurring edits (CAL-09/CAL-10) — v1.x.
- Writing to the other member's personal calendar — out (read-only overlay in v1).
- SSE-based live sync-state push — after the Phase 4 SSE-over-Pangolin gate; Phase 3 uses polling.
