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
6.2 KiB
Session prompt: connection pooling in crdt_sync
Paste everything below the line into a fresh Claude Code session started in
~/src/utils (that is where the library lives — not ~/src/diet-guard).
Add HTTP connection pooling to the shared crdt_sync library at
~/src/utils/crdt-sync, then bump the tag and re-pin ~/src/diet-guard to it.
Why
Every HTTP call in crdt_sync goes through module-level requests.get /
requests.put / requests.post / requests.delete, so each one pays a fresh
DNS + TCP + TLS handshake. There is no requests.Session anywhere in the
package.
Measured on this machine, 2026-08-21, against the two real backends:
| Host | fresh conn | session reuse | saving |
|---|---|---|---|
api.github.com |
108ms | 26ms | 82ms/req |
kuhy-syncs-…firebasedatabase.app |
82ms | 32ms | 51ms/req |
A diet-guard full sync tick currently makes 27 requests (12 GitHub, 15 Firebase) in 7.6s, so pooling projects to ~1.7s saved, about 22%.
Reproduce both numbers before you start and again at the end — the second run is the acceptance check, and the first guards against the situation having changed.
Scope
In scope
- Connection pooling in
~/src/utils/crdt-sync/crdt_sync/, across exactly 9 call sites in 3 files:_github.py: lines ~73, ~84 (get), ~163 (put), ~238 (delete)_firebase.py: ~189, ~319 (get), ~254 (put), ~300 (delete)_firebase_auth.py: ~290 (post)
- A
timeout_secondskeyword onfirebase_client_forin_config.py(see "Second fix" below). - Tag bump + re-pin
~/src/diet-guard/pyproject.tomland~/src/diet-guard/requirements.txt(both name the tag).
Out of scope — do not touch
- The other consumers.
~/src/screen-lockeris already oncrdt-sync-v0.7.0;~/src/leetcode-guard,~/build_your_xand~/src/wake-alarmare oncrdt-sync-v0.5.1. Leave every one of those pins alone and say so in your final report. ~/src/diet-guard/diet_guard/_sync*.pylogic. That work is finished and committed; this task only re-pins the dependency.
The constraint that decides the design
16 tests patch the module attribute, e.g.
patch.object(fb.requests, "get", return_value=...):
crdt_sync/tests/test_firebase.py— 8crdt_sync/tests/test_github.py— 5crdt_sync/tests/test_firebase_auth.py— 3
A naive switch to self._session.get(...) breaks all 16. Do not mass-edit
the tests to preserve an implementation choice — pick an implementation that
keeps <module>.requests.get patchable, e.g. a module-level session object
exposed so the existing patch target still resolves, or a thin shim whose
.get/.put/.post/.delete the tests can patch unchanged.
Whatever you pick, the test diff should be near-zero. If you find yourself rewriting many tests, that is the signal the design is wrong, not the tests.
Second fix, same release
firebase_client_for (_config.py, ~line 140) accepts no timeout, so
FirebaseSyncClient silently uses its 15s per-request default while
SYNC_TIMEOUT_SECONDS reaches GitHub only. diet-guard currently works around
this by assigning the private _timeout_seconds post-construction, in
diet_guard/_sync_client.py::_apply_timeout — read that function, it documents
the whole problem.
Add a timeout_seconds: float = _DEFAULT_TIMEOUT_SECONDS keyword and thread it
through. Leave the diet-guard workaround in place in this task: it is
guarded by tests and must keep working for anyone still on an older pin. Just
note in your report that it can be simplified in a follow-up.
Gates (both repos)
crdt_syncrequires 100% branch coverage (fail_under = 100,--cov-branchin itspyproject.toml) and lints withselect = ["ALL"].- diet-guard:
python -m pytest diet_guard/tests/ --cov=diet_guard --cov-branch --cov-fail-under=100— currently 830 passing at 100%. pre-commit run --files <changed>in whichever repo you touched.- The repo blocks
noqaandtype: ignoreoutright (no-noqahook). Fix the underlying issue instead; do not add a suppression, and do not add one to the ignore list without asking. - 250-line cap per file, enforced by a hook.
~/src/diet-guardhas ano local crdt_sync dependency_overridepre-commit hook that exists to stop a local path override leaking into a commit. Do not defeat it — re-pin to a real pushed tag.
Production install path (this has caused a 3-day outage before)
diet-guard-gate.service runs /usr/bin/python, not a venv. After re-pinning:
/usr/bin/python3 -m pip install --user --break-system-packages -e ~/src/diet-guard
/usr/bin/python3 -c "import crdt_sync, sys; print(crdt_sync.__file__)"
Verify against /usr/bin/python3, never the dev venv.
Watch out
- Do not run diet-guard's CLI against real data. State lives in
~/.local/share/diet_guard/(441 log entries, 117 foods). Use the test suite, or a redirected data dir. A_test_guardwill raiseRealUserStateWriteErrorif a test tries to write there — that is a feature. - A sync tick pushes to a shared remote that the phone also reads. Timing a
real
run_sync()is fine (it is idempotent), but do not add throwaway writes. ~/src/utilsis a monorepo holding several packages. Stage narrowly —crdt-sync/only — and note thatcrdt-sync/tool/seed_session.pyis already modified andcrdt-sync/firebase-debug.logis untracked; both predate this task, so leave them out of your commit.- Tag
crdt-sync-v0.7.0already exists, so the new tag is v0.8.0. Note that 0.7.0 also carries "Let a mirror read survive the primary being down", which diet-guard does not have yet — re-pinning picks that up too, so re-run diet-guard's suite after the bump rather than assuming only your change landed.
Done means
crdt_syncat 100% branch coverage, lint clean, with a near-zero test diff.- A pushed
crdt-sync-v0.8.0tag. ~/src/diet-guardre-pinned in bothpyproject.tomlandrequirements.txt, 830 tests still green at 100%.- Installed into
/usr/bin/python3's user site-packages and verified there. - A re-measured full tick, reported against the 7.6s / 27-request baseline above. State the real number even if it undershoots the projected 1.7s.