From 03e14e17f3b83202406a94dedcc3da8b4074e60c Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Mon, 24 Aug 2026 15:57:20 +0200 Subject: [PATCH] Adopt the four markdown namespaces and gate them Renames this repo's markdown onto README.md / CLAUDE*.md / DOCS*.md / TODO*.md so a future session can tell a live task from a finished record without reading the file to find out. TODO files carry the literal "REMOVE ME AFTER FINISH" and are deleted when the work lands. Enforced by the md-naming pre-commit hook and CI workflow, both delegating to the shared gate in kuhyx/utils so this repo's idea of a valid name cannot drift from every other repo's. Includes the patch bump this repo's bump-patch-version hook applies to app/pubspec.yaml on every commit. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01A47aX5DJwmA3QFn3pkEWi7 --- .github/workflows/md-naming.yml | 38 +++++ .pre-commit-config.yaml | 10 ++ AGENTS.md | 22 +-- DESIGN_AUDIT_TODO.md | 151 ------------------ README.md | 2 +- app/README.md | 2 +- app/pubspec.yaml | 2 +- docs/{design.md => DOCS-design.md} | 0 ...design.md => DOCS-flutter-rules-design.md} | 0 ...uage.md => DOCS-flutter-rules-language.md} | 0 ...d => DOCS-flutter-rules-state-and-data.md} | 0 ... DOCS-flutter-rules-testing-and-assets.md} | 0 ...r-rules-ui.md => DOCS-flutter-rules-ui.md} | 0 ...phone.md => DOCS-kuchnia-wikinga-phone.md} | 0 ...nia-wikinga.md => DOCS-kuchnia-wikinga.md} | 0 ...meal-schedule.md => DOCS-meal-schedule.md} | 0 .../{sync-latency.md => DOCS-sync-latency.md} | 0 ...use.md => DOCS-crdt-sync-session-reuse.md} | 0 ...uard.md => TODO-dopamine-ux-diet-guard.md} | 2 + scripts/check_md_naming.sh | 32 ++++ 20 files changed, 96 insertions(+), 165 deletions(-) create mode 100644 .github/workflows/md-naming.yml delete mode 100644 DESIGN_AUDIT_TODO.md rename docs/{design.md => DOCS-design.md} (100%) rename docs/{flutter-rules-design.md => DOCS-flutter-rules-design.md} (100%) rename docs/{flutter-rules-language.md => DOCS-flutter-rules-language.md} (100%) rename docs/{flutter-rules-state-and-data.md => DOCS-flutter-rules-state-and-data.md} (100%) rename docs/{flutter-rules-testing-and-assets.md => DOCS-flutter-rules-testing-and-assets.md} (100%) rename docs/{flutter-rules-ui.md => DOCS-flutter-rules-ui.md} (100%) rename docs/{kuchnia-wikinga-phone.md => DOCS-kuchnia-wikinga-phone.md} (100%) rename docs/{kuchnia-wikinga.md => DOCS-kuchnia-wikinga.md} (100%) rename docs/{meal-schedule.md => DOCS-meal-schedule.md} (100%) rename docs/{sync-latency.md => DOCS-sync-latency.md} (100%) rename prompts/{crdt-sync-session-reuse.md => DOCS-crdt-sync-session-reuse.md} (100%) rename prompts/{dopamine-ux-diet-guard.md => TODO-dopamine-ux-diet-guard.md} (99%) create mode 100755 scripts/check_md_naming.sh diff --git a/.github/workflows/md-naming.yml b/.github/workflows/md-naming.yml new file mode 100644 index 0000000..1bb197c --- /dev/null +++ b/.github/workflows/md-naming.yml @@ -0,0 +1,38 @@ +name: md-naming + +# The four markdown namespaces, enforced on push as well as at commit time. +# The local pre-commit hook can be skipped (a fresh clone that never ran +# `pre-commit install` has no hooks at all), so the convention needs a second +# gate that no one can forget to install. +# +# Deliberately a SEPARATE workflow from any release job: a badly named doc +# should fail lint, not block publishing an artifact. +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +jobs: + md-naming: + name: markdown naming convention + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # The gate and its exemption list live in the shared utils repo so every + # repo enforces the same namespaces. Checking it out beats vendoring a + # copy here, which is exactly how a gate and a survey start disagreeing. + - name: Check out the shared gate + uses: actions/checkout@v4 + with: + repository: kuhyx/utils + path: .utils + + - name: Enforce the naming convention + run: bash .utils/scripts/check_md_naming.sh --all + + # Warns only: no machine can prove a task is finished, so an old TODO + # gets a nudge, never a failure. + - name: Warn about stale TODOs + run: PYTHONPATH=.utils python3 .utils/md_naming/stale.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5046b16..e24f7cc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -195,3 +195,13 @@ repos: language: system pass_filenames: false files: ^diet_guard/ + + # Four markdown namespaces (README / CLAUDE* / DOCS* / TODO*), plus the + # rule that a TODO carries "REMOVE ME AFTER FINISH" and nothing else may. + # Shared gate in ~/utils owns the namespaces and the exemption list, so + # one repo's idea of a valid name cannot drift from every other repo's. + - id: md-naming + name: markdown naming convention + entry: scripts/check_md_naming.sh + language: system + files: \.(md|markdown)$ diff --git a/AGENTS.md b/AGENTS.md index c1aa72b..6859660 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,7 +11,7 @@ streaks, a YTD tally and weekly/monthly averages, all derived from `_daystatus.py` / `day_status_service.dart` and `_averages.py` / `average_service.dart`. -`docs/design.md` holds the original spec (slot timing, the Tue/Wed/Thu +`docs/DOCS-design.md` holds the original spec (slot timing, the Tue/Wed/Thu catch-up rule). ## Commands @@ -75,7 +75,7 @@ every idle tick to approximate the two moments state actually changes here. - **Interactive paths must not block, and stale peers cost real time.** The threading rules, the interactive timeout, and `prune-peers` (including the `revs/` marker trap that made pruning *slower*) are in - [docs/sync-latency.md](docs/sync-latency.md) — read it before touching + [docs/DOCS-sync-latency.md](docs/DOCS-sync-latency.md) — read it before touching `_sync_refresh.py`, the fetch button, or the publish paths. - Every test that logs a meal would otherwise hit the network through these new call sites; `conftest._isolate_state` patches each one @@ -159,7 +159,7 @@ reach the running service. `app/` builds for **Android** and **web** only. There is no `app/linux/` — Flutter's GTK embedder manages ~20fps at 3840x2160 where the same Dart in -Chrome sustains ~144fps (`~/todo/docs/desktop-performance-findings.md`). The +Chrome sustains ~144fps (`~/todo/docs/DOCS-desktop-performance-findings.md`). The desktop app is the web build served by `bin/diet_guard_desktop.dart` in a Chrome `--app` window. @@ -184,7 +184,7 @@ many meals fall between them, evenly divided. Default `(8, 20, 4)` is the old hardcoded 08/12/16/20. Four load-bearing rules (integer-only arithmetic, whole-hour slots, the count clamp, the `last + 2h` cutoff), the forward-only history, and the two edit surfaces are documented in -[docs/meal-schedule.md](docs/meal-schedule.md) — read it before touching +[docs/DOCS-meal-schedule.md](docs/DOCS-meal-schedule.md) — read it before touching `_slots.py` / `slot.dart`. ## Averages (`_averages.py` / `average_service.dart`) @@ -207,7 +207,7 @@ phone show both. ## Do NOT -- Don't relax the meal-slot logic without re-reading `docs/design.md`. The +- Don't relax the meal-slot logic without re-reading `docs/DOCS-design.md`. The off-hours clamp in `slot_for_log`/`slotForLog` (before the first slot → the first slot, after the enforcement window → the last slot) must stay byte-identical across Python and Dart; do NOT widen `elapsed_slots`, which @@ -228,7 +228,7 @@ phone show both. - Don't let the catering import log unattended (delivered ≠ eaten), don't let its Python and Dart halves drift (one shared fixture gates them), and don't make the synced password machine-local — the phone could not then fetch. - [docs](docs/kuchnia-wikinga.md), [phone](docs/kuchnia-wikinga-phone.md). + [docs](docs/DOCS-kuchnia-wikinga.md), [phone](docs/DOCS-kuchnia-wikinga-phone.md). - Don't add a dependency without the production install-path check above. - Don't reintroduce a seal/`chattr +i` on the budget file. - Don't re-add a Linux embedder target, and don't change the wrapper's port or @@ -243,8 +243,8 @@ _Vendored from [flutter/flutter docs/rules/rules.md](https://github.com/flutter/ via `~/.claude/CLAUDE.md` Flutter AI tooling setup. Re-fetch periodically. Split across five files to stay under the 250-line cap._ -- [Language, style and architecture](docs/flutter-rules-language.md) -- [Architecture, lint rules, state and data](docs/flutter-rules-state-and-data.md) -- [Code generation, testing and theming](docs/flutter-rules-testing-and-assets.md) -- [UI: theming, layout and overlays](docs/flutter-rules-ui.md) -- [Colour, type, documentation and accessibility](docs/flutter-rules-design.md) +- [Language, style and architecture](docs/DOCS-flutter-rules-language.md) +- [Architecture, lint rules, state and data](docs/DOCS-flutter-rules-state-and-data.md) +- [Code generation, testing and theming](docs/DOCS-flutter-rules-testing-and-assets.md) +- [UI: theming, layout and overlays](docs/DOCS-flutter-rules-ui.md) +- [Colour, type, documentation and accessibility](docs/DOCS-flutter-rules-design.md) diff --git a/DESIGN_AUDIT_TODO.md b/DESIGN_AUDIT_TODO.md deleted file mode 100644 index 2c1a2bf..0000000 --- a/DESIGN_AUDIT_TODO.md +++ /dev/null @@ -1,151 +0,0 @@ -# Design audit — diet-guard - -Generated against safe-design-rules (anthonyhobday.com/sideprojects/saferules). -Report only — nothing in this repo was changed by the audit itself. - -This repo has two UI surfaces, audited separately below. - ---- - -## Flutter app (`app/`) - -Theme entry point: `app/lib/main.dart:52` — -`ThemeData(colorSchemeSeed: Colors.teal, useMaterial3: true)`. This is the -**entire** theme definition: no `darkTheme`, no `textTheme` override, no -component themes (`elevatedButtonTheme`, `cardTheme`, etc.), no -`ThemeExtension`. Everything downstream of this one line either inherits -Material 3's generated defaults or bypasses the theme with raw `Colors.*` -literals in individual widgets — sampled across `screens/` and `widgets/` -(11 of 21 files). - -### Violations - -- **Rule 1 (near-black/near-white)** — `app/lib/widgets/day_status_calendar.dart:79` uses `Colors.black` for the "not logged" cell fill, and `:87`/`:121` use pure `Colors.white` for text — both bypass the muted near-black/near-white the seeded `ColorScheme` would otherwise supply. -- **Rule 2 (saturate neutrals)** — `app/lib/widgets/day_status_calendar.dart:78,104` (`Colors.grey.shade800`) and `app/lib/widgets/slot_selector_row.dart:49` (`Colors.grey`) use Material's generic, zero-chroma grey instead of a grey tinted toward the teal seed. -- **Rule 4 (everything deliberate)** — no centralized token beyond the one-line `ThemeData` call; `day_status_calendar.dart` (8 raw `Colors.*` refs), `slot_selector_row.dart` (4 raw refs, lines 46-49), and `settings_screen.dart:567` each invent status/error colors independently instead of reading `Theme.of(context).colorScheme`. -- **Rule 4 (inconsistency, concrete pair)** — the same semantic "error" state is styled two different ways in the same app: `history_screen.dart:603` uses `Theme.of(context).colorScheme.error`, but `settings_screen.dart:567` hardcodes `Colors.red` for the same purpose. -- **Rule 9 (distinct brightness values)** — `day_status_calendar.dart:80-82` mixes `Colors.red.shade400` (lighter) with `Colors.amber.shade700` / `Colors.green.shade700` (darker) for three parallel status swatches meant to read as one family — inconsistent shade selection, not a deliberate brightness ramp. -- **Rule 11 (mathematically related measurements)** — corner radii are inconsistent across near-identical use cases: `BorderRadius.circular(8)` in `day_status_calendar.dart:105` and `photo_attach_field.dart:95` vs `BorderRadius.circular(6)` in `history_screen.dart:638` for the same "thumbnail clip" purpose, with no shared base unit. -- **Rule 20 (body text ≥16px)** — `day_status_calendar.dart:123` (`fontSize: 14`), `:146` (`fontSize: 11`), `:181` (`fontSize: 12`) are all below the 16px minimum, with no larger default applied elsewhere to compensate for this widget. -- **Rule 28 (icon contrast lower than text)** — `slot_selector_row.dart:54` (`Icon(..., color: color)`) and `:57` (`labelStyle: TextStyle(color: color)`) give the check icon and its adjacent label text the *same* full-strength color — the icon should read lighter/lower-contrast than the text, not equal. - -### Passes worth recording - -- **Rule 3** — clear hierarchy exists elsewhere: `history_screen.dart:603` correctly pulls the delete/error action from `colorScheme.error`. -- **Rule 18 (container brightness limits)** — only one nested-container case was found (`day_status_calendar.dart`'s `grey.shade800` panel on the default light scaffold); no evidence of a violation. -- **Rule 23 (two typefaces max)** — no `fontFamily` or `google_fonts` import anywhere in `app/lib/` — the whole app uses exactly one (system default) typeface. -- **Rule 26 / 27 (shadows/depth)** — no `BoxShadow`, `elevation:`, or `Card(` usage found in the sampled files; zero depth technique used, so it's trivially consistent (though see Notes — this also means rule 15/16/17 have nothing to evaluate). -- **Rule 28 (partial pass)** — `day_status_calendar.dart:113,127` (`Colors.white70` chevron icons) sit next to `:121` (`Colors.white` full-opacity month label) — here the icon *is* correctly lower-contrast than the text. - -### Not applicable - -- Rule 5 (optical alignment) — no asymmetric icon/shape widgets found requiring hand-tuned centering. -- Rule 6 (letter-spacing/line-height by size) — no manual `letterSpacing`/`height` found anywhere in `screens/`/`widgets/`; the app relies entirely on Material 3's built-in type scale, which already encodes this rule. -- Rule 7 (container border contrast) — the one border found (`day_status_calendar.dart:172-174`, `Colors.white70` on `Colors.black`) has adequate contrast against both surfaces; no counter-evidence. -- Rule 8 (everything aligns) — default `MainAxisAlignment.spaceBetween`/`spaceAround` usage throughout; no counter-evidence gathered. -- Rule 10 (warm or cool, not both) — the app doesn't saturate its neutrals at all (see Rule 2 violation above), so warm/cool consistency has nothing to check. -- Rule 12 (order by visual weight) — no clear violation or pass identified from the sampled files; would need a full-screen layout review. -- Rule 13 (12-column grid) — mobile-first single-column screens; no grid system in use. -- Rule 14 (space between high-contrast points) — insufficient evidence gathered from the sample. -- Rule 15 (closer = lighter) — no elevation/z-stacking found to evaluate (see Rule 26/27 pass note). -- Rule 16 (shadow blur ≈ 2× distance) — no `BoxShadow` in the codebase. -- Rule 17 (simple on complex) — flat design throughout; no complex background/foreground pairing to break the rule. -- Rule 19 (outer padding ≥ inner padding) — holds everywhere checked, e.g. `day_status_calendar.dart:102` (`EdgeInsets.all(12)` outer) vs `:168` (`EdgeInsets.symmetric(vertical: 2)` cell margin). -- Rule 21 (line length ~70 chars) — no long-form body text in the sampled screens (mostly labels/numbers). -- Rule 22 (button padding h=2×v) — no explicit `ButtonStyle.padding` override found anywhere; buttons run on Material 3 defaults, which already approximate this ratio. -- Rule 24 (nest corners) — no nested corner-radius container pairs found to check a concentric relationship. -- Rule 25 (avoid adjacent hard divides) — insufficient evidence gathered from the sample. - -### Notes - -- The theme is effectively unstyled beyond a seed color. Every rule above that reads "no evidence"/"insufficient evidence" is really a symptom of the same root cause: there is no `theme.dart`, no `ThemeExtension` for semantic colors (success/warn/danger), and no component themes, so status colors (green/red/amber/grey) get re-invented per-widget instead of being defined once. Centralizing those into a `ThemeExtension` (e.g. `DietGuardStatusColors`) would fix the Rule 4/9/28 violations above in one pass and make Rule 15/16/17/18/26/27 actually checkable against a real design system instead of "nothing to evaluate." -- `day_status_calendar.dart`'s status colors (`red.shade400`/`amber.shade700`/`green.shade700`) do not literally match the Python gatelock's calendar palette (`#ff5555`/`#e0c33c`/`#33cc66` — see Python section below) even though the widget's own doc comment (`day_status_calendar.dart:9`) says it "mirrors" that view. Worth reconciling into one shared value if visual parity between the phone app and the PC lock screen actually matters. - ---- - -## Python/Tkinter gatelock UI (`diet_guard/`, not `app/`) - -Files audited: `_gatelock_ui.py` (474 lines), `_gatelock_mealflow.py` (349), -`_gatelock_calendar.py` (466), `_gatelock_core.py` (196), -`_gatelock_nutrition.py` (230), `_gatelock.py` (211), `_gatelock_support.py` -(82), `_calendar_view.py` (151). - -**Correction to prior research going in:** there *is* a color-constants block -(`_gatelock_ui.py:27-32`: `BG`, `FG`, `_ACCENT`, `ERR`, `_FIELD_BG`, -`_MUTED`), so "no color/theme constants module" is not quite right — the -real problem is worse than absence: it's **triplication**. `_gatelock_ui.py` -is the closest thing to a canonical module, but `_gatelock_calendar.py:58-60` -and `_calendar_view.py:25-33` each **redefine their own copies** of the same -values instead of importing them (see Violations below). `_gatelock_calendar.py:55-57` -even has a comment justifying this: *"BG/FG/ERR come from `_gatelock_ui`'s -public exports; the rest are private to that module, so equivalents are -defined locally rather than reaching across the boundary."* That's a -structural decision (avoid touching another module's private names) that -produces exactly the drift risk a shared module is supposed to prevent. -Confirmed **no `ttk.Style()` call anywhere** in the 8 files (0 grep hits). -Hex-literal count is also off from the prior estimate: **25 occurrences of -12 distinct hex values** (not ~4) across the 3 files that define palette -constants. Inline `font=` literal count is confirmed accurate: **35 -occurrences**. - -### The shared `LockConfig.bg` token - -`~/utils/gatelock/gatelock/_window.py:71` — `LockConfig.bg: str = "#1a1a1a"` -is the one real shared design token in this family (used by `screen-locker`, -`wake_alarm`, and `diet_guard` alike via `GateRoot`/`LockWindow`). - -- `diet_guard/_gatelock_ui.py:27` — `BG = "#1a1a1a"` **re-hardcodes the same - literal instead of importing `gatelock.LockConfig.bg`**. It happens to - match today, but nothing keeps it in sync — if `LockConfig`'s default ever - changes, this constant silently goes stale. -- `diet_guard/_gatelock.py:147` — `LockConfig(mode=..., bg=BG)` then passes - that duplicated literal back into `LockConfig` explicitly. This call is - redundant today (it matches `LockConfig`'s own default) and masks the - duplication: it *looks* like `diet_guard` is deliberately overriding the - background, when it's actually just echoing the default via a second, - unlinked constant. -- Fix direction (report-only, not applied): `_gatelock_ui.py` should import - `LockConfig.bg` (or a `LockConfig()` default instance's `.bg`) rather than - defining its own `BG` literal, and `_gatelock.py:147` should drop the - explicit `bg=BG` kwarg entirely once it's provably redundant. - -### Violations - -- **Rule 1 (near-black/near-white)** — `_calendar_view.py:25` `_NOT_LOGGED_FILL = "#000000"` is pure black; `_gatelock_ui.py:434` and `:459` (`fg="white"`) are pure white. This is inconsistent with the rest of the palette, which correctly uses `#1a1a1a`/`#e0e0e0` (near-black/near-white, not pure). -- **Rule 2 (saturate neutrals)** — every neutral in the shared palette is a zero-chroma grey (equal R/G/B hex pairs): `BG "#1a1a1a"`, `_FIELD_BG "#2a2a2a"`, `_MUTED "#9a9a9a"` (`_gatelock_ui.py:27,31,32`), plus the duplicate `LockConfig.bg = "#1a1a1a"` (`gatelock/_window.py:71`). None carry any tint — exactly the "generic gray" this rule warns against. -- **Rule 4 (everything deliberate / centralization)** — `_MUTED = "#9a9a9a"` is defined **three times** verbatim: `_gatelock_ui.py:32`, `_gatelock_calendar.py:58`, `_calendar_view.py:33`. `"#003322"` (status text color) is likewise defined 3×: `_gatelock_ui.py:191,421`, `_gatelock_calendar.py:154`, `_calendar_view.py:32`. `_FIELD_BG "#2a2a2a"` and `_ACCENT "#00ff88"`/`"#00cc66"` are each duplicated across `_gatelock_ui.py` and `_gatelock_calendar.py`. No `ttk.Style()` centralizes any of this. -- **Rule 11 (mathematically related measurements)** — font sizes in use: 10, 11, 12, 13, 14, 15, 16, 22, 30 (`_gatelock_ui.py` and `_gatelock_calendar.py`, e.g. `_gatelock_ui.py:130,145,161,285,371,378`) — no common ratio or base unit. Spacing is similarly mixed: `ipady=3` (`_gatelock_ui.py:147,216`) vs `ipady=2` (`:256,330`; `_gatelock_calendar.py:148`) used interchangeably for the same "entry field" role. -- **Rule 20 (body text ≥16px)** — the dominant font size is 12pt (9 occurrences in `_gatelock_ui.py` alone: lines 161,185,209,225,249,260,334,343,... ) with many labels at 11-13pt; only headline-style text (22, 30) clears a 16px-equivalent minimum. - -### Passes worth recording - -- **Rule 3 (high contrast for important elements)** — `_gatelock_ui.py:416-425` ("Log & Continue", the primary action) uses bright `_ACCENT #00ff88`; `:429-438` ("Fetch from sync", secondary) uses a muted `#334455`/`#445566` pair. Clear, deliberate hierarchy. -- **Rule 9 (distinct brightness values)** — `_calendar_view.py:28-30`: `GREEN #33cc66` / `YELLOW #e0c33c` / `RED #ff5555` are visually distinct hues at roughly matched brightness — better-executed than the Flutter app's equivalent (see Flutter Rule 9 violation above). -- **Rule 18 (container brightness limits)** — `BG "#1a1a1a"` (~10% luma) vs `_FIELD_BG "#2a2a2a"` (~16% luma), a ~6% delta — comfortably within the ~12% dark-interface guideline (`_gatelock_ui.py:27,31`). -- **Rule 19 (outer padding ≥ inner padding)** — outer frame padding (e.g. `padx=6` at `_gatelock_ui.py:144`) is consistently ≥ field-level `ipady=2-3`. -- **Rule 23 (two typefaces max)** — exactly two families used: "Arial" (34 occurrences) and "Courier" (1 occurrence, `_gatelock_ui.py:292`). -- **Rule 26 / 27 (no shadows / single depth technique)** — `relief=` (Tk's raised/sunken/groove bevel, its closest thing to a shadow) is never used in any of the 8 files (0 grep hits); zero depth technique applied, trivially consistent. - -### Not applicable - -- Rule 5 (optical alignment) — no asymmetric icon/shape widgets in this Tk UI. -- Rule 6 (letter-spacing/line-height by size) — Tk's `font=` tuples have no letter-spacing control and no independent line-height axis; not expressible in this toolkit. -- Rule 7 (container border contrast) — `highlightthickness` varies 0/1/2 (`_gatelock_ui.py:174,193,229`; `_gatelock_calendar.py:235`) but the one case with a matched-to-background `highlightbackground` (`_calendar_view.py:108-115`, future-day cells) is intentional per its own docstring (`day_status_calendar.dart:9`-equivalent design: blend future days into the background), not a rule violation. -- Rule 8 (everything aligns) — grid/pack-based layout; no counter-evidence gathered. -- Rule 10 (warm or cool, not both) — the neutrals aren't saturated at all (Rule 2 violation above), so there's no warm/cool choice to be consistent about. -- Rule 12 (order by visual weight) — not assessed from the sampled files. -- Rule 13 (12-column grid) — fixed-size fullscreen dialog, not a column-grid layout. -- Rule 14 (space between high-contrast points) — insufficient evidence gathered. -- Rule 15 (closer = lighter) — Tk has no z-stacking/elevation concept; nothing to evaluate. -- Rule 16 (shadow blur ≈ 2× distance) — Tk has no drop-shadow primitive; unused. -- Rule 17 (simple on complex) — flat single-color backgrounds throughout; no complex imagery to conflict with. -- Rule 21 (line length ~70 chars) — `wraplength=900` (pixels, e.g. `_gatelock_ui.py:410,446`) is a pixel wrap, not a character-count guarantee; can't verify without rendering. -- Rule 22 (button padding h=2×v) — no `tk.Button` in the sampled files sets explicit `ipadx`/`ipady`; only `Entry` widgets do (grep-confirmed). Buttons run on Tk's own default padding, unexamined by this rule. -- Rule 24 (nest corners) — Tk widgets here are flat-relief rectangles; no corner-radius concept applies. -- Rule 25 (avoid adjacent hard divides) — insufficient evidence gathered. -- Rule 28 (icon contrast lower than text) — this UI uses unicode glyphs embedded in button `text=` (e.g. `"⟳ Fetch from sync"` at `_gatelock_ui.py:431`, `"✕ Close Demo"` at `:456`) rather than a separately-styled icon widget; there's no independent icon-vs-text contrast axis to check. - -### Notes - -- The real fix for the Python surface's Rule 4 violations is structural: promote `_gatelock_ui.py`'s 6 constants (plus `_calendar_view.py`'s status-color dict) into one importable module that every gatelock file reads from, and have that module import `gatelock.LockConfig`'s `bg` default rather than re-literal-ing `"#1a1a1a"`. That single change collapses 3 duplicate `_MUTED`/`"#003322"` definitions and closes the `LockConfig.bg` drift risk in one pass. -- Because `LockConfig.bg = "#1a1a1a"` is shared by `screen-locker` and `wake_alarm` too, if those repos independently re-hardcode `"#1a1a1a"` the same way `diet_guard` does, this is a family-wide pattern, not a `diet_guard`-only one — worth a follow-up grep across those repos if/when this gets fixed. diff --git a/README.md b/README.md index 0e743b0..914beaa 100644 --- a/README.md +++ b/README.md @@ -96,4 +96,4 @@ python -m venv .venv && .venv/bin/pip install -r requirements.txt ``` See `CLAUDE.md` for scheduling details and production deployment gotchas, -and `docs/design.md` for the original feature spec. +and `docs/DOCS-design.md` for the original feature spec. diff --git a/app/README.md b/app/README.md index 2c6f400..3249e67 100644 --- a/app/README.md +++ b/app/README.md @@ -13,7 +13,7 @@ desktop, sharing one food log through GitHub-backed sync. There is no `linux/` directory. Flutter's GTK embedder manages ~20fps at 3840x2160 -- measured on a stock `flutter create` counter app, so it is the toolkit rather than this code -- where the same Dart rendered by Chrome -sustains ~144fps (`~/todo/docs/desktop-performance-findings.md`). Running +sustains ~144fps (`~/todo/docs/DOCS-desktop-performance-findings.md`). Running `flutter create --platforms linux` here would silently restore the slow path. ## Commands diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 7caff65..6eb1bf1 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -2,7 +2,7 @@ name: diet_guard_app description: "Companion phone app for diet_guard: log meals on the go." publish_to: 'none' -version: 1.0.69+1 +version: 1.0.70+1 environment: sdk: ^3.12.2 diff --git a/docs/design.md b/docs/DOCS-design.md similarity index 100% rename from docs/design.md rename to docs/DOCS-design.md diff --git a/docs/flutter-rules-design.md b/docs/DOCS-flutter-rules-design.md similarity index 100% rename from docs/flutter-rules-design.md rename to docs/DOCS-flutter-rules-design.md diff --git a/docs/flutter-rules-language.md b/docs/DOCS-flutter-rules-language.md similarity index 100% rename from docs/flutter-rules-language.md rename to docs/DOCS-flutter-rules-language.md diff --git a/docs/flutter-rules-state-and-data.md b/docs/DOCS-flutter-rules-state-and-data.md similarity index 100% rename from docs/flutter-rules-state-and-data.md rename to docs/DOCS-flutter-rules-state-and-data.md diff --git a/docs/flutter-rules-testing-and-assets.md b/docs/DOCS-flutter-rules-testing-and-assets.md similarity index 100% rename from docs/flutter-rules-testing-and-assets.md rename to docs/DOCS-flutter-rules-testing-and-assets.md diff --git a/docs/flutter-rules-ui.md b/docs/DOCS-flutter-rules-ui.md similarity index 100% rename from docs/flutter-rules-ui.md rename to docs/DOCS-flutter-rules-ui.md diff --git a/docs/kuchnia-wikinga-phone.md b/docs/DOCS-kuchnia-wikinga-phone.md similarity index 100% rename from docs/kuchnia-wikinga-phone.md rename to docs/DOCS-kuchnia-wikinga-phone.md diff --git a/docs/kuchnia-wikinga.md b/docs/DOCS-kuchnia-wikinga.md similarity index 100% rename from docs/kuchnia-wikinga.md rename to docs/DOCS-kuchnia-wikinga.md diff --git a/docs/meal-schedule.md b/docs/DOCS-meal-schedule.md similarity index 100% rename from docs/meal-schedule.md rename to docs/DOCS-meal-schedule.md diff --git a/docs/sync-latency.md b/docs/DOCS-sync-latency.md similarity index 100% rename from docs/sync-latency.md rename to docs/DOCS-sync-latency.md diff --git a/prompts/crdt-sync-session-reuse.md b/prompts/DOCS-crdt-sync-session-reuse.md similarity index 100% rename from prompts/crdt-sync-session-reuse.md rename to prompts/DOCS-crdt-sync-session-reuse.md diff --git a/prompts/dopamine-ux-diet-guard.md b/prompts/TODO-dopamine-ux-diet-guard.md similarity index 99% rename from prompts/dopamine-ux-diet-guard.md rename to prompts/TODO-dopamine-ux-diet-guard.md index aae2ebf..9ccb7df 100644 --- a/prompts/dopamine-ux-diet-guard.md +++ b/prompts/TODO-dopamine-ux-diet-guard.md @@ -204,3 +204,5 @@ whitelist entry before it can be tested. - diet-guard state lives under XDG (`~/.local/share/diet_guard`), unlike screen-locker's in-repo JSON. Tests isolate it via `~/diet-guard/diet_guard/tests/conftest.py:97` `_isolate_state`. + +REMOVE ME AFTER FINISH diff --git a/scripts/check_md_naming.sh b/scripts/check_md_naming.sh new file mode 100755 index 0000000..50deaa0 --- /dev/null +++ b/scripts/check_md_naming.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# ============================================================================ +# Fail if any markdown file breaks the shared naming convention. +# +# Thin delegate to the shared gate in ~/utils, which owns the four namespaces +# (README / CLAUDE* / DOCS* / TODO*), the "REMOVE ME AFTER FINISH" marker rule +# and the exemption list. Copying that logic here is what lets one repo's idea +# of a valid name drift from every other repo's -- so this script only locates +# the shared checker and forwards its arguments. +# +# Usage: +# scripts/check_md_naming.sh [ ...] # pre-commit passes these +# scripts/check_md_naming.sh --all # whole tree, from cwd +# ============================================================================ + +set -euo pipefail + +readonly SHARED_GATE="${UTILS_ROOT:-$HOME/utils}/scripts/check_md_naming.sh" + +main() { + if [[ ! -x "$SHARED_GATE" ]]; then + echo "Error: shared markdown-naming gate not found at $SHARED_GATE" >&2 + echo " Clone github.com/kuhyx/utils to ~/utils, or set" >&2 + echo " UTILS_ROOT to where it lives." >&2 + exit 1 + fi + + exec bash "$SHARED_GATE" "$@" +} + +main "$@"