aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/specs/2026-07-12-component-generation-spec.org68
-rw-r--r--todo.org25
2 files changed, 64 insertions, 29 deletions
diff --git a/docs/specs/2026-07-12-component-generation-spec.org b/docs/specs/2026-07-12-component-generation-spec.org
index 5ee30df..95c4712 100644
--- a/docs/specs/2026-07-12-component-generation-spec.org
+++ b/docs/specs/2026-07-12-component-generation-spec.org
@@ -4,34 +4,36 @@
#+TODO: TODO | DONE
#+TODO: DRAFT READY DOING | IMPLEMENTED SUPERSEDED CANCELLED
-* DRAFT Widget component generation
+* DOING Widget component generation
:PROPERTIES:
:ID: 3ac0d42c-db1a-4d21-bce4-e63785fef0ba
:END:
+- 2026-07-12 Sun @ 20:57:50 -0500 — READY → DOING: phases decomposed into todo.org tasks under "Retro widget catalogue" (=:SPEC_ID:= stamped); Phase 1 extraction starts now per the option-1 approval.
+- 2026-07-12 Sun @ 20:57:50 -0500 — DRAFT → READY: spec-review passed (Ready; 3 findings — the option-1 supersession, the card-record refactor, stale counts — all accepted and folded same pass).
- 2026-07-12 Sun @ 10:12:06 -0500 — drafted.
** Prototype iterations
Per =claude-rules/ui-prototyping.md=, a non-trivial-UI spec carries its prototype evidence here. This spec's UI evidence is the [[file:../prototypes/panel-widget-gallery.html][panel widget gallery]] itself — the living catalogue is the prototype set, not a numbered iteration series:
- *Research:* reference photos of period hardware (Berna 3 studio suite, aviation clusters, broadcast consoles, pedals, marine/telegraph instruments) filed in [[file:../../working/retro-stereo-widgets/references/][working/retro-stereo-widgets/references/]]; in-chat-pasted references have provenance noted in card notes and the 2026-07-11/12 session archive.
-- *Iterations:* the gallery's git history is the iteration record — N-series base widgets, then reference-derived R01–R31 built and behaviorally verified card by card (commits 7fff507 through 52a43ec, 2026-07-12). 84 cards total, every one CDP-verified (drag tracking, click response, animation, zero console errors).
-- *Final:* the gallery as of 52a43ec is the settled visual + behavioral spec each component port is judged against.
+- *Iterations:* the gallery's git history is the iteration record — N-series base widgets, then reference-derived R01–R56 built and behaviorally verified card by card (7fff507 through the gallery-upgrades squash merge bc93388 and beyond, 2026-07-12). 109 cards as of the 2026-07-12 review, every one CDP-verified (drag tracking, click response, animation, zero console errors); the committed probe suite lives in =tests/gallery-probes/=.
+- *Final:* the gallery at current =main= is the settled visual + behavioral spec each component port is judged against — it keeps growing, so a port is judged against its card as it stands, not a frozen SHA.
* Metadata
-| Status | draft |
+| Status | doing |
|----------+-----------------------------------|
| Owner | Craig Jennings |
|----------+-----------------------------------|
-| Reviewer | (spec-review pending) |
+| Reviewer | Claude Code (archsetup) |
|----------+-----------------------------------|
| Related | [[file:../../todo.org][todo.org — Retro widget catalogue]] |
|----------+-----------------------------------|
* Summary
-The panel widget gallery (84 behaviorally-verified retro-instrument cards) is a spec, not yet a library. This document defines how gallery cards become reusable components for three real targets — web (vanilla JS, the gallery itself as first consumer), Emacs (svg.el), and waybar (GTK CSS) — driven by actual demand rather than porting all 84.
+The panel widget gallery (109 behaviorally-verified retro-instrument cards as of the 2026-07-12 review) is a spec, not yet a library. This document defines how gallery cards become reusable components for three real targets — web (vanilla JS, the gallery itself as first consumer), Emacs (svg.el), and waybar (GTK CSS). The web library is extracted whole (a lossless transform of code that already exists); the Emacs and waybar ports are driven by actual demand rather than porting the full catalogue.
* Problem / Context
-The gallery grew card by card as a visual and behavioral catalogue: each card is a self-contained inline builder function inside one 2258-line HTML file. That was right for the collection phase — fast iteration, one canvas, one review surface. It is wrong for consumption: a waybar panel, an Emacs game, or a web UI that wants a VU meter today would have to copy-paste from the gallery's internals and hand-fork the styling.
+The gallery grew card by card as a visual and behavioral catalogue: each card is a self-contained inline builder function inside one ~4300-line HTML file (as of the 2026-07-12 review; it still grows). That was right for the collection phase — fast iteration, one canvas, one review surface. It is wrong for consumption: a waybar panel, an Emacs game, or a web UI that wants a VU meter today would have to copy-paste from the gallery's internals and hand-fork the styling.
The groundwork is already laid. Tokens are single-sourced in [[file:../prototypes/tokens.json][tokens.json]]; =gen_tokens.py= emits the gallery's =:root= CSS block, [[file:../prototypes/tokens-waybar.css][tokens-waybar.css]], and [[file:../prototypes/gallery-tokens.el][gallery-tokens.el]] (27 tests, 100% coverage). An svg.el proof widget ([[file:../prototypes/gallery-widget.el][gallery-widget.el]], the needle gauge, 10 ERT tests plus an rsvg-convert side-by-side render) proved the Emacs pipeline — the riskiest unknown — end to end. What's missing is the middle layer: parameterized, importable widgets per target, and a decision procedure for which widgets earn a port.
@@ -43,14 +45,14 @@ The groundwork is already laid. Tokens are single-sourced in [[file:../prototype
- Every port carries tests in its target's idiom (CDP behavioral for web, ERT + visual harness for Emacs, panel test suite for waybar).
** Non-Goals
-- Porting all 84 cards. Most cards are catalogue entries; a port with no consumer is inventory nobody asked for.
+- Emacs/waybar ports of the full catalogue. Most cards are catalogue entries; a scripted port with no consumer is inventory nobody asked for. (The web extraction is exempt — it transforms code that already exists.)
- Shared rendering code across targets. Reuse lives in shared tokens and shared SVG geometry math, not shared code — each target renders in its own idiom (recorded architecture decision).
- Framework wrappers (React or otherwise) ahead of a real framework consumer.
- Level-2/3 codegen (widget-spec → renderer generation) in this spec's v1 — that's the Phase 5 decision point, deliberately after hand-porting experience exists.
** Scope tiers
-- v1: demand inventory, web library extraction, Emacs ports of the demanded widgets, one waybar pilot panel, the Level-2 generator go/no-go.
-- Out of scope: new widget collection (R-series closed), shared cross-target rendering code, interaction parity beyond each target's native idiom.
+- v1: full web library extraction (with the card-record refactor), demand inventory for the scripted targets, Emacs ports of the demanded widgets, one waybar pilot panel, the Level-2 generator go/no-go.
+- Out of scope: new widget collection as part of this work (the catalogue keeps growing on its own track — new cards land as =GW.*= calls once extracted), shared cross-target rendering code, interaction parity beyond each target's native idiom.
- vNext (log to todo.org at hand-off): React/framework wrappers, Level-2/3 codegen if Phase 5 says go, ports beyond the demand matrix as consumers appear.
* Design
@@ -64,12 +66,12 @@ Waybar: no widget functions — waybar consumes =tokens-waybar.css= plus the ban
** For an implementer
Three layers, already agreed: tokens (values) → widget spec (the gallery card: geometry, params, behavior) → per-target renderers. The card is the contract. A port re-reads the card's builder for geometry constants and behavioral rules (detent snapping, VU ballistics via the =vuDb()= law, exclusive-select), then re-expresses them natively. Geometry math (polar helpers, scale interpolation tables like =EDGE_SCALE=, =SEG14_MAP=) is copied deliberately per target and cross-checked by tests, not shared as a runtime dependency — the false-coupling judgment from the token work applies to code too.
-Extraction order inside Phase 2: the card builders already share =svgEl=/=polar= helpers and document-scoped gradients/filters; lifting them means (a) moving each demanded builder into =widgets.js= behind a parameter object, (b) replacing its gallery card with a call, (c) re-running the existing CDP behavioral probes unchanged — the probes drive the rendered DOM, so a green re-run is the no-regression proof.
+Extraction order inside Phase 1: the card builders already share =svgEl=/=polar=/=vuDb=/drag helpers and document-scoped gradients/filters; lifting them means (a) moving the shared engine and each builder into =widgets.js= behind a parameter object, (b) replacing its gallery card with a declarative card record (no / title / stage builder / options / readout / note / spec sheet incl. reference link / validation lamp) rendered by one =card()= path, (c) re-running the existing CDP behavioral probes unchanged — the probes drive the rendered DOM, so a green re-run is the no-regression proof. Batches of roughly 10-15 widgets keep each commit reviewable and the gallery working throughout.
* Alternatives Considered
** Port everything to every target up front
- Good, because the catalogue would be uniformly consumable.
-- Bad, because ~84 × 3 ports is months of work with no consumer for most of it, and unconsumed ports rot silently.
+- Bad, because ~109 × 3 ports is months of work with no consumer for most of it, and unconsumed ports rot silently.
- Bad, because it front-loads the Level-2 codegen question before hand-port experience exists to answer it.
** Shared renderer core (one geometry engine, thin target adapters)
@@ -101,11 +103,11 @@ Extraction order inside Phase 2: the card builders already share =svgEl=/=polar=
- Consequences: easier — each target feels native; harder — behavioral parity is a per-port judgment, tested per target rather than shared.
- Resolved live with Craig (2026-07-11).
-** DONE Demand-driven porting
-- Context: 84 cards, three targets, most cards have no consumer today.
-- Decision: a widget is ported when the demand matrix names a real consumer (a waybar panel, an Emacs game/UI, a web surface); the matrix is Phase 1's deliverable and Craig approves it.
-- Consequences: easier — effort lands where it's used; harder — the catalogue stays partially ported indefinitely, by design.
-- Agreed in the 2026-07-12 outline.
+** DONE Demand-driven porting (Emacs and waybar targets)
+- Context: 109 cards (as of 2026-07-12 review), three targets, most cards have no Emacs or waybar consumer today.
+- Decision: an *Emacs or waybar* port happens when the demand matrix names a real consumer (a waybar panel, an Emacs game/UI); the matrix is Phase 1's deliverable and Craig approves it. The *web* extraction is exempt: it is a lossless transform of code that already exists, so it covers the full catalogue (option-1 approval, 2026-07-12).
+- Consequences: easier — port effort lands where it's used, and the web library is complete from day one; harder — the Emacs/waybar surface stays partially ported indefinitely, by design.
+- Agreed in the 2026-07-12 outline; web-extraction exemption approved with the option-1 go-ahead (2026-07-12).
** DONE Gallery-as-spec
- Context: the ui-prototyping rule wants working prototypes as design evidence.
@@ -129,14 +131,25 @@ Extraction order inside Phase 2: the card builders already share =svgEl=/=polar=
- Context: the gallery is a single self-contained =file://= HTML page; ES modules don't load over =file://=, and a React consumer doesn't exist yet.
- Decision: =widgets.js= ships as a classic script exposing one namespace object (working name =GW=), loaded by the gallery via a relative =<script src>=; the shared helpers (=svgEl=, =polar=, =vuDb=, scale tables) move inside it. Framework wrappers are vNext, demand-gated.
- Consequences: easier — gallery keeps working from =file://=, zero build tooling; harder — no tree-shaking or import isolation (acceptable at this scale).
-- Approved by Craig 2026-07-12 (componentization go-ahead, option 1); build gated on his per-card validation pass (lamps in the gallery masthead cards).
+- Approved by Craig 2026-07-12 (componentization go-ahead, option 1). The extraction itself is ungated — a lossless transform verified by the CDP probes; Craig's per-card validation pass (the status lamps) gates only the per-widget Emacs ports and the final blessing.
+
+* Review findings [3/3]
+** DONE Extraction scope and gate superseded by the option-1 approval :blocking:
+The spec's Phase 1 → Phase 2 order gates the web extraction on the demand matrix, and the Web-library-packaging decision says the build is "gated on his per-card validation pass." Craig's componentization go-ahead (option 1, 2026-07-12 ~21:30) superseded both: the web extraction covers the *full* catalogue as a lossless transform and starts immediately; the demand matrix and the validation lamps gate only the per-widget Emacs ports and the final blessing. An implementer reading the spec as written would follow the retired order. Recommended change: re-scope the Demand-driven-porting decision to the Emacs/waybar targets, drop the extraction gate from the packaging decision, and reorder/reword Phases 1-2.
+Disposition: accepted — pre-agreed by Craig (recorded in todo.org and the 2026-07-12 session log). Folded into Decisions 4 and 8 and Phases 1-2.
+** DONE Card-as-component refactor absent from Phase 2
+The approved build includes restructuring each gallery card into a declarative record (no/title/stage builder/options/readout/note/spec-sheet incl. reference link/validation lamp) so the page becomes data plus =GW.*= calls, but Phase 2 as written only covers lifting builders into =widgets.js=. Without it the "gallery becomes calls into the library" claim leaves the card chrome hand-rolled per card. Recommended change: name the card-record refactor as part of Phase 2's deliverable.
+Disposition: accepted — folded into the Design section and Phase 2.
+** DONE Stale gallery facts
+The spec states 84 cards, a 2258-line file, the R-series closed at R31, and 52a43ec as the final SHA. The gallery has since grown to 109 cards (R-series through R56, ~4300 lines) across the gallery-upgrades merge and the takuzu-survey builds. Not a design problem, but stale numbers in the contract mislead the implementer sizing the extraction. Recommended change: refresh the counts and phrase them as of the review date, since the catalogue still grows.
+Disposition: accepted — counts refreshed and dated throughout.
* Implementation phases
-** Phase 1 — Demand inventory
-Build the widget-to-target matrix from real consumers: walk the live waybar panels (net/bt/audio/maint), the Emacs surfaces Craig names (games, dashboards), and any web UI, and record which gallery cards each actually wants. Deliverable: a short matrix table in this spec's appendix, approved by Craig. Tree untouched.
+** Phase 1 — Web library extraction
+Lift *all* card builders into =docs/prototypes/widgets.js= behind parameter objects (classic script, =GW= namespace, shared helpers inside), and restructure each gallery card as a declarative record (no / title / stage builder / options / readout / note / spec sheet incl. reference link / validation lamp) so the page becomes data plus =GW.*= calls. Batched (roughly 10-15 widgets per batch); a green re-run of the CDP behavioral probes (=tests/gallery-probes/=) is the per-batch no-regression gate, and each batch leaves the gallery fully working from =file://=. Ungated by the validation lamps (option-1 approval — lossless transform).
-** Phase 2 — Web library extraction
-Lift the demanded cards' builders into =docs/prototypes/widgets.js= behind parameter objects; the gallery becomes calls into the library. Green re-run of the existing CDP behavioral probes is the no-regression gate. Each extraction batch leaves the gallery fully working.
+** Phase 2 — Demand inventory (Emacs / waybar)
+Build the widget-to-target matrix for the *scripted-port* targets: walk the live waybar panels (net/bt/audio/maint) and the Emacs surfaces Craig names (games, dashboards), and record which gallery cards each actually wants. Deliverable: a short matrix table in this spec's appendix, approved by Craig. Tree untouched. Runs in parallel with or after Phase 1 — the extraction does not wait on it.
** Phase 3 — Emacs ports
Extend the =gallery-widget.el= pattern for the demanded widgets: per-widget ERT (token resolution, geometry math normal/boundary/error, SVG structure, state-tracks-value) plus the rsvg-convert side-by-side visual harness against the gallery card. Keymap/click-region interaction designed per widget. Wired into =make test-elisp=.
@@ -149,7 +162,7 @@ After ~5 hand ports, revisit Level-2 codegen with evidence: how much of each por
* Acceptance criteria
- [ ] Demand matrix exists in the appendix and Craig has approved it.
-- [ ] Every demanded web widget is a =widgets.js= call in the gallery; CDP probes green; gallery renders unchanged from =file://=.
+- [ ] Every gallery card is a declarative record calling into =widgets.js=; CDP probes green; gallery renders unchanged from =file://=.
- [ ] Every demanded Emacs widget has ERT coverage and an rsvg side-by-side render matching its card; =make test-unit= green.
- [ ] The audio panel reads its palette from =tokens-waybar.css=; panel suite green; manual-testing checklist entry filed.
- [ ] Phase 5 go/no-go recorded as a dated decision.
@@ -160,7 +173,7 @@ Answer each, or write "N/A because…".
- Errors, empty states & failure: builders validate parameter ranges and clamp (the gallery's existing behavior — e.g. no-cross flag clamps, detent wrap); Emacs widgets signal =user-error= on out-of-range tokens/params (the =gallery-widget-token= missing-token error is the pattern).
- Security & privacy: N/A because everything is local rendering of design assets; no credentials, no network.
- Observability: web — CDP probes plus zero-console-error checks; Emacs — ERT output; waybar — the panel's existing smoke/AT-SPI harness.
-- Performance & scale: N/A beyond the existing gallery scale (84 cards render fine); ports are per-widget, no aggregate load.
+- Performance & scale: N/A beyond the existing gallery scale (109 cards render fine); ports are per-widget, no aggregate load.
- Reuse & lost opportunities: tokens and geometry constants reused by value with cross-checking tests; svg.el, librsvg, and GTK CSS used as the platforms provide them; deliberate non-reuse of cross-target code recorded above.
- Architecture fit & weak points: fits the shipped 3-layer architecture; weak point is spec drift between a card and its ports — mitigated by the side-by-side harness and by the gallery-as-demo property on web.
- Config surface: no new knobs; token values remain the only tuning surface.
@@ -171,7 +184,7 @@ Answer each, or write "N/A because…".
* Risks, Rabbit Holes, and Drawbacks
- Pure-CSS cards demanded into Emacs need SVG re-expression — sized per widget in Phase 3; if one balloons, it goes back to the demand matrix rather than stalling the phase.
-- The gallery extraction could tempt a rewrite-everything pass; the phase is scoped to *demanded* builders only, monolith remainder stays put.
+- The gallery extraction could tempt a redesign pass; the phase is a *lossless transform* only — builders move and cards become records, but no widget's look or behavior changes (the probes enforce it).
- GTK CSS renders differently from the browser (no SVG filters, different gradient behavior); the pilot may reveal idioms that don't translate — acceptable, the pilot exists to find them, and findings feed the composition-idiom notes rather than blocking.
- Hand-duplicated geometry constants can drift before Phase 5; each port's tests pin its constants against the card's values.
@@ -182,6 +195,11 @@ Answer each, or write "N/A because…".
- Demand matrix: (Phase 1 deliverable — lands here.)
* Review and iteration history
+** 2026-07-12 Sun @ 20:57:50 -0500 — Claude Code (archsetup) — reviewer + responder
+- What: full spec-review (code read against the live gallery, probes re-baselined green at 753380e). Three findings, all accepted and folded: the option-1 approval superseded the demand-gated extraction order (Phases 1-2 swapped and re-scoped, Decisions 4 and 8 reworded), the card-record refactor named as part of the extraction phase, stale counts refreshed (84→109 cards, R31→R56). Rubric: Ready. Flipped READY, then DOING with the phase decomposition into todo.org.
+- Why: Craig's componentization go-ahead (option 1, 2026-07-12 ~21:30) landed after drafting — extraction is a lossless transform and proceeds ungated; the validation lamps gate only Emacs ports and the final blessing. The spec had to match the approved build before tasks decomposed from it.
+- Artifacts: the three completed findings under =* Review findings=; probe repair commit 753380e; todo.org build tasks under "Retro widget catalogue" (=:SPEC_ID:= 3ac0d42c-db1a-4d21-bce4-e63785fef0ba).
+
** 2026-07-12 Sun @ 10:12:06 -0500 — Craig Jennings — author
- What: initial draft.
- Why: collection phase closed at R01–R31; porting needs a decision procedure and per-target shape before any consumer work starts.
diff --git a/todo.org b/todo.org
index 535fe7c..d08d48c 100644
--- a/todo.org
+++ b/todo.org
@@ -60,17 +60,34 @@ Six period families defined (green = P1 phosphor built on =phos=, amber = P3 on
*** 2026-07-12 Sun @ 13:15:19 -0500 Added spec sheets to all 84 cards
Every card now carries a collapsible "spec sheet" (a details element under the note) with up to 8 fields: input (always present, names the model — click ports everywhere including Emacs click-regions, drag needs a click/key idiom there, display widgets take no real input), solves, use (common vs specialty + where it shines), limits, origin, difficulty, prefer-when, and period (present on 41 of 84 — only where the component is clearly not timeless, e.g. nixie 1955-75 sits with keypads/telegraphs and clashes with VFD and LED seven-seg). Content lives in one INFO object keyed by card number; card() renders it. CDP-verified: 84/84 sheets present (missing-key check), fields render, zero exceptions.
*** TODO Widget validation pass
-Craig validates every control before any componentization build (his call — the lamps are his worklist, not agent-checkable). Each card carries a status lamp at the upper-right: click cycles off → amber → green, state persists per card in localStorage (key =gv-<no>=). When the pass completes, bake the final statuses into the gallery source and use the green set as the build order for the widgets.js extraction.
+Craig validates every control via the card lamps (his worklist, not agent-checkable): click cycles off → amber → green, state persists per card in localStorage (key =gv-<no>=). Gate change with the option-1 approval (2026-07-12): the lamps no longer gate the widgets.js extraction (lossless, proceeds now) — they gate per-widget Emacs ports and the final catalogue blessing. When the pass completes, bake the final statuses into the gallery source.
*** TODO Component classification taxonomy
Brainstorm WITH Craig (after the squash merge, not solo): break the components down by use — freeform output, binary selection, multi-selection, fine-tuning, etc. The taxonomy identifies use-cases with no appropriate component, which fills out the gallery with some confidence of completeness.
** DOING [#B] Retro widget catalogue :feature:design:
-The panel widget gallery ([[file:docs/prototypes/panel-widget-gallery.html][docs/prototypes/panel-widget-gallery.html]]) grows into a retro-instrument component catalogue: reference photos of period hardware → gallery cards (the visual + behavioral spec) → reusable components for three targets (emacs svg.el, web/React, waybar). Tokens single-sourced in [[file:docs/prototypes/tokens.json][tokens.json]] (gen_tokens.py emits web/waybar/elisp); svg.el proof widget shipped (gallery-widget.el, needle gauge). Reference photos live in [[file:working/retro-stereo-widgets/][working/retro-stereo-widgets/]]. R-series cards (R01-R31) are the reference-derived widgets — collection phase COMPLETE 2026-07-12 (84 cards, all behaviorally verified).
+:PROPERTIES:
+:SPEC_ID: 3ac0d42c-db1a-4d21-bce4-e63785fef0ba
+:END:
+The panel widget gallery ([[file:docs/prototypes/panel-widget-gallery.html][docs/prototypes/panel-widget-gallery.html]]) grows into a retro-instrument component catalogue: reference photos of period hardware → gallery cards (the visual + behavioral spec) → reusable components for three targets (emacs svg.el, web/React, waybar). Tokens single-sourced in [[file:docs/prototypes/tokens.json][tokens.json]] (gen_tokens.py emits web/waybar/elisp); svg.el proof widget shipped (gallery-widget.el, needle gauge). Reference photos live in [[file:working/retro-stereo-widgets/][working/retro-stereo-widgets/]]. Collection converged at R56 (109 cards, all behaviorally verified; probes in [[file:tests/gallery-probes/][tests/gallery-probes/]]).
-Next: spec-review of the [[file:docs/specs/2026-07-12-component-generation-spec.org][component-generation spec]] (DRAFT), then decompose via spec-response. The spec carries the agreed 5-phase plan (demand inventory → web library extraction → emacs ports → waybar audio pilot → Level-2 generator go/no-go) and the baked decisions (SVG-first, single token source, per-target interaction, demand-driven porting, gallery-as-spec). Banked variant/composition ledger lives in the 2026-07-11/12 session archive.
+Build runs per the [[file:docs/specs/2026-07-12-component-generation-spec.org][component-generation spec]] (DOING; reviewed + decomposed 2026-07-12): web extraction first (ungated, lossless), then demand-gated Emacs/waybar ports. Banked variant/composition ledger lives in the 2026-07-11/12 session archive.
*** 2026-07-12 Sun @ 10:14:10 -0500 Wrote the component-generation spec (DRAFT)
[[file:docs/specs/2026-07-12-component-generation-spec.org][2026-07-12-component-generation-spec.org]] via spec-create: full spine (summary, problem, goals, two-altitude design, alternatives, 8 decisions with 1 open, 5 phases, acceptance criteria, readiness dimensions, risks). Gallery cited as the prototype evidence per the ui-prototyping rule (filed references + R01-R31 iteration history + final at 52a43ec). vNext items logged as the "Widget catalogue vNext" task.
*** 2026-07-12 Sun @ 20:24:37 -0500 Web library packaging approved — classic-script widgets.js + GW namespace
-Craig approved with the componentization go-ahead (option 1): =widgets.js= as a classic script exposing one =GW= namespace, relative =<script src>= so =file://= keeps working, shared helpers inside, framework wrappers vNext. Decision flipped DONE in the spec (cookie 8/8); spec is review-ready. Build gated on Craig's per-card validation pass (the status lamps).
+Craig approved with the componentization go-ahead (option 1): =widgets.js= as a classic script exposing one =GW= namespace, relative =<script src>= so =file://= keeps working, shared helpers inside, framework wrappers vNext. Decision flipped DONE in the spec (cookie 8/8). Gate per the same approval: extraction proceeds ungated (lossless transform); the validation lamps gate only per-widget Emacs ports and the final blessing.
+*** 2026-07-12 Sun @ 20:57:50 -0500 Spec reviewed and decomposed (DRAFT → READY → DOING)
+spec-review passed (Ready): 3 findings, all accepted and folded same pass — option-1 supersession of the demand-gated extraction order (Phases 1-2 swapped: extraction first, ungated), the card-record refactor named in Phase 1, stale counts refreshed (109 cards / R56). Probe baseline repaired first (753380e — two stale assertions from the evening sprint). Phase tasks below; =:SPEC_ID:= stamped on this parent.
+*** TODO Phase 1 — web library extraction :refactor:solo:
+Lift all 109 card builders into =docs/prototypes/widgets.js= (classic script, =GW= namespace, shared engine inside: svgEl/polar/vuDb/dragX/dragY/dragDelta/seg7/SCREEN_FAMS/gradients); restructure each card as a declarative record (no/title/stage/options/readout/note/spec-sheet incl ref/lamp) rendered by one =card()= path. Batches of ~10-15; per-batch gate = green =tests/gallery-probes/probe.mjs= + =probe-fams.mjs=; commit+push per batch. Gallery stays working from =file://= throughout. Close with the slide toggle (card 01) as the first fully-realized component: its four option groups become constructor args (on/off/offText/thumb).
+*** TODO Phase 2 — demand inventory (Emacs/waybar) :design:
+Widget-to-target matrix for the scripted-port targets: walk the live waybar panels (net/bt/audio/maint) and the Emacs surfaces Craig names; record which cards each actually wants. Lands in the spec's appendix; Craig approves. Tree untouched. Not =:solo:= — the matrix is his call.
+*** TODO Phase 3 — Emacs ports of demanded widgets :feature:
+Extend the =gallery-widget.el= pattern per demanded widget: ERT (tokens, geometry normal/boundary/error, SVG structure, state-tracks-value) + rsvg-convert side-by-side against the card; keymap/click-region interaction per widget; wired into =make test-elisp=. Gated on the Phase 2 matrix and Craig's green lamp per widget.
+*** TODO Phase 4 — waybar pilot: audio panel :feature:dotfiles:
+Restyle the audio panel's GTK CSS onto =tokens-waybar.css= + the banked composition idioms. Lives in =~/.dotfiles=; archsetup drives edit/test/commit/push end to end + inbox note. Visual result gets a manual-testing checklist entry (daily-driver panel).
+*** TODO Phase 5 — Level-2 generator go/no-go :design:
+After ~5 hand ports, weigh widget-level codegen with evidence (mechanical duplication vs judgment per port). Recorded as a dated decision in the spec; go spawns its own spec.
+*** TODO Flip the spec to IMPLEMENTED
+When the phases above close: status heading keyword → =IMPLEMENTED=, dated history line with the reason, Metadata =Status= mirror. Three lines, one file.
** DONE [#C] Net panel: Enterprise error never dismisses :bug:dotfiles:network:
CLOSED: [2026-07-12 Sun]
Fixed in dotfiles =a157bed=. Root cause: error toasts are sticky by design (so background refreshes can't wipe an unread error), but the enterprise join hint's flow posts no follow-up status and row clicks post none either, so nothing ever replaced it. Fix: a window-wide capture-phase click gesture dismisses a sticky toast on the user's next interaction; policy in =viewmodel.toast_action_plan= (unit-tested), timed toasts and background clears unchanged. Panel smoke run confirms launch/doctor/close with the gesture installed. Pointer-level dismiss is a manual-testing child (AT-SPI can't drive pointer gestures). Repro screenshot: =~/pictures/screenshots/2026-07-10_195911.png=.