mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 21:07:15 +01:00
612b0b3c0a
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 8a556f8d7d |
Cache .mypy_cache so mypy stops re-analysing the stdlib every run
Profiled the 23s hook step per hook. It is not evenly spread: mypy ~10s and pylint ~9s are the whole of it, and the remaining 21 hooks share ~4s. Local timings with a warm cache put mypy at 0.25s against 5.7s cold, so nearly all of its CI cost is re-analysing the stdlib and third-party stubs from scratch into a 19MB cache dir that was then thrown away. Keyed on the config rather than on the sources. The mypy cache metadata already records the interpreter, the flag set and a hash per source file, so mypy re-checks whatever actually changed and a restored cache cannot let stale code pass. The config hash is in the key regardless, so bumping the mypy rev or editing its args busts it. Deliberately not keyed on github.sha, which is the other common pattern: that re-saves 19MB x3 on every commit and would evict the 68MB hook caches under the 10GB LRU budget for the repo. A fixed key keeps the dependency analysis, which is the part that costs the 10s. pylint needs no change -- it already runs --jobs=4. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019kMvSMtsVMB3d2uoZ56pbp |
|||
| a473e91485 |
Stop installing linters the pre-commit jobs never use, and add cache fallbacks
Two follow-ups measured on the warm-cache run of
|
|||
| d56b936b48 |
Cache pre-commit hooks per package, and pip, so CI stops reinstalling
Some checks are pending
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
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
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
Measured on
|
|||
| aa032c95e4 |
Drop the gatelock dependency, and actually sync the pool
Two things the pool needed to be real rather than merely correct.
**freedays no longer depends on gatelock.** It imported
gatelock.log_integrity for ~15 lines of HMAC, but importing gatelock runs
its __init__, which imports tkinter for the lock-window machinery. So a
headless policy library had acquired a hard dependency on a GUI toolkit,
and `import freedays` failed anywhere without Tk:
ImportError: libtk8.6.so: cannot open shared object file
A vmbox run caught it. The host masked it completely -- Tk is installed
here for the lockers -- and so did CI, whose own comment claimed "no
display needed" while the job would have needed libtk. freedays/_hmac.py
now does the signing with hashlib and hmac.
The format is deliberately unchanged (HMAC-SHA256 over compact
sorted-key JSON), so nothing has to be re-signed: all 8 entries already
in the real audit trail, written by gatelock's implementation, verify
against the new one. That was checked, not assumed.
This also dissolves the version diamond that shaped the app rollout:
freedays now pins only crdt-sync, so it can never conflict with whatever
gatelock tag an app carries.
**The pool now syncs on a schedule.** A `sync-quiet` subcommand plus a
systemd user timer every 15 minutes, because "it syncs" was otherwise
only true if you typed `freedays sync` yourself -- a day marked on the
phone would sit there. sync-quiet exits 0 when there is no network or no
credential, on purpose: a unit that goes red every time the laptop is
offline is a unit you learn to ignore, and a real bug still reaches the
journal through the library's logging.
install.sh gives freedays its own venv rather than borrowing an app's --
the pool is shared by five apps, so binding its CLI to one of them would
make "is freedays installed?" depend on something unrelated, and
uninstalling that app would take the command with it.
Verified in vmbox first (systemd), then on this host: the timer is
enabled and scheduled, and the service *finishes* rather than failing
when there is no remote.
seed_session.py gains freedays, without which the one command that can
give the pool a Firebase session would reject it outright (--app is
choices-validated) and the pool would stay local-only with nothing
saying why. That file was already exactly at the 250-line cap, so the
app list and its rationale move to tool/_seeded_apps.py.
freedays: 109 tests, 100% branch coverage. crdt-sync: 433 pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|||
| ef69619597 |
Add freedays: one shared pool of days when every gate stands down
Some checks are pending
dependency freshness / dependencies on newest stable (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
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
Five apps (diet-guard, wake-alarm, screen-locker, leetcode-guard, home-guard) each enforce something daily, and none of them had a way to say "not today". screen-locker was the only one with any notion of a day off, and it had two overlapping ones: a budgeted sick day designed to be hard to take, and an undocumented scheduled_skips.json that no other app could see. This is the second thing generalised, not the first. Free days are pre-declared, carry no justification, allow consecutive runs, and are capped only by an annual budget -- 35 per calendar year, resetting Jan 1. Sick days stay in screen-locker exactly as they are: their rolling windows (1/7d, 3/30d, 10/90d) exist precisely to forbid the consecutive runs a holiday is made of, so merging the two policies would have had to ruin one of them. One global pool: a free day is free for every app at once, so there is nothing per-app to mark and nothing per-app to forget. The integration is one call, `freedays.is_free_day()`, which reads a single local JSON file and never the network -- a gate fires from a systemd timer and a hung sync must not be able to hold one open or shut. It returns False for anything it cannot parse, so an unreadable pool means the normal rules apply rather than everything switching off. Two design points worth keeping: - Un-marking flips a `state` field rather than tombstoning the record. crdt-sync deletes are monotonic, so a tombstoned date could never be marked free again. - `consumed` is a sticky flag. Releasing a day that has not arrived refunds it; releasing today does not, because those hours were already unguarded. It is OR-ed against the stored value on every write so two devices either side of midnight cannot hand a spent day back. Timezone is local, decided in _day.today() and nowhere else. The apps disagreed about this before: screen-locker's lock chain computes the day in UTC while add_scheduled_skip.py uses local time, so a skip added near midnight could name a date the chain never matched. 94 tests, 100% branch coverage, no suppressions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |