Changes touching this path

  • loot-first in Rust: land policy behind a Forge seam (#218) — new loot-first bin crate (ledger/forge/policy/orchestrator), in-process Workspace reads via loot-cli lib split, typed pr-map owner + shared ferry::WipState; every policy decide-tested against a fake forge. Build+test only; shadow-run, real land, and ps1 deletion remain operator-gated. 58c28888 · dbf3dbe6…
  • The harbor: an on-demand lock serializes landing to git-main (#229, closes #195) 8adf34a2 · dbf3dbe6…diff
  • Workspace accepts its clock; lane flag-gate goes pure so cmd_* tests never touch a real .loot (#322) 20ac82e1 · dbf3dbe6…diff
  • loot-first land: report the provisional-branch reap instead of swallowing it (#625) ed9ad0c2 · dbf3dbe6…diff
  • the ledger reap gains an authoritative half, so a row whose change id stopped being the work's id can still be cleared (#793) #624 made the pr-map self-heal on discovery, and it does — but its proof is "a version carrying this row's durable change id is published on origin/main", and that question can become unanswerable for work that plainly landed. Ask 1 was to pin why, and the answer is neither candidate the ticket named. It is not gc and it is not the resolutions minting their own ids: the reviewed change landed as ff89d2c, its version IS in the graph, and it carries durable change id f7d93995 while its row still named aec9021d. The row is written once, in review(), and thereafter only ever removed. Nothing re-keys it. A durable change id is stable across re-SNAPSHOTS, but a bounce recovery that re-creates the working change rather than amending it hands the same work a fresh one -- and the ledger never hears about it. That row was then unreapable forever. The obvious repair is unavailable, and change_published_on_origin's own doc already says why: a live sibling lane's unsigned WIP never enters the shared graph either, so "absent from the graph" is the normal state of a row that is genuinely in flight, and reaping on it would eat every concurrent agent's row at once. Nothing local separates a stranded row from a live one. So the second half is authoritative and online: closed_rows asks the forge whether the row's PR is still open. Merged counts as over -- it is what GitHub calls the zero-diff collapse that IS the landing signal here. It is spent in review and land, which already hold a forge, rather than in status, the constantly-run verb #624 deliberately kept offline. Both sweeps run BEFORE their verb's own work. The operator most likely to be looking at a phantom row is the one with nothing to project, and a sweep behind review's `nothing to review.` return would be unreachable for exactly them. land sweeps too, because land is what strands rows in the first place -- it clears its own row as its last act, so a land that dies after publishing leaves one behind -- which makes the re-run the pass most likely to meet one. land excludes its own PR: a land that died after the collapse leaves the row with the PR already reading Merged, which is precisely what this reaps, so without the exclusion the retry would delete the row it needs and then fail to find it. A row nothing can be proven about is still always kept, so a forge that will not answer changes nothing. Rows are not aged out on a guess (ask 3): over-reaping costs a land that cannot find its own PR, under-reaping costs a line of output. Ask 4 is answered as far as it honestly can be: status cannot say which of its surviving rows is stranded (it cannot see the difference), so instead of guessing it says where the answer lives. Both reap bodies now share one door (reap_rows), so the local and authoritative passes cannot drift apart on the two things that matter -- going through the ledger's locked write door, and being best-effort. ADR 0034's #336 amendment and docs/agents/concurrent.md said every ledger write "applies only its own row"; the reap passes have removed other positions' rows since #624, so both now record the exception and why it is safe. 5cdfa18c · dbf3dbe6…diff
  • a land stops depending on one endpoint being up: viewer_login falls back to GraphQL when REST /user is down, and a failure names both routes instead of sending the reader to check their scopes (#1061) 620aec8a · dbf3dbe6…diff
  • the one-place path spellings become reachable and reach: tree_path goes pub(crate) and covers the five walk-derived surfaces that could not call it, lane merge stops being the face #1049 missed, and two doc claims shrink to what is true (#1063) 94908511 · dbf3dbe6…diff

Renames are not followed. loot's tree maps a path to an address, so a rename is a delete and an add. This list is the history of the name, not of the bytes.