0600 and ownership stay consistent.Nothing to install. The tool is a single script:
cd rime-ledger
python3 tools/ledger.py --help
Record what happened to one address:
python3 tools/ledger.py observe 203.0.113.7 \
--project my-project --stage page_load --outcome blocked \
--reason "challenge never resolved"
Then look at what the house currently believes:
python3 tools/ledger.py views
python3 tools/ledger.py audit
python3 tools/ledger.py views # derive fresh + reusable
cat views/fresh-ips.json # read the criteria and generated_at first
Treat an empty view as a photograph: check generated_at, then trust the store, not the file.
python3 - <<'PY'
import json
row = json.load(open("ledger/ip-ledger.json"))["203.0.113.7"]
for h in row.get("history", []):
print(h["at"], h["project"], h["stage_reached"], h["outcome"], h["reason"][:60])
PY
python3 tools/ledger.py audit
RIME_IP_LEDGER — overrides the store path. The same variable name is used by ip_ledger.py, so relocating the ledger once moves both tools at the same time. Do not point one tool somewhere else.~/.rime_ip_ledger.json — the symlink bridge. Never delete it; never let anything os.replace onto it without resolving realpath first.