Changes touching this path

  • loot runners lists the runner rows a forge holds for this repo, part 2 of 2 of this ticket: name, key, the step kinds each may claim, live or retired, and when the forge last heard from it, owner-only because it is the owner configuration, retired rows included because who was allowed to run a version is what an audit asks. last seen needed a column, migration 0021 runner.last_seen_at, written by the runner door on every admitted request and throttled in its WHERE clause to one write per runner per 60 seconds, so a runner polling every second costs one write a minute; a registration never sets or clears it, so a runner registered and not started reads never seen, and deriving it from job rows was rejected because an idle runner finding no work leaves none. the first spelling of that throttle, last_seen_at <= $3 - $4, failed on Postgres 18 at the first touch, which would have made every runner request a 500 on the live forge while every in-memory test passed; the edge is computed in Rust now, and landed part 1 never wrote the column. the shape is born frozen under ADR 0023: porcelain pubkey state capabilities last_seen and the name last because it may hold a space, JSON with contract, remote and one object per runner, absent times as null, both from one value and pinned byte for byte. the verb census cost, counted: MACHINE_OUTPUT gains runners, the README block and its sentence move to 85 verbs, verb lines 133 to 134 at three main.rs sites and one ADR 0066 claim, dispatched verbs 84 to 85, dispatch table 83 to 84, machine output 32 to 33 with its named list, and two ADR 0066 lines that are dated records were left alone as the census skips them; the site verb list gains runners and its gate is green. the verb runs end to end through the spawned binary against a real forge. red under mutation, counts read each time: the touch unthrottled (1 passed and 1 failed), the door never touching (0 passed and 1 failed), the name not last (0 and 1), an absent time spelled as a dash in JSON (0 and 1), and a registration allowed to set last seen (1 and 1) once its pin moved into the store, where the defence lives, after a first attempt at the route proved unobservable; on Postgres 18 the throttle removed from the SQL went red at 0 passed and 1 failed after a green unmutated arm, each restored green. bash ci/local.sh is green against Postgres 18 (4258 passed over 136 binaries, 10 ignored). migration 0021 rides the forge binary, so the forge owes a deploy (#2158) 6dd6ae69 · dbf3dbe6…
  • loot runner add enrols a runner and every push to a forge keeps it current, the second land of #2130 (ADR 0091 §3, §4): add registers the row on the forge first, which judges it, then writes the runner's key into .loot/runners, and when it minted the key writes a home file under .loot/runner-homes/ in ADR 0059's KEY=VALUE dialect with the forge URL, name, kinds, pubkey and private seed, and deposits through the same route a push takes. a push to a forge reads the repo's runner rows from /runners/list and seals a key-only grant, DagRepo::grant_key_only, for each held Restricted or Internal key inside each live runner's scope, filed through /runners/deposit and deduped by the (remote, oid, pubkey) ledger, written only once a batch is delivered; an embargoed key is never deposited, since grant_key_only reads the keyring and not the escrow, and a forge that will not answer the list is a note and not a failed push. ⚠ the #2162 amendment put a runner in .loot/peers, which is also the burn-trust set, the unquarantined grantors and every timed grant's recipients, so the runner file is its own and only the attester trust reads it, keeping the operator's trusted-but-not-a-recipient decision by construction; ADR 0091 records the correction. the scope always reaches .lootpipeline, added when left out. the verb census moves: README 88 verbs, 146 usage lines, ADR 0066 at 88 dispatched and 51 refusing the flag, PROSE_ONLY_CEILING 51 to 52 with its reason, the placeholder census and the site verb list. red under eleven named mutations, each restored, counts read each time: the key-only grant falling back to the escrow (0 passed and 1 failed), and 1 passed and 1 failed over the two workspace tests for no scope filter, no ledger check, a retired runner planned, no Internal lane, the ledger written before delivery, the attester trust ignoring the runner file and the runner file read from peers, five of which also went 0 and 1 end to end, as did the runner written into .loot/peers, a push depositing nothing to runners and the pipeline file left out of the scope. the loot-cli, loot-core, loot-identity and loot-net suites green but for two census tests fixed since, and the site gate green at 842 passed (#2130) 37a00dd9 · dbf3dbe6…diff
  • loot runner once and serve, the runner side and the last land of #2130 (ADR 0091 §5, §7 to §11): a store-less runner reads its home file, or the same LOOT_RUNNER_* keys from the environment, claims one job of a kind it can do, leaves a job below its --trust floor for its lease to return, and fetches the one version through /jobs/fetch. before a byte is written the node's id must derive from the tree the forge sent and a node naming an author must carry its signature, since the pass it signs names that version; the tree opens with its key-only grants into a ScratchTree, now built from rows by ScratchTree::of_rows, which also refuses a path that would leave it, and pipeline::run_kind runs that kind on that trigger through the same step executor as run, teed so the output is kept. only a pass is signed; the detail is each step's name, outcome, exit code and duration and the count of unopened paths, and anything that quotes the tree, the unopened paths, a step's last 8 KiB and an unreadable declaration's refusal, rides a log tail sealed to the repo's owner as a runner-signed SealedGrant. serve is once in a loop, store-less too since a runner key cannot pull, claiming again after a judged job and waiting --poll after anything else. measured from an empty home against a release forge holding this repo's tree as one change of 1,693 files: runner add deposited every key in 0.42 s and runner once took 2.74 s from claim to posted verdict with the check 1.45 s of it, leaving 0 files behind. ADR 0091 records the departures from §5 and §7, what the runner cannot check and what is not built, and the review's corrections; loot_core re-exports change_id. red under sixteen named mutations, each restored, counts read each time: 6 passed and 1 failed over the seven runner tests for the id not re-derived, the signature not verified, an unstartable step not unrunnable, a stepless kind passing, output in the detail, the log keeping each step's head, the log sealed to the runner, serve waiting after a judged job, a home whose key is not its pubkey, a path leaving the scratch tree, a refusal echoed into the detail and the unopened paths unnamed; 21 and 1 over the pipeline tests for a job running every kind and a job's steps not kept; and 0 and 1 end to end for a pass signed on a failed job. the verb census moves to 148 usage lines and classifies <floor>, and after the review fixes the census, runner, pipeline and runner end-to-end tests were re-run green, the whole suite being the land gate's (#2130) 872ff35a · 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.