Pin pre-commit's ruff to 0.16.7 and satisfy the CPY001 it brings

The three Python packages pinned ruff twice at different versions:
requirements.txt at 0.16.7, .pre-commit-config.yaml at v0.15.2. Only the
older one ever ran, so `select = ["ALL"]` was enforced two minor versions
behind. Measured before aligning: v0.15.2 reports 0 findings, every 0.16.x
reports CPY001 on each file -- 70 crdt-sync, 23 freedays, 71 gatelock, and
no other rule.

Resolved by adding the notice rather than ignoring the rule, so the gate
keeps its teeth.

Two gatelock modules sat at exactly the 250-line cap, so a one-line header
tipped them to 251. Both are split along a real seam rather than shaved:

  _widget_fills.py    colour arithmetic over LockConfig, no tkinter import
  _surfaces_focus.py  selects among existing surfaces, never mutates them

The focus split keeps _surfaces.py's documented containment (it stays the
only module that creates, moves or destroys windows), and the static guard
in test_recovery_invariants.py globs _surfaces*.py, so the new sibling is
covered with no list to extend. widgets.py re-exports the fills helpers,
which keeps gatelock.widgets the single public surface its tests import.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019kMvSMtsVMB3d2uoZ56pbp
This commit is contained in:
Krzysztof Rudnicki 2026-09-12 18:11:24 +02:00
parent 561714e8ad
commit 6154dc09bf
169 changed files with 262 additions and 48 deletions

View File

@ -65,7 +65,7 @@ repos:
types: [python] types: [python]
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.2 rev: v0.16.7
hooks: hooks:
- id: ruff - id: ruff
args: [--fix, --unsafe-fixes, --exit-non-zero-on-fix, --show-fixes] args: [--fix, --unsafe-fixes, --exit-non-zero-on-fix, --show-fixes]

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Shared CRDT merge scheme + pluggable remote sync transports.""" """Shared CRDT merge scheme + pluggable remote sync transports."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Turning a Firebase auth response into a message, and reading its verdict. """Turning a Firebase auth response into a message, and reading its verdict.
Split from :mod:`crdt_sync._firebase_auth`, which keeps the token provider. Split from :mod:`crdt_sync._firebase_auth`, which keeps the token provider.

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""The one place every app learns how to reach Firebase. """The one place every app learns how to reach Firebase.
Before this module each caller re-read ``~/.config/crdt-sync/firebase.json`` Before this module each caller re-read ``~/.config/crdt-sync/firebase.json``

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Firebase credentials and the stores that persist them. """Firebase credentials and the stores that persist them.
Split from :mod:`crdt_sync._firebase_auth`, which keeps the token provider. Split from :mod:`crdt_sync._firebase_auth`, which keeps the token provider.

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""This device's stable sync identity. """This device's stable sync identity.
Every device that pushes into a namespace needs an id that is *its own*: it Every device that pushes into a namespace needs an id that is *its own*: it

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""The errors the Firebase sync backend raises. """The errors the Firebase sync backend raises.
Split from :mod:`crdt_sync._firebase` for the 250-line cap, mirroring Split from :mod:`crdt_sync._firebase` for the 250-line cap, mirroring

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Escaping arbitrary strings into Firebase Realtime Database keys. """Escaping arbitrary strings into Firebase Realtime Database keys.
Split from :mod:`crdt_sync._firebase`, which keeps the client. RTDB forbids Split from :mod:`crdt_sync._firebase`, which keeps the client. RTDB forbids

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Firebase Realtime Database as dumb keyed storage, over its REST API. """Firebase Realtime Database as dumb keyed storage, over its REST API.
The RTDB REST endpoints are plain HTTPS, so this works identically under The RTDB REST endpoints are plain HTTPS, so this works identically under

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Firebase Authentication over its REST API, with no SDK dependency. """Firebase Authentication over its REST API, with no SDK dependency.
The Firebase Admin SDK authenticates with a service-account key, which The Firebase Admin SDK authenticates with a service-account key, which

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""The errors the GitHub sync backend raises. """The errors the GitHub sync backend raises.
Split from :mod:`crdt_sync._github` for the 250-line cap. Kept separate so a Split from :mod:`crdt_sync._github` for the 250-line cap. Kept separate so a

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Minimal GitHub Contents API client used as dumb file storage. """Minimal GitHub Contents API client used as dumb file storage.
GitHub is used purely as file storage via the REST Contents API, not a git GitHub is used purely as file storage via the REST Contents API, not a git

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Hybrid Logical Clock: a totally-ordered, monotonic per-node timestamp. """Hybrid Logical Clock: a totally-ordered, monotonic per-node timestamp.
An HLC combines wall-clock time with a logical counter so that two ticks An HLC combines wall-clock time with a logical counter so that two ticks

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Pooled HTTP sessions, so every request does not re-handshake. """Pooled HTTP sessions, so every request does not re-handshake.
Every call site in this package used the module-level ``requests.get`` / Every call site in this package used the module-level ``requests.get`` /

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Log: a collection of Records keyed by id, with a union-merge.""" """Log: a collection of Records keyed by id, with a union-merge."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""A remote store that writes to two backends and reads from both. """A remote store that writes to two backends and reads from both.
Exists for the GitHub -> Firebase cutover: each app can move to Firebase Exists for the GitHub -> Firebase cutover: each app can move to Firebase

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Downloading peers' logs, skipping the ones we already have. """Downloading peers' logs, skipping the ones we already have.
Split from :mod:`crdt_sync._sync`, which keeps the push half and the Split from :mod:`crdt_sync._sync`, which keeps the push half and the

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Record: a per-field LWW map with a sticky (monotonic) delete flag. """Record: a per-field LWW map with a sticky (monotonic) delete flag.
This is the unit CRDT merges operate on. It's deliberately domain-agnostic -- This is the unit CRDT merges operate on. It's deliberately domain-agnostic --

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Backend-neutral remote-storage contract that sync talks through. """Backend-neutral remote-storage contract that sync talks through.
Deliberately tiny: :func:`crdt_sync.sync_log` and every app-level sync Deliberately tiny: :func:`crdt_sync.sync_log` and every app-level sync

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""The revision string a device publishes alongside its log. """The revision string a device publishes alongside its log.
Split from :mod:`crdt_sync._sync` so both the push and pull halves can import Split from :mod:`crdt_sync._sync` so both the push and pull halves can import

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Local JSON persistence for a ``Log``. """Local JSON persistence for a ``Log``.
Mirrors ``crdt_sync_dart``'s ``logToJson``/``FileLogPersistence`` serialization Mirrors ``crdt_sync_dart``'s ``logToJson``/``FileLogPersistence`` serialization

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Domain-agnostic pull/merge/push sync orchestration. """Domain-agnostic pull/merge/push sync orchestration.
Generalizes diet_guard's original ``_sync.py`` (pull every other device's Generalizes diet_guard's original ``_sync.py`` (pull every other device's

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""The three argument bundles :func:`crdt_sync.sync_log` takes. """The three argument bundles :func:`crdt_sync.sync_log` takes.
Split from :mod:`crdt_sync._sync` for the 250-line cap. Grouping sync_log's Split from :mod:`crdt_sync._sync` for the 250-line cap. Grouping sync_log's

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Where a device records what it has already pushed and pulled. """Where a device records what it has already pushed and pulled.
Split from :mod:`crdt_sync._sync`, which keeps the sync itself. The state is Split from :mod:`crdt_sync._sync`, which keeps the sync itself. The state is

View File

@ -1 +1,2 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for the crdt_sync package.""" """Tests for the crdt_sync package."""

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Shared pytest fixtures for crdt_sync's test suite.""" """Shared pytest fixtures for crdt_sync's test suite."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for the shared Firebase configuration loader. """Tests for the shared Firebase configuration loader.
Every failure mode here is one that would otherwise surface as an Every failure mode here is one that would otherwise surface as an

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for building a sync client from a config file. """Tests for building a sync client from a config file.
Split from ``test_config.py`` (250-line cap); Split from ``test_config.py`` (250-line cap);

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for reading the sync password and building a client from config. """Tests for reading the sync password and building a client from config.
Split from ``test_config.py`` (250-line cap), which keeps loading and Split from ``test_config.py`` (250-line cap), which keeps loading and

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for this device's persisted sync identity.""" """Tests for this device's persisted sync identity."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for the Realtime Database sync client. """Tests for the Realtime Database sync client.
The HTTP layer is fully mocked, so every branch -- success, absent path, The HTTP layer is fully mocked, so every branch -- success, absent path,

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for Firebase Authentication over the REST API. """Tests for Firebase Authentication over the REST API.
The HTTP layer is fully mocked, so every branch -- sign-in, refresh, rotated The HTTP layer is fully mocked, so every branch -- sign-in, refresh, rotated

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for the Google sign-in path. """Tests for the Google sign-in path.
Split from ``test_firebase_auth.py`` (250-line cap), which keeps credential Split from ``test_firebase_auth.py`` (250-line cap), which keeps credential

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for the auth session lifecycle. """Tests for the auth session lifecycle.
Split from ``test_firebase_auth.py`` (250-line cap); Split from ``test_firebase_auth.py`` (250-line cap);

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for ID-token refresh and the session lifecycle. """Tests for ID-token refresh and the session lifecycle.
Split from ``test_firebase_auth.py`` (250-line cap), which keeps credential Split from ``test_firebase_auth.py`` (250-line cap), which keeps credential

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for Firebase writes, string maps and deletion. """Tests for Firebase writes, string maps and deletion.
Split from ``test_firebase.py`` (250-line cap), which keeps key escaping Split from ``test_firebase.py`` (250-line cap), which keeps key escaping

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for the GitHub Contents API sync client. """Tests for the GitHub Contents API sync client.
The HTTP layer is fully mocked (``requests.get``/``requests.put``), so every The HTTP layer is fully mocked (``requests.get``/``requests.put``), so every

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for GitHub writes and access checks. """Tests for GitHub writes and access checks.
Split from ``test_github.py`` (250-line cap), which keeps the read paths. Split from ``test_github.py`` (250-line cap), which keeps the read paths.

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for the Hybrid Logical Clock.""" """Tests for the Hybrid Logical Clock."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for merge_logs, including its CRDT convergence properties.""" """Tests for merge_logs, including its CRDT convergence properties."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for the dual-write client used during the GitHub -> Firebase cutover. """Tests for the dual-write client used during the GitHub -> Firebase cutover.
The asymmetry is the whole point and is what these assert: a primary failure The asymmetry is the whole point and is what these assert: a primary failure

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for mirror fallback reads, revision maps and lifecycle. """Tests for mirror fallback reads, revision maps and lifecycle.
Split from ``test_mirror.py`` (250-line cap), which keeps plain writes, Split from ``test_mirror.py`` (250-line cap), which keeps plain writes,

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for Record, merge_field, and merge_record.""" """Tests for Record, merge_field, and merge_record."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for local Log persistence (dump/load and atomic file read/write).""" """Tests for local Log persistence (dump/load and atomic file read/write)."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for the pull/merge/push sync orchestration.""" """Tests for the pull/merge/push sync orchestration."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for the revision tracking that keeps sync inside the free tier. """Tests for the revision tracking that keeps sync inside the free tier.
Two savings, both measured against the GitHub-backed history this replaces: Two savings, both measured against the GitHub-backed history this replaces:

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for backends without bulk map reads, and publishing order. """Tests for backends without bulk map reads, and publishing order.
Split from ``test_sync_revisions.py`` (250-line cap); Split from ``test_sync_revisions.py`` (250-line cap);

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for revision handling across peers. """Tests for revision handling across peers.
Split from ``test_sync_revisions.py`` (250-line cap), which keeps revision Split from ``test_sync_revisions.py`` (250-line cap), which keeps revision

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for the peer files sync_log declines to merge. """Tests for the peer files sync_log declines to merge.
Split from ``test_sync.py`` (250-line cap). A peer whose pushed file is Split from ``test_sync.py`` (250-line cap). A peer whose pushed file is

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for ``tool/google_id_token``, the loopback OAuth ID-token minter. """Tests for ``tool/google_id_token``, the loopback OAuth ID-token minter.
No network and no browser. The callback server is replaced wholesale so the No network and no browser. The callback server is replaced wholesale so the

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for ``tool/google_id_token``'s command line entry point. """Tests for ``tool/google_id_token``'s command line entry point.
Split from :mod:`test_tool_google_id_token` to stay under the repo's 250-line Split from :mod:`test_tool_google_id_token` to stay under the repo's 250-line

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for ``tool/interop_seed``, the Python half of the interop check. """Tests for ``tool/interop_seed``, the Python half of the interop check.
Patched at the module's own boundary -- ``firebase_client_for``, Patched at the module's own boundary -- ``firebase_client_for``,

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for token inspection and linking in ``tool/link_google``. """Tests for token inspection and linking in ``tool/link_google``.
``main()`` and ``_read_token`` are covered in ``main()`` and ``_read_token`` are covered in

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for ``_read_token`` and ``main()`` in ``tool/link_google``. """Tests for ``_read_token`` and ``main()`` in ``tool/link_google``.
Split from :mod:`test_tool_link_google` to stay under the 250-line cap. Split from :mod:`test_tool_link_google` to stay under the 250-line cap.

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for ``describe_google_token`` in ``tool/link_google``. """Tests for ``describe_google_token`` in ``tool/link_google``.
Split from :mod:`test_tool_link_google` (which covers linking) and Split from :mod:`test_tool_link_google` (which covers linking) and

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for the GitHub-reading half of ``tool/migrate_github_to_firebase``. """Tests for the GitHub-reading half of ``tool/migrate_github_to_firebase``.
``main()`` is covered in :mod:`test_tool_migrate_github_main`, split to stay ``main()`` is covered in :mod:`test_tool_migrate_github_main`, split to stay

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for ``main()`` in ``tool/migrate_github_to_firebase``. """Tests for ``main()`` in ``tool/migrate_github_to_firebase``.
Split from :mod:`test_tool_migrate_github` to stay under the 250-line cap. Split from :mod:`test_tool_migrate_github` to stay under the 250-line cap.

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for the one-shot OAuth redirect catcher in ``tool/_oauth_callback``. """Tests for the one-shot OAuth redirect catcher in ``tool/_oauth_callback``.
No network access: everything binds 127.0.0.1 on a port the module itself No network access: everything binds 127.0.0.1 on a port the module itself

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for the individual checks in ``tool/preflight_firebase``. """Tests for the individual checks in ``tool/preflight_firebase``.
``main()`` and the loading helpers are covered in ``main()`` and the loading helpers are covered in

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for ``tool/preflight_firebase``'s loaders and ``main()``. """Tests for ``tool/preflight_firebase``'s loaders and ``main()``.
Split from :mod:`test_tool_preflight_firebase` to stay under the 250-line file Split from :mod:`test_tool_preflight_firebase` to stay under the 250-line file

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for ``seed_apps`` in ``tool/seed_session``. """Tests for ``seed_apps`` in ``tool/seed_session``.
``main()`` is covered in :mod:`test_tool_seed_session_main`, split to stay ``main()`` is covered in :mod:`test_tool_seed_session_main`, split to stay

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for ``main()`` in ``tool/seed_session``. """Tests for ``main()`` in ``tool/seed_session``.
Split from :mod:`test_tool_seed_session` to stay under the 250-line cap. Split from :mod:`test_tool_seed_session` to stay under the 250-line cap.

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""One-shot operational scripts for crdt_sync. """One-shot operational scripts for crdt_sync.
A package rather than a loose directory so the linter treats these as real A package rather than a loose directory so the linter treats these as real

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""The one-shot local HTTP server that catches Google's OAuth redirect. """The one-shot local HTTP server that catches Google's OAuth redirect.
Split from :mod:`google_id_token`, which keeps the token exchange. Google Split from :mod:`google_id_token`, which keeps the token exchange. Google

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Which apps keep a desktop Firebase session, and why the list is hand-kept. """Which apps keep a desktop Firebase session, and why the list is hand-kept.
Split out of ``seed_session.py`` for the 250-line cap. The rationale is worth Split out of ``seed_session.py`` for the 250-line cap. The rationale is worth

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
r"""Fetch a Google ID token for this project, via a local loopback OAuth flow. r"""Fetch a Google ID token for this project, via a local loopback OAuth flow.
``link_google.py`` needs a Google ID token whose ``aud`` claim is an OAuth ``link_google.py`` needs a Google ID token whose ``aud`` claim is an OAuth

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Write the Python half of the live cross-language interop check. """Write the Python half of the live cross-language interop check.
``crdt_sync_dart/tool/interop_check.dart`` merges a Dart record into ``crdt_sync_dart/tool/interop_check.dart`` merges a Dart record into

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Link a Google identity to the existing sync account, keeping the same uid. """Link a Google identity to the existing sync account, keeping the same uid.
The security rules pin exactly one uid (``auth.uid === '<uid>'``), so signing The security rules pin exactly one uid (``auth.uid === '<uid>'``), so signing

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""One-shot migration of the GitHub-backed sync repo into Firebase RTDB. """One-shot migration of the GitHub-backed sync repo into Firebase RTDB.
Reads through the GitHub API rather than a local clone: a checkout goes stale Reads through the GitHub API rather than a local clone: a checkout goes stale

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Validate ``~/.config/crdt-sync`` before anything is migrated. """Validate ``~/.config/crdt-sync`` before anything is migrated.
Every failure this catches is one that would otherwise surface *after* data Every failure this catches is one that would otherwise surface *after* data

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
r"""Reseed each app's desktop Firebase session by signing in with Google. r"""Reseed each app's desktop Firebase session by signing in with Google.
The sync account moved to Google-only sign-in, so the password flow that used The sync account moved to Google-only sign-in, so the password flow that used

View File

@ -65,7 +65,7 @@ repos:
types: [python] types: [python]
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.2 rev: v0.16.7
hooks: hooks:
- id: ruff - id: ruff
args: [--fix, --unsafe-fixes, --exit-non-zero-on-fix, --show-fixes] args: [--fix, --unsafe-fixes, --exit-non-zero-on-fix, --show-fixes]

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""One shared pool of pre-declared days on which every gate app stands down. """One shared pool of pre-declared days on which every gate app stands down.
The whole point of this package fits in one call. A gate app asks:: The whole point of this package fits in one call. A gate app asks::

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Ask, mark, release, report -- the whole public surface. """Ask, mark, release, report -- the whole public surface.
:func:`is_free_day` is the one every gate app calls, and it is deliberately :func:`is_free_day` is the one every gate app calls, and it is deliberately

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Append-only, HMAC-signed trail of every mark and release. """Append-only, HMAC-signed trail of every mark and release.
Nothing reads this to make a decision -- the CRDT log is the truth, and this Nothing reads this to make a decision -- the CRDT log is the truth, and this

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Calendar-year accounting for the pool. """Calendar-year accounting for the pool.
One global pool, shared by every app: a day is either free everywhere or One global pool, shared by every app: a day is either free everywhere or

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""The ``freedays`` command: the only thing that ever talks about free days. """The ``freedays`` command: the only thing that ever talks about free days.
Every subcommand that says anything is pull, never push: nothing notifies, Every subcommand that says anything is pull, never push: nothing notifies,

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""The one stdout/stderr sink every ``freedays`` subcommand writes through. """The one stdout/stderr sink every ``freedays`` subcommand writes through.
A thin wrapper over ``sys.stdout.write`` (the shape diet-guard and home-guard A thin wrapper over ``sys.stdout.write`` (the shape diet-guard and home-guard

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""On-disk locations, remote paths and the one policy number that matters. """On-disk locations, remote paths and the one policy number that matters.
Every path here is a *default*. Public functions take the corresponding Every path here is a *default*. Public functions take the corresponding

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""What "today" means, in one place. """What "today" means, in one place.
The apps this package serves disagreed about this before it existed: The apps this package serves disagreed about this before it existed:

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Why a mark or un-mark was refused. """Why a mark or un-mark was refused.
Each of these is a *policy* refusal with a message meant to be shown to the Each of these is a *policy* refusal with a message meant to be shown to the

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Signing the audit trail, using nothing but the standard library. """Signing the audit trail, using nothing but the standard library.
This deliberately does not call ``gatelock.log_integrity``, even though the This deliberately does not call ``gatelock.log_integrity``, even though the

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Translating between a free day and a crdt-sync ``Record``. """Translating between a free day and a crdt-sync ``Record``.
The record id *is* the ISO date, so two devices marking the same day produce The record id *is* the ISO date, so two devices marking the same day produce

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Every file this package owns, as one value that can be swapped wholesale. """Every file this package owns, as one value that can be swapped wholesale.
Threading five separate ``*_path`` keyword arguments through the API was the Threading five separate ``*_path`` keyword arguments through the API was the

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Pushing and pulling the pool, so a day taken on the phone lands on the PC. """Pushing and pulling the pool, so a day taken on the phone lands on the PC.
Sync is a *separate* operation from every decision in :mod:`freedays._api`. Sync is a *separate* operation from every decision in :mod:`freedays._api`.

View File

@ -1 +1,2 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Tests for :mod:`freedays`.""" """Tests for :mod:`freedays`."""

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Redirect every on-disk path away from real user state, for every test. """Redirect every on-disk path away from real user state, for every test.
This is one ``monkeypatch`` of one function, and that is the whole point. This is one ``monkeypatch`` of one function, and that is the whole point.

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Marking, releasing, and the budget arithmetic behind both.""" """Marking, releasing, and the budget arithmetic behind both."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""The audit trail: best-effort, signed, and never in the way.""" """The audit trail: best-effort, signed, and never in the way."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""The command line: the only surface that ever mentions free days.""" """The command line: the only surface that ever mentions free days."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Date handling: the one place allowed an opinion about "today".""" """Date handling: the one place allowed an opinion about "today"."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Signing, and the ways it is allowed to fail.""" """Signing, and the ways it is allowed to fail."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Record translation, and the CRDT properties the design leans on.""" """Record translation, and the CRDT properties the design leans on."""
from __future__ import annotations from __future__ import annotations

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""The path bundle itself, exercised unpatched. """The path bundle itself, exercised unpatched.
The autouse redirect in ``conftest`` replaces ``resolve_paths`` *as imported The autouse redirect in ``conftest`` replaces ``resolve_paths`` *as imported

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Sync: convergence across devices, and silence when the network is not there.""" """Sync: convergence across devices, and silence when the network is not there."""
from __future__ import annotations from __future__ import annotations

View File

@ -65,7 +65,7 @@ repos:
types: [python] types: [python]
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.2 rev: v0.16.7
hooks: hooks:
- id: ruff - id: ruff
args: [--fix, --unsafe-fixes, --exit-non-zero-on-fix, --show-fixes] args: [--fix, --unsafe-fixes, --exit-non-zero-on-fix, --show-fixes]

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Shared lock-window and HMAC log-integrity backend for blocking-overlay apps. """Shared lock-window and HMAC log-integrity backend for blocking-overlay apps.
Used by ``screen-locker``, ``diet-guard`` and ``wake-alarm``, which all need Used by ``screen-locker``, ``diet-guard`` and ``wake-alarm``, which all need

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Decide which of N locker apps may hold the screen. """Decide which of N locker apps may hold the screen.
On 2026-07-25 two lockers armed at the same boot. One won the X grab; the On 2026-07-25 two lockers armed at the same boot. One won the X grab; the

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""Bringing the lock up: VT-disable, backdrop, surfaces, and the input grab. """Bringing the lock up: VT-disable, backdrop, surfaces, and the input grab.
Split out of :mod:`gatelock._window`, which keeps the object's construction Split out of :mod:`gatelock._window`, which keeps the object's construction

View File

@ -1,3 +1,4 @@
# Copyright (c) 2026 Krzysztof Rudnicki
"""The claim an app publishes while it holds the screen, and how to read one. """The claim an app publishes while it holds the screen, and how to read one.
Split from :mod:`gatelock._arbiter`, which keeps the arbiter itself. A claim Split from :mod:`gatelock._arbiter`, which keeps the arbiter itself. A claim

Some files were not shown because too many files have changed in this diff Show More