Commit Graph

4 Commits

Author SHA1 Message Date
9f271b0d37 Fix the cap hook in CI, and the re-exports its --all-files run exposed
The hook entry was an absolute /home/kuhy/utils path, copied from a config
written for ~/.claude where it only ever ran locally. On an Actions runner
that is exit code 127 — "No such file or directory" — so gatelock-precommit
and crdt-sync-precommit failed on every commit of this refactor while the
hook silently checked nothing. Now repo-relative, matching the sibling hooks
(`entry: scripts/check_subproject_scope.sh`): pre-commit always runs from the
git root, so it resolves the same in both places.

Fixing that made the CI configs runnable locally, and `--all-files` then found
what per-file runs had missed — ruff pruning imports that exist *for* their
re-export. `import crdt_sync` was broken three separate ways (FileSyncStateStore,
encode_key, FileCredentialStore). Each affected module now states an explicit
__all__ so the autofixer cannot take them again, and the two files that pushed
past the cap once __all__ was added are split further:

  _firebase.py 260 -> 247 + _fberrors 25
  _sync.py     257 -> 188 + _syncargs 91

Test patch targets followed the code they patch: gatelock._outputs.shutil ->
_xrandr.shutil, gatelock._arbiter.Path -> _claims.Path.

gatelock and crdt-sync both pass `pre-commit run --all-files` in full;
389 and 259 tests at 100% branch coverage; the root gate exits 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CFSGeWxHPY5rHUGrPqhcmG
2026-08-22 15:52:59 +02:00
48f6c7420f Gate the 250-line cap on every commit, repo-wide
Some checks are pending
crdt-sync pre-commit / pre-commit (push) Waiting to run
crdt-sync tests / test (3.10) (push) Waiting to run
crdt-sync tests / test (3.11) (push) Waiting to run
crdt-sync tests / test (3.12) (push) Waiting to run
design_system tests / test (push) Waiting to run
gatelock pre-commit / pre-commit (push) Waiting to run
gatelock tests / test (3.10) (push) Waiting to run
gatelock tests / test (3.11) (push) Waiting to run
gatelock tests / test (3.12) (push) Waiting to run
palette drift / palette (push) Waiting to run
sync_settings_ui tests / test (push) Waiting to run
web_ui tests / test (push) Waiting to run
A refactor without a gate silently regrows, so this is the part that makes the
cap stick. Until now the repo had no root .pre-commit-config.yaml at all --
`git commit` ran zero hooks, and the five subproject configs only covered their
own directories.

Adds a root config wiring scripts/check_file_length.sh as a local hook, and
carries the same hook in each of the five subproject configs so committing
with one of those is gated too. Staged files only, so an unrelated commit
never breaks on a violation it did not introduce; exit 1, not a warning; no
baseline and no allowlist, since those are suppressions.

Verified in a throwaway worktree, both directions:
  - a staged 261-line file fails the commit (exit 1, HEAD unchanged, no
    commit object created)
  - a staged 200-line file commits normally (exit 0)

The 44 files still over the cap cannot block this: the hook only ever sees
what a commit touches.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CFSGeWxHPY5rHUGrPqhcmG
2026-08-22 14:31:35 +02:00
39e52d07c2 Stop the recovery tick stealing our own grab, and fix pre-commit for the monorepo
`_holds_grab` asked `grab_current() is self._root`, but our own transient
children take the grab for themselves: a posted Tk menu grabs the menu
window, so the test read "the grab was lost" and `grab_set_global()` took it
back a second later, off our own widget mid-interaction. That is what made
screen-locker's sport selector unusable while locked on 2026-07-26. The
predicate is now `grab_current() is not None` -- any window we own means the
lock still has pointer and keyboard -- and it is public, `holds_grab`, so an
embedder can ask the same question instead of re-deriving it. Anything that
does not resolve against our widget map (a Tcl-created `ttk.Combobox`
popdown, a stale name) raises `KeyError` and counts as lost: fail closed,
because losing a popdown beats believing we hold a grab we do not. The
blind spot for a second `tk.Tk()` reporting its root as "." is unchanged from
the old test, and now written down.

`_verify` and `_drain` scheduled the next tick *after* running it, so any
exception ended all re-assertion of coverage, grab and VT for the rest of the
lock -- the exact fail-open this module exists to prevent, in a file whose
docstring is a monotonicity proof. The reschedule moves into `finally`, and
the warnings only fire when the reason changes: these states can last the
whole lock, and a 1Hz journal stream is not the alternative to silence.

The pre-commit side: both subproject configs were written as if cwd were the
subproject, but pre-commit runs hooks from the git root -- which is ~/utils,
not gatelock. Every pushed run since at least 2026-07-11 has been red, and
for compounding reasons: pylint and bandit could not find their config,
bandit's tests exclusion never matched, the pytest hook ran with no config at
all, and with no `files:` filter each config linted the *whole* monorepo, so
gatelock's mypy was type-checking crdt-sync. All paths are now root-relative,
each config is scoped to its own subproject, and the pytest hook goes through
a shared `scripts/run_subproject_tests.sh` that supplies the missing `cd` and
fails loudly if the subproject is gone.

Scoping via `files:` has one sharp edge -- rename the directory and the regex
matches nothing, so every hook passes on zero files, green and useless. An
`always_run` scope-guard hook turns that silent pass into a failure.

bandit 1.7.10 threw inside its AST visitor on Python 3.14 and *skipped* every
file while still reporting zero issues; 1.9.4 actually scans. Codespell was
also flagging a real typo the noise had buried.

Housekeeping the above turned up: `gatelock/.github/` and `crdt-sync/.github/`
were dead -- GitHub only reads the root `.github/workflows`, which already has
all four jobs -- and the two subproject `.gitignore`s were byte-identical to
each other and subsumed by the new root one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 15:08:41 +02:00
1c49abe8c2 Initial implementation: unified CRDT merge scheme + GitHub sync transport
Extracted and generalized from diet_guard's existing tombstone-merge scheme
and GitHub Contents API client, extended with per-field HLC LWW so the same
library can also cover todo's mutable notes and wake_alarm's single-value
sync (Workstream D scoping decision, 2026-07-04). 100% branch coverage,
clean ruff/mypy/pylint/bandit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017McuA1nAi6jBT1EaS5BrVf
2026-07-05 20:40:09 +02:00