LockConfig's colours moved into a nested LockPalette record; every
_COLORS.<colour> read follows. Nothing about the gate's behaviour changed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HHCbkJWXHjtTUaqvnHRAqA
Also bumps Flutter 3.47.3, flutter_secure_storage 11.1.0, idb_shim 2.9.9,
mcp 2.2.0 and ruff 0.16.7 so the freshness gate lets this through.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AwtowrowDXx6ccmWVPkCaF
Python side: gatelock v0.7.1 -> v0.7.2, crdt-sync v0.9.0 -> v0.9.1 (both
re-cut so consumers stop resolving pre-upgrade constraints) and every `>=`
floor turned into an exact pin, five majors among them (mypy 1 -> 2.3.1,
pylint 3 -> 4.0.7, pytest 8 -> 9.1.1, pytest-cov 4 -> 7.1.0, ruff 0.8 ->
0.16.5).
app/: twenty pins, of which permission_handler 12.0.3 -> 13.0.1 and
workmanager 0.9.0+3 -> 0.10.9 are real major moves the lockfile had been
holding back, plus the flutter_secure_storage 11 chain (compileSdk 37 /
AGP 9.3.2 / Gradle 9.7.1). CI's Flutter pin was 3.44.8 against an .fvmrc of
3.47.2; both say 3.47.2 now, and the gate reads that pin.
`scripts/ci_mirror.sh` green end to end: the Python suite in a clean venv and
706 Flutter tests, pre-commit --all-files clean, gate exit 0.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CRykabMwPgDzFHcARoqpaK
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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A47aX5DJwmA3QFn3pkEWi7
Replace this repo's stale file-length hook with the shared gate every other
repo will use. The old hook capped at 500 lines, called a repo-local
scripts/check_file_length.py, and filtered to types_or: [python, shell] --
so it never looked at the Flutter app in app/ or at any prose. Two caps that
disagree is worse than one, so the old one is deleted rather than kept.
The new hook checks only the files in the commit and exits 1; CI runs --all
as the backstop, since a fresh clone that never ran `pre-commit install` has
no hooks at all. The exemption list lives with the checker in
~/utils/file_length/config.py so the gate and the cross-repo survey cannot
disagree about what "too long" means.
Two things this repo has that ~/todo (the reference implementation) did not:
- A pre-commit CI job running --all-files, where $HOME/utils does not exist.
The shared gate is checked out to .utils and reached via UTILS_ROOT, or the
hook fails on a missing checker rather than on anything in this repo.
- Tests that isolate live user state with dotted-string patches
(`patch("diet_guard._state.FOOD_LOG_FILE", ...)`). unittest.mock.patch fails
OPEN: once a refactor moves a name, the old path still imports, the patch
redirects nothing, the test still passes -- and the suite writes to the real
~/.local/share/diet_guard, which diet-guard-sync.timer publishes within 15
minutes. check_patch_targets.py resolves all 30 patch targets statically so
that failure is loud instead of silent. It is landed before any split for
exactly that reason.
The gate is red at 52 files; the splits that follow drive it to zero.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MK3HCZrM75sRHL1gL8usve
run_number counts workflow RUNS, not code. Two failure modes, one of which
already bit: it resets to 1 if this file is renamed (the existing NOTE warned
about that), and it can fall BEHIND a build produced outside this workflow.
On 2026-08-09 diet-guard's phone held a manually sideloaded vc 8 while CI's
next build was vc 6, so `adb install -r` refused every CI build with
INSTALL_FAILED_VERSION_DOWNGRADE. The only non-destructive escape was
re-running the workflow until the counter passed 8 -- forcing a downgrade
needs an uninstall, which wipes app data.
`git rev-list --count HEAD` only ever increases, tracks the code rather than
the CI file, and is already far ahead of every installed build (diet-guard
62 vs 9, screen-locker 118 vs 5, wake-alarm 41 vs 5, todo 51).
Needs fetch-depth: 0 -- checkout@v4 is shallow by default and would count 1.
Verified the count is identical from the repo root and from app/, so the
job's `working-directory: app` default does not affect it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZH89WEqAjuJT8WZdqc7AP
diet-guard had no APK build at all; releases were not produced. Adds a
standalone release-apk.yml plus the release signing config the app was
missing.
Signing follows the pattern proven in home_inventory: gradle reads
android/key.properties when present and falls back to the debug key when
absent, so local `flutter run --release` is unaffected. CI writes that
file from repository secrets and shreds it afterwards, and apksigner
fails the build closed if a debug-signed APK ever appears.
Only the signingConfig line changes here: isMinifyEnabled, isShrinkResources
and proguardFiles are left exactly as they were.
This repo has no Flutter analyze/test job, so the release job is not
gated on tests — a broken commit still publishes, with the build failing
as the only backstop. Add `needs:` if a Flutter CI job is added later.
versionCode is github.run_number, which is per-workflow-file — this file
must never be renamed, or the counter resets and updates stop installing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014dzgcZxmpS3VtmLci2sbxj
This job has been red since the keyboard tests landed: they drive real Tk --
widget heights and the focus ring come from the font engine, and no mock can
answer what they ask -- and a runner has no X display, so they failed with
"no display name and no $DISPLAY" rather than skipping. Thirteen tests,
including the two that assert the gate fits 1366x768, were reporting nothing
about the code.
xvfb-run gives them the display they need, which is what every local run of
these tests already used.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BsXnTHyuuCUZsqetTaajcF
Rewrites python_pkg.diet_guard imports to diet_guard, vendors the
shared as_float coercion helper, drops the monorepo PYTHONPATH from
install.sh and the systemd unit (package is now pip-installed), and
scaffolds standalone lint/test config matching testsAndMisc's real
enforced bar (pylint --fail-under=10 with tests excluded and the
use-implicit-booleaness/consider-using-with disables, mypy's actual
disabled-error-code set, ruff ALL, bandit, 100% branch coverage).