mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 19:07:17 +01:00
Some checks are pending
crdt_sync_dart tests / test (push) Waiting to run
crdt_sync_flutter tests / test (push) Waiting to run
crdt-sync pre-commit / pre-commit (push) Waiting to run
crdt-sync tests / test (push) Waiting to run
dependency freshness / dependencies on newest stable (push) Waiting to run
design_system tests / test (push) Waiting to run
file length / file-length (push) Waiting to run
freedays pre-commit / pre-commit (push) Waiting to run
freedays tests / test (push) Waiting to run
gatelock pre-commit / pre-commit (push) Waiting to run
gatelock tests / test (push) Waiting to run
github_device_auth tests / test (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
music_theory tests / test (push) Waiting to run
palette drift / palette (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
sync_settings_ui tests / test (push) Waiting to run
web_ui tests / test (push) Waiting to run
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AwtowrowDXx6ccmWVPkCaF
140 lines
6.9 KiB
Markdown
140 lines
6.9 KiB
Markdown
Add a structural-token drift checker to CI
|
|
|
|
## findings (2, ranked by value over effort)
|
|
|
|
1. **Spacing, radius and type have never been drift-checked** — `palette_check.py`
|
|
parses hex only, so three whole token categories can diverge across stacks
|
|
while CI stays green. Motion inherits the same hole.
|
|
2. **`palette_map.py` points at a "scale check" that does not exist** — a
|
|
comment describing a guarantee nobody wrote.
|
|
|
|
## what
|
|
|
|
`palette_check.py` guarantees the colour palette agrees across all stack copies.
|
|
It does **not** check anything else — verified 2026-08-16 by reading its four
|
|
parsers, every one of which requires a `#RRGGBB` value:
|
|
|
|
```python
|
|
parse_css : r"(--[a-z0-9-]+)\s*:\s*(#[0-9A-Fa-f]{6})\s*;"
|
|
parse_dart: r"static const Color (\w+) = Color\(0x[fF]{2}([0-9A-Fa-f]{6})\)"
|
|
parse_tk : r'^\s{4}(\w+):\s*str\s*=\s*"(#[0-9A-Fa-f]{6})"'
|
|
parse_md : r"^\|\s*`([a-z0-9-]+)`\s*\|\s*`(#[0-9A-Fa-f]{6})`"
|
|
```
|
|
|
|
So **spacing, radius and type have been silently unprotected all along**, and the
|
|
motion tokens added by prompt 01 inherit the same hole. A `--duration-fast: 120ms`
|
|
is invisible to every parser: CI passes while the stacks drift apart.
|
|
|
|
Worse, `scripts/palette_map.py:159` claims structural values are "checked by the
|
|
scale check" — **no such script exists anywhere in `~/src/utils`**. That comment
|
|
describes a check that was never written. This prompt writes it.
|
|
|
|
## where
|
|
|
|
Repo: `~/src/utils`.
|
|
|
|
**Create** `~/src/utils/unified-design-system/scripts/structural_check.py`.
|
|
|
|
**Edit** `~/src/utils/.github/workflows/palette-drift.yml` — add a step invoking it.
|
|
The workflow deliberately has no `paths:` filter; keep it that way.
|
|
|
|
**Fix** the stale comment at `~/src/utils/unified-design-system/scripts/palette_map.py`
|
|
(~:159) to name the real script.
|
|
|
|
Sources to compare (three code stacks + the prose freeze):
|
|
|
|
| Role | Path |
|
|
|---|---|
|
|
| prose freeze | `~/src/utils/unified-design-system/tokens.md` (spacing/radius/type) |
|
|
| motion freeze | `~/src/utils/unified-design-system/motion.md` (**created by prompt 01** — run it first) |
|
|
| web/React | `~/src/utils/web_ui/src/tokens.css` |
|
|
| Flutter/Dart | `~/src/utils/design_system/lib/src/tokens.dart` |
|
|
| Python/Tkinter | `~/src/utils/gatelock/gatelock/_window.py` (`class LockConfig`) |
|
|
|
|
## must
|
|
|
|
- Cover **motion** (durations, easing) **and** the already-unprotected
|
|
**spacing, radius and type** scales, in one checker.
|
|
- Mirror `palette_check.py`'s two-halves design, because it is the part that
|
|
actually works:
|
|
1. **Agreement** — for each mapped token, resolve it in every non-`n/a` stack
|
|
and fail if values disagree.
|
|
2. **Completeness, bidirectional** — every structural value parsed out of any
|
|
source must be mapped, or explicitly exempted. This is what catches
|
|
"added it to one stack, forgot the others".
|
|
- Support an explicit **`n/a` per stack**, and require a reason string. Tkinter
|
|
has no animation framework; a duration legitimately does not exist there. An
|
|
honest `n/a` with a reason is correct — a fabricated constant is not.
|
|
- **Adjudicate with exit codes.** Exit non-zero on drift with a message naming
|
|
the token and the disagreeing files. No warnings-only mode.
|
|
- Keep every file ≤ **250 lines** (`~/src/utils/file_length/config.py`). Note
|
|
`palette_check.py` is 231 and `palette_map.py` is 162 — that pair was split
|
|
precisely to stay under the cap. **Split yours the same way from the start**
|
|
(`structural_check.py` + `structural_map.py`) rather than discovering the
|
|
problem at 251 lines.
|
|
- Ruff-clean under the repo's config. No `# noqa`, no `type: ignore`.
|
|
|
|
- **Expect it to fail on first run.** Spacing/radius/type have never been
|
|
compared; there may be real pre-existing drift. That is the point of writing
|
|
it. Fix whatever it surfaces, in the stack copy that is wrong, and say in the
|
|
session summary what drifted.
|
|
- must not: weaken the checker, add an exemption, or narrow its scope to make it
|
|
green. If a token genuinely differs per stack for a good reason, encode it as
|
|
an `n/a`/variant **with the reason recorded**, not as a silent skip.
|
|
- must not: modify `palette_check.py`. It works; it is simply colour-only. The
|
|
two scripts run side by side.
|
|
- must not: change any token *value* to resolve a disagreement without saying so
|
|
explicitly — that is a design change, and `tokens.md` is a freeze. Surface it
|
|
and let kuhy decide which value is canonical.
|
|
|
|
- optional: teach it the shadow tier too, if that falls out cheaply.
|
|
|
|
## done
|
|
|
|
1. `python3 ~/src/utils/unified-design-system/scripts/structural_check.py` exits 0,
|
|
and exits non-zero when you deliberately break one stack copy (**test both
|
|
directions** — a checker that never fails is not a checker).
|
|
2. It is wired into `~/src/utils/.github/workflows/palette-drift.yml` and the
|
|
workflow passes.
|
|
3. `palette_map.py`'s "scale check" comment names the real script.
|
|
4. `~/src/utils/scripts/check_file_length.sh --all` reports no new violations.
|
|
5. The session summary states what drift, if any, the first run found.
|
|
|
|
## verify
|
|
|
|
Desktop. Run the script, paste the output. Then prove it fails: change one
|
|
spacing or duration value in **one** stack copy, re-run, paste the non-zero exit
|
|
and the message, and revert. Both halves of that demonstration are required —
|
|
the passing run alone proves nothing.
|
|
|
|
## read first
|
|
|
|
- `~/src/utils/unified-design-system/scripts/palette_check.py` — the design to
|
|
mirror. Read `NON_COLOUR_CSS`: it is the regex that currently *excludes*
|
|
spacing/radius/type/shadow from the colour check, and therefore the precise
|
|
list of what you are now covering.
|
|
- `~/src/utils/unified-design-system/scripts/palette_map.py` — the `PALETTE` tuple of
|
|
`Token(canonical, md, css, dart, tk, why)` rows. Your map wants the same shape,
|
|
including the `why` field.
|
|
- `~/src/utils/.github/workflows/palette-drift.yml` — how `palette_check.py` and
|
|
`ramp_check.py` are invoked; add your step alongside.
|
|
- `~/src/utils/unified-design-system/motion.md` — what prompt 01 created.
|
|
- `~/src/utils/unified-design-system/tokens.md` — the spacing/radius/type tables.
|
|
**Do not edit it**; it is 260 lines and already over the cap.
|
|
|
|
## context you would otherwise rediscover
|
|
|
|
- The four "stack copies" are really **three code stacks plus a prose freeze**.
|
|
There is no fourth code stack; do not hunt for one.
|
|
- `~/src/dufs-cloud/app/lib/ui/theme.dart` is a **fifth, uncompared copy** of the
|
|
palette (the Flutter app has no `design_system` dependency and hand-restates
|
|
every hex). It is out of scope here — prompt 07 wires it up properly. Do not
|
|
add it as a source to this checker; wait until 07 has removed it.
|
|
- Three Flutter apps (diet-guard, workout_app, wake_alarm) similarly
|
|
hand-transcribe tokens into local `lib/ui/theme.dart` files. Those are
|
|
deliberately outside the checker's scope for now — bringing them in is a much
|
|
larger job than this prompt.
|
|
- `~/src/utils/gatelock/` is a package inside this monorepo, not a separate repo.
|
|
|
|
REMOVE ME AFTER FINISH
|