Changes touching this path

  • day 0: loot hosts loot f4c30e75 · dbf3dbe6…
  • evidence: crew minted and verified (#86) 1fada823 · dbf3dbe6…diff
  • catch up: GB1 loot ferry lands (PR #114) 6816f50d · dbf3dbe6…diff
  • normalize working tree to LF: byte-stable co-located bridge (.gitattributes -text) e58fdda6 · dbf3dbe6…diff
  • Liveness: one loot-core home for live/superseded/divergent/parked + the head partition (#216); CONTEXT.md vocabulary; rides along: cargo-dist release config (dist-workspace.toml, release workflow, 0.1.0 manifests) from the install-prototype session (loot-site map, #206) 3630469b · dbf3dbe6…diff
  • 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…diff
  • Forge service skeleton: /ingest, the sync surface, and CLI forge remotes (#502) A new `loot-forge` crate and binary, sibling to the relay and never a mutation of it: `loot-net` is a dependency of `loot-cli`, so a storage driver in the relay would ship inside the released CLI binary (ADR 0041:53-57). The ban runs one way -- the forge may use the other crates; none of them may gain a driver. Every endpoint is envelope-authenticated, where a relay authenticates only /stow. The one declared exception is GET /info: a client reads the capability probe before it knows how to authenticate. POST /ingest = envelope_sign(bundle || head_declaration), one signature over both, so a genuine bundle can never be replayed under someone else's head claim. CAS first; nothing is written before the generation compare. A lost CAS answers with a 409 BODY carrying the current generation and head set -- behind, not bounced -- so the client re-carries with no extra round trip. /stow keeps relay parity and moves no ref, and consumes no generation either, since a client reads the generation once and then stows N batches. It DEFERS a change whose objects have not all arrived; /ingest REFUSES one, because a declared head whose objects are missing is a repo no pull can complete. That asymmetry is what keeping /stow is for. Bundles are filtered PER OBJECT by the caller's access class, closing the leak the ticket names: bundle_impl ships a key for every ANYONE-granted object, i.e. every Internal object. Change metadata rides the second #494 axis and gates the whole walk -- a ChangeNode carries the full tree, so shipping one while withholding its bytes still discloses every path, address, message and author. Validation before any write: author signatures, and a tree whose visibility contradicts its objects is rejected. vis_tag is derived from the SealedObject and never trusted from the tree, which is what makes content-addressed upserts safe. Forge purge policy: burn iff burner == object.introduced_by, recorded at first arrival as introducing.author else the envelope pubkey; maroon read off grant_log, global and exact. Both are judged before any object is stored and outside the CAS transaction. Repos are pubkey-addressed at /k/<pubkey>/<repo>, auto-created on first push, and may_push holds iff the signer owns the namespace. resolve_remote is untouched -- still no default host. CORS from day one. Storage sits behind three narrow traits with in-process reference implementations the whole suite runs against; the Postgres DDL they mirror is checked in at docs/sql/forge-schema.sql and its driver is #516. CLI: /info capability detection, the live head declaration off the Liveness view, and a refusal to push a lane -- v1 ingests the primary position only. verify_authored_change moves to loot-codec so the forge runs the identical gate without linking the fs-hardwired engine. Recorded in ADR 0041, the spec and CONTEXT.md: the forge stores no content key but a published one, because filing the ANYONE key lane would let the server read every Internal object, and the keystone is that only Published is server-readable. The cost is stated rather than hidden -- a fresh clone of your own Internal content from a forge is ciphertext you cannot open until #488 lands. Closes #502. 300e06ff · dbf3dbe6…diff
  • loot tutorial: remove the temp tree on Ctrl-C (#513) fa318ba8 · dbf3dbe6…diff
  • Release v0.2.0: lockstep versions, dist-able loot-forge, pinned rust-toolchain (#628) 7eef425d · dbf3dbe6…diff
  • emit_snapshot calls verbs in-process; test-support feature retired (#661) 8033f451 · dbf3dbe6…diff
  • release: bump loot-cli and loot-forge to v0.3.0 for a relay+forge redeploy 15ba4ad7 · dbf3dbe6…diff
  • release: bump loot-cli and loot-forge to v0.3.1 for a relay+forge redeploy beab8725 · dbf3dbe6…diff
  • a change records when it was authored, so a projected commit stops reading '6 years ago' on GitHub (ADR 0043) loot changes carried no timestamp, so the git bridge fabricated one: BASE_EPOCH + generation, one second per ancestor depth from a 2020 epoch. All 526 commits sat inside seven minutes of September 2020. Earlier repairs (#626's floor, the missing-generation refusal) fixed ORDERING and never touched the absolute date, which is why this kept coming back. ADR 0028 inherited the no-timestamp constraint rather than choosing it. The real reason is upstream: a version id is blake3 over authored content, and a clock inside that hash gives two peers different ids for identical content, destroying the dedup and convergence of ADR 0001/0004. So authored_at rides the label seam ADR 0029 already cut for change_id -- covered by the finalize signature (no relay can restamp it) but never folded into the version id. The wasm golden vectors prove the separation held: FROZEN_VERSION_ID, FROZEN_OBJ_ADDR and FROZEN_SIGN are byte-identical, and only the version marker and one presence byte moved. Advisory, and never an ordering input: a self-reported clock is a claim, not evidence (ADR 0025). in_order/ids_topo, buoy and path_touch.ordinal are all untouched, the forge indexes nothing on it, and the projection floors it past every git parent so ancestry holds whoever's clock is wrong. Format v11: additive for readers (a v<=10 change decodes as None and an absent timestamp adds nothing to the signed message, so every existing signature still verifies), breaking for writers, so loot-cli and loot-forge go to 0.4.0 in lockstep. Forge migration 0004 stores it as bigint, not timestamptz -- signed data must round-trip bit-exact or pullers reject the change. Only new work gets real dates. Every commit on main predates v11, main is push-fast-forward-only, and backfilling would fabricate the very claim this replaces. Perf-Baseline: reset the change body grew one presence byte, plus eight where a timestamp is present, so bundle_bytes/store_bytes/wire_bytes step once at the v11 boundary eaa56d99 · dbf3dbe6…diff
  • release: bump loot-cli and loot-forge to v0.4.1 for the forge ingress deploy (#690) 70c27a07 · dbf3dbe6…diff
  • adopt: catch up to landed main f266c856 da01da3d · dbf3dbe6…diff
  • release: bump loot-cli and loot-forge to v0.4.2 for the forge ingress deploy (#690) f266c856 · dbf3dbe6…diff
  • release: bump loot-cli and loot-forge to v0.4.3 for the relay grant-auth redeploy (#818) a595bfd9 · dbf3dbe6…diff
  • release: bump loot-cli and loot-forge to v0.4.4 for the 0006 migrate and the gc-tmp and auth-preamble redeploys (#895) 324e05c8 · dbf3dbe6…diff
  • release: bump loot-cli and loot-forge to v0.4.5 for the 0007 identity migrate and the /account deploy (#753) 2f7eb70e · dbf3dbe6…diff
  • release: bump loot-cli and loot-forge to v0.4.6 so a deploy release carries the 0052 relay abandon-head (#996) 470db09e · dbf3dbe6…diff
  • a store knows which machine materialized it: an arrived copy refuses to record until loot rehome, so a bootstrap cannot silently capture every sealed path as deleted (#986) 4c15a2ca · dbf3dbe6…diff
  • release: bump loot-cli and loot-forge to v0.4.7 so the public installer matrix has a tag to build off GitHub (#1021) 042e1270 · dbf3dbe6…diff
  • release: bump loot-cli and loot-forge to v0.4.8 so a deploy release carries the account-aware write rule (#927) f69ff6fd · dbf3dbe6…diff
  • release: bump loot-cli and loot-forge to v0.4.9 so a deployed binary carries migration 0008 (#927) 40c9e2d6 · dbf3dbe6…diff
  • release: bump loot-cli and loot-forge to v0.4.10 so a deployed forge and site can read credentials from a file (#1034) 21181dc8 · dbf3dbe6…diff
  • release: bump loot-cli and loot-forge to v0.4.11 so the deployed forge carries migration 0009's owner tier and a /wants that answers a whole address list (#1056) 43ce995d · dbf3dbe6…diff
  • release: bump to v0.4.12 so the deployed forge carries an ingest that loads the arriving delta's visibilities in one query (#1072) 44dbe40f · dbf3dbe6…diff
  • release: bump to v0.4.13 so the public catalog can carry the allow widening that its own durable-host guide documents (#1100) ec7728db · dbf3dbe6…diff
  • release: bump to v0.4.14 so the deployed forge can serve the grants peek that #1114 mounted 076042d3 · dbf3dbe6…diff
  • release: bump to v0.4.15 so the deployed forge carries the /offer walk that stopped probing Postgres and R2 once per (change x entry) (#1154) 0d37053d · dbf3dbe6…diff
  • release: bump to v0.4.16 so the public matrix carries the custody passphrase, the widened mis-seal gate, loot converge and the honest doctor e61b48cc · dbf3dbe6…diff
  • the unlock session holds the seed sealed under this repo's own ciphertext instead of the passphrase you typed, so a synced config directory leaks a window and not a secret you reuse elsewhere, and the passphrase is zeroized from the moment loot owns it (#1173) 1943d2c7 · dbf3dbe6…diff
  • loot 0.4.17: the Known Issues page is re-reviewed against the binary it now names, four entries move because their fixes shipped, and the land runbook learns that a skip drops three gates and not one 44de9890 · dbf3dbe6…diff
  • loot 0.4.18: the Known Issues page is re-reviewed against the binary it now names, the seal-away-from-yourself entry leaves because the lockout gate shipped, and the reverted-peer-edit entry narrows to the locked pull that can still do it 29f571e7 · dbf3dbe6…diff
  • loot-revset stops being a finished parser wired to nothing, because `loot log <revset>` and `loot shortlog` now read one door that tries the historic selector shape FIRST and only parses a non-selector word as an expression — which is what keeps `loot log <change-id>` working, since the crate reads bare words as hex while a change id is the letters k-z, so the grammar was never the strict superset its own docs and this ticket both claimed (#1495) dd223bf0 · dbf3dbe6…diff
  • the harness stops measuring only what a run produces and starts measuring what it does, because the three work counters this run built and threw away are now one family in loot-count that a single during region reads whole, with logical object opens and disk reads kept as separate numbers since 2,000 of the first can cost zero of the second, and the family ships compiled out rather than as cfg(test) one-offs because cfg(test) reaches neither an integration test nor loot-perf and would foreclose the gate #1602 exists to add, at a cost measured at zero bytes in the released binary (#1600) 482a72c1 · dbf3dbe6…diff
  • loot 0.4.19: the Known Issues page is re-read against the binary it now names by running it rather than re-reading its source, the six entries pin 5 held leave on the release that finally carries their fixes, and the pin retires with its emptied table on its own instruction — the re-run is what caught the evolog entry rotting without an edit, because loot log grew a when column somewhere in this range and the entry had claimed for two releases that evolog was the only time the CLI prints, and the recovery-door note is rewritten rather than deleted since loot id phrase shipping does not change that both it and recover open the repo first; and the restore no-op test stops calling its own instrument blind when the clock is the coarse thing, because it stamped the setup write and the restore microseconds apart against a file clock that ticks every 15.6 ms — it was failing four runs in five on main, standalone, while passing inside a full suite slow enough to straddle a tick, so it now probes for a distinguishable mtime rather than sleeping a constant that would bake this filesystem granularity into the assertion 4dcc9ff6 · dbf3dbe6…diff
  • user-declared gates arrive as data rather than as hooks, and the decision the ticket owed splits rather than picking one of its three options, because the gate vocabulary is two halves with different properties. The mechanism moves down into loot-cli, since its value is concentrated in the fake - a FakeSpawner that panics on an unstubbed step is what turns no process spawned from a claim into a failure, and two fakes drift with a fake that has quietly stopped intercepting being indistinguishable from one that works; loot-first keeps a re-export shim so no orchestrator caller changed. The phase axis is duplicated deliberately because it is not the same axis: loot-first asks about two trees, one of which only a land produces, while the CLI asks about two commitments, and a shared enum would carry four variants of which each consumer must refuse two - a rule nothing checks, where two small enums are checked by the type system. A new crate was rejected on arithmetic rather than taste, since loot-first already depends on loot-cli and there is no pair needing a bridge; loot-core was rejected because only half of #1682's criterion transfers, and that half is now a census asserting the engine spawns nothing rather than a sentence. A gate runs after the capture and can never prevent it: it does not decide whether the tree is recorded, only whether it is signed or sent, so a refusal costs the signature and nothing else, which is the ordering #174 already chose. On the confidentiality boundary the absolute form of the criterion is unachievable by any mechanism that runs a command in the working tree, and saying so is better than a strong claim that will not hold - loot surface writes and never deletes, so a path whose grant lapsed stays on disk as stale plaintext readable by cat, grep, the editor and every process running as the operator. The guarantee is therefore the narrow checkable one, that a gate is granted no read the operator does not already have, held up by four facts each of which a regression would have to break first: the runner never sees a Workspace, nothing is materialized, a Step carries program args and cwd with no environment channel, and there is no shell. A fifth fact answers a different attack - the declaration is untracked, so a pull cannot write one, which is git's own reason for never transporting hooks and matters more here since ADR 0075 has the forge holding proposals. This ticket also understated the surface that already exists: loot resolve --tool hands a user command decrypted plaintext today via LOOT_BASE and its siblings, so gates are not the first such door but they are the one that opens none (#1538) 44d4869a · dbf3dbe6…diff
  • loot ferry parses both policy files once per commit instead of once per changed path, and the instrument had to be built before the fix because PolicyLoads sat on Attributes::load while both ferry doors call parse, so the counter read a structural zero over this whole path and would have read zero after the fix too - a 0-valued counter being indistinguishable from one watching code that does not run. The tally moves to Attributes::parse and Ignore::parse_recorded rather than being routed through a counted door, because the fix itself removes those door calls: a counter on them would read zero afterwards, which is the same blindness relocated. That changes what the counter MEANS, from policy file reads to policy re-derivations, so all three existing pins were re-read rather than adjusted until green - status moves 2/3 to 3/4 with the +1 being its single Ignore::load now counted, and the point is that the GROWTH half passed untouched (narrow equals wide) while only the constant moved, so the test is re-pinned and not re-decided; the tier-exclusion test is still green because the in-process tier links loot-core and never loot-cli, so ADR 0073's exclusion needs no re-taking; and lane_new_sweep's note that policy_loads is one per read_tree_at is repointed to two, since read_tree_at calls both loads. The instrument was proved non-vacuous against the UNFIXED code first, at 18, 66 and 258 parses over four commits of two, eight and thirty-two changed paths, which is exactly 2 plus 2 times commits times width; after, it is 2 plus 2 times commits, so 258 falls to 10 at width 32 and stays 10 as width grows. The most useful thing learned here is a red proof that inverts an assumption: blinding the instrument by putting the tally back on load makes the counter read a constant 1 everywhere, so the constancy pin passes AND the parses-greater-than-zero guard passes, and only the GROWTH assertion catches it - a positive-value pin does not protect against a blinded instrument, which is what ADR 0072's controls bullet credited it with, and that bullet is corrected rather than left standing. This ticket's own wall clock does not reproduce and is corrected rather than repeated: the removed re-parse is 4.63 microseconds per path in release against this repo's real policy files, not 22.0, so a full-history ferry is about 1.9 seconds rather than 8,819 milliseconds - 22.0 is close to the debug reading of 31.53, so the hunt appears to have measured a debug build, and a figure taken under a different build is not a smaller version of the same number. ignored_under is deleted rather than kept as a pure forward once the parse is hoisted, and ADR 0028 is amended because it argued its delete-arm decision partly on an Ignore::parse per deleted path, a cost that no longer exists - the decision stands on the attribution argument, which was load-bearing anyway. seal_under takes a parsed Attributes and narrows pub to pub(crate) since Attributes is crate-private, and its doc said it keeps the bridge from re-parsing the policy twice per path, which was true about the wrong unit: it halved a cost that should never have been per-path. One honest regression is recorded rather than hidden: a deletions-only commit now costs 2 parses where it cost 0, because the hoist is unconditional (#1704) 1822132f · dbf3dbe6…diff
  • loot archive grows prefix, format, -o and a pathspec, and the pathspec is the DECLARED group rather than a fourth matcher: no Glob, no matches and no string compare against a pattern is written anywhere in this change, so the empty-match refusal and the 1330 cwd rebase arrive free with the attachment. the attachment forced one thing the ticket did not name - archive was declared NO_PATHS, so under 1551 the group trailing list would have begun at position ZERO and swallowed the output file - and it now states its own arity of two opaque slots first, both opaque because a file name, an -o value and a prefix are not repo paths and must not be rebased. the honesty criterion is the one that carried risk, since this adds a SECOND reason an archive can be partial beside the reason 416 built the summary for, and the two must not collapse into one number that reads as either: three populations are kept apart, written, then unreadable as selected minus written which KEEPS 416 word partial, then outside as total minus selected which gets its own clause, its own denominator and the explicit words by request not unreadable. the first denominator switches to selected and SAYS selected exactly when a pathspec is in force, so 1 of 2 cannot be read against a five path change, and the pathspec clause prints EVEN AT ZERO because silence there is indistinguishable from no pathspec at all. written is derived from selected by MEMBERSHIP, so written under selected under total holds by construction rather than by a subtraction that could underflow, and the engine skipped count is deliberately NOT used because it is taken over the whole tree and would therefore count paths the operator never asked about - that IS the collapse. the format is tar.zst and it adds an EDGE rather than a crate: zstd is already default-on in loot-codec and loot-core takes it with default features, so it already compiles into the shipped binary and the lock gained exactly one line with no new package. gzip was rejected on MEASUREMENT rather than taste - flate2 is in the lock but its only dependent is automerge, which only spike-crdt links, so it reaches NO shipped binary and choosing it would put a second compressor in the released loot; the wider extractor reach is the real cost and the format table says so. it does not reuse the codec own compressor either, because sharing it would weld archive bytes, a thing people compare hashes of, to a level chosen for objects in a store. the byte-reproducibility promise is NARROWED where an operator reads it: the ustar bytes are host independent, the zstd framing is reproducible only for a given zstd build. two pins were aimed rather than merely live - the -o ambiguity mutation is invoked with @ rather than HEAD precisely so the mutated build SUCCEEDS, which makes refusal the assertion, and tar.zst is checked by DECOMPRESSING rather than by length, since a wrap that compressed the wrong buffer stays green under a size assertion. and a stale doc claim was found on the way: readable_tree was described as what loot grep searches, false since 1500 moved grep to readable_object, narrowed here and in the copy of it that archive carried (#1530) 95a1cfeb · dbf3dbe6…diff
  • the no-false-absence guard 1527 landed was BYPASSABLE, and the bypass was neither of the two escape routes its doc ruled out: buoy and bisect return from main before the notice single call site, so assemble measured the frontier and threw it away unprinted, and a plain loot buoy on a shallow position exits 2 with no buoy - a REFUSAL-SHAPED false absence, which the comment four lines up calls the shape an operator most needs the line for. the repair is SHAPE rather than a third bullet: main is now a two statement wrapper and the whole former body is dispatch(), which is the only expression in main that produces an exit code, so every exit code the binary emits is that call return value and a return anywhere inside it - any depth, any verb, ahead of the table or behind it - returns INTO the notice. a new early return is not a new escape route, it is the SAME route, and because nothing is enumerated nothing has to be maintained. that matters because the old doc argued unbypassability by ENUMERATING escape routes and closing each, which reads as exhaustive, is not, and failed on the first route nobody listed - the same shape as a hand written count beside a derived number, which this run watched go stale three times. the residual is STATED rather than enumerated away: a process that never returns through main, process::exit or abort or panic, which is a property of process TERMINATION and not of the verb table, so nothing a verb does BY RETURNING can miss the notice. a census pinning exactly one raw exit was considered and refused, because that walker own consumer count is itself a derived-and-pasted census and adding a consumer churns it. the failed enumeration is kept as HISTORY, marked as the thing that failed, with the shape argument replacing it, and a THIRD site carrying the same claim was found in CONTEXT.md glossary which the ticket never named. FRONTIER_WIDTH stops being a process global read by verbs that hold the authority: both callers now ask their own workspace, and the public spelling no longer compiles from outside the module, which is the narrowing made structural rather than promised. three pins that asserted nothing are gone. the re-encoding privacy pin is DELETED because no byte seam is reachable - the transport is a TYPED seam, so the test re-encoded its own recorded id vectors and asserted the codec is linear in their length, true for every possible input - and its doc now records what it did against what it claimed, with the criterion standing on the other two pins, which carry positive controls. the partition pin is read out of the RENDERED sentence now rather than from literal triples the constructor never saw. two mutations make the case by experiment: moving the notice back to the end of dispatch reddens the new pin while log and show stay GREEN, and re-adding the old partition body under a scratch name PASSES, so vacuity is demonstrated rather than argued. an eighth pin was written and then deleted, because a mutation proved the existing assertion already sits on the live case (#1828) b5eb05df · dbf3dbe6…diff
  • loot 0.4.20: loot-cli and loot-forge move to 0.4.20 with their lock entries, the first public release since 0.4.19 and the one that carries the opt-in telemetry client, format major 14 and forge migration 0017; the relay and forge already read format 14, which ADR 0066 requires before the CLI publishes. the Known Issues page is re-reviewed by running the release binary against a local relay rather than re-reading source: both entries reproduce word for word and the unlock session file holds no raw passphrase, but the run falsified the pages own remedy. it read unlock, rehome, then converge, and when rehome refuses, which it does in exactly that state, carrying on to converge captures the stale copy the same way describe does, after which surface --force re-materializes the stale bytes. measured from the pristine post-pull state, moving the file aside and re-running rehome, or surface --force, each put the arrived version on disk, and describe then undo does too; the second column now says that in that order and says to stop before converge, and the entry says converge does the capture unasked. gone from the history was wider than the run, since the arrived change stays in the log one below a tip that reverts it, and the entry now says that. the converge capture is filed as 1963. tsc, the site suite, the build, the byte budget and the published-surfaces pins are green (#1960) b53bd00d · dbf3dbe6…diff
  • loot 0.4.21: loot-cli and loot-forge move to 0.4.21 with their two lock entries, the first public release since 0.4.20 and the one that carries the locked-pull fix. format major stays at 14 and the live relay already reports 14, so ADR 0066 has nothing to sequence here, and the top forge migration is still 0017, so this release owes no schema step. the Known Issues page is re-reviewed by running the 0.4.21 binary against a local loot-relayd rather than by re-reading source, and the locked-pull revert NO LONGER REPRODUCES: rehome materialized rather than refusing and put v2 from alice on disk, the converge the note names next answered already on one line and left it there, loot status reported an empty working change and loot log showed the arrived change as the tip, which is the state the printed advice implies, reached by typing the printed advice. so that entry is deleted, and FIXED_IN_MAIN, its HELD_ENTRIES row and pin 5 go with it, on that pin own instruction, leaving loot edit, which reproduced word for word, as the one entry. REVIEWED_AGAINST moves to v0.4.21 and LAST_REVIEWED to 2026-09-19, and the locked-pull paragraph further down the page stops pointing at a deleted entry and says what rehome does now. RELEASE_TAG is deliberately NOT moved: it names what dl.millerbyte.com can serve, and this release has reached nothing yet. the privacy page verb-count claim was re-checked against the binary rather than assumed, since that is what fell over before the last cut, and note_dispatched is called on all three dispatch routes, the table, buoy and bisect, so every verb this release newly publishes is counted. the site byte budget is re-recorded and exactly one ceiling moves, /known-issues lowered from 210944 to 208896 by the deleted entry, with no raise anywhere. tsc, the site suite (659 passed and 61 skipped over 60 files), the build, the byte budget and the published-surfaces pins are green, and the workspace suite is green (3970 passed over 122 binaries, 7 ignored) (#2089) 71ed6938 · dbf3dbe6…diff
  • loot-hygiene (#2128, map #2099 ticket 4): the land text gates move from loot-first into a crate with no dependency that builds for wasm32, re-exported as loot_first::hygiene so every gate row, checkout test and AGENTS.md path reads unchanged; a new crate rather than loot-codec because three consumers now read it, loot-first, loot-cli and loot-wasm, and the wasm one is the fact ADR 0076 §2 no-new-crate reasoning did not have. Corpus::from_entries files an in-memory tree under exactly the allowlist the directory walk applies, top-level files plus SOURCE_ROOTS filtered by TEXT_EXTENSIONS minus SKIP_DIRS and SKIP_PATHS, through one filing rule both constructors share, and a link resolves against the entry set with dot and dotdot folded, so a Worker with no directory answers what the land answers. CORPUS_CHECKS is the table a .lootpipeline check step names, keyed by the land gate names and pinned to them, holding the floor-free halves: the land refusals still refuse a vacuous walk first because a mis-rooted land must not read as clean, but a three-file repo is not mis-rooted, so a check answers about the files it was handed. loot pipeline now runs check steps in-process over one corpus walk per run, a finding is failed and exits 2, an unknown name cannot start and names the set and exits 1, and the ? deferral #2127 shipped this morning is retired the same day with the ADR 0023 amendment saying so. loot-wasm links the crate and a wasm-bindgen test runs the three checks from entries under node. Measured: the site wasm is 475667 bytes before and after, unchanged, because nothing exported calls the crate; native the three checks over a 1120-file synthetic corpus take 0.8 ms in release and 28.0 ms under wasm in node; through the release binary on this repo, roughly 1355 covered files and 20 MB by an approximate count, the three checks cost 160 ms warm against a 73 ms listing and 6.5 s on a cold page cache. Two lands worth of censuses read off their refusals: the destination allowlist row for the moved file, and no other. Five pins broken once by a named mutation, red at 0 passed 1 failed then green at 1 passed: from_entries skipping widened, link resolution made true, the table key misspelled, a finding made a pass, an unknown check made a pass; the fifth sweep needed a second pass because its first restore string matched twice and left the mutation applied, caught by the full run that followed. 66 test binaries green across loot-hygiene, loot-cli and loot-first. No wire, format or store byte moves, no migration (#2128) 858575e1 · dbf3dbe6…diff
  • loot 0.4.22: loot-cli and loot-forge move to 0.4.22 with their two lock entries, the first public release since 0.4.21 and the one that carries the seek follow-ups, a fetch depth the hosts honour (#2123), the browser SDK bounded read (#2124) and the seek cache cap with --gc (#2125), beside the pipeline verb (#2127) and every land since 3039521e. format major stays at 14 and both live hosts already report 14, so ADR 0066 has nothing to sequence here, and the top forge migration is still 0017, so this release owes no schema step; the relay and the forge still deploy before the site, since #2123 is what the SDK bounded read refuses without. the Known Issues page is re-reviewed by running the 0.4.22 binary in a sandboxed home rather than by re-reading source: loot edit on an older change refuses with change tlqyroot has descendants, v1 edits only a tip (childless) change, word for word and exit 1, while on the tip it reopens the version as the working change, so the one entry stays as written; loot seek --gc --dry-run in that sandboxed home lists no positions and the defaults. REVIEWED_AGAINST moves to v0.4.22 and LAST_REVIEWED to 2026-09-20. RELEASE_TAG is deliberately NOT moved: it names what dl.millerbyte.com can serve, and this release has reached nothing yet. the site byte budget is re-recorded: NOT re-recorded, because no ceiling has to move: every one of the 62 surfaces is under its ceiling, and the uniform +150 to +170 B on every surface is #2127 CLI row in the shared docs chunk they all fetch, one growth and not sixty-two, and not this cut own; the site gate is green in the lane (669 passed and 62 skipped over 61 files). the workspace suite is green at the base (4023 passed over 126 binaries, 7 ignored, on the #2125 lane a commit below, and this land gate runs it again) and cargo build --release --locked validates the lock edit (loot 0.4.22 from the lane binary, and loot-forge 0.4.22 built beside it, refusing to open its storage without its URL, which is its answer outside a deploy) 8b4aa08f · dbf3dbe6…diff
  • loot 0.4.23: loot-cli and loot-forge move to 0.4.23 with their two lock entries, the first public release since 0.4.22 and the one that carries the seal-over-tree-entry arc, where every site that acted on a change tree entry unsigned visibility field now asks the seal instead (#2185 the three acting sites, #2188 the timed deposit lane, #2187 the push-time deposit plan, #2196 the git bridge projection, #2203 the git-side ingest, #2205 both grant doors and #2212 the sync ingest door, with #2206 and #2214 measuring and correcting the prose behind them), beside the forge runner and job tables (#2157, ADR 0091, migration 0018), the owner side of a proposal (#2162, ADR 0075), the pre-land gate learning which stream a doctest reports on and refusing a cargo it could not start (#2084, #2140, #2199, #2066), a patch that carries the ending of the line it shows (#2005), the relay mailbox taking the door the relay already writes objects through (#2112), and every other land since 3cfbe9b, 30 in all, the first of which is the RELEASE_TAG move that published 0.4.22 (#2147). format major stays at 14, format.rs has no diff at all in the range, and both live hosts answer format_major 14 over /info, so ADR 0066 has nothing to sequence. the top forge migration is now 0018_runner_and_job.sql where the 0.4.22 cut said 0017, so unlike the last release this one DOES owe a schema step: 0018 is include_str-ed into MIGRATIONS and rides the forge binary, so the forge deploys BEFORE the site. the Known Issues page is re-reviewed by running the 0.4.23 binary in a throwaway home, with HOME and USERPROFILE and XDG_CONFIG_HOME and XDG_CACHE_HOME all redirected into a temp directory and a local loot-relayd for the pull half, rather than by re-reading source: the one entry reproduces word for word, change xoxokopy has descendants - v1 edits only a tip (childless) change at exit 1, while loot edit on the tip reopens version 0101b025 as the working change, so it stays. the custody prose was re-run rather than re-read as well: once loot lock cleared the session, status, log, diff, grep, surface, whoami, describe and push each refused with the ADR 0068 message while lock and unlock still ran, a wrong LOOT_PASSPHRASE said so and was ignored, the session file held loot-unlock v2 and machine and sealed hex with the passphrase own hex in no file under the config directory, loot id phrase refused both a pipe and a redirect with no override, loot undo refused across the push barrier in the words the page quotes, and loot burn printed the never-pushed and pushed tiers with one line per disclosed host. ONE CLAIM IS CORRECTED, and it had rotted without an edit: the locked-pull paragraph read since {REVIEWED_AGAINST} the ingest writes down the claim it could not check, which was exact when #2089 wrote it at v0.4.21 and false one cut later, .loot/stale-disk-unverified being in the v0.4.21 tag and absent from v0.4.20, so it is the literal v0.4.21 now, for the reason the session-file boundary is the literal v0.4.17; the behaviour itself was re-run and holds, a locked pull leaving the receiving disk on the old bytes and parking .loot/stale-disk-unverified while the rehome its note names materialized the arrived version after unlock. REVIEWED_AGAINST moves to v0.4.23 and LAST_REVIEWED to 2026-09-21. RELEASE_TAG is deliberately NOT moved: it names what dl.millerbyte.com can serve, and this release has reached nothing yet. the site byte budget is NOT re-recorded, because no ceiling has to move: all 62 surfaces are under theirs, /known-issues is +7 B against a 208896 B ceiling, and the one figure worth a reader eye is /privacy at +586 vs recorded with 907 B of headroom, which is not this cut own since nothing here touches that page. the site gate is green in the lane (tsc, the build, 669 passed and 62 skipped over 61 files, and the budget), the workspace suite is green (4140 passed over 132 binaries, 8 ignored, 0 failed) and cargo build --release --locked validates the lock edit (loot 0.4.23 from the lane binary, and loot-forge 0.4.23 built beside it) 078d5ce1 · dbf3dbe6…diff
  • loot 0.4.24: loot-cli and loot-forge move to 0.4.24 with their two lock entries, the first public release since 0.4.23 and the one that carries the proposal read surface and its database views (#2174, #2175, #2177, #2180), the land gate reading foreign authorship and refusing on a require line (#2178), the forge keeping the attestations a push carries (#2250, migration 0019), the runner routes and loot runners (#2158, migration 0021), the browser sdk transport watchdog (#2070), the perf follow-ups from #2222 to #2247, and every other land since 8fb0716, 35 in all. format major stays at 14 and format.rs has no diff in the range, so ADR 0066 has nothing to sequence. the top forge migration is now 0021_runner_last_seen.sql; 0019 and 0020 are already live from the deploy-only v0.4.23-deploy.1, so 0021 is the one new schema step, and it rides the forge binary, so the forge deploys BEFORE the site. the Known Issues page is re-reviewed by running the 0.4.24 binary in a throwaway home with a local loot-relayd and a loot-forge --dev, not by re-reading source: the one entry reproduces word for word, change lkorrwmk has descendants - v1 edits only a tip (childless) change at exit 1, while loot edit on the tip reopens version f318c57a, so it stays; the eight custody verbs refuse with the ADR 0068 message once loot lock clears the session and lock and unlock still run, a wrong LOOT_PASSPHRASE on a relay pull is reported and ignored, that locked pull files keys and leaves the disk on its old bytes and parks .loot/stale-disk-unverified while rehome after unlock materializes what arrived, a locked forge pull refuses by name, the session file holds loot-unlock v2 and machine and sealed with the passphrase hex in no file under the config directory, loot id phrase refuses a pipe and a redirect, loot undo refuses at the push barrier in the quoted words, and loot burn prints the never-pushed tier and the pushed tier with one line per disclosed host. three probes were first mis-driven by the harness and re-run, which the page records. REVIEWED_AGAINST moves to v0.4.24 and LAST_REVIEWED to 2026-09-23; RELEASE_TAG is deliberately NOT moved, since it names what dl.millerbyte.com can serve and this release has reached nothing yet. cargo build --release --locked validates the lock edit (loot 0.4.24), the published-surfaces pins pass (6 passed) and the site gate is green with nothing recorded (#2276) 4ad8f503 · dbf3dbe6…diff
  • loot-cli and loot-forge are 0.4.25, the release that first carries the loot.build names (map #2412, ADR 0099), and the Known Issues page is re-read against it by hand in a throwaway home: one claim had rotted with no edit, since #2389 gated the reads of an allowlisted relay and a locked pull there now refuses by name as a forge does, so the page says an open relay runs while locked; one entry is added first, found by driving burn further than any pass had: burning a finalized path a forge has not yet received makes every later push to that forge refuse and the path cannot leave the tree, older than this release and filed as #2441, with the undo-first workaround that was run; LAST_REVIEWED is 2026-09-26 and REVIEWED_AGAINST v0.4.25. published_surfaces 6 passed; site gate 819 passed, /known-issues within budget; release build of the lane reports loot 0.4.25 and names security@loot.build and https://loot.build/trust in its help (#2419) c594ee28 · 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.