From d9a9bdfafa09ee4d2edfa295bf1b5671edb3a5bb Mon Sep 17 00:00:00 2001 From: Hector Alvarez Date: Sun, 13 Sep 2026 16:51:42 -0500 Subject: [PATCH 1/8] docs: record housekeeping merge, production verification, and HK-6 cache finding --- memory-bank/activeContext.md | 55 ++++++++++++++++++++---------------- memory-bank/progress.md | 7 ++++- tasks/backlog.md | 19 +++++++++++++ tasks/sprint.md | 25 +++++++--------- 4 files changed, 65 insertions(+), 41 deletions(-) diff --git a/memory-bank/activeContext.md b/memory-bank/activeContext.md index 33a35e1..77925f1 100644 --- a/memory-bank/activeContext.md +++ b/memory-bank/activeContext.md @@ -1,37 +1,42 @@ # Active Context -Updated: 2026-09-13 +Updated: 2026-09-13 (post-merge) ## Current focus -**Repo housekeeping — DONE on branch `chore/repo-housekeeping`** -(5 commits off `dev`, awaiting PR into `dev` + review): - -1. ✅ Memory bank initialized (HK-4). -2. ✅ README corrections (HK-1): `robots.txt` removed from `src/public/` tree, - build-time generation note added, alarm storage test added to tests tree, - `tasks/` added to the repo-layout table. -3. ✅ Actions bump (HK-2): checkout@v7, setup-node@v7, setup-buildx@v4, - login@v4, build-push@v7, hadolint-action@v3.5.0. All four Dockerfiles - pre-validated locally with hadolint 2.15.1 (repo config: only info-level - DL3059 in the webhook image). -4. ✅ Husky guard (HK-3): hook skips lint-staged unless staged files match - `^web/.*\.(ts|js|json|css|md)$`; verified silent on yml- and md-only - commits (noise previously confirmed on both). -5. ✅ `tasks/` close-out: US-001 marked merged+deployed (Release #5, - healthz 200); HK-1..4 removed; HK-5 (nginx 1.27 EOL re-pin) added as a - backlog candidate. +**Housekeeping: MERGED.** PR #14 rebase-merged into `main` (7 commits, +`16dbbdd`); all four CI checks passed _on the bumped actions_; Release run #6 +succeeded 21:47Z (images rebuilt, webhook deploy fired, `healthz` 200). + +**Production verification (2026-09-13 ~22:05Z):** + +- Fresh homepage (cache-busted via query string) serves the US-001 alarm + build (`index-XH8wPmEB.js`, 200, alarm code present, 20 alarm refs in HTML). +- **Remaining manual DoD: audible alarm-tone check (needs a human ear).** + +## Open finding: stale-HTML → dead-asset window (→ HK-6) + +ADR 0006's assumption ("old hashed assets remain edge-resident so stale HTML +still resolves its assets") does NOT hold in practice: + +- A rebuild changed asset hashes even though app code was unchanged; the + edge-cached homepage (2 h TTL) referenced `index-CpV5GK4V.js`, which now + 404s on origin — and the 404 response itself got edge-cached (HIT). +- Until the HTML cache entry expires (~23:28Z), the cached homepage is + broken. Query strings DO vary the cache key (cache-busting works). +- Fix candidates: CF API purge after deploy (needs API token), retain previous + build's assets on origin in `deploy.sh`, or shorter HTML TTL. Logged as + backlog HK-6. ## Environment state -- `chore/repo-housekeeping` = dev + 5 commits; `dev` = `origin/dev` = `223d41f`. -- Local `main` = `origin/main` = `c7ecdca` (post-rebase-merge sync). -- US-001 deployed; homepage edge cache may lag up to 2 h. +- `dev` = `origin/dev` (223d41f + this doc commit); `main` = `origin/main` + (16dbbdd). Housekeeping branch merged and deletable. +- Local `chore/repo-housekeeping` rebased onto main pre-merge; may be deleted. ## Next steps -- Open PR `chore/repo-housekeeping` → `dev`; merge (no production risk — - workflow changes ride CI on next dev push). -- Owner: production audio check (alarm tone) → US-001 fully Done. +- Owner: audible alarm-tone check → US-001 fully Done. - Pick next epic: US-002 (recurring alarms) vs US-004 (multi-clock). -- Schedule HK-5 (nginx 1.27 → current stable, tag + digest together). +- Schedule HK-5 (nginx 1.27 EOL re-pin) and HK-6 (post-deploy cache purge or + asset retention). diff --git a/memory-bank/progress.md b/memory-bank/progress.md index c296477..ffa14f0 100644 --- a/memory-bank/progress.md +++ b/memory-bank/progress.md @@ -20,8 +20,13 @@ Site is live at `clock.taylormadetech.net`. - Production audio QA: alarm tone not yet verified by a human (jsdom can't test audio) — last open US-001 DoD item. +- **Stale-HTML → dead-asset window after every deploy** (HK-6): a rebuild can + change asset hashes; the 2 h edge-cached homepage then references assets + that 404 on origin, and the 404 gets edge-cached too (observed 2026-09-13). + Fix candidates: CF API purge post-deploy, retain old assets in `deploy.sh`, + or shorter HTML TTL. - Edge-cached homepage can lag up to 2 h behind a deploy (expected; judge - freshness via `/healthz` or hashed assets). + freshness via `/healthz` or a query-string cache-bust, which works). - CI actions pinned to Node-20-runtime majors (HK-2 — fix in progress). - `nginxinc/nginx-unprivileged:1.27-alpine` is an EOL mainline branch (HK-5 candidate: re-pin to current stable + digest). diff --git a/tasks/backlog.md b/tasks/backlog.md index ac13f97..5433ab3 100644 --- a/tasks/backlog.md +++ b/tasks/backlog.md @@ -51,3 +51,22 @@ sized/sequenced by the SDM. the image tag in `.github/workflows/ci.yml` (nginx-config-check), and run `nginx -t` locally on both configs. - Priority: Medium — security updates are accruing on the EOL branch. + +### HK-6 — Eliminate the stale-HTML / dead-asset window after deploys + +- Status: Candidate (observed live 2026-09-13 ~22:00Z). +- Finding: after a deploy that changes asset hashes, the edge-cached homepage + (2 h Cache Rule TTL, per ADR 0006) references assets that no longer exist + on origin; requests 404, and **Cloudflare caches the 404 itself** + (`cf-cache-status: HIT` on a 404). Until the HTML entry expires, the + homepage is broken. ADR 0006's assumption that old hashed assets remain + edge-resident does not hold in practice. +- Fix candidates (pick one, or combine): + 1. Purge the CF cache after a successful deploy (needs a CF API token — + scope decision + secret management). + 2. Retain the previous build's `assets/` on origin in `scripts/deploy.sh` + so old hashes keep resolving (simplest, no CF dependency). + 3. Shorten the HTML Edge TTL (e.g. 5-10 min) to shrink the window. + - Also consider making builds hash-deterministic for unchanged code. +- Priority: Medium-High — every deploy currently risks a broken homepage for + up to 2 h. diff --git a/tasks/sprint.md b/tasks/sprint.md index 01f87b2..9d4be46 100644 --- a/tasks/sprint.md +++ b/tasks/sprint.md @@ -17,19 +17,14 @@ Sprint window: active (no fixed calendar sprint; pipeline-driven). ## In flight -### Housekeeping branch `chore/repo-housekeeping` (→ PR into `dev`) - -- HK-1 README corrections, HK-2 Actions bump to Node-24 majors - (checkout@v7, setup-node@v7, buildx@v4, login@v4, build-push@v7, - hadolint-action@v3.5.0), HK-3 husky lint-staged guard, HK-4 memory bank - init, plus US-001 sprint close-out (this file). -- All committed on the branch; local `main` reset to `origin/main` after the - rebase-merge rewrote SHAs. +Nothing. Housekeeping (HK-1..HK-4 + US-001 close-out) merged via PR #14 +(rebase, 2026-09-13 21:47Z; Release run #6 deployed; healthz 200). ## Ready (not started) -Nothing. Next sprint content comes from the backlog once the owner picks the -next epic: US-002 (recurring alarms) vs US-004 (multi-clock). +Next sprint content comes from the backlog once the owner picks the next +epic: US-002 (recurring alarms) vs US-004 (multi-clock). HK-5/HK-6 are +standalone housekeeping candidates. ## Dependencies & sequencing @@ -42,8 +37,8 @@ next epic: US-002 (recurring alarms) vs US-004 (multi-clock). ## Risks -| Risk | Likelihood | Impact | Mitigation | -| ------------------------------------------------------- | ---------- | ----------------------- | --------------------------------- | -| Production alarm audio unverified | Medium | Medium (US-001 DoD gap) | Owner manual check; tracked above | -| nginx 1.27 base gets no security updates (EOL mainline) | High | Medium | HK-5: re-pin to current stable | -| Edge cache hides new deploys for up to 2 h | By design | Low | Judge freshness via `/healthz` | +| Risk | Likelihood | Impact | Mitigation | +| ----------------------------------------------------------------------------------------- | ---------- | --------------------------------------------- | -------------------------------------------- | +| Production alarm audio unverified | Medium | Medium (US-001 DoD gap) | Owner manual check; tracked above | +| Stale edge HTML references dead assets after each deploy; cached 404s extend the breakage | High | Medium (broken homepage up to 2 h per deploy) | HK-6: purge, asset retention, or shorter TTL | +| nginx 1.27 base gets no security updates (EOL mainline) | High | Medium | HK-5: re-pin to current stable | From 29261c20a11e844c48f7b4ae7f678520c5e5cf6b Mon Sep 17 00:00:00 2001 From: Hector Alvarez Date: Sun, 13 Sep 2026 19:09:49 -0500 Subject: [PATCH 2/8] docs(stories): add US-005 UX polish story with baseline screenshots --- .../stories/US-005-ux-polish-accessibility.md | 99 ++++++++++++++++++ .../screenshots/before/01-clock-idle.png | Bin 0 -> 31271 bytes .../before/02-alarm-panel-open.png | Bin 0 -> 41632 bytes .../before/03-alarm-panel-rows.png | Bin 0 -> 49203 bytes .../screenshots/before/04-alarm-error.png | Bin 0 -> 50324 bytes .../screenshots/before/05-ring-overlay.png | Bin 0 -> 45969 bytes .../screenshots/before/06a-focus-toggle.png | Bin 0 -> 48335 bytes .../screenshots/before/06b-focus-name.png | Bin 0 -> 50092 bytes .../screenshots/before/06c-focus-time.png | Bin 0 -> 51183 bytes .../screenshots/before/07-timer-panel.png | Bin 0 -> 43498 bytes .../before/08-mobile-alarm-panel.png | Bin 0 -> 25418 bytes .../before/09-mobile-alarm-rows.png | Bin 0 -> 29585 bytes .../before/10-mobile-ring-overlay.png | Bin 0 -> 24209 bytes .../before/11-reduced-motion-panel.png | Bin 0 -> 40555 bytes .../before/12-narrow-alarm-panel.png | Bin 0 -> 26096 bytes 15 files changed, 99 insertions(+) create mode 100644 docs/stories/US-005-ux-polish-accessibility.md create mode 100644 docs/stories/US-005/screenshots/before/01-clock-idle.png create mode 100644 docs/stories/US-005/screenshots/before/02-alarm-panel-open.png create mode 100644 docs/stories/US-005/screenshots/before/03-alarm-panel-rows.png create mode 100644 docs/stories/US-005/screenshots/before/04-alarm-error.png create mode 100644 docs/stories/US-005/screenshots/before/05-ring-overlay.png create mode 100644 docs/stories/US-005/screenshots/before/06a-focus-toggle.png create mode 100644 docs/stories/US-005/screenshots/before/06b-focus-name.png create mode 100644 docs/stories/US-005/screenshots/before/06c-focus-time.png create mode 100644 docs/stories/US-005/screenshots/before/07-timer-panel.png create mode 100644 docs/stories/US-005/screenshots/before/08-mobile-alarm-panel.png create mode 100644 docs/stories/US-005/screenshots/before/09-mobile-alarm-rows.png create mode 100644 docs/stories/US-005/screenshots/before/10-mobile-ring-overlay.png create mode 100644 docs/stories/US-005/screenshots/before/11-reduced-motion-panel.png create mode 100644 docs/stories/US-005/screenshots/before/12-narrow-alarm-panel.png diff --git a/docs/stories/US-005-ux-polish-accessibility.md b/docs/stories/US-005-ux-polish-accessibility.md new file mode 100644 index 0000000..01aaac0 --- /dev/null +++ b/docs/stories/US-005-ux-polish-accessibility.md @@ -0,0 +1,99 @@ +# User Story: UX Polish & Accessibility Hardening + +**Story ID:** US-005 +**Epic:** Platform Quality (cross-feature) +**Status:** In progress + +--- + +## 1. Description + +**As a** visitor using the clock, timer, or alarms, +**I want** the panels to be legible, proportional, and fully accessible, +**So that** the product feels deliberate and cohesive, and future features +build on a design system instead of fighting one. + +Priority owner decision (2026-09-13): this story **takes priority over +US-002 (recurring alarms) and US-004 (multi-clock)**. It absorbs backlog +US-003 items 1–3. + +--- + +## 2. Context & Scope + +- **In Scope:** + - Visible, persistent field labels for every input (placeholder alone is + not a label — current placeholders are browser-default gray on `#111`) + - One shared control scale across alarm and timer panels (the alarm create + row currently mixes 1.2em inputs, an 0.8em/0.7-opacity Add button, and + ~20px tap targets) + - WCAG AA contrast for all text/background pairs, enforced by computed + ratios (error `#f00` on `#1a1a1a` is ≈4.35:1 today; note text at opacity + 0.55 ≈4.5:1; disabled rows ≈3:1) + - Semantic design tokens to replace the per-element "opacity soup" + (0.3–0.75) — text tiers, placeholder, input surface, focus ring, danger + - Keyboard + screen-reader behavior: focus moves into opened panels, + returns to the toggle on close; ring overlay traps focus and is + `aria-modal`; toggles expose `aria-expanded`/`aria-controls`; alarm list + changes announced + - `prefers-reduced-motion` support for pulses and panel/FLIP animations + - Outside-click no longer closes the alarm panel while the ring overlay is + up (absorbed US-003 item 2) + - FLIP panel helper extracted to `shared/dom/` (absorbed US-003 item 1) +- **Out of Scope:** + - Retheming (the green/dark terminal aesthetic stays — this story + normalizes within it) + - New features, behavior changes to the pure cores, storage format changes + - Sound design (alarm tone is `playBeep()`, unchanged; audible verification + stays a manual QA step) + +--- + +## 3. Acceptance Criteria + +- [ ] **AC-1:** Every input has a persistent visible label; placeholder text + uses a themed token. +- [ ] **AC-2:** All text/background pairs pass WCAG AA (4.5:1 normal text, + 3:1 large text), verified by computed ratios recorded in this story. +- [ ] **AC-3:** Alarm and timer panels share one control scale; the alarm + create section uses a labeled layout with comfortable spacing. +- [ ] **AC-4:** Keyboard-only pass: opening a panel moves focus into it, + closing restores focus to the toggle, the ring overlay traps focus and + is `aria-modal` (Esc/Enter dismiss), and no keyboard trap exists. +- [ ] **AC-5:** Panel toggles expose `aria-expanded`/`aria-controls`; alarm + list changes are announced via a polite live region; all rendered row + controls are labeled. +- [ ] **AC-6:** `prefers-reduced-motion` disables pulses, panel open/close, + and FLIP animations. +- [ ] **AC-7:** Interactive targets are ≥24×24 px (WCAG 2.5.8), ~44 px where + space allows. +- [ ] **AC-8:** Outside click does not close the alarm panel while ringing. + +--- + +## 4. Technical Guidance & Architectural Constraints + +- **Token layer first:** `variables.css` gains semantic tokens (text tiers, + input surface, placeholder, focus ring, AA-safe danger, control sizes); + component CSS consumes tokens — no raw opacities for text tiers. +- **Markup:** `index.html` gains `