ledgerThe store itself — one JSON dict keyed by IP address, plus the field specification that explains it and the two auxiliary ledgers that are deliberately not merged into it.
ledger/ip-ledger.json — the store, 1,322 lines.ledger/FIELDS.md — 124 lines: what each field means, and the two states that are computed rather than stored.ledger/firecrawl_ip_ledger.json — 9 entries, a separate provenance set.ledger/proxy_ledger_paragadis_verified.json — 10 entries, the verified provider set.A row is keyed by the IP itself, and every address in the store carries the same fields. A real example:
103.161.249.236
country BT isp SuperNet Infocomm
provider (empty) endpoint (empty)
session_tag (empty) country_code (empty)
url_template (empty) cred_ref (empty)
projects ["outlook-creator"]
stage_reached probe
outcome promising
reason HumanCaptcha x3 (px3 terbit tiap round)
attempts 0
first_seen 2026-09-19T17:45:29
last_seen 2026-09-19T19:19:44+00:00
history [ 1 observation ]
| Measure | Value |
|---|---|
| Rows | 37 |
Rows carrying history | 37 — every entry dated 22 Sep is a canonical reconstruction (source: pemulihan-22sep), see architecture.md |
| Projected split | outlook-creator 31 · grok-register 6 |
| Outcomes present (22 Sep) | captcha_failed 12 · blocked 8 · promising 7 · transient 4 · failed 4 · success 2 |
tools/ledger.py (read/write), ip_ledger.py (read/write), every project that wants a verdict before spending an address.first_seen and last_seen use different clock formats — first_seen is naive local ISO, last_seen carries +00:00. Both are strings; nothing parses them yet. Worth normalising before anything sorts by them.attempts: 0 beside outcome: success appears in migrated rows: the count was never tracked by the tool that created them. Read it as unknown, not as zero attempts.session_tag/url_template cannot be re-dialled. That is why the reusable view is empty: the store today is a reputation archive, not a dialable pool.