Seat web.dev on the design council; record PWA backfill

This commit is contained in:
2026-06-07 20:39:56 +03:00
parent d94480f56d
commit dcb7037a71
3 changed files with 46 additions and 22 deletions
+12 -4
View File
@@ -36,7 +36,7 @@ Pull the **minimal** relevant member(s) for the decision at hand — do **not**
four; that wastes tokens and dilutes the answer. Map the decision to its seat(s):
| Decision in front of you | Primary seat → then |
| ---------------------------------------------------------- | ------------------------------------------------------ |
| ---------------------------------------------------------------- | ------------------------------------------------------ |
| Error / failure / empty-state / notification **copy** | **GOV.UK** → Carbon notifications → NN/g heuristic #9 |
| Keyboard / focus / ARIA roles of an **interactive widget** | **WAI-ARIA APG** → Carbon component |
| **Latency / feedback / loading / progress** budgets | **NN/g** response-time limits → Carbon loading pattern |
@@ -44,6 +44,7 @@ four; that wastes tokens and dilutes the answer. Map the decision to its seat(s)
| General **usability** gut-check on a flow | **NN/g** 10 heuristics |
| **Visual** styling (type, spacing, colour, component look) | **Carbon** + our `docs/architecture/09` |
| **Which chart** for the data/intent (chart-type choice) | **FT Visual Vocabulary** + **Datawrapper** |
| **PWA / offline / install / SW-update / storage-persistence** UX | **web.dev** (+ vite-plugin-pwa / Workbox for the API) |
Then: read the cited file(s), extract the **specific** principle, and report it back with
a **citation (member + file path)** and a one-line "how it lands in Astrolabe." Don't
@@ -55,13 +56,14 @@ All paths are under `/Users/oleh/code/reference/`. Treat clones as **inspiration
law** — they drift; the published guidance is the truth, the clone is the fast index.
| Member | Path | Authoritative for | How to query |
| ------------------------------ | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ------------------------------ | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **IBM Carbon** | `carbon-website/src/pages/` | Notification taxonomy, status levels, empty/loading states, content basics, data-viz styling | grep `.mdx` under `components/notification`, `patterns/{empty-states,loading,status-indicator}-pattern`, `guidelines/content` |
| **GOV.UK Design System** | `govuk-design-system/src/` | Error & validation messages, failure pages, forms, plain-language content, accessibility | `index.md` under `components/{error-message,error-summary,notification-banner}`, `patterns/{problem-with-the-service-pages,service-unavailable-pages,check-answers}`, `accessibility/` |
| **WAI-ARIA APG** | `aria-practices/content/patterns/` | Keyboard interaction, focus management, ARIA roles/states for widgets | `<pattern>/<pattern>-pattern.html` — e.g. `dialog-modal`, `alertdialog`, `alert`, `listbox`, `menu-button`, `disclosure`, `switch`, `tabs`, `tooltip`, `windowsplitter` |
| **Nielsen Norman (distilled)** | `principles/nielsen-norman.md` | 10 usability heuristics; response-time / feedback budgets (0.1s / 1s / 10s) | read directly — it is short and curated |
| **FT Visual Vocabulary** | `chart-doctor/visual-vocabulary/` | Chart choice: data-relationship taxonomy (Magnitude, Correlation, Change-over-Time, Ranking, Distribution, Deviation, Part-to-whole, Spatial, Flow) → chart type | read `README.md` — the taxonomy is prose; each category gives a "use when…" definition + recommended chart types |
| **Datawrapper (distilled)** | `principles/datawrapper.md` | Chart choice in plain language; practical rules of thumb (bar-is-safe-default, line-vs-column, circles hard to compare, size = quantity) | read directly — short and curated; pairs with the FT clone |
| **web.dev (distilled)** | `principles/web-dev.md` | PWA/offline: service-worker update flow (`registerType: 'prompt'`), persistent storage (`navigator.storage.persist()`), quota/`estimate()`, installability — with the exact vite-plugin-pwa/Workbox API we use | read directly — short and curated; cites local `web-dev/`, `vite-plugin-pwa/`, `workbox/` clones |
## Close the loop
@@ -85,10 +87,16 @@ contract, not the external source.
have never been applied before. This is the one event that reopens the one-off sweep
(see _Scope_); after it, pointwise maintains the new seat like the rest.
Candidate future seats (not yet seated): **Shopify Polaris** (UX-writing depth),
**web.dev** (perceived performance / PWA / offline UX — seat at M6 per the plan).
Candidate future seats (not yet seated): **Shopify Polaris** (UX-writing depth).
Seated at M4 (chart choice — our domain): **FT Visual Vocabulary** (clone) +
**Datawrapper** (distilled). Backfill is scoped to the Chart Builder itself (new
surface — no pre-existing chart-choice code to reconcile), so the seating debt is
discharged by building the builder against this canon rather than a separate sweep.
Seated at M6 (PWA/offline — our domain): **web.dev** (distilled, with
vite-plugin-pwa/Workbox for the exact API). Backfill reconciled the existing PWA wiring:
it surfaced that `registerType: 'prompt'` was configured but never consumed (no update
prompt) and that `navigator.storage.persist()` was never requested — both fixed in M6 and
recorded in `docs/architecture/10`. Remaining gap (logged, not silently passed): the web
app manifest ships no icons, so the app is not yet installable — a design-asset task.
+5 -3
View File
@@ -437,11 +437,13 @@ entries).
`DONATE_URL` pending the real link).
- **Offline/installable:** verify the SW + manifest give a working offline + installed app.
**⏳ Remaining** — needs manual verification in a running/installed app.
- **Council** — seat **web.dev** for the PWA/offline/storage surfaces none of the seated
- **Council** — ~~seat **web.dev** for the PWA/offline/storage surfaces none of the seated
members cover: the service-worker **update-available** prompt (`registerType: 'prompt'`),
storage **persistence** (`navigator.storage.persist()`), and the quota **estimate**
(`StorageManager.estimate()`). **⏳ Remaining** (storage monitor is its consumer; seating
triggers a one-off backfill — see [`/council`](../.claude/skills/council/SKILL.md)).
(`StorageManager.estimate()`)~~ ✅ seated + backfilled (update-prompt toast + `persist()`
request; estimate already wired). **⏳ Remaining gap:** manifest ships no icons → not yet
installable (design-asset task). See [`/council`](../.claude/skills/council/SKILL.md) and
[arch 10](architecture/10-interaction-and-feedback.md).
**Manual checks:** keyboard-only run-through; reload restores view from URL;
offline reload works; install as standalone; reduced-motion honored. **⏳ Still owed**
@@ -320,6 +320,20 @@ Datasets (⌘/Ctrl+K), or check the dataset name in your spec."_ — instead of
must match the actual cause (NN/g #9, GOV.UK error-message). The thrown
`DatasetNotFoundError` carries `datasetName` so the surface can name it.
**Resolved — service-worker update prompt & persistent storage (web.dev seat).** The build
uses `registerType: 'prompt'`, so a new service worker waits and never takes over a running
session on its own — the app **must** tell the user, or "ask before updating" silently means
"never update." `orchestration/pwa.ts` consumes `virtual:pwa-register` and surfaces
`onNeedRefresh` as a **durable** (non-auto-dismissing) info toast with a **Reload** action
that calls `updateSW()`; `onOfflineReady` is a transient success toast. Separately, browser
storage is best-effort and evictable under pressure, which for a local-first workspace is data
loss — so we request `navigator.storage.persist()` once at startup
(`infrastructure/storage-persist`), feature-detected and silent on denial (Chromium decides
automatically; nothing for the user to act on). _(Consulted via /council → web.dev, with the
exact API from vite-plugin-pwa/Workbox; see `reference/principles/web-dev.md`. This bullet is
the contract; cite it, not the source.) **Known gap:** the manifest ships no icons, so the app
is not yet installable — a design-asset task, logged not passed._
## 6. Motion & accessibility as default
Not features to add later — the baseline every surface is built on.