From 0dd42294321206684b3d69211ecea3d97a16eb66 Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Sat, 15 Aug 2026 15:29:53 +0200 Subject: [PATCH] unified-design-system: record the extraction audit, unstale the phase headings Answers "did we extract every component we actually use?" now that Phases 1-3 have shipped. The headline: the extractions hold up. No shipped component was a false positive, and the reverse check -- were the donor copies actually deleted? -- is clean except for billsplit's `_SectionHeader`, fixed separately in testsAndMisc@54054e7. The one clear miss is `DeviceCodeDialog` x3, two copies of which are byte-for-byte identical; it belongs in `sync_settings_ui` rather than `design_system` because it depends on GitHub auth types. Also corrects two things the audit surfaced: `nielsen-audit.md` described Phase 2 *and* Phase 3 as "not started". Both shipped -- gatelock 0.5.0 and web_ui-v0.3.1. A planning doc that says "not started" about finished work is worse than no doc, because the next session reads it as a backlog and rebuilds what already exists. Both headings now state what shipped, and the plan text is kept below as the record of why. The Phase 2 note also spells out that screen-locker and wake-alarm keeping local fan-out copies is deliberate (only two consumers were bumped, to avoid restarting live systemd services) so it does not read as a regression to be "fixed". The audit also found a fourth shared package the phase briefs omit: `sync_settings_ui`, consumed by four apps. It resolves most of the `SettingsScreen` cluster, which the grid still listed as outstanding. The remaining true duplicates (`_PrefsPersistence`, `Clock`, mulberry32 RNG) are non-UI utilities outside every package's remit, and are recorded as such rather than as a reason to widen web_ui into a general utility package. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01U4Rj3s7K2qzrLNgJqqPhno --- .../extraction-audit-2026-08-15.md | 124 ++++++++++++++++++ unified-design-system/nielsen-audit.md | 17 ++- 2 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 unified-design-system/extraction-audit-2026-08-15.md diff --git a/unified-design-system/extraction-audit-2026-08-15.md b/unified-design-system/extraction-audit-2026-08-15.md new file mode 100644 index 0000000..b41a536 --- /dev/null +++ b/unified-design-system/extraction-audit-2026-08-15.md @@ -0,0 +1,124 @@ +# Extraction audit — did we extract everything? (2026-08-15) + +Answers "are all the components we actually use extracted?" across all three +shared packages, after Phases 1–3 shipped. Companion to `nielsen-audit.md` +(the grid) and `phase3-record.md` (Phase 3's verdicts). + +**Short answer: yes, with one leftover — now fixed — and one clear miss.** + +The three packages' extractions hold up. No shipped component turned out to be +a false positive, and the reverse check (did the donor copies actually get +deleted?) is clean except for one case. + +## There is a fourth shared package + +The phase briefs name three. There are four: + +| Package | Stack | Consumers | +| --- | --- | --- | +| `design_system` | Dart/Flutter | 6 repos | +| `gatelock` | Python/Tk | 4 guard apps (2 bumped) | +| `web_ui` | TS/React | dufs-cloud, awesome-mcp-explorer | +| **`sync_settings_ui`** | Dart/Flutter | todo, home_inventory, diet-guard, wake-alarm | + +`sync_settings_ui` (`backup_slot.dart`, `firebase_sync_controller.dart`, +`sync_settings_screen.dart`) changes the coverage answer for the whole sync +cluster — four of the five `SettingsScreen`s already delegate to it, so that +cluster is largely resolved rather than outstanding. + +## Fixed in this pass + +**billsplit's `_SectionHeader`** — a genuine leftover donor copy. +`billsplit/lib/ui/people_screen.dart` imported `design_system` while still +defining and using its own `_SectionHeader`. The shared `SectionHeader`'s +own doc names billsplit as a donor and sizes `defaultPadding` as +`fromLTRB(md, md, md, xs)` precisely to reproduce billsplit's `(16,16,16,4)`. +The union shipped; this donor was never deleted. Retired in +`testsAndMisc@54054e7`, verified geometrically identical. + +(untools' `_SectionHeading`, the other named donor, *was* correctly deleted.) + +## The one clear miss — `DeviceCodeDialog` ×3 + +The strongest finding. A modal showing a GitHub device-flow user code: +copies to clipboard, launches the verification URL, polls for the token, +pops with it or renders an error. + +| Repo | Path | Lines | +| --- | --- | --- | +| todo | `lib/ui/device_code_dialog.dart` | 110 (public) | +| wake-alarm | `phone_app/lib/screens/github_mirror_screen.dart:157-240` | ~84 (private) | +| diet-guard | `app/lib/screens/github_mirror_screen.dart:398-481` | ~84 (private) | + +**The wake-alarm and diet-guard copies are byte-for-byte identical** (`diff` +returns empty). todo's differs only by being public/keyed with doc comments. +Same domain types (`DeviceCodeResponse`, `GitHubDeviceAuth`), same props, same +`String? _error` state, same `initState`→`_poll` lifecycle. + +**Belongs in `sync_settings_ui`, not `design_system`** — it depends on GitHub +auth types, so it is not a generic widget. Not yet extracted. + +Note this is a *leaf* of the `GitHubMirrorScreen` ×4 cluster, which is +deliberately app-local (each copy carries the "connecting here also triggers +an actual sync" comment). The screen stays local; the dialog need not. + +## True duplicates outside every package's remit + +Real duplication, but none of it is UI, so no existing package owns it. +**These are not a reason to widen `web_ui`'s remit** — it is a UI package, and +the games were explicitly out of Phase 3 scope. A separate shared utility +module would be the vehicle, in a future phase. + +- **`_PrefsPersistence` ×3** — todo, home_inventory, diet-guard, all + `implements LogPersistence`, all at the identical line number. Belongs to + `crdt_sync_dart`'s remit. +- **`Clock` / `createRealClock` / `createManualClock` ×2** — konbini-67 (59 + lines) and iron-and-anvil (49). Same interface, same `realClock` shared + instance with the same rationale, doc comments near-verbatim. +- **mulberry32 seeded RNG ×4** — konbini-67, sims3-clone, europe-county-map, + hotline3d. Identical `0x6d2b79f5` core in all four, but the *interfaces* + genuinely differ (closure-returning-methods vs mutable-state-plus-free- + functions; `float`/`next` naming; `chance` in only one). Extractable, but + it is an API reconciliation, not a lift-and-shift. + +## Correctly not extracted (name collisions) + +Confirmed structurally disjoint — do not re-raise these: + +- **`SettingsScreen` ×5** — four already delegate to `sync_settings_ui`; + dufs-cloud's is a WebDAV connection form (`_url`/`_user`/`_pass`), not sync + preferences. +- **`FilterSheet` ×3** — todo and home_inventory are Stateful, dufs-cloud is + Stateless. The split alone rules out a common component. +- **`FilterBar`** — settled in `phase3-record.md`. +- **`EntryTile` ×2** — kuhylog log entries vs dufs-cloud `DirEntry` rows. +- **`HomeShell` ×2**, **`HomeScreen` ×2** — unrelated shells/screens. +- **`formatDuration` ×2** — personal-website takes a `Duration` (CV date + range), dufs-cloud takes `ms: number` (media length). Disjoint signatures. +- **`ConfirmDialog`, `PromptDialog`, `StatBar`, `SummaryCards`** — single-use. + +## Reviewed and judged benign + +**leetcode-guard's five raw `tk.Button(` sites** (`_view.py:160,190,247`, +`_escape_flow.py:219`, `_study_strip.py:184`) persist despite the repo +importing `make_button`. All five sit inside the gate/lock-window path marked +do-not-touch, and each already applies the `fg=config.on_fill` contrast +discipline manually with an explanatory comment — the exact bug `make_button`'s +`variant` API exists to prevent. Worth migrating opportunistically; the +invariant is currently upheld. + +## Not fully verified + +`WrapperServer` ×4 (habit_stack 155 / home_inventory 217 / todo 223 / +diet-guard 254) was assessed from line counts and in-file architectural +comments, not a full body diff. If a hard verdict is wanted, that one still +needs opening. + +## Phase 4 inputs (deferred, per the Q2 decision) + +`personal-website`, `konbini-67`, `europe-county-map`, `sims3-clone`, +`steam-backlog-enforcer/web` and `iron-and-anvil` do not consume +`@kuhyx/web-ui`. All the `Clock`/RNG duplication lives entirely in this group. +`europe-county-map` and `iron-and-anvil` still define **zero** custom +properties, so they are token-adoption candidates independent of any component +work. diff --git a/unified-design-system/nielsen-audit.md b/unified-design-system/nielsen-audit.md index f6fcf38..9f6b35b 100644 --- a/unified-design-system/nielsen-audit.md +++ b/unified-design-system/nielsen-audit.md @@ -178,7 +178,15 @@ dep, as todo, untools, focus_owner, kuhylog, epopeja_karta and billsplit now do. These six were never off-palette — they transcribe the right values by hand — so this is duplication cleanup, not a visual fix. -### Phase 2 — Python/Tk (`~/utils/gatelock`), not started +### Phase 2 — Python/Tk (`~/utils/gatelock`), SHIPPED (gatelock 0.5.0) + +> **Status: done.** `make_button`, `heading`/`row`, `ScrollableSurface` and +> `WidgetGroup` all ship in gatelock 0.5.0 (`c963cd8`, `d82107a`, `d25f288`); +> diet-guard and leetcode-guard are the migrated proof consumers. +> screen-locker (v0.4.0) and wake-alarm (v0.4.1) keep local fan-out copies +> **by design** — only two consumers were bumped to avoid restarting live +> systemd services. That asymmetry is not a regression; do not "fix" it. +> Everything below this line is the original plan, kept as the record of why. Not a new package: gatelock already owns the tokens (`LockConfig`), the Tk plumbing and 4 consumers. Add composite widgets, which is where its scope @@ -208,7 +216,12 @@ gain. > path. Then launch each gate under `xvfb-run -s "-screen 0 1366x768x24"` and > confirm buttons render and **`` activates** them. -### Phase 3 — TypeScript (`~/utils/web_ui`), not started +### Phase 3 — TypeScript (`~/utils/web_ui`), SHIPPED (web_ui-v0.3.1) + +> **Status: done** — see `phase3-record.md` for what shipped and, importantly, +> why `FilterBar` was *not* extracted (a name collision, not a duplicate). +> Both proof consumers (dufs-cloud, awesome-mcp-explorer) are migrated. +> Everything below this line is the original plan, kept as the record of why. Lowest confirmed duplication (2 components, 2 repos) and the only stack needing a brand-new consumption mechanism, so it carries the worst effort-to-payoff