mirror of
https://github.com/kuhyx/diet-guard.git
synced 2026-11-11 16:53:57 +01:00
Some checks are pending
file-length / file length <= 250 lines (push) Waiting to run
pre-commit / pre-commit (push) Waiting to run
Tests / test (3.10) (push) Waiting to run
Tests / test (3.11) (push) Waiting to run
Tests / test (3.12) (push) Waiting to run
release-apk / release (APK) (push) Waiting to run
Two independent costs in the background tick, both pure waste.
`list_directory` was called four times per tick -- once by the log pull and
once by each of the three bank syncs. It is the single most expensive call
in a tick at ~445ms mirrored (the GitHub half alone is ~360ms), so that was
~1.3s spent asking the same question four times. It is now listed once in
`run_sync` and passed down.
The curated-bank loop was worse: 17s and 62 requests to fetch *zero* useful
bytes. Firebase returns None for every peer's `food_bank_manual.json`, so
`MirrorSyncClient.get_file_text` treated each miss as "this device has not
migrated yet" and fell through to GitHub, which answers `{}` after ~320ms.
`_primary_only_text` skips that per-peer fallthrough for this one artifact.
Checked before narrowing rather than assumed, because CLAUDE.md requires
both halves of the food bank to sync: reading every peer's curated bank
straight off the mirror found 23 absent, 2 empty, and zero non-empty. No
curated food exists on the mirror alone. The probe is written into the
docstring so it can be re-run before anyone widens this again.
Measured end to end: manual-bank loop 17.0s -> 3.4s, full tick ~27s -> 15.2s,
log/bank/peer state unchanged (441 entries, 117 foods, 22 peers).
`_pull_remote_logs` now returns the revisions it saw instead of mutating a
caller-supplied dict, which keeps it under the argument limit and makes the
data flow visible at the call site.
Deliberately NOT done: revision-skipping the derived food bank. `run_sync`
rebuilds that bank from the merged log immediately before syncing it, so
unlike the log the peer records are not durably held locally -- skipping a
peer would drop its counts from the pushed bank and oscillate under
max-count-wins. Verified empirically: the on-disk bank and a pure log-derived
rebuild are identical (117 foods, 0 differing counts), and the 2 foods peers
know that the local bank lacks are discarded by the existing `if name in
local` filter anyway. The loop is off every interactive path now, so the
remaining cost is background-only.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJ5YnA3CERitQ57HjMu2Qz
73 lines
2.6 KiB
Python
73 lines
2.6 KiB
Python
"""Tests for this machine's persisted sync device id.
|
|
|
|
Split out of ``test_sync.py`` to keep it under the repo's 500-line cap.
|
|
Covers the migration from the fixed ``"pc"`` role constant to a per-install
|
|
uuid -- specifically that the old path is still recognised as this device's
|
|
own, so its pre-migration log is not re-merged as a peer's.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import MagicMock
|
|
|
|
from crdt_sync import DeviceIdentity, SyncState
|
|
|
|
from diet_guard import _sync
|
|
from diet_guard._device import device_id, device_identity
|
|
|
|
|
|
def _mock_client(*, devices: tuple[str, ...] = ()) -> MagicMock:
|
|
"""Build a mock sync client that lists ``devices`` and holds no files."""
|
|
client = MagicMock()
|
|
client.list_directory.return_value = list(devices)
|
|
client.get_file_text.side_effect = lambda _path: None
|
|
del client.get_string_map
|
|
return client
|
|
|
|
|
|
class TestPullSkipsOwnLegacyPath:
|
|
"""The uuid migration leaves this device's old 'pc' log behind."""
|
|
|
|
def test_skips_the_devices_own_legacy_id(self) -> None:
|
|
"""devices/pc/ is this machine's own history, not a peer's.
|
|
|
|
Without the legacy id in the skip set, every tick would download and
|
|
re-merge the log this machine pushed before it migrated -- idempotent
|
|
under LWW, but hundreds of KB of pure waste, 96 times a day.
|
|
"""
|
|
client = _mock_client(devices=("pc", "phone"))
|
|
state = SyncState(pushed_rev=None, peer_revs={})
|
|
|
|
_, _seen = _sync._pull_remote_logs(
|
|
client,
|
|
{},
|
|
state,
|
|
identity=device_identity(),
|
|
device_ids=("pc", "phone"),
|
|
)
|
|
|
|
fetched = [call.args[0] for call in client.get_file_text.call_args_list]
|
|
assert "diet-guard-sync/devices/pc/food_log.json" not in fetched
|
|
assert "diet-guard-sync/devices/phone/food_log.json" in fetched
|
|
|
|
def test_pulls_the_legacy_path_once_it_is_disowned(self) -> None:
|
|
"""Negative control: with no legacy id, devices/pc/ IS a peer.
|
|
|
|
Proves the skip above is the legacy id's doing, not an artifact of
|
|
the fixture -- and documents what happens after the old path is
|
|
reclaimed and SYNC_LEGACY_DEVICE_ID drops to None.
|
|
"""
|
|
client = _mock_client(devices=("pc",))
|
|
state = SyncState(pushed_rev=None, peer_revs={})
|
|
|
|
_, _seen = _sync._pull_remote_logs(
|
|
client,
|
|
{},
|
|
state,
|
|
identity=DeviceIdentity(device_id=device_id()),
|
|
device_ids=("pc",),
|
|
)
|
|
|
|
fetched = [call.args[0] for call in client.get_file_text.call_args_list]
|
|
assert "diet-guard-sync/devices/pc/food_log.json" in fetched
|