Expand description
ev migrate — backfill an existing decision history into the ledger.
Four PURE, format-aware extractors turn a source substrate (&str) into a Vec<MigrationRecord>:
a chat-room/git log (## R<N> records), the to-human RESOLVED/FLAG markdown blocks (the
authority substrate), a decisions-immutable §N document, and an escalation log (the SAME
RESOLVED/FLAG reader, path-parameterized). The extractors parse rulings + structured
rejected-roads only — they NEVER NLP a free-text reason into a ground (grounds_are_never_ synthesized): a road becomes a ground iff the source declares it structurally (a rejected:
token), otherwise the record carries zero grounds and stays an honest capture.
The command driver then runs an IDEMPOTENT backfill loop (deterministic source_key sort →
prospective-parent compute_id → ticks_dir pre-check → skip-if-present) on top of the shared
capture::append, plus a --reconcile join and a --bind-check harvest.
Structs§
- Backfill
Summary - The outcome of one backfill pass (idempotent): how many records were imported, skipped (already
present by content-addressed id), re-linked (a back-dated mid-chain insert that re-parented), and
how many were source-only gaps that could not be appended (e.g. a source lacking authors with no
--blamefallback). Rendered by the command layer. - Migration
Record - One extracted, not-yet-appended decision from a source substrate.
source_keyis the stable, deterministic dedup/sort key (e.g.R2289,#555,§3) used to order the backfill and to reconcile against the store;observecarries that key as a durable token so reconcile can read it back from the HASHED payload, not from the events log. Grounds are ONLY the structurally declared rejected-roads — never synthesized from prose. - Reconcile
Report - A reconcile bucket count: how many source rulings are IN BOTH the source and the store, how many
are SOURCE-ONLY (the capture gap — a ruling the source has that the ledger never captured), how
many are STORE-ONLY (in the ledger, absent from this source), and how many store ticks could not
be keyed at all (no round token in their hashed observe). Keys come from the HASHED
observe/round_id, never from events.jsonl, so they are durable.
Functions§
- backfill
- Run the idempotent backfill of
recordsinto the store atrepo. Deterministic order: records are sorted bysource_keyfirst so a re-run replays the same chain. Idempotency is keyed on the durablesource_key(carried into the hashedobserve+ the non-hashedround_id): a record whose key is already in the store is SKIPPED — chain-position-independent, so a re-run over a now-non-empty store writes nothing. The chain is kept by threading the PROSPECTIVE parent (the id we just wrote/found) instead of re-reading the live HEAD each step, so the lineage stays stable across re-runs. A skipped record whose stored parent differs from where it would now land is a back-dated mid-chain insert and is reported as re-linked.blame_fallbacksupplies the author for a record carrying none; a record with neither is a source-only gap (R5 stays intact — we never invent an author).--dry-runreports the would-import count but writes nothing. - bind_
check - The
--bind-checkharvest: build a harvestedCheck::Test(counter_test None, full liveness) for the given selector, reusing the Task-5 migrate-only constructor. This is the SAME constructor the harvested-binding path uses — no second half-harvest gate. The caller attaches it to a ground. - extract_
decisions_ immutable - Extractor 3 — decisions-immutable: a document split on
## N./## §Nsection headers, one decision per numbered section. The section number is the source_key; the header text after the number is the decision; structured rejected-roads in the section body become grounds. - extract_
escalation - Extractor 4 — escalation: the SAME RESOLVED/FLAG reader, path-parameterized — escalation is just the reader over a different file, with NO hardcoded layout of its own.
- extract_
gitlog - Extractor 1 — gitlog / chat-room: each
## R<N> …header is one decision; the header text after the round token (and an optional—em-dash separator) is the decision; any structurally declared rejected-road line in that record’s body becomes a ground. TheR<N>/#<n>token is the source_key and is carried into observe as a durable provenance token. Reasons are NEVER NLP’d. - extract_
to_ human - Extractor 2 — to-human: the RESOLVED/FLAG markdown blocks (the authority substrate).
- reconcile
- Reconcile a source’s extracted records against the store. The store-side key is read from each
tick’s HASHED payload — its
round_idif present, else the first round/#N token inobserve— so the join is durable (NOT dependent on the non-hashed events log). A source key with no store match is a SOURCE-ONLY gap (the capture gap to surface); a store key with no source match is STORE-ONLY; a store tick with no derivable key is counted separately as un-keyable.