Changes touching this path
- AI skill: land-change — finalize, review, and land from a lane (#406)
6a5eb60d · dbf3dbe6… - land-change: make the skill a thin pointer to workflow.md (#511)
b4d26432 · dbf3dbe6…diff - Document the describe -m PowerShell truncation trap (#540)
ef744fd6 · dbf3dbe6…diff - Gate loot push on the relay's format major; carry a failed relay push in the land verdict (#519)
6c5cb6e0 · dbf3dbe6…diff - Skills hygiene: adopt the invocation split, give the binary preamble one home, fix describe -m guidance (#561)
d6a368bf · dbf3dbe6…diff - Say that reaping a lane needs the session that spawned it (#564)
d9813a9b · dbf3dbe6…diff - Landing moves the shared primary: correct the catch-up command, warn about readers (#618, #616)
62a99602 · dbf3dbe6…diff - land-change: pick the catch-up command by where HEAD is (#640)
02ade00f · dbf3dbe6…diff - land-change: loot side first, and prove a dirty file is yours before discarding it (#687)
7008a7dd · dbf3dbe6…diff - loot adopt: the git-first catch-up fast-forwards content-identical work unsigned and names foreign paths (#705)
044c84ac · dbf3dbe6…diff - loot-first: land folds a pre-finalized change so the perf point rides it (#725)
d98f26f6 · dbf3dbe6…diff - loot-first: land folds a pre-finalized change so the perf point rides it (#725) (conflict resolution: .claude\skills\land-change\SKILL.md)
64e36708 · dbf3dbe6…diff - a land from the primary refuses when the git checkout is parked on another branch, so a projection can no longer write across someone else's work (#618)
Level A of #618, first half. `reconcile_onto` materializes the reconciled tree
over the running position's disk; from the primary that disk is the shared
checkout, the one position that also carries a .git. Parked on another session's
branch it takes landed content across their working copy — observed live, the
primary ended up holding main's content against research/tracker-prior-art, and
only luck (their work was committed and pushed) made it harmless.
`projection_target` (policy.rs) decides from two facts: the position running the
land, and the branch its checkout is on. A lane's projection writes its own tree
and leaves the primary for its own `loot adopt` (#265), so the guard is silent
there rather than crying wolf on the normal way to work. Off-branch from the
primary refuses, naming the branch; --allow-off-main is the break-glass. An
unreadable branch (detached HEAD, no .git, a git that failed) proceeds but says
the guard did not run, so a broken git cannot mute it silently.
The refuse/proceed decision is carried out on Gate::Proceed's new `note` rather
than re-derived by the caller, so what gets reported cannot drift from what was
decided.
Level A's second half — refuse a primary tree dirty with content that is not
this land's — is deliberately absent: from the primary the implicit snapshot
(ADR 0030) has already captured that dirt into the landing change, and dirt
arriving after the review round is already refused by review_currency (ADR
0033). The residual, recorded in policy.rs: a land with no reviewed_version
takes Currency::Current unconditionally, so that path is still unguarded.
Levels B and C remain open.
c1148309 · dbf3dbe6…diff - adopt: catch up to landed main 795bc2f6
58aa958a · dbf3dbe6…diff - the land-change skill reads the branch= verdict field, so a failed branch reap is no longer reported as a clean land (#650)
d4753206 · dbf3dbe6…diff - the lane runbooks stop assuming a shell that remembers anything (#883)
Found running ticket-to-lane for #867 end to end. Its step 4 exported
LOOT_SESSION in bash and its step 5 said to cd into the lane, all subsequent
work happening there — and neither survives a call here. Variables do not
carry, and this repo resets the working directory back to the primary after
every call, so step 5 certified a state the harness discarded a moment later
and every one of the ~20 later commands needed its own Set-Location.
The reset is a good default, so the runbooks lean into it rather than fight it:
a lane is a path you carry, not a directory you move into. Step 5 becomes Pin
the lane path.
The rule is shared — land-change runs entirely from a lane — so it lands once
in BINARIES.md beside Where you run them, as the fresh shell, with both skills
pointing at it. It names the two things that ride every call and not just the
first: the Set-Location prefix, and $env:LOOT_SESSION, which was written as a
spawn-time formality even though lane gc is session-scoped too and needs the
same label set again in that call.
Three smaller ones from the same run: step 1 gains a
`git log origin/main --grep=(#<n>)` check, because open is not unbuilt here and
a ticket whose work landed under another id stays open until someone notices;
the BINARIES pointer said before step 1 when the first loot call is step 3; and
the primary-only rule was stated three times, so the guardrail bullet folds
into step 4, where its mechanism explains why step 3 checks at all.
The frontmatter description promised the skill cds you into the lane, which the
step 5 change makes untrue — it now says it hands back the path.
3bf849b5 · dbf3dbe6…diff - a land runs from a lane: the position gate replaces #618's checkout guard, and level A is deleted rather than kept beside it (#932, ADR 0050)
b629f752 · dbf3dbe6…diff - the doctrine catches up with the gate: primary-only splits into materializing and not, and the lander stops catching up someone else's tree (#935)
a498c914 · dbf3dbe6…diff - the agent runbooks stop naming one machine: the primary is derived, not spelled, and every hazard says which platform it is about (#1006)
130b15a6 · dbf3dbe6…diff - the primary stops authoring: describe -m and new -m refuse on a shared floor and print the exact lane take that carries the work onward - ADR 0058's loot lane take built, --allow-primary now a triple (#985)
67df9345 · dbf3dbe6…diff - an ADR number stops being picked from a stale position: a land reads landed main and refuses a number it already holds, before it signs the subject that would name it wrong (#1080)
aa99ef0a · dbf3dbe6…diff - a hygiene check runs at the moment that makes it true: the two silent-damage checks move into every land where --skip-tests cannot reach them, the CI net they were said to have turns out not to exist, and the ADR number is re-asked under the lock that makes the answer hold (#1082, #1105)
cd3021b8 · 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 - an offline land skips the site gate loudly instead of refusing, the verdict grows a site= field read like relay=, and only a provable npm network failure ever earns the skip (#1251)
3326a228 · dbf3dbe6…diff - a --skip-tests land that converges stops publishing a merged tree no gate ever saw, because the eight gates are one table now and each declares when it runs, so the re-gate asks that table per gate instead of reading the perf gate's return value as if it spoke for all eight (#1408)
a998f52b · dbf3dbe6…diff - the one flake four runbooks name as the thing to re-run CANNOT FAIL A LAND, and has not been able to for the whole life of the advice: all three describe_contention tests have carried the ignore attribute since #476, whose own subject is move contention stress tests out of the land gate - the gate is cargo test --locked and never passes --ignored, so run directly the file reads 0 passed, 0 failed, 3 ignored. the advice naming it was written by #406 and #404, both ANCESTORS of #476 as merge-base confirms, and nothing updated it when the ground moved. that is the strongest possible argument against writing a list, so what replaces it is the PROPERTY with the fixed instances as examples: the two recurring shapes, a control failure and a Windows sharing error out of a rename or a remove; a four-step triage that captures to a FILE before re-running, reads the COUNT rather than the word, and records that a green re-run is NOT evidence; and an explicit what-would-make-this-section-wrong clause. the concurrency framing this ticket was filed under does not survive anywhere, because the fifth occurrence fired with NO second session running and a process check to prove it - so running alone is not evidence against a flake, and no runbook now says otherwise. the root cause is confirmed FIXED rather than assumed: a statement-scoped census over the WHOLE workspace, not just the crate its own census test covers, reads ten temp_dir occurrences and zero shared roots, each read individually - two are pure string tests, one is a read_dir gated on a prefix that cannot reach the testkit dirs, two are children carrying their own pid, two are false positives whose pid arrives in the next statement, and one derives its stem from a fixture dir both constructors give a pid. the two originally named tests split, and the split is the point. the settled ledger one is COVERED: at the fix parent it read the bare shared root, so resolved() was the single file under TEMP that all 161 fixture sites shared, and a sibling saving an empty ledger between this test save and its load reads back exactly the reported empty map - it is also the test the fix own perturbation experiment PREDICTED and then hit. the persist codec one is NOT covered and never was: it has never used the shared root, its directory has carried a pid and a counter since #252, an ANCESTOR of the fix, so #1667 neither caused nor cures it - its race is its own eight threads renaming onto one destination, and per this ticket explicit non-goal NO RETRY was added, only the two facts recorded where the next reader meets them. and the control-failure signature is corrected before being written down, because tonight refuted its narrowing: #1864 also failed at a control and its medium was a process-global static rather than a directory, so the rule is that a control failure is the signature of SHARED STATE something outside the test wrote, with both media named. it is deliberately not written as therefore it is a flake, because a control can also fail when the change broke the setup path - it says where to look FIRST, not what to conclude (#1606)
c87a13f6 · dbf3dbe6…diff - the catch-up stops leaving its own consequence to a runbook the reader may never have loaded: adopt now prints the git step IT JUST CREATED, and only when it actually moved the tree and the checkout is measurably behind - naming the paths it wrote, which is exactly the set needing the proof. the ancestry is judged on the LOOT GRAPH through the mark map rather than by asking git, because git cannot answer it: the checkout has not fetched the landed commit. there are two arms by position, since which git command is correct depends on where HEAD is, and neither arm ever recommends git before a catch-up, because git-first WEDGES the primary and loot-side-first is and stays the order. and the land closing note is narrowed so its final word about the primary cannot read as being about the checkout: it now says which thing the fast-forward moves, says HEAD does not move with the dock, and names the verb that says the rest. the finding that changed the procedure is bigger than the ticket: the skill had the FETCH AFTER THE PROOFS, and a land pushes main FROM THE MIRROR, while the only fetches a land runs in the checkout are its pre-land drift and ADR guards - so at the exact moment an operator needs this procedure their origin/main is stale by that very land, every landed path reads as differing, and the freshly landed perf point does not resolve at all. followed literally the skill produced the precise wrong conclusion it exists to prevent, so the fetch is hoisted with the reason recorded, and the printed block fetches first by construction. twelve mutations with counts read, of which two are worth the reading. the tenth is a CONTROL: the skill quote wraps across two indented lines, so with the whitespace flattening removed the citation pin reddens over LAYOUT rather than over words, which is what makes the flattening load-bearing rather than decorative. and the fifth is the one to learn from - the lane guard test PASSED WITH THE GUARD DELETED, because the lane was silent for an unrelated reason, landed main having been recorded on the primary so the lane lineage-filtered graph had never seen it and the ancestry answered false. a pass that survives deleting the thing under test is not a pass, so the arrangement was rebuilt with landed main recorded THROUGH the lane and two explicit preconditions proving the lane reaches the checkout and can answer the ancestry at all - after which the same mutation reddens. what is NOT done is said rather than implied: a bare ferry still says nothing about git, its catch-up being a different path, so the note claims only the dock for it; the block deliberately stays silent on a repeat adopt, because its claim is that THIS run wrote over your tree and a no-op cannot make that claim; and none of this was reproduced live (#1679)
c8ebe232 · dbf3dbe6…diff - loot-first land now asks the loot binary it pushes with which FORMAT_MAJOR it writes, through a new loot --version --json that prints the contract and the crate version, and reads the major the landed commit declares out of the mirror. the relay push runs only when both were read and are equal; otherwise the verdict says relay=REFUSED, the land stands, and a final block gives the reason. the landed line gains a trailing pusher= field naming that binary as version/v<major>@path, with UNKNOWN in place of the version and major when it reported neither, and the bare loot --version line is unchanged. stub pushers staged as real child processes pin the refusal, the matched push, a pre-1776 binary and an unreadable tree: removing the equality went red (207 passed, 1 failed), pushing past the refusal went red (205 passed, 3 failed), trusting the linked constant instead of asking went red (206 passed, 2 failed) and dropping the field went red (202 passed, 6 failed), and the spawned --version --json pin was red before the shape existed (0 passed, 1 failed). the land-change and afk-loop skills, workflow.md, CONTEXT.md, ADR 0023 and ADR 0088 follow. the workspace suite is green (#1776)
d3e2f994 · dbf3dbe6…diff - review sweep 7 fix-up: loot-first now reads loot --version --json with a JSON parser, so the relay push is decided on a single JSON object whose top-level contract fits a u8 and whose top-level version is a string, in any key order and beside other fields, while a duplicated field, trailing text or a looser number refuses the push. the pusher= path now percent-encodes control characters as well as percent signs and whitespace, and workflow.md says so. land-change gains the relay=REFUSED recovery (catch the primary up, cargo build --release, check the contract loot --version --json prints against the major the landed commit declares, then loot push, and record the push output on the issue), says the refused block names both majors on a mismatch and a read failure otherwise, and stops counting the relay and branch states. afk-loop agrees that a FAILED or REFUSED land stands and owes a push, gains that push as a step, and counts the ticket done once the push is recorded on the issue. format.rs, ADR 0066 and ADR 0083 note that a land carrying a FORMAT_MAJOR bump normally comes out relay=REFUSED rather than FAILED, and the --version usage line, the print_out and dispatcher comments and a verdict test name follow. both new pins went red before the change (2 passed, 2 failed), the control-character pin went red with that arm removed (1 passed, 1 failed), and a serde_json Value reader went red on the duplicated field (1 passed, 1 failed). the workspace suite is green (#1979)
ce994e1d · dbf3dbe6…diff - review sweep 8 fix-up: the owed relay push recovery now lives once, in a new workflow.md section, paying an owed relay push, which covers relay=FAILED and relay=REFUSED in both shells with the position on every command, the build job cap and the in-flight guard, and states one done-when: the push succeeded, or its format skew is recorded on the issue as owed to the release relay redeploy. land-change and afk-loop point at it instead of carrying their drifted copies, afk-loop refers to that item and to its sections by name rather than by step number, as AGENTS.md now does too, and its when-it-goes-wrong list gains relay=FAILED. probe_pusher now says why a report was refused, with the parser message or the version check, and keeps the pre-1776 explanation for output that does not open a JSON object, and the pusher= docs say UNKNOWN means the report was not read. the new pin and the tightened pre-1776 pin went red before the change (0 passed, 2 failed), and red again with the pre-1776 arm removed (9 passed, 1 failed) and with the pre-1776 explanation given for the new pin reports (9 passed, 1 failed). LanePeek becomes a struct and a dead unwrap_or_default becomes an expect, the 4.2 s lanes figures in heads.rs and lanes.rs are labelled as history, the PositionHalf doc credits the reorder with matching the documented load order, the ObjectIndexScan doc no longer names its CLI consumer, ADR 0028 says merge_tips reads tree_at itself, and rewrap leftovers in land-change, format.rs and CONTEXT.md are joined. the workspace suite is green (#1983)
2ee76c18 · dbf3dbe6…diff - 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 - a cargo that could not be started gets its own refusal and the merged pass stops sending that lander after a combination nothing compiled: #2066 asked where a failed spawn belongs and the answer is a kind of its own rather than the no-answer one #2071 sharpened, because NoAnswer needs a crash on both runs while a spawn failure is never re-run at all, an emptied incremental cache being unable to put a program on PATH, and because its remedy is cargo clean, a cargo command for an operator whose cargo would not start, which is the #944/#962 shape of naming a remedy the tool then declines. the premise verified on the tree, where cargo_test_once minted a Refusal::Finding for the one thing a Spawner Err can mean and merged_refusal handed that to regate_remedy, the ADR 0055 semantic-conflict story plus loot edit. cargo_test_once returns the operating system reason as text now and the gate, which knows what the first run reached, decides the kind: Refusal::NotRun under a PRE_LAND_NOT_RUN heading, whose merged remedy keeps the lane-state facts and drops both the loot edit procedure and the cargo clean, naming the machine instead. the #2071 rule is asked of the new kind too, so a re-run that could not start after a first run that reached diagnostics stays a finding, those diagnostics being the only verdict either run reached, and the retry is deliberately not widened to a missing program. red under mutation, counts read each time: the first-run spawn arm minting a Finding again (191 passed and 1 failed, the refusal reading Finding where NotRun belongs), NotRun routed to the no-answer remedy (191 passed and 1 failed, cargo clean back in the merged prose), the diagnostics-then-spawn case made a NotRun (191 passed and 1 failed), the first-run spawn failure sent on to the re-run (191 passed and 1 failed, the fake naming an unstubbed second cargo test) and the heading taken off the not-run prose (190 passed and 2 failed), each restored to 192 passed and 0 failed. workflow.md and the land-change skill carry the third heading and point at the Refusal enum as what defines the set, and the From impl records that the other spawning gates are still on the finding default. no migration, no wire or format byte moves and no host behaviour moves, but what a merged-tree gate prints moves on the client, so this rides the next release and owes no deploy. the workspace suite is green (4109 passed over 132 binaries, 8 ignored) (#2066)
510752c3 · dbf3dbe6…diff - the permissive deposit arm gets the pin its defence was resting on, the standing-lane assertion that could not fail gets a comparison, and the declined cross-shape census weighs the instrument it never considered: #2194 carries the sweep 14 fix-ups plus the five a focused review of #2188 found, each premise re-verified on the tree first. item 8 is judged kept rather than closed to match its siblings, because where the seal cannot be produced embargoed_paths keeps the tree entry claim and the tree entry instant, which an unsigned tree can spell 0, and the recorded defence is real, grant_sealed reading the same object through the same door before it seals anything; so the arm stays and both halves are asserted now, the row surviving with the number the entry chose and the grant that row plans refusing at the same address, under a control that the same call succeeds while the seal reads. item 9 is made to bite: a second path over the same Restricted seal is entered honestly, so the standing-lane arm is a comparison rather than an absence, and the comment names the mutation that reddens it. item 10 narrows a pin message that reached past what it asserted, onto the deposit-plan pins that do assert the fan-out. item 1 corrects the ADR 0023 cost paragraph, which named the spool leaf where the endpoint moved too, off an unescaped format string onto the shared escaping, so an endpoint holding a quote or a backslash had been emitting JSON a parser rejects; the matching commit correction is already a comment on #1971. item 3 weighs the text census and records a measurement instead of an assumption: it needs no visibility widening and spawns nothing, so no census can was the wrong shape of decline, but what a text census reads is a spelling and section 3 is a rule about rendered bytes, and measured, the comma-join needle finds its own home and sites that are not columns while the contract field is not spelled one way, so a needle on either spelling reads a subset and says nothing about a shape carrying no such field at all, which is the defect #1971 came here to fix. item 2 replaces a false inference in the land-change skill: those three headings belong to the cargo test gate, and every other gate arrives as a finding under prose of its own, the line-ending gate among them, so an unfamiliar heading is another gate before it is a new kind; workflow.md scopes the same sentence. item 11 takes the completeness claim off the deposit accessor doc, where privacy is what bounds the callers, and off the census block that asserted a key guard over a membership rule which does not check it. item 12 names the two readers still deciding off the entry, the mirror projection and the forge manifest fold, with what bounds each, and records that neither belongs to #2187. items 4 to 7 are the smells: the forwarding closure, the clone taken and then borrowed, the exemption pin that read the real machine config and now builds its report from values, and the reversed import. red under mutation, counts read each time: the unreadable-seal arm dropped (68 passed and 1 failed, the row reading empty), that arm handing on a substituted instant (68 passed and 1 failed, 9999 where 0 belongs), restricted_paths made to ask the seal (68 passed and 1 failed, secret.txt joining owned.txt in the standing lane), a contract field added to the report the sender posts (6 passed and 2 failed) and joined_col joining with a semicolon (loot-cli 1335 passed and 8 failed), each restored to 69 passed and 0 failed. no migration, no wire or format byte moves and no host behaviour moves, and no output byte moves either, every code edit here being a refactor or a test, so this owes no deploy. the workspace suite is green (4110 passed over 132 binaries, 8 ignored) (#2194)
609afd9f · dbf3dbe6…diff - the adr guard says on the verdict line that its fetch did not answer, and the test whose subject is that fetch asks whether it ran before it reads the refusal: #2140 was filed from a land refused by the_adr_guard_fetches_the_collision_the_local_refs_still_hide under the note that origin could not be reached, which is the documented degrade, so the guard did exactly what it promises and the test failed anyway with a message naming a property rather than a cause. the premise was narrowed on the tree first, and the ticket asks for that: the test never reaches a real origin at all, origin_and_clone builds a git repo under the temp dir and clones it, so pointing it at a local fixture remote was already done and what failed in the sighting was a local git fetch. severing that remote reproduces the sighting byte for byte, the same note above the same panic reading the fetch must surface the collision the local refs hide, so the condition was made rather than waited for. the ask carries its degrade out now as well as speaking it: refuse_adr_collision returns an AdrAsk of a refusal and a reason, git_fetch_main says which step did not answer instead of a bare none, and the note both fetch-before-read guards share quotes that reason, the sighting having captured nothing beyond the note itself. the test reads the fetch before the refusal, so under the same severed remote it says the fetch did not run and that it measured nothing about the collision, with the reason beside it. the loudness question is answered yes and recorded as an ADR 0065 amendment: a degraded guard reaches the verdict line as adr=STALE-REFS with a block under it, on the #1251 posture, because the note from the first ask lands minutes of cargo and npm above the verdict and what a stale answer can publish is a duplicate ADR number on main, which is #1080 itself. the field reports the last ask a land made, every ask putting the same question to the same landed main, so an ask that fetched supersedes one that did not. red under mutation, counts read each time: the ask dropping its reason again (190 passed and 3 failed), the pass no longer recording it (192 passed and 1 failed), the verdict word made unconditional (191 passed and 2 failed), the block taken off (191 passed and 2 failed), the reason no longer naming the step (191 passed and 2 failed) and the kill no longer naming the bound it happened at (192 passed and 1 failed), each restored to 193 passed and 0 failed. no migration, no wire or format byte moves and no host behaviour moves, but what a land prints on its verdict line moves, so this rides the next release and owes no deploy. the workspace suite is green (4111 passed over 132 binaries, 8 ignored) (#2140)
17277998 · 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 - every land now states which versions it published that the lander did not write, and refuses nothing - ADR 0092's detection half, part 1 of 2 of this ticket. a version is foreign when its author is not in the lander's own key set, which is new: loot_identity::own_signing_keys reads the active id.pub plus every id.pub.rotated archive that loot id rotate writes, exposed as Workspace::own_signing_keys beside author_pubkey rather than instead of it, because the two answer different questions. carry_line's Foreign asks may I RE-AUTHOR this and only the current key can sign, while the gate asks did I WRITE this and authorship is historical, so a rotated operator's own change is foreign to the carry and theirs to the gate and both are right - each site now names its own question and points at the other, since unifying them breaks a caller in either direction. the judged set is the ancestor closure of the landed change minus the closure of the main it was judged against, read BEFORE the pass because by verdict time main already includes the landed change and the difference would be empty on every land, and it is the whole closure rather than carry_line's first-parent chain because a stack carrying a merge of its own would otherwise have one side waved through. an absent author is foreign, which is carry_line's answer too, so the two predicates disagree only about which keys are mine. the count rides the verdict line as foreign= and a block names the versions, since the count says that and the next question is which. foreign= sits immediately BEFORE pusher= and not after it, which I got wrong first: pusher= carries an arbitrary percent-encoded path and is designed as the tail, workflow.md says the path comes last, and five pusher tests read it with ends_with - appending after it broke exactly those, while inserting before it breaks only a fixed-index reader and the repo has none, and those five pass unmodified. the key set reads only id.pub.rotated and never the private id.rotated spelling, which holds a secret key and has no business answering a question about authorship. a machine that pulled rather than rotated holds no archive, so there your own pre-rotation work reads as foreign, which fails toward asking for an approval nobody owed and never toward waiving one, and the block and workflow.md both say so. red under mutation, counts read each time: the key set ignoring the archive (52 passed and 1 failed), the filter admitting the private archive spelling (52 passed and 1 failed), and an unauthored change read as the lander's own (202 passed and 1 failed), each restored to 53, 53 and 203. ADR 0092's status now says which sections are built, because section 5 - the gating column, review/approve and the refusals - is part 2 and until it lands detection reports and nothing refuses, which is that section's decided default anyway. no migration, no wire or format byte moves, and nothing on a host moves, so this owes no deploy. the workspace suite is green (4189 passed over 133 binaries) (#2178)
8cb77a56 · dbf3dbe6…diff - the offline site gate block stops stating its compensating detector as a fact, the shape #2071 fixed one block over: site-main.yml is still named as the net, but only if the land moved a path on its list and only when that job actually runs, which nothing in the land can see, and the fix line now says npm ci and npm run gate in site/ answers on this machine whether or not that job ran. the block does not hard-code whether Actions minutes exist, though the latest site-main.yml run was refused for account billing, the state #1916 found for test-main.yml. ci/local.sh is not named because what ci/test-main.sh runs of the site is its live-database pg tests and not the gate, and the comment there that said a land runs the gate only when it moves a site path and that site-main.yml runs it on main now says neither. land-change and workflow.md, which paraphrase the block, carry the same qualifier. the existing byte-for-byte pin over the block is moved to the new text and went red first (0 passed and 1 failed); red under mutation, counts read each time: the new qualifier dropped from the net line (0 passed and 1 failed) and the fix line put back to its old ending (0 passed and 1 failed), each restored to 1 passed. no migration, no wire or format byte moves and no host behaviour moves, so this owes no deploy. the workspace suite is green (4179 passed over 133 binaries, 9 ignored) (#2074)
c136bcb2 · 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 merged-tree re-gate that fails stops asserting a cause it cannot know: regate_remedy no longer says the change is green on its own and breaks combined, and says instead what the gate knows, that the merged tree failed it after the tree of the lane itself got through the pre-land pass, naming the combination and a run that failed for a reason outside the tree (a Windows file lock, a timeout under load) as causes it cannot tell apart; its recovery is ordered, re-run what failed alone and read the count, change nothing and re-land if it passes, and only if it fails again the loot edit procedure. the finding stays a finding: a test ran and failed, so the kind was right and the claim was wrong. the cargo test gate now names each failing test libtest reported under the unchanged pre-land cargo test failed heading, through hygiene::failed_tests, and beside a test whose own captured block carries a spelling in hygiene::SHARING_OS_ERRORS it says Windows returns that when another handle holds the file and that a lock and a defect both produce it (#2233 was a defect), deciding nothing on it: no retry and no skip. the plain pre-land finding and the merged finding are pinned whole over the #2079 shape, concurrent_stage_of_same_address_does_not_tear red on os error 5. red under mutation, counts read each time: the old ADR 0055 story restored (2 passed and 1 failed), cargo_test_once naming nothing (0 and 3), the first-run finding without its names (1 and 2), the re-run finding without its names (2 and 1), a lock-shaped failure re-run (1 and 2), the sharing error searched over the whole stdout (hygiene 1 and 1), the block not stopped at the next test header (1 and 1), the code matched without its closing paren (0 and 2), the FAILED line matched mid-line (1 and 1), each restored to green. ADR 0055 gains a #2310 amendment, and workflow.md and the land-change skill carry the ordered recovery and the failed lines. 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 (4356 passed over 137 binaries, 12 ignored) (#2310)
157034cc · 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 - the review-sweep fix-up over #2308, #2310, #2311, #2312 and #2313. the lock note beside a failed test is said only on a Windows land: loot-hygiene failed_tests now takes whether the run was on Windows, since os error 5 and 32 are an I/O error and a broken pipe on macOS and Linux, and loot-first passes cfg!(windows); both answers are pinned on this host, red under mutation with counts read each time (recognised everywhere 2 passed and 1 failed, nowhere 0 and 3, loot-first passing false 1 and 4). the plain pre-land test finding now prints the re-run-first recovery the merged pass prints, for each gate row that runs programs and rides the merged pass, derived from the row and pinned whole (no triage 3 and 2, ignoring the merged pass or the row judgement 4 and 1 each, the order swapped 4 and 1). the timing line noun is a ServerKind enum whose relay and forge lines are pinned byte for byte (a misspelled noun 7 and 1), and the loot-s3 put refusal calls the idle duration the idle budget and keeps floor for the rate (the old word 18 and 1). tutorial.rs qualifies the #2311 halt as run on Windows and reasoned elsewhere, and a reap failure no longer prints could not run; ADR 0075 names the graph read by MetadataStore::repo_change_graph and its callers rather than a list that missed propose::admit; sync.rs states the store property the scoped forge offer rests on and what would break it, and its round-zero comments speak of the remote; land-change SKILL.md, workflow.md and ADR 0055 carry the re-run-first order and the Windows-only note. the (idle, uplink_floor) data clump in loot-s3 is left as it is. no migration, format byte or wire byte moves; the loot-first change is live once the primary release binaries are rebuilt. the workspace suite is green (4406 passed over 139 binaries, 13 ignored) (#2348)
77d9c94c · dbf3dbe6…diff - a plain loot ferry in a lane refuses to project anything no land has carried, where it projected the lane unlanded line onto the mirror main every position shares so the next land from any of them pushed it unreviewed: the pass asks what it would project before the ingest and again at the gate seam after the reconcile, since --seal-wip can seal into the line, and loot-first land marks its own pass with RunOpts landing; a lane catch-up that projects nothing runs as before, and the refusal names the land of the PR that carries the lane tip or else the fresh-lane route of #962. the review reap says landed only from a land pass, on main for a projected version otherwise, and signed, no land has carried it for an unprojected one, where it said landed for any signed version. the seal-wip recovery recipe is chosen by position: the primary keeps its follow-up round and a lane gets the fresh-lane route, one const shared with the #2314 refusal. reproduced through the 0.4.24 binaries in a scratch repo with its own lanes (the advised ferry projected 2 lane changes and printed landed) and checked through the lane-built binary (refused, mirror main unmoved, lane catch-up still runs, reap and recipe reworded). the lane-simulated lands in the ferry tests now run as land passes, and 2 primary reap pins read on main. pinned by six new tests; red with each piece undone, counts read each time, each restored green over the ferry tests: the guard off (69 passed and 3 failed), a land pass refused too (61 and 11), every lane pass refused (70 and 2), the seam ask dropped (71 and 1), the PR route dropped (71 and 1), the old reap word (69 and 3), the recipe always the primary one (71 and 1) or always the lane one (71 and 1). ADR 0039 amended, CONTEXT.md, concurrent.md and the land-change skill updated. no format constant, codec byte or migration moves. the workspace suite is green (4442 passed over 139 binaries, 13 ignored) (#2366)
dac3385d · dbf3dbe6…diff - a land from a lane syncs origin from the primary: origin is now the forge (#2388) and loot push refuses to push a lane to a forge (ADR 0075, unchanged), so the post-land sync that pushed in the landing position was refused on every lane land. from a lane the sync now runs loot adopt then loot push in the primary checkout, after reading the primary in-process and refusing by name, before touching it, when it holds a non-empty working change or carries finalized changes landed main does not contain (so nothing unreviewed is published to origin), failing closed when that cannot be read; a primary land still pushes in position. the harbor is held until the sync finishes so two lands cannot write the primary at once, the #1776 format check still runs first, and the verdict keeps relay= and its tokens, a primary that holds work spelling REFUSED with a block that says what to clear; the block headings and fix text now say origin, and workflow.md and the land-change skill say what the land now does. nine new tests over the spawner and real primaries, each red under a named mutation and restored; loot-first 239 lib tests, workspace suite 4542 passed over 141 binaries, 13 ignored. live only once the primary release binaries are rebuilt (#2390)
b6484d1b · 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.