Changes touching this path

  • 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…
  • the pre-land cargo test gate tells a compiler that did not answer from code that failed. cargo test now tees its stderr through a new Spawner::tee_stderr, and hygiene::classify_cargo_test_failure reads it: inside a run where cargo said could not compile, an ICE banner (internal compiler error, query stack during panic, the I-ICE bug-report note) or a compile whose process line shows a 0xc exit code or a signal death is a compiler that did not answer, any other build failure is one a corrupt incremental cache can fake, and a failing test is neither. a build failure of either kind clears target/debug/incremental and runs cargo test once more, and the re-run is the result: a pass lands with tests=RETRIED on the verdict and a block naming each classified first run, a second crash refuses as a new Refusal::NoAnswer whose merged-tree prose never prints the ADR 0055 story or its loot edit procedure, and anything else refuses as a finding that says a re-run happened. a failing test still refuses at once with the old message, un-retried. the classifier is pinned against the t1561 crash tail, unwrapped and trimmed, the t1870 151-error tail, and a reconstructed ICE banner, since no ICE transcript survived. red under mutation: the could-not-compile requirement dropped (1 passed, 1 failed), the --crate-name check dropped (1 passed, 1 failed), a failing test re-run (0 passed, 1 failed), a double crash given the merged-tree remedy (0 passed, 1 failed), RETRIED dropped from the line (0 passed, 1 failed), and the cache left uncleared (0 passed, 1 failed). no migration, no wire or format byte moves, and no forge or relay byte moves, so this owes no deploy. the workspace suite is green (3936 passed over 123 binaries, 7 ignored) (#1873) 74728216 · dbf3dbe6…diff
  • a lander can no longer read a pre-land finding as the refusal whose recovery is to change nothing, and the gate claims no verdict only when neither run reached one. the no-verdict refusal opens on a heading of its own, pre-land cargo test: NO VERDICT, and a finding keeps the old heading and never says in words of its own that the compiler did not answer, so the crash it quotes from the first run cannot be mistaken for the other refusal; land-change keys its two recoveries on those headings. a build failure and then a crash is now a finding, not no verdict: the first diagnostics are the only verdict either run reached and the crash neither confirmed nor cleared them, so telling the lander there is nothing to fix would claim more than the gate knows. a re-run that cannot start cargo now says a re-run happened, leaving the merged-tree remedy to #2066. afk-loop reads the verdict line through land-change instead of keeping a second list of values, the --skip-tests block stops stating the CI net as a fact and names ci/local.sh for when the job does not run, and the claims that the job is only cargo test are narrowed to what ci/test-main.sh runs. red first: a finding carrying the no-verdict words, a build failure and a crash judged as no verdict, and a re-run spawn failure that never said a re-run happened (0 passed, 3 failed). red under mutation: the finding rendered with the retry evidence (2 passed, 1 failed), the no-verdict guard dropped from the first run (1 passed, 2 failed), the re-run note dropped from a spawn failure (2 passed, 1 failed), and the deadline dropped from the new wire pin (0 passed, 1 failed). the ticket premise about a deadline ceiling is corrected: in reqwest blocking a request timeout replaces the client per-wait timeout, so a deadline is not undercut by the transfer budget, and a local server pins that. the smells are taken: the fake spawner stdio choice is an enum, wire post takes a budget as get does, Endpoint get sends in one place, the transport remedy sentence is written once, add_attestation is add_attestations with one record, and CargoTestFailure Other is named Finding. no migration, no wire or format byte moves and no forge or relay byte moves, so this owes no deploy. the workspace suite is green (3946 passed over 122 binaries, 7 ignored) (#2071) bb8acc52 · dbf3dbe6…diff
  • the pre-land gate reads the stream a doctest reports on, and the four failures in the sighting turn out to be the four that link rather than the compile_fail probes: #2084 asked for the condition to be reproduced rather than guessed, and it reproduces in one command, a transitive dependency rlib under target/debug/deps held open with no sharing, after which cargo test --locked -p loot-cli --doc comes back 6 passed and 4 failed with rustc saying crate socket2 required to be available in rlib format, the four being the doctests that link, cargo not rebuilding because the rlib mtime is as readable as ever, and the handle released giving 10 passed again. two premises in the ticket body are corrected off its own land log: the four it names are the doctests without compile_fail, a compile_fail probe never reaching a link at all, and the feature-unification hypothesis is refuted by profile, since the perf gate builds loot-perf-gate with --features count under --release into target/release while the suite reads target/debug, and that land test build was already fresh at 0.66s, so nothing in the invocation built anything to collide with. the gate could not see any of it because the evidence is on stdout, under the libtest captured-output heading, while tee_stderr set Captured stdout to empty by construction, so classify_cargo_test_failure read a finding off a stream that could not hold it. tee_stderr becomes tee and drains both pipes, stdout on a thread of its own because two pipes read in turn deadlock; CargoTestFailure gains ArtifactForm, keyed on cargo naming the doctest step on stderr together with a line opening error: crate on stdout, which is the widening #2079 declined and which answers the objections of that ticket rather than stepping around them; a first run classified that way buys the re-run #1873 already gives, and the same condition on both runs refuses as a no-verdict rather than as a finding, so a merged pass owes cargo clean and never the ADR 0055 story. the NO VERDICT heading says neither run judged the tree now rather than naming a crash, the third question is answered no in the doc of the gate itself with what a split would cost, and the stale #2079 bullet saying this classifier reads stderr is corrected where it stands. red under mutation, counts read each time: the stdout half never asked (loot-hygiene 39 passed and 1 failed, loot-first 193 passed and 3 failed), the doctest-step anchor dropped (39 passed and 1 failed, a real compile failure reading ArtifactForm), the line-start anchor dropped (39 passed and 1 failed, a quoted source line classifying), the real adapter dropping stdout again (loot-cli 17 passed and 1 failed), a doctest link failure counted as a verdict on the tree (194 passed and 2 failed) and the no-verdict closing sentence removed (195 passed and 1 failed), each restored to 196 passed, 40 passed and 1344 passed. no migration, no wire or format byte moves and no host behaviour moves, but what the pre-land gate prints and whether it retries moves on the client, so this rides the next release and owes no deploy. the workspace suite is green (4117 passed over 132 binaries, 8 ignored) (#2084) aa28e802 · dbf3dbe6…diff
  • the no-verdict refusal stops telling a lander there is nothing to fix when a doctest really did fail, and the two lists asserted as complete are replaced by the question that decides membership: #2199 asked for every premise to be re-verified on the tree first and each of them held — cargo test here carries no --no-fail-fast, so the step cargo names on stderr is the one that failed and every step it ran before that one passed, and doctest_artifact_form returns the first rlib line whatever else the stream holds, while the two pins that cover those posed the real error and the rlib line in separate fixtures, so nothing saw the combination. the fix is the prose and not the classifier, because deciding which error on a stream is the genuine one is the text guess #2079 declined, while what a run left the gate unable to judge is a fact the gate already holds: unjudged is an exhaustive match over CargoTestFailure that takes no wildcard, so a classification added there cannot inherit a sentence written for a different one, which is exactly how this defect arrived; each run's line in the refusal now carries its own clause, the shared sentence says only that neither run reached a verdict, the heading says neither run reached one rather than neither run judged the tree, and the merged-tree remedy stops saying there is nothing to fix in it. one stream holding a genuinely broken doctest and the held-rlib line is entered as a fixture in both crates, red-first. the verdict-line test stops naming three runbooks that quote it and says what makes something a reader of that line, and ADR 0088 section 4's V4 decline keeps its load-bearing claim while stating the membership question instead of four ways to miss, two of the hits fitting none of the four. Spawner::tee carries a dead drain thread's panic through instead of reading it as empty stdout, which is the pre-#2084 blindness reached by another route. red under mutation, counts read each time: the wide shared sentence restored (196 passed and 1 failed), the ArtifactForm arm inheriting the crash sentence (196 passed and 1 failed), the per-run clause dropped from the layout (196 passed and 1 failed), the heading's coverage claim restored (196 passed and 1 failed), the merged remedy's nothing-to-fix restored (196 passed and 1 failed), the drain panic swallowed again (loot-cli 1344 passed and 1 failed) and the classifier made to weigh the rest of the stream (loot-hygiene 40 passed and 1 failed), each restored to 197 passed, 1345 passed and 41 passed. no migration, no wire or format byte moves and no host behaviour moves, but what a pre-land refusal prints moves on the client, so this rides the next release and owes no deploy. the workspace suite is green (4120 passed over 132 binaries, 8 ignored) (#2199) 0bd49130 · dbf3dbe6…diff
  • the deposit cost test measures the shape its comment claimed and the ships-nothing push is measured rather than assumed: #2206 asked for every premise to be re-verified on the tree first and the leading one holds, the comment saying a peer that already holds the tip while the code passed have = &[], a peer that holds nothing, so what it measured was the shipping push twice — the promotion the zero rests on comes from ride_entry probing every entry of every sent change, and send nothing, promote nothing. the missing shape is on the same fixture now: have = [tip] with no want promotes no address at all, the send pass skipping a held change before it touches the manifest and the wants lane skipping on empty wants, so the deposit plan behind it pays the whole cold walk, 64 object gets and 64 disk reads against the zero disk reads behind a push that ships, which is the cold arm number and not the pushing one. it is recorded rather than repaired and the reason stands where a reader meets it: the waste is plan_standing already-deposited filter, a map lookup, running after each lane has built its list with a store read per row, and putting the ledger first needs the remote and the recipient the lanes take no argument for, which gives the dedupe rule two spellings whose failure direction is a standing self-grant silently not planned, so it is #2208 and ADR 0012 takes an eleventh amendment carrying the number, the measurement and the scope the tenth amendment zero really had. the third Visibility comparison keeps the discriminant and says why rather than leaving it to a later tidy, the value under a tier being unable to move a path between lanes so that reading it withholds a self-grant over a difference that files the key in the same place, with same_seal named as the strictly stricter call it must not become and the row that separates them pinned; the case that doc named and the function cannot see, an entry spelling an embargo instant the seal does not, is gone. the two grant-apply doors asserted as complete become the question that decides membership — Keyring::insert callers against the one filing keyed on obj.vis — at the code, in the ADR and in #2205 body, refresh_hold and the save/load unions being routes the count missed. the silent drop keeps its decline and stops resting on a state an honestly captured tree cannot enter, an ingested tree being the only kind the repair is for. the standing fail-open arm is asserted over both lanes in one comparison, a struct Run no longer collides with a test-local alias, unjudged residual arm stops claiming the suite answered, kept_or_unwind records that its resume orphans the child, and the ungrammatical no-verdict sentence is fixed at the gate doc and in workflow.md. red under mutation, counts read each time: the tier comparison made same_seal (73 passed and 1 failed), the fail-open arm made to drop (73 passed and 1 failed, both lanes empty), the seal question moved ahead of the key guard (73 passed and 1 failed, object_gets reading 65 where 64 belongs), the ships-nothing peer made to hold nothing (73 passed and 1 failed, the bundle opening 65 where 0 belongs), the new pin fixture made to agree (73 passed and 1 failed, the vacuity control firing) and the Internal lane made to stop asking (71 passed and 3 failed), each restored to 74 passed and 0 failed. no migration, no wire or format byte moves, no host behaviour moves and nothing an operator can observe moves, the one string that changed being a clause no refusal quotes today, so this rides the next release and owes no deploy. the workspace suite is green (4128 passed over 132 binaries, 8 ignored) (#2206) 723c7f1e · dbf3dbe6…diff
  • the sync ingest door weighs the seal this store holds rather than the one that arrived beside the key, so a tag-0 bundle spelling a weaker tier at an address this position already owns can no longer file a live embargo's key into the Keyring: #2212 asked for item 1 to be demonstrated before it was repaired and the reproduction read exactly as the ticket claimed, bob holding oid sealed Embargoed 9_000 and a Sync frame carrying a byte-identical object that spells vis Internal beside the real key leaving bob's Keyring holding that key at a clock of 0, which is the state #2205's own new pin forbids reached by changing the frame tag, no plaintext escaping because sealed::open's header gate still refuses. the same read carries grant_ids and that half was demonstrated too, a copy spelling the ANYONE marker over a held Restricted seal getting a key past the entitlement filter #864 built, so every question this door puts to a seal now goes to the copy that will stand at the address. it is asked before the put while the arriving object is still in hand, because first-write-wins makes the held copy the standing one only where the store holds the address at all, so the cost is zero store reads on a fresh address and one on a dedup, which is the read the key verification already owed and now answers the seal's questions with its own; the already-held guard consults both lanes, so the lane the first door chose is the one that stands. the prose is the harder half and the lesson is sharper than do not list members: the sentence that failed was in the correct derived shape, the set of them is Keyring::insert's callers which the compiler enumerates, with a hand-maintained count welded on in the same breath, and the count is the half that was wrong, so every replacement names what decides membership and stops there, at ADR 0007's amendment, escrow.rs, CONTEXT.md, custody.rs twice, ADR 0012's tenth and twelfth amendments, negotiation.rs and the grant-door pin, and escrow.rs's headline stops claiming that no route moves a key between lanes when flush is one and a grant is a new filing at the recipient rather than a carry. secondary items: the stale pin citation and the now-false claim around it, spawn.rs's three false statements about the orphaned child, the unproducible-seal fallback recorded as releasing nothing only at the instant it files, expires_at declined as a term of the staging max with the reason at the code, the demotion refusal naming which of the two recordings fired, the census group sentence that named its members, ADR 0012's push qualifier at the tip with no want, the ingest cost fixture given a publishes-nothing control, workflow.md's three refusals derived from CargoTestFailure and the PRE_LAND constants, a usize subtraction restated as a sum so the sentence beside it can print, and orchestrator.rs's tombstoned pin names declined with the reason. red under mutation, counts read each time: the vis term reverted to the arriving copy (659 passed and 1 failed), the grant_ids term reverted (659 passed and 1 failed), the already-held guard narrowed to the one lane it writes (659 passed and 1 failed), the seal question asked through a second store read (659 passed and 1 failed, object_gets reading 8 where 0 belongs), the lying sync copy made a different object (659 passed and 1 failed, the vacuity control firing), the lying grant ids made to agree (659 passed and 1 failed, the second vacuity control firing), the publishes-nothing control inverted (1353 passed and 1 failed), the refusal made to say both either way (1352 passed and 2 failed) and the ingest cost relation moved by one (1353 passed and 1 failed), each restored to 660 and 1354 passed with 0 failed. no migration, no wire or format byte moves and no host behaviour moves, but which lane a sync-borne key is filed into moves on the client, so this rides the next release and owes no deploy. the workspace suite is green (4140 passed over 132 binaries, 8 ignored) (#2212) c643aadc · dbf3dbe6…diff
  • the land now type-checks sdk/: a new sdk gate, right after the site gate in orchestrator::GATES, runs npm ci, npm run build:wasm and npm run typecheck in the landing position sdk/ (hygiene::SDK_GATE_STEPS), refusing on a failed build or a type error, riding the merged-tree re-gate, skipping under --skip-tests as sdk=SKIPPED, and degrading a provably offline npm ci to sdk=SKIPPED-OFFLINE with a block of its own, so the verdict line gains sdk= after site=; the two npm gates now share run_npm_gate and supersede_offline. the land was chosen over ci/test-main.sh because only a land refuses before main moves and GitHub Actions had not run since 2026-09-19, and over the site gate step because site= would then speak for two packages. measured in a fresh lane: npm ci 1.4 s, build:wasm 17.8 s cold but 1.7 s once the site gate has built the same crate, tsc 1.0 s, the whole gate 5.05 s. proved live through the sdk row with real npm, wasm-pack and tsc: clean, red at npm run typecheck with TS2322 for a string assigned to a number in sdk/src/hex.ts, clean again once removed. ADR 0071 gains the #2080 amendment and CONTEXT.md an SDK gate entry, and workflow.md, the land-change skill and sdk/README.md say what runs and that npm test still does not. red under mutation, counts read each time: the typecheck step dropped (7 passed, 2 failed), the sdk row running the site gate (5 and 4), the sdk= field reading the site slot (7 and 2), the supersede rule reading one fixed gate (8 and 1), an offline install refused rather than degraded (7 and 2), each restored to green. a land runs the primary release loot-first, so the gate is live once those binaries are rebuilt; no migration and no format byte moves, so this owes no deploy. the workspace suite is green (4322 passed over 137 binaries, 12 ignored) (#2080) 072abcc1 · dbf3dbe6…diff
  • the review-sweep fix-up over #2291, #2043 and #2080. loot verify no longer walks past the deferred-bodies refusal: it finds its store by layout through resolve_store_dot and never met the record, so in a store carrying .loot/deferred-bodies it reported a body it had never fetched as missing, and verify --accept-loss wrote that body into .loot/lost as unrecoverable while the remote still held it. the refusal is now decided once, in BodyNeed::admit, which the open (Workspace::assemble) and the layout door both call, so the doors it guards are that function callers: resolve_store_dot takes a BodyNeed, verify declares Held and is refused naming the state, and doctor and config declare the new Unread, since they read no body. the relay doors take none, and loot_net::is_relay records why: each refuses a store without the relay role marker before reading an object, no code that writes the record makes a relay, and gc there removes only objects the store holds; gc --dir, count-objects --dir, relay reap-grants, relay abandon-head and serve --dir were each driven through the binary at a deferred store and each refused it. the refusal now says the verb did not declare it fetches first rather than that it reads a body, since whoami, status and log read none, and doctor, ADR 0093 section 3 and CONTEXT.md say the same; section 3 is restated as the property and records the #2295 correction. false sentences fixed: the counts beside GATES in spawn.rs and orchestrator.rs now point at the rows, the sdk gate doc and SDK_GATE_STEPS say build:wasm can reach the network and refuses rather than degrading there, the in_progress verb and operand docs state the property instead of listing verbs, HUNT-PERF stops counting the reads around the graph load, and the rewrap leftovers in the land-change skill and ADR 0071 are fixed; resolve_store_dot also gets back its own doc, which sat on registered_peer_keys. red first through the binary: verify answered 1 missing (0 passed, 1 failed). red under mutation, counts read each time: verify declaring Unread (1 passed and 1 failed), verify refused but --accept-loss let through, which accepted 1 missing object as lost (1 and 1), the refusal in admit keyed on the wrong need (0 and 2), each restored to green. no migration and no format byte moves, so this owes no deploy. the workspace suite is green (4323 passed over 137 binaries, 12 ignored) (#2295) ded7dfa3 · dbf3dbe6…diff
  • a gate row whose program could not be started now refuses as not run rather than as a finding, the cargo re-run after a first run that reached diagnostics excepted as #2071 decided: impl From<String> for Refusal is gone, so each GATES row names the kind of each refusal where it builds it. spawn::require takes its refusal type from the caller, so the npm gates build a NotRun in the spawn-failure closure and a Finding in the non-zero one, and the lockfile and perf gates carry their spawn failures the same way; gates::guard_with now answers gates::Refused, the CliError plus unstarted, read off the runner outcomes (true when each gate that did not clear never started), which loot new and loot push convert with the same ? and the user-gates row maps to NotRun. an npm step that could not be spawned refuses in its own words, naming the gate, the step, npm as this platform spawns it and the operating system reason, in place of the step failure advice; the offline degrade does not cover it, since it classifies the output of an npm ci that ran. the merged pass gives any NotRun regate_not_run_remedy, which names no program and no longer claims that nothing was built or run, that no gate judged the tree, or that the cause is the machine rather than the tree, each false for some row that now reaches it; a program that never started is re-run nowhere. pinned by a census over GATES that drives each row with every spawn failing (a row that reached the spawner refuses NotRun naming the program and the reason, spawns nothing more, and on the merged pass gets a remedy with neither the ADR 0055 story nor the program) and by its positive control with every step failing (still a finding, still the story on the merged pass); the finding prose of each spawning row was captured before the change and is byte-identical after it. red first against the unchanged code (1 passed and 1 failed). red under mutation, counts read each time, each restored to green: the user-gates row always a finding (1 and 1), always not run (1 and 1, the control), the npm install spawn failure a finding (1 and 1), that spawn retried once (1 and 1), the npm local step spawn failure a finding (0 and 1), the lockfile spawn failure a finding (1 and 1), the perf build spawn failure a finding (1 and 1), the merged NotRun given the cargo clean remedy (1 and 1), given the ADR 0055 story (1 and 1), the npm refusal not naming its program (1 and 1), unstarted read as any rather than each (0 and 1), unstarted forced false (0 and 1), a malformed declaration read as unstarted (0 and 1). ADR 0055 gains a 2193 amendment and the land-change skill no longer names the From default. no migration, no format byte and no published wording moves, so this owes no deploy, but a land runs the primary release loot-first, so this is live only once those binaries are rebuilt. the workspace suite is green (4385 passed over 138 binaries, 12 ignored) (#2193) 20ef1484 · 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.