Changes touching this path

  • ADR 0098 records the decisions on #2411: the web writes tickets as signed changes the browser builds, seals and pushes, one per action and stow-first, and the forge becomes a second writer to main for ticket-only changes, those whose every path is under tickets/ and whose signer is a key on the owner account. the forge refuses an ingest that would drop a head it does not descend from; a land folds ticket-only forge changes in before the gate and fails closed on any other forge-only change; a web write racing a land is folded by the sync as a ticket-only merge with no gate, pinned by a test that no gate input reads tickets/; the CLI reads web tickets through a read-only forge overlay; a web change subject is content-free (ticket <id>: <verb>); and tickets never reach git main or GitHub. docs/specs/loot-tickets.md gains dated amendments: created-at on c/ and r/, event position keyed on the space-stripped path so a move keeps order, loot tickets --state replacing --closed, no new --id, the BOM strip on --body-file -, the web write path, criterion 2 met in dependency waves, and the map #2422 slicing. ADR 0028 gains the ticket-free projection and ADR 0063 the gate-less ticket-only sync fold. CONTEXT.md amends Ticket and gains Second writer, Ticket-only change and Stow-first publish. the doc link, line-ending, hygiene corpus and runbook suites are green (22 passed), and the link gate went red under a broken link in the new ADR (1 failed, 2 passed) and was restored. docs only, no code moves (#2423) 2669a01a · dbf3dbe6…
  • the forge refuses an /ingest that would drop a current head it neither descends from nor retires by name (ADR 0098 section 3, map #2422): ingest::heads_this_push_drops judges the declared heads against the heads read at the push generation, before the store transaction, so the CAS makes it sound and a push at a stale generation still loses the swap as before; the walk over the push own changes answers an ordinary push with one read, the head set, and only a head that walk does not reach costs the repo graph, through the landed closure propose already has. a refusal is a 412 whose text body names the count, the remedy (loot pull first) and each head, so a client from before this reads a sentence and this client prints the count it read with the same remedy. retirements ride the signed head declaration as a trailer after the kinds, written only when a push names one, so a push retiring nothing is the old bytes and a forge from before this reads past the names and replaces its heads wholesale as it always did. the client names each forge head its declaration does not reach and that this position has seen, holding the change or naming it in its abandoned record, so abandon --head and supersession are covered with no list of verbs, and never names a head it has not seen. four conformance cases run on the memory store and on Postgres through the assembled forge: a fast-forward carried or already held, a dropped unseen head refused and named with the ref unmoved, an explicit retire that lifts only the head it names, and a racing push that still loses the CAS; a runners test that replaced its root with a new root now retires it by name. red under ten named mutations, each 0 passed and 1 failed (2 failed for the trailer) and restored: no refusal, no generation guard, retirements ignored, no overlay fast path (an existing pin saw the graph read), the overlay alone, the client retiring nothing, the client retiring unseen heads, a view-only seen, the kinds left out ahead of the names, and the client not reading the 412. bash ci/local.sh is green against Postgres 18, 4599 passed over 143 binaries with 13 ignored and the site pg suite at 67 passed. no migration; the forge behaviour changes, so this owes a forge deploy (#2426) e1e5c828 · 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.