mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-11 19:14:00 +01:00
Some checks failed
file length / file-length (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
design_system tests / test (push) Has been cancelled
gatelock pre-commit / pre-commit (push) Has been cancelled
gatelock tests / test (3.10) (push) Has been cancelled
gatelock tests / test (3.11) (push) Has been cancelled
gatelock tests / test (3.12) (push) Has been cancelled
web_ui tests / test (push) Has been cancelled
Markdown across every repo had accumulated a dozen ad-hoc names (refactor_claude_todo.md x23, DESIGN_AUDIT_TODO.md, NEXT_SESSION, HANDOFF, PLAN, SPEC) with nothing distinguishing a live task from a finished record. An audit found docs asserting work was pending that shipped months earlier, and one asserting completion while the work was open. Four namespaces now: README.md, CLAUDE*.md, DOCS*.md, TODO*.md. Task files carry the literal "REMOVE ME AFTER FINISH" and are deleted when the work lands. Enforced bidirectionally -- a TODO without the marker fails, AND any file carrying the marker that is not named TODO*.md fails. Without the reverse rule a task can be renamed into the permanent namespace and quietly live forever, which is the failure being fixed. md_naming/ mirrors the file_length topology and imports its tables (EXCLUDED_DIRS, THIRD_PARTY_REPOS, VENDORED_ANYWHERE, GENERATED_PATTERN) rather than restating them, so the two gates cannot disagree about the same file. 71 tests, 100% branch coverage. stale.py warns on TODOs past 90 days but never fails: no machine can prove a task is finished, so the honest mechanism is a nudge. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A47aX5DJwmA3QFn3pkEWi7
29 lines
4.1 KiB
Markdown
29 lines
4.1 KiB
Markdown
Implement Phase 2 of the shared component work: extend `~/utils/gatelock` (Python/Tk) with the composite widgets that four guard apps each reimplemented. Treat this as `override` on the spec gate — the spec is below, it is complete, and I do not want a round of questions before you start.
|
||
|
||
**Goal.** gatelock already owns the design tokens (`LockConfig`) and the Tk plumbing, and has four consumers. Its scope stops short of composite widgets, so each consumer grew its own. Move those into gatelock and retire the copies in two proof consumers.
|
||
|
||
**This is NOT a new package.** Add to `~/utils/gatelock`, which already exists and is consumed as `gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.4.1#subdirectory=gatelock`.
|
||
|
||
**Build these four, in order:**
|
||
|
||
1. `gatelock/widgets.py` — `make_button(parent, *, text, variant, command)`. Canonical implementation is diet-guard's `_gatelock_buttons.py::make_button`: its `variant` API picks the text colour *from* the fill, which structurally prevents the `fg`-vs-`on_fill` contrast bug the README documents. leetcode-guard's `_button` (no `<Return>` binding) and screen-locker's inline `tk.Button` are the regressions being retired. Two non-obvious traps both copies had to solve independently and which the shared version must keep: `<Return>` is unbound on `tk.Button` under X11, and the default focus ring is 1px black, invisible on `#211D1B`.
|
||
2. `gatelock/widgets.py` — `heading()` and `row()`, from `leetcode_guard/_status_sections.py`.
|
||
3. **Export the existing `ScrollableSurface`** and delete `leetcode_guard/status_view.py::_scrollable`, a hand-rolled reimplementation that lost `takefocus` and the focus ring the shared version already fixes. This one is a straight accessibility regression repair, not a refactor.
|
||
4. `gatelock/widget_group.py` — `WidgetGroup`, the per-output fan-out reimplemented four times (~916 lines total: screen-locker 173, leetcode-guard 105, diet-guard 309, wake-alarm 329). Highest line-count win on this stack.
|
||
|
||
**Proof consumers: `diet-guard` and `leetcode-guard`** — the donor and the worst offender, so the API is validated against both ends. Bump **only these two**. Leave screen-locker and wake-alarm on their current pin: Phase 2 is additive, untouched consumers keep working, and restarting more live services than necessary is blast radius for no gain. Ask me before restarting anything live.
|
||
|
||
**Extraction criterion.** Build a component only where two or more repos already contain a structurally similar implementation. Shipping a widget nobody imports is the failure mode to avoid. Corollary I learned the hard way in Phase 1: when you extract something, **retire the donor copies in the same pass**, or you have shipped a duplicate rather than removed one.
|
||
|
||
**Verification gate — non-negotiable.** gatelock backs live systemd services; a bad import takes 3–4 of them down at once.
|
||
|
||
- `/usr/bin/python3 -c "import gatelock"` against the **real** interpreter, not a dev venv. The library is tag-pinned in site-packages while the apps are editable, so a cwd-relative check will lie to you.
|
||
- Then diet-guard's and leetcode-guard's test suites.
|
||
- Then launch each gate under `xvfb-run -s "-screen 0 1366x768x24"` and confirm buttons render **and `<Return>` activates them** — that is the specific regression this phase repairs, so it is the specific thing to observe.
|
||
- Do **not** touch the gate window's X-grab path. Those fullscreen surfaces carry input-hijack invariants; a deadlock there has frozen the PC before.
|
||
- `pre-commit run --files <changed>` in every touched repo, respect the 250-line file cap, and keep each repo's coverage bar.
|
||
|
||
**Done means:** the four items exist in gatelock with tests, the two proof consumers import them with their local copies deleted, `<Return>` verifiably activates a button in each gate under xvfb, and everything is committed and pushed.
|
||
|
||
Context, if you want it: `~/utils/unified-design-system/nielsen-audit.md` has the full grid and the Phase 1 record. Phase 1 (`~/utils/design_system`, Dart) is done — 7 exports, 100% coverage, six consumers — and is the pattern to imitate: `publish_to: none`, own analysis config, own tests, own coverage gate, tag-pinned git dep.
|