screen-locker/scripts
Krzysztof kuhy Rudnicki 86b63108c7 Tombstone sync records durably: a ledger the PC re-pushes every tick
manual:2026-09-13T14:30 -- the synced copy of the football that this
morning's day-key rekey let back in under a second id -- made every
workout-sync tick log "Manual-workout budget exhausted -- not ingested".
Tombstoning it once did not stick: sync_log pulls only the OTHER devices'
logs and _manual_push re-derives the PC's log from log.json each tick, so
the next push overwrote the tombstone ("tombstoned", then "LIVE" five
seconds later). Deletion is monotonic only for records still in the merge.

- New _sync_tombstones: {id: {deleted_hlc, reason, tombstoned_at}} in
  screen_locker/sync_tombstones.json (gitignored with its siblings). The
  HLC is minted once and stored so re-pushing does not churn the store.
  The ledger path is resolved at call time, not as a default argument, so
  the test suite's redirect actually applies -- verified by hashing the
  real ledger before and after the run.
- _manual_push.records_from_workout_log merges the ledger over the live
  derivation, so every push carries the tombstones.
- scripts/tombstone_sync_record.py <id> [--apply --reason ...]: dry run
  reports live/tombstoned; --apply writes the ledger, runs one tick and
  reports what the store holds afterwards. Rerunnable.
- tests/_isolated_state.py redirects SYNC_TOMBSTONES_FILE (both bindings).

Verified: --apply -> "tombstoned"; a second ordinary tick -> "already
tombstoned" with the same HLC; workout-sync.service now logs "Sync record
manual:2026-09-13T14:30 is tombstoned -- skipping it" and the budget line
for that id is gone. log.json untouched (the local entry stays; it shares
the original's credit per duplicate_credits.json).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7vgacLhb4WJjxuVj2QLEP
2026-09-13 20:20:06 +02:00
..
__init__.py Finish the Python side: scripts, conftest, and the last test modules 2026-08-15 20:57:29 +02:00
_popup_form_check.py Take gatelock 0.8.1: nested LockConfig 2026-09-12 19:52:38 +02:00
_xvfb_reexec.py Finish the Python side: scripts, conftest, and the last test modules 2026-08-15 20:57:29 +02:00
add_scheduled_skip.py Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 18:46:28 +02:00
annotate_duplicate_credits.py Replay today's earned shutdown credit in the daily base reset 2026-09-13 20:00:05 +02:00
check_dependency_freshness.sh Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 18:46:28 +02:00
check_enforcement_armed.py Serve the lock decision, its history and its health at 127.0.0.1:8770 2026-08-29 22:50:19 +02:00
check_file_length.py Enforce the 250-line cap for real, and on Dart 2026-08-15 22:42:57 +02:00
check_flutter_coverage.sh workout_app: add Google sign-in support for the Firebase sync account 2026-08-14 10:56:16 +02:00
check_md_naming.sh Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 18:46:28 +02:00
check_no_crdt_sync_override.sh Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 18:46:28 +02:00
check_requirements_sync.py Add CI-mirror pre-push gate + requirements-sync check 2026-07-11 17:42:45 +02:00
check_silent_failures_dart.py Split storage_service.dart (781) into part extensions 2026-08-15 21:12:08 +02:00
check_silent_failures.py Re-arm the locker, and make a disarmed enforcer impossible to miss 2026-08-17 16:47:25 +02:00
ci_mirror.sh Add CI-mirror pre-push gate + requirements-sync check 2026-07-11 17:42:45 +02:00
demo_workout_handoff.py Take gatelock 0.8.1: nested LockConfig 2026-09-12 19:52:38 +02:00
disarm_guard.sh Make disarming survive the install scripts, not just systemd 2026-08-22 12:54:13 +02:00
finish_2026_08_24.sh Tell "could not check" apart from "no workout", and stop double-granting bonuses 2026-08-24 13:07:20 +02:00
fix_2026_07_26_sport.py Grade against 3.14 too, not just run on it 2026-08-29 11:42:47 +02:00
migrate_scheduled_skips.py Replace scheduled skips with the shared free-day pool 2026-09-07 15:42:41 +02:00
refresh_refactor_todo.py Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 19:07:30 +02:00
rekey_log_entry.py Key every workout day on the LOCAL calendar day, not UTC 2026-09-13 09:50:06 +02:00
restore_and_bonus.py Make the recovery scripts say why they failed, not just print it 2026-08-24 13:10:53 +02:00
revoke_sick_day.py Grade against 3.14 too, not just run on it 2026-08-29 11:42:47 +02:00
setup_mcp.sh Add read-only MCP server exposing workout/lock status 2026-07-10 21:28:09 +02:00
split_dart_test.py Add todo_finish_dart_250_prompt.md and the Dart test splitter 2026-08-15 21:49:15 +02:00
tombstone_sync_record.py Tombstone sync records durably: a ledger the PC re-pushes every tick 2026-09-13 20:20:06 +02:00
verify_lock_popup_safety.py Finish the Python side: scripts, conftest, and the last test modules 2026-08-15 20:57:29 +02:00
verify_screen_fits.py Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 18:46:28 +02:00
verify_workout_credited.py Make the recovery scripts say why they failed, not just print it 2026-08-24 13:10:53 +02:00