Changes touching this path

  • verbs/: seam scaffold + the repo family (init/clone/config) (#661) 28849eaa · dbf3dbe6…
  • verbs/change: the working-change family (status/diff/describe/new/edit/abandon/adopt) (#661) cfae20f3 · dbf3dbe6…diff
  • edit guard agrees with status; premature-finalize remedies tell the truth (#682, #683) c78e9a39 · dbf3dbe6…diff
  • a view step refuses over work no change records, and a primary finalize says so on stderr (#436) a3248ede · dbf3dbe6…diff
  • a path publish tier rides the delta itself, so diff and status stop disagreeing about what is published (#786) c98b2dad · dbf3dbe6…diff
  • loot diff --stat counts the lines each path moved, and a path it cannot read says why rather than reporting zero (#416) 08d586c7 · dbf3dbe6…diff
  • the change graph gets one read view, and the two forwarding bands over it retire (#868) 826c3339 · dbf3dbe6…diff
  • not a lane is not the same as shared: the finalize notice stops telling clone users their private tree is crowded (#967) The #436 warning fired on `lane_id().is_none()`, which is true of the dev primary AND of every clone (ADR 0026) — and then asserted that other sessions share the tree and pointed at `loot lane new`. In a clone every clause is false: separate repo, own store, own keypair, nobody else in it, and the clone already IS the isolation. Its audience is the reader least able to catch that, because a clone exists for a different AUTHOR (ADR 0047). The position now asks the store how many other positions exist over it (`registered_lane_count`, the registry read without the per-lane peek — a finalize is not the place to pay a `loot lanes` sweep) instead of inferring it from its own name. That is a fact rather than a guess and it is right in both directions the moment it changes. Two texts, because the hazard has two sizes and saying the larger one everywhere costs the smaller one its credibility. With siblings: named, counted, and the lane remedy. Without: the half that is always true — this signed the tree in front of you, `loot undo` steps it back. ⚠ The old #436 test asserted the sharing clause over a freshly init-ed repo with no lanes at all — byte-for-byte the state of a clone — so it was pinning the bug. It now spawns a lane first, to MAKE the claim true rather than assume it, and #967 gets its own test for the negative. Proven by running it: a lane-less repo says `directly on the working tree (no lane)`, and the same repo one `lane new` later says `1 lane live over this store — they share it`. 2f805d57 · dbf3dbe6…diff
  • the second machine's bridge stops being frozen: ferry learns landed main from the checkout, and adopt says when its answer is stale (#1000) 93bce6cc · dbf3dbe6…diff
  • status names landed content instead of letting it read as your edits, and the bootstrap actually puts loot on PATH (#1010, #1009) d6cddffa · 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
  • 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
  • the one-place path spellings become reachable and reach: tree_path goes pub(crate) and covers the five walk-derived surfaces that could not call it, lane merge stops being the face #1049 missed, and two doc claims shrink to what is true (#1063) 94908511 · dbf3dbe6…diff
  • a verb that could only publish to main unreviewed is retired: lane merge goes, its fold machinery stays where adopt needs it, and the mirror-free fold that genuinely leaves with it is named rather than glossed (#1048) 3f7635a9 · dbf3dbe6…diff
  • every durable .loot artifact declares its format discipline in one inventory, and the fixed-width set files refuse malformed bytes instead of reading as empty (#1135) 58072a13 · dbf3dbe6…diff
  • a seal to a holder list that excludes its author refuses and names what nobody could ever open, --allow-lockout is the deliberate way through, and ADR 0038 records why the gate refuses rather than filing a key for the author (#1249) bbb858b0 · dbf3dbe6…diff
  • the consent slices become one Allowances struct a swap cannot compile against, the lockout gate calls the engine predicate it used to mirror, and the site gate steps destructure so a third step stops compiling (#1272) ac6e2096 · dbf3dbe6…diff
  • three papercuts from the alpha sweep: a defaulted diff on a clean tree agrees with status instead of exiting 1, evolog's when column shows the authored clock instead of the git-bridge stamp while porcelain keeps the frozen one, and view stops claiming a deletion it never performs and counts what it left on disk 19473311 · dbf3dbe6…diff
  • the four consents become one owned Consents parsed and rebased at a single argv door, so allow-demote stops travelling a route of its own and the transposition Allowances was built to prevent has one place left that could still make it instead of eight ffb85a76 · dbf3dbe6…diff
  • a signing seam reads the working tree once and walks it once, so describe and land stop buying two whole-tree byte reads to look at file names, and loot-perf grows the capture timing that can see it (#1383) 31995cb5 · dbf3dbe6…diff
  • the three hints that speak when a git pull ran ahead of a loot pull say one thing, and the hazard names loot new, the verb that actually signs, instead of describe, which does not (#1391) 7a273f8d · dbf3dbe6…diff
  • the landed-content hazard names loot edit, the second route to the same signature, because reopening a finalized change carries its handle and the loot new that closes the amend signs under it, and the block three hints rebuilt by hand at an indent a comment asked for is now assembled once in landed.rs (#1404) 909e8b37 · dbf3dbe6…diff
  • deleting a named read on Workspace stops being free, because the 377 places that reached past it into the engine and the store now go through those faces instead — repo() no longer exists, store() is module-private, and the three extracted children share their fixtures by name rather than through the parent's private test module (#1411) c454db04 · dbf3dbe6…diff
  • a second renderer stops being able to disagree with the first about which paths changed, because "what changed between two points" is now one seam taking (from, to, pathspec) whose endpoints may be a recorded change or the live working tree, and the six-rung content ladder and the in-the-clear plaintext count moved into it — so a renderer formats a number it is handed instead of tallying its own, and status and diff stop computing the same delta twice (#1541) 289ddd4e · dbf3dbe6…diff
  • the everyday `loot diff` stops answering about a change instead of about your work, because the endpoint you did not type is now the disk — one rule replacing two defaults, so `status` and `diff` read one DeltaSpec rather than two spellings of it, and seeing your own uncaptured edits no longer costs you a subject line you have not thought of yet (#1491) f07d74e7 · dbf3dbe6…diff
  • loot status stops reading the whole working tree twice, because the working row and the pending delta now come from one walk taken through the door #1383 built for exactly this verb, and that walk's plaintext moves into the live side rather than being copied out of a tree nobody reads again, while the read-only door finally carries a number: a cli-tier status sample whose control refuses the two shapes that read the tree fewer times, and a test-only walk counter that pins the count at one (#1549) 8a9411f2 · dbf3dbe6…diff
  • loot status stops re-reading .lootattributes once per listed path, because the publish column now comes from the one-load derivation #481 built for exactly this, so a 2000-path listing pays one policy read instead of 2001 and that count is pinned as a number that does not grow with the tree, while the two whole-tree decrypts this ticket named measure at 1.5 ms and 4 ms and are left alone with those numbers written at the seams (#1591) 24dd342b · 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
  • the pathspec option group gets its first production consumer, and being inert turns out to have been invisible by construction: all five .groups attachments sat inside cfg(test), so Pathspec::keep returned at its is_active guard on every production call and no test could see it, because a filter that never runs changes no output - which is why delta.rs claimed in the present tense that diff, status and show were all served by that line while none of them attached the group. diff and status now attach it, diff narrowing at #1541's seam so rows, --stat and --content inherit one filter rather than each applying its own, and a -- separator arrives with it because a pathspec needs a way to say the rest are paths. Two states the ticket did not name are where the real bugs were. status builds its delta lazily, gated on the human format, so --porcelain and --json never reached the seam at all and attaching the group alone would have left both machine formats printing an unfiltered listing at exit 0 - the format an agent reads, which is the caller this class is dangerous to; and with no working change status returns before reading the tree, so loot status zzz would still have exited 0 in the primary checkout while passing every test on a seeded temp repo, since a seeded repo is never empty. Both are now answered from the seam, the second gated on is_active so pathless callers pay nothing. status also stops silently dropping its argument, which removes it from OPEN_BUT_TAKES_NONE and leaves 23 - by the other route, taking paths properly rather than declaring NO_ARGS, and the list's prose implies the latter is the fix for the names still on it, which would foreclose the better answer for surface, converge and ferry. The false sentence is narrowed rather than deleted and carries why it was written a ticket early, in delta.rs, flags.rs, the census doc and CONTEXT.md. Eight breakages proved the tests non-vacuous, planned before they were written, and dropping both attachments - the exact pre-ticket inert state - turns six of six process tests red plus the census pin (#1493) 35ed624c · dbf3dbe6…diff
  • loot show becomes the fourth rendering over the one delta seam and grows no differ of its own: it calls Endpoint::base, ws.content_delta and render_delta, produces no hunk, counts no line and matches no content, and the pin is byte equality rather than shape - show ends with exactly the bytes loot diff --content <parent> <sel> produces in both content and stat modes, with the leftover prefix asserted to name no path, hold no hunk header and hold no disclosure line, so a second opinion about the parent or a renderer choosing its own words for the seam's tally both go red. Four breakages proved it, and a fifth attempt was a false negative caught by its author: truncating to the last newline is a no-op, so it passed, which is exactly as misleading as a vacuous test and is why it is named here rather than quietly replaced. Three of this ticket's premises were wrong. The two commands it says reading a change takes are really one command plus reading a parent id out of loot log by eye, because <version-prefix>~1 is not a form the #305 grammar spells and only HEAD~<n> is. Subject does not mean what the criteria assume: the tree defines it as the first line of the message and this repo writes single-line paragraphs, so the first run printed a two-thousand-character subject row - nothing truncates anywhere in the CLI, so rather than invent a rule the subject moves to the last header row, above the diff where git show puts the body, instead of pushing the lineage off screen. And the no-selector arm was ambiguous in a way that made the first message false: loot status prints a live working-change row computed off the disk under ADR 0030 while working_id and the @ selector both say there is none, so saying nothing is in progress contradicted the verb next door about the same tree - the message now names which absence it is, explains the live row, and points at diff and status, and show is deliberately not widened to render anchor against disk, because that delta is bare loot diff's by construction and a second verb answering it under a header claiming a non-durable version id is the duplication #1541 deleted. A merge names which parent it is taken against and prints the command for the other side rather than pretending the diff is whole. PROSE_ONLY_CEILING rises 50 to 51 deliberately with its reason written beside it, which is the mechanism landed one change ago doing what it was built for, and a pre-existing comment claiming the arity gate is a no-op for all but one verb is repointed at the property since it has been four for some time (#1492) 7ff52d8e · 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
  • the dirty question stops reading every file to answer one boolean, and the two clocks it depends on are not the same clock: a stat cache lands at .loot/<position>/stat-cache as a PositionOwned artifact the store treats as opaque bytes, so nothing derived from it reaches the graph, a manifest, a bundle, the wire or any peer - its version header is a local self-check whose only failure mode is read as no cache, which is the opposite of a compatibility break since an older loot does the full read and gets the same answer. An entry is trusted only when size and mtime match AND mtime is older than the walk's own stamp, so a write inside the walk's tick is always re-read and no granularity is assumed on any platform. What that missed on the first attempt is that the stamp comes from the PROCESS clock and every mtime from the FILESYSTEM clock, which on Windows are the precise and coarse system times about 15.6 ms apart - warm scans hit nothing at all, because the cache file's own mtime read as older than the stamp it carried. A one-second margin fixes it in the safe direction and is self-healing, and gross skew is caught separately by discarding a table whose file is older than the stamp it declares. loot lanes reads a foreign lane's cache and deliberately never writes one: the write would have been correct, and it was refused on a different ground, that ticket-to-lane's runbook promises this verb is read-only and agents run it against live lanes to read the claim board. So TreeScan has two named doors, read for a position walking its own tree and peek for one walking someone else's, and which a seam takes is spelled at the call site rather than inferred from the store it was handed. The cost of that refusal is named rather than hidden: with lanes warm, which is the steady state since every lane's session runs status, it is 13.6 to 16.8 percent against the 16.1 the write bought, and with every lane cold it falls to 4.5, which is not the cache at all but the seam now hashing each plaintext once where it hashed twice. status --porcelain is 24.8 percent. And the pin that #1536 asked for cannot do the job it was asked for: delete the cache and get the same answer passes on every answer assertion even when the cache is never consulted, because an inert cache answers correctly by doing all the work - what distinguishes them is counting hits and reads, whose cold zero-and-N is its own positive control, and a poisoned row that keeps size and mtime, carries a wrong digest over a genuinely clean tree, and must answer dirty. Three of this ticket's premises were also wrong: the 46 ms status baseline was measured where status never walks the tree, since with no working change it returns at is_clean, so the gap over the control was never the tree read; the byte read is a quarter of what holds these verbs up rather than the whole of it; and human status on a dirty tree cannot benefit at all, because rendering a per-path delta needs the plaintext (#1669) 96d922e8 · dbf3dbe6…diff
  • every conflict-stopping verb gets a named way out, and building it corrected the ticket in both directions rather than just adding flags: merge does not stop on a conflict at all, since merge_tips records the triples and fold_onto then signs the merge node and materializes the merged tree, so an abort there is a view step off signed history rather than the forgetting of a stop; while cherry-pick, revert and squash do the opposite and return before writing anything of their own, so their stop leaves even the paths that merged cleanly unapplied. the five named verbs are also not the whole set: converge, pull, adopt and ferrys carry bounce reach the same fold and the same ingest, and the stale-disk settle files a conflict on the way past any capturing verb with no operation behind it at all, so the covered set is now a census rather than an assumption. the state is one position-owned artifact at .loot/position/in-progress carrying the verb, its operand, and the op-log index the view sat at before the verb ran, declared Refuse on malformed content because a torn record read as absent answers nothing to abort over a tree that really is mid-operation, which is the single failure the record exists to prevent. it is a real artifact rather than a derivation because conflicts-are-non-empty-and-the-newest-op-is-a-stopping-verb answers no the instant the last resolve lands, which is exactly when continue must still work. nothing here re-implements a rollback: the inventory row is Captured at ordinal 7, so abort is that one index handed to op restore, which already restores the view, re-materializes the tree, refuses over edits made after the stop, and appends the compensating operation the op-log criterion asked for; force is declared on the five verbs and refused without abort. continue closes the stop rather than replaying it, because the re-run was built first and measured to reproduce the identical conflict: these verbs are capture-first and a resolve on the pre-dock home position never writes the tree, so the closure states instead that the operation applied nothing. status and conflicts name the operation through one derivation, and the pin asserts the identical line in both (#1506) 21b9faf1 · dbf3dbe6…diff
  • the cardinal beside a growing list is deleted rather than corrected, and a census now refuses its return: every prose count of the stopping verbs is gone from resume.rs, pick.rs, lib.rs, main.rs and ADR 0080, and no_prose_beside_stopping_states_a_count fails any comment paragraph whose subject is that family and that puts a quantifier within three words of a noun the family comes one of per member. scope is a paragraph rather than a file because a cardinal is ordinary english and this crate is full of correct ones; run over the whole crates tree it selected the wrong sentences and nothing else, in both directions, and both controls sit in the body. the ADR half is amended by hand and left unguarded, said so rather than implied, because the same gate cannot be made quiet over a document whose every paragraph is about that family and which states correct cardinals about other closed sets. the class was also wider than the eleven sites the ticket listed: hand written verb enumerations in change.rs, in resume.rs and in ADR 0080 had gone false on the same day and are now derived or generalised. the detached doc block is reattached to resolve_sub with subcommand_word given its own, and the sweep the ticket asked for found a SECOND instance it did not name, since 1799 inserted STOPPING between the no positionals census and its 45 line doc, leaving that test undocumented ever since; both are repaired and no guard is offered, because a correct sentence attached to the wrong item is lexically identical to a wrapped paragraph. ADR 0082 is brought to house style and pinned, and what is pinned is less than the ticket claimed: 81 of 82 do not open with a numbered heading, only 25 do, so the census holds the three lines all 82 agree on, an h1 title, a blank line and the Status section. buoy --nearest name is kept and recorded in CONTEXT.md as the deliberate git describe match pattern it is, named there as having shipped undisclosed in 1509 so the record carries the finding rather than the flag alone. and apply-patch stops refusing a patch that only DELETES a CRLF file: a deletion writes no result and so rewrites no line ending, which is the entire cost ADR 0082 states, so the check moved below the deletion arm, the ADR sentence was narrowed to match, and the pin carries a modify patch refused over the very same bytes in the same fixture as its control (#1807) eff3dc92 · dbf3dbe6…diff
  • ahead and behind against a remote without pushing to find out, and the thesis constraint is met as a property of the REQUEST rather than as advice: the question carries an EMPTY PAYLOAD and every comparison is local. a relay is asked POST /haves with a zero length body, a forge POST /ref with a signed envelope over zero bytes, so a repo of one path emits BYTE IDENTICAL bytes to a repo of ten thousand and the question has no room to encode paths, object addresses, or even our own heads. the two endpoints that could are forbidden on this path and ADR 0021 now records why: /wants sends our object addresses, which are per-content identifiers, so a status in a loop hands the relay a per-path edit-frequency profile of ciphertext it cannot open - ADR 0083 refusal at a higher call rate - and /offer sends our head ids, which a push may do because a push is a CHOSEN act and status is not. the pin asserts the recorded path-and-body list SET EQUAL to exactly /info and /haves both empty, asserts the two recordings equal across two very different positions, and carries a positive control that a real push through the same stub records a NON-EMPTY body; mutated into the rejected design it goes red with /wants carrying a literal 32 byte address. offline is split POSITIVELY, the site gate SKIPPED-OFFLINE rule: only reqwest own is_connect and is_timeout may be called offline, and anything that ARRIVED - a refusal, a 404, a proxy page, a truncated body - is unusable, because those are different facts and collapsing them is how a guess gets reported as a measurement. the relay answered and holds nothing is a THIRD thing and reads as declared with a count. every unknown count renders dash or null and NEVER zero, so a machine that never reached the network cannot emit a number, and log --unpushed REFUSES rather than printing an empty listing, because a listing has no row meaning I could not ask and an empty one reads as everything is pushed. the asymmetry is stated rather than faked: unpushed is exact, being the same change lane a push would send through the same ancestor_closure, while unpulled is zero exactly when every declared head is held here and UNKNOWN otherwise, since a head declaration says what the tips are and not how deep they run. no FORMAT_MAJOR bump and the reason is recorded: ADR 0019 marker exists to prevent misparse of a durable or on-wire artifact, an unasked status emits byte identical porcelain, and the R row lives behind a flag that did not exist when the shape froze. no revset predicate either, because loot-revset is handed a GraphView and a KeyOracle and nothing else (#868), so a predicate answering over HTTP would put a network round trip inside revset::select and therefore inside grep and format-patch too (#1522) 2237a331 · dbf3dbe6…diff
  • the first review sweep of this run finds three live defects and six sentences that read wider than their subject, and the one worth the sweep is that status and log DISAGREED: a working change is a head, so RemoteDelta counted it, while scoped_view drops it from the listing - status said 3 where log listed 2, and the extra was a change push would never send. it was unpinned because every fixture FINALIZES, so the fixture came first and settled it rather than the argument; the subtraction is spelled as the two node projections, author present and signature absent, which is the same discriminator the bundle uses and ferry already reads. verify graded a pack I/O failure as object CORRUPTION while the loose arm propagated the identical fact, twelve lines under a doc saying cannot-read must never pass as verified - now verifies() is one predicate literally shared by both arms rather than two spellings that agree today, and scan_one_pack is split out so the propagating half is TESTABLE at all: an index read and a body read are two opens of a file not immutable at its name, so the only deterministic way to fail the second and not the first is to take the index and then remove the file. and [info] swallowed a real failure, since any resolve_remote error read as unconfigured including an unreadable settings file, so the arm now asks settings() a second time rather than matching on prose, keeping unconfigured for a genuine solo repo. the prose half is the doc scope-drift class six times over. read_index claimed to open a store in fewer syscalls WITHOUT reading a body and reads the whole file into memory; the syscall half was true and the bytes half was not, and the ranged read is left to 1525 with the obligation recorded there, including that a span past the end is currently checked against a buffer read_index already holds. two operator surfaces still said LOOSE objects after 1524 taught the census to count packed, and a THIRD site the ticket never named was found in DagRepo::census own doc. ADR 0023 claimed nothing changes what an unasked status emits, which was false twice - the JSON gained a field and 1524 moved contract 13 to 14 on the same shape in the same diff - so the surviving claim is the narrow one, that neither channel can be misparsed, for two DIFFERENT reasons. ADR 0019 now records that contract 14 names two status JSON shapes, because the marker buys a REFUSAL rather than shape identity, a floor and not an equality. the verbs census sentence had gone wrong one run after 1799 guarded the number beside it and warned in that very file that a derived figure can sit next to a claim that has not moved. the forge arm of the privacy pin was prose only and is now tested, and deliberately NOT by byte equality, because a forge envelope names its asker under ADR 0061 - what is pinned is that the payload unwrapped through the real unwrap_envelope is ZERO bytes on both positions, with the greater-than-64-byte envelope beside it refuting the recorder cannot see bodies (#1819) 124faca4 · dbf3dbe6…diff
  • shallow clone lands with the cut on the RECEIVING side, and that is why no wire moves and no format major does either: the fetch body is a format-marked pair of oid runs, so a depth field would be a new wire shape and therefore a bump, where taking the whole change lane and KEEPING n generations needs no new field, no new endpoint and no server change - a shallow client works against every relay and forge already deployed, including older ones. the price is stated rather than glossed: the change lane metadata crosses once in full on the first round, and what is saved is the object bodies, which is where a history bytes are, exact from the second round onward. the no-false-absence guard lives in THREE places and none of them is a verb - assemble, which every CLI open lands in, measures the frontier; apply_bundle_reaching, the only thing that can move one, re-measures it; and the dispatcher states it on stderr after BOTH the success and the refusal arm, because a refusal is a false absence WORST shape. it cannot be bypassed by a verb that forgets to ask: there is no path from the CLI to history that skips assemble, and the one way to open without measuring is to declare RepoNeed without graph, which makes the first history read PANIC - so the declaration that would silence the notice is the same one that aborts the verb. it rides stderr rather than the shape, so json and porcelain stay byte identical under ADR 0023, and a complete position emits nothing at all. depth never reaches the remote AT ALL, pinned three ways: every recorded request re-encoded through the real codec is exactly header plus 32 bytes per id with no room for a depth or a path, the union of every have and wants is a SUBSET of what the relay itself named in a prior answer, and the aimed one is that two positions cloning the same history at the same depth and differing ONLY in their sparse view emit BYTE IDENTICAL requests. the test relay recorder had to start capturing IDS rather than counts, because a privacy claim about a request cannot be checked against a length. two findings came out of the sweep rather than the design. one mutation stayed GREEN and refuted a claim already written into four files - that shallowness is stable because the frontier id rides the declared closure - since a declared have IS a closure claim and the held tips therefore already subtract everything behind the cut; every occurrence is now the narrow true sentence with the refutation beside it. and a count assertion caught a silent no-op: the obvious deepen posture, the closure minus the frontier, comes back with an EMPTY change lane REPORTING SUCCESS, because the remaining ids are still descendants of the cut - a deepen must declare NOTHING, and the posture is now derived from the bound so the wrong pair cannot be spelled. the body-deferring filter is NOT attempted and is the one criterion left: it needs a lazy object read on every get, surface and diff path plus a policy for what happens offline, and half-building it would put a FIFTH kind of not-here into a store that already distinguishes four (#1527) 2cccbe27 · 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
  • the delta reaches the TypeScript SDK as a SHAPE rather than as prose, and it is the FIRST INSTANCE of #1763 rule rather than a bespoke design: DeltaShape::of is a PROJECTION of the seam and nothing else - the mark is the #306 gutter rather than a new alphabet, the rung is the LineDelta variant, the counts are its own counts and the tally is the disclosure verbatim - so nothing here was hand-designed and the shape cannot drift from what the human rendering shows. three decisions carry the weight. added and deleted are NEVER ZERO where the count is unknown, they are absent, exactly where --stat calls a row uncounted, and ONE function now feeds both channels so the two cannot disagree. a sealed row WITHHOLDS the path, the from-path and the recipient list in both channels, because a path name is CONTENT under #306 - the shape refuses to leak through the encoding what the prose refuses to print. and the machine channel is ONE SHAPE REGARDLESS of --content and --stat, verified byte-identical, because those flags pick WORDS over a delta while this picks an ENCODING of it. the contract number is the shared VERDICT_CONTRACT and not a per-verb one, which ADR 0023 already answered for every shape and #1516 declined explicitly for porcelain, and an SDK test asserts diff and status report the SAME number so a per-verb version would go RED. a defect was caught BEFORE the freeze, which is the only time that is cheap: the first encoder used to_string_lossy, so on Windows a FROZEN contract would have shipped a backslash path beside a human line printing a forward slash - caught by the pin that compares the two RENDERINGS rather than asserting each is non-empty, and its unit pin uses an EMBEDDED backslash rather than a nested path, because a nested-path fixture is vacuous on POSIX. wire names stay snake_case deliberately, since a camelCase mirror would be a second vocabulary for one frozen contract and the only thing it could do is drift. nine mutations with counts read, and the ceiling comes DOWN 57 to 56 - the first entry on that list to PAY rather than be excepted (#1554) ac5700af · dbf3dbe6…diff
  • the shorthand whose NAME states the path axis while its SHAPE states the arity axis is DELETED, so the terse spelling is now the one that REFUSES - which was this ticket whole thesis, that the wrong declaration was cheaper to write than the right one and that is why the silent-drop class kept recurring. every site that meant it now types the open constructor out, and the only shorthand left is the one that takes nothing. option A beat option B on BOTH axes, measured rather than preferred: B would have changed the constructor signature, so EVERY open call site owed a reason string - including the path-taking and the genuinely variadic ones - and the two dozen dispatch verbs would each have written the SAME sentence, which is boilerplate that teaches nothing and is itself a hand-maintained population. so A has the smaller blast radius AND the stronger property. the blast radius is ZERO BEHAVIOURAL, because the retired constant was literally that expression: no verb declared arity, no slot kind and no refusal moved - thirty-five declaration sites, eleven imports and about twenty-five prose sites, with the workspace check clean and no new warnings. the exemption list was ALREADY down to its two legitimate names before this began, since #1569 narrowed the other twenty-one hours earlier, so nothing was added to it or taken from it, and the #545 refusal that earns those two their place is untouched by construction - pinned rather than incidental, because the mutation that hands one of them the no-arguments declaration reddens all three censuses. the rename then exposed two more counts standing beside sets that MOVE, and both are fixed rather than carried: a fixture doc claiming all FOUR verbs it exists to serve are exactly this shape, where there are FIVE production attachers and NONE of them is that shape, and a line naming the four verbs that used the retired constant. both now state the rule and count nothing. the new guard refuses BINDING the zero-slot open claim to a name, which is the single edit that would undo this, while deliberately NOT refusing a leaf that spells the claim out at its own spec - the two told apart by what PRECEDES the constructor, with both run through the predicate before its answer is read. its limits are in its own header. and the control that mattered is the second: with the comment-strip removed AND the predicate control disabled, the tree scan names the flags file itself, over the retired declaration QUOTED INSIDE THE SURVIVING CONSTANT OWN DOC - so the strip is load-bearing rather than decorative. the first and third mutations are each other discrimination, one reddening only the tree arm and the other only the binding-versus-spelling arm, and the fourth proves the floor fires at zero files rather than agreeing silently (#1675) 123fdbd4 · 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
  • the condition that could not be false is gone, and so is the pair that made it possible: merged stops being a FIELD set by hand at three construction sites and becomes a DERIVED method over the one bit that decides it, so the two cannot disagree - unrepresentable rather than guarded. eighteen reads follow it, and eight of those were conjunctions that are now TAUTOLOGIES, reduced to one term rather than left standing to read as two conditions. the test was rebuilt by moving a DIFFERENT AXIS, because a second catch-up can never reach the block at all: the fixture now puts a real second commit on the checkout main, so the DOCK is still behind and the catch-up genuinely runs, writes the tree and reaches the block, while the CHECKOUT is level and the block declines - and deleting the predicate reddens two tests. the DISCRIMINATION is the part worth reading: under that same mutation the OLD test stays GREEN, which is precisely the defect this ticket describes, demonstrated rather than asserted. the printed recipe stops handing the operator a command that ERRORS. the tree delta now returns what was WRITTEN and what was REMOVED apart, and a removal gets a tree read for its proof, because there is no file to hash, and a checkout for its repair - placed BEFORE the merge, since restoring the file is what lets the merge run at all. the plumbing needed a pin of its own, and that is proved rather than assumed: folding removals back into the written set reddens the workspace pin while the rendering pin stays GREEN. the off-main arm gains its PROOF and withholds only its REMEDY, and says that it withholds it and why, because the byte comparison does not turn on where HEAD is while the repair does - with that limit stated in the same list the module other limits live in, rather than left for a reader to discover. the section this run added about careful sentences gets its own grammar fixed, a stray fragment from an earlier draft removed and a clause given its missing object - and NO count added, with a number that was being carried forward replaced by the property, consecutive sweeps each turning one up. the only-shorthand claim is narrowed at all three sites to the width of the check that backs it, which is a claim about ONE declaration and nothing wider. and the tenth copy of the short-hash helper becomes one, with the unguarded universal above it replaced by what it actually is and an explicit note of what it does not cover (#1911) 53ede622 · dbf3dbe6…diff
  • a revset is accepted wherever a selector is, through the door that already existed - and the verb population is DERIVED from the shipped help text rather than from the dispatch table, which closes the two-spellings trap that had already cost two tickets UPSTREAM of this change, since help is pinned set-equal to the table in both directions. a placeholder-name list could undercount a DIFFERENT way, so the whole placeholder vocabulary of the help text is a SECOND set-equality: a verb spelling its change argument some new way now reddens the build instead of dropping silently out of the population. twenty-five selector-taking verbs, TWO of which a hand list would have missed and the derivation found - diff spells from and to, merge spells head, and neither says selector. four are adopted here, exactly the four #1563 named, all through the existing door via one shared consumer: no second parser and no per-verb precedence, because two verbs disagreeing about what a bare word means is worse than neither having revsets. the point-versus-set question is decided PER VERB with its reason rather than made uniform. cat is a point because its product is one path bytes written verbatim with no frame around them, so two versions arrive concatenated and indistinguishable from one file containing both. archive is a point because N trees are either N files, which is a different verb, or one file whose members collide path-for-path. blame is a point because the lineage walk STARTS there and there is no column for a second start. and ignore-rev is a SET USED WHOLE, because the only use of its result is a membership test, so every member is taken. diff is the interesting refusal: a two-member set does NOT collapse into the pair, because the pair is already spelled as the two arguments, so collapsing would give one argument an arity decided by data the operator cannot see - the same expression a comparison on one repo and a refusal on another - and a set has no SIDES, so a topological order would silently come to mean oldest-versus-newest. that is rejected explicitly and recorded rather than overlooked. the shared rule is exactly one, else REFUSE naming the count, and the door never takes a member. sixteen verbs are left, in two groups, both NAMED in the census rather than merely absent: nine where a set is a fan-out over a REWRITE, needing an order, a per-change failure rule, an undo story and a confirmation surface that do not exist - guessing on a destructive verb being the worst place to guess - and seven that are points by nature and left on scope, two of which have a coherent set arm and so are decisions rather than transcriptions. every pin RUNS THE VERB against a real three-change repo, each row in its own fresh copy with declared setup, so a refusal that fires BEFORE the selector resolves cannot pass vacuously - which is the exact failure this ticket exists downstream of, a criterion once pinned only at the flag gate. ten mutations with counts read. the control that matters is the one dropping a placeholder: the VERB census stayed GREEN, because diff line also spells another, while only the vocabulary census fired - which is what makes that second guard load-bearing rather than decorative. and the ignore-rev pin carries its own control, because without it the equality would hold just as well between two no-ops. three prose claims this change made FALSE are fixed, and one existing pin was MOVED rather than deleted, onto a verb the census names as selector-only so the choice cannot go stale silently (#1689) 5e9b9cb6 · dbf3dbe6…diff
  • a const inserted BETWEEN a doc block and its function had silently stolen two of them, and the consts move above the blocks so each documents its own subject again: diff_spec gets back the section recording that diff is a POINT VERB AT EACH ENDPOINT - the deliverable of the very ticket whose edit displaced it - and archive gets back its omit-versus-refuse argument, its two inherited limits and its pathspec section. each const gains a doc about ITSELF, saying what the string holds and who interpolates it, which is the shape the two siblings that were already right had. a THIRD site of the same shape was found by sweeping for it rather than by assuming the two were all, and it is from August rather than from this run. the nothing-catches-this claim is MEASURED rather than asserted: re-inserting the defect gives zero build warnings, zero rustdoc diagnostics at the site and a fully green suite, because intra-doc links still resolve. and the guard question is answered honestly as REVIEW rather than a gate - the mechanical heuristic yields seventeen candidates workspace-wide, all seventeen were READ, and exactly ONE was real, so a gate built on it would ship sixteen hand-maintained exemptions of noise, which is the roster class this run has been burned by five sweeps running. the sha-shortening item finishes the EXTRACTION rather than fixing the sentence, and on evidence found before deciding: one arm of the same enum already called the helper while another sliced flat, two arms of one message shape disagreeing about the same value. the doc stops saying every, states the property, names what each of the two sweeps covered, names the non-scope, and says OUTRIGHT that nothing enforces the scope - a hand-written slice still compiles and review is all there is - with its surviving headline claim, a prefix and never a panic, pinned for the first time. and the ticket OWN PREMISES were refuted twice, which is the part worth carrying forward. the diff exemption was DEAD rather than load-bearing: deleting it leaves the test green, and an instrumented run prints diff answering thirty-six bytes, because loot diff leaves the second endpoint at the pending state and an empty WORKING CHANGE is not an empty DELTA - so it is deleted rather than justified, with the reason recorded at the site. and the claim that all twenty-five selector-taking verbs read the selector HEAD is false, because edit refuses it through a THIRD resolver - measured against the built binary, and now pinned with a control rather than left as prose. the unpublished figure behind a 215-millisecond claim is rounded to the table rather than published unmeasured, and the removals proof gives BOTH its outcomes a meaning, pinned by a mutation whose sibling stays GREEN (#1917) 0ad19cad · dbf3dbe6…diff
  • the policy counter is renamed PolicyParses and policy_parses because it has counted parses since #1704, and the policy.rs block and the ADR 0073 row now point at the variant doc instead of restating why; no stored perf record carried the old key, because the gate does not record this counter. PUSH_SHAPE_DEPTH, OFFER_GUARD_DEPTH and MISSING_DEPTH are literals rather than aliases because their reasons have diverged, and each is still 128. ride_entry takes one RideState instead of three maps, while the one_pass_bundle oracle keeps its own transcribed walk and memo so the byte-identity test still compares two walks, and still went red when the key arm was disabled. the gated counters read 743, 200 and 24 before and after (#1718) bbd04ef4 · dbf3dbe6…diff
  • the zero-arity pin now asks owes_an_arity which verbs owe an arity instead of spelling its own narrower rule, and expects the same verbs as before; it went red when owes_an_arity alone exempted heads and when the heads row was re-opened. the OPEN_BUT_TAKES_NONE doc and CONTEXT.md stop listing or counting its readers and point at owes_an_arity. the Admitted doc and CONTEXT.md name the methods that do not read through the spec, as a reading of the impl rather than a rule, and with_leading_word now says it rewrites argv by position. the flags.rs censuses take the src half of the source_walk walk instead of a copy, and the Admitted census still went red on a planted leading_word read in verbs/change.rs; the consumer count is unchanged, and the stale main.rs consumer count in the consumer walk doc is gone. the loot-perf depth docs stop promising an equality nothing checks, change.rs points at the PolicyParses variant doc, and the rewrap leftovers the ticket lists are fixed, with a long line in the CONTEXT.md arity paragraph (#1944) c5819020 · dbf3dbe6…diff
  • loot resolve no longer refuses a delete/modify conflict that ours deleted: the #1988 guard reads a conflict record whose ours is its base as a deletion, so a disk with no file there matches it and a file written back there is still refused over, and on a shared primary its refusal names loot describe --allow-primary, the capture that works there. spawned-binary tests on a ferry-bounced two-head home position went red before the change for the ours-deleted resolve and the restored file (1 passed, 3 failed with the primary hint test), and with the deleted-ours arm removed (3 passed, 1 failed), with ours read as bytes whatever the record says (2 passed, 2 failed) and with a position-blind hint (3 passed, 1 failed). the implement brief now takes the job cap as a placeholder, keeps deploys inside the warrant and names SKILL.md, cites only what AGENTS.md says, says which commands need the lane position and gives the CR count and describe in PowerShell too; AGENTS.md gains the cargo fmt ban, ADR 0062 names the per-ticket safeguard that replaced the implement review, and the redeploy commands in workflow.md and diagnose-push-rejected name the new tag, scope the relay override to a forward bump and say the forge takes none, as the scripts repo reads them. ADR 0082 and apply-patch say the text deletion arm checks no preimage either (#1992) and pin that --check refuses a binary deletion the same way, the line-ending docs say CRLF and NUL, nul_offenders is private, and the sweep 10 wrap leftovers are fixed. the workspace suite is green (#1993) 7ecaa467 · dbf3dbe6…diff
  • a locked pull stops leaving a stale copy for the next verb to capture: the ingest parks the claim it cannot check, and the first open holding the key finishes it. #1256 recorded nothing when it could not open the pre-ingest content, on the ground that loot rehome materializes and moots the question, which it does not do when it refuses, and in that state it refuses: the untouched pre-pull copy read as an edit no change had recorded, so rehome declined it and loot converge, the next step the pull note names, captured it silently, one change below the version that had just arrived. the claim, being the path, the pre-ingest oid and the digest of the bytes on disk, now goes to .loot/stale-disk-unverified, a position-owned artifact of the same shape and codec that nothing in force ever reads, and Workspace::settle_unverified_stale_disk makes the same comparison at the first unlocked open that was given a graph, beside heal_hold and under its gate: bytes that match move into the record in force, bytes that do not are the operator own work and the claim dies, an open that cannot answer leaves it parked, and a write that disposes of the bytes a claim is about retires it, whether it wrote over them or pruned them. rehome refusal stops asserting the arrival guard would refuse a capture where no guard stands: it asks Workspace::arrived_unmaterialized, keeps the circle where the guard does stand, and elsewhere says what recording those bytes actually does and that a verb capturing on entry records them whatever rehome refused. the locked pull note says to stop if rehome refuses. review fixes: the pin for the printed order now runs the three printed commands and nothing else, since any extra verb opens the repo and an open is what settles the claim, with the record own story moved to a second test; and the three malformed-record refusals stop offering a first remedy the refusal itself prevents, because they refuse at the open, so the file has to go before any verb can run. the Known Issues entry stays, wearing FIXED_IN_MAIN, because v0.4.20 is the binary a reader can install, and pin 5 comes back over it as its own retirement note instructed. red first: the note recipe, run in order, left the arrived version on disk only after the fix (0 passed, 1 failed). red under mutation, each 0 passed and 1 failed unless noted: the claim dropped rather than parked, the open never settling, the settle promoting without the check, dropping rather than keeping what it could not check, leaving a checked claim parked, and running on an open given no history; the surface, the whole-tree write and the one-path write each keeping a refuted claim (that last two 6 passed and 1 or 2 failed); the disposed set naming only what a surface wrote and not what it pruned; rehome claiming the guard everywhere and rehome never claiming it at all; the note without its stop clause; the page deleting the held entry, the page dropping the marker, and the held row witnessing a fix the tree does not carry. no migration, no wire or format byte moves, since the new file is local to a position and never bundled, and no forge or relay byte moves, so this owes no deploy; the CLI change owes a release, and the Known Issues entry leaves with it. the workspace suite is green (3962 passed over 122 binaries, 7 ignored) (#1963) f7b7e533 · dbf3dbe6…diff
  • ADR 0076 amended by #2101: .loot/gates gains a land phase and two hand-offs, and git hook names are mapped or refused by name. Phase::ALL has three members and every sentence that spells the set derives from it (Phase::words, Phase::usage_alternatives), so the parser refusal, the loot gates usage and the --phase errors moved without a second edit. A land gate is the user-gates row of orchestrator::GATES, between the text gates and the expensive ones, PreLandAndMerged and Outside: it runs on the lane tree and again on the merged tree when the converge moved the position, --skip-tests never silences it, and loot-first land gains --skip-gates which honors honored and never required per declared posture and records the skip in the op log after each pass, because a gate holds no Workspace. A finalize or land gate may write {message}, which expands to the path of a temp file holding the message about to be signed, newline-terminated and unlinked the moment the child returns, and {paths}, the touched paths root-relative with forward slashes, sorted, deduplicated, one argument each, deletions included; a push gate that names either is malformed, since a push has no single change, by Phase::commits_one_change rather than a list. The hand-off is built by Workspace::gate_handoff only when a gate in the phase names a placeholder, so a declaration that never asks never pays the working-delta walk, and gates::run still takes no Workspace; that accessor is the 384th Workspace method and the verb tier module doc now says so. A {message} with no message is unstartable, never a pass. The spelling was decided by running the tools, not reading them: pre-commit 4.6.2 files stage hands a hook the paths as separate arguments and its commit-msg stage hands exactly one filename, and a bare script reads that file, so a file path and argv tokens are the compatible spellings; pre-commit itself needs a .git and so cannot run inside a lane, recorded in the amendment. git pre-commit and pre-push are refused naming finalize and push; any other word is refused by name with the one sentence that holds for every unmapped hook, no index, no checkout, no rebase, no merge commit, and GIT_HOOK_PHASES is the map, never a claim about git set; the optional init --from-git was not built. Measured through the real binary in a throwaway repo, since .loot/gates is shared over the store and a land line there would make every other session binary refuse its finalize phase as malformed, which the amendment and workflow.md now warn about: two Python gates over 13 paths and the message cost 77 ms and 64 ms wall for the whole phase against 23 ms for a listing, so a contended land pays about 140 ms; loot new through the binary handed the message file and 13 paths, and --skip-gates recorded skipped p in the op log. Five pins each broken once by a named mutation and confirmed red at 0 passed 1 failed, then green at 1 passed: the row demoted to PreLand, the message file cut to its first line, the sort dropped, pre-commit unmapped, and required skipped under the flag. CONTEXT.md Phase entry and workflow.md step 7 say the same. loot-cli gates 25 passed, change and sync 65 passed, loot-first lib 225 passed after the two table assertions learned the ninth row; two lands refused on censuses the targeted runs never selected, the module-doc method count and the help placeholder classification in revset_everywhere, and each fix is one line saying the new spelling. No wire, format or store byte moves, no migration (#2101) 5c4e3996 · dbf3dbe6…diff
  • loot pipeline (#2127, ADR 0091, map #2099 ticket 3): the tracked .lootpipeline at the repo root, in the .lootattributes grain with no dependency column, one step per line as name, trigger, kind and what, where the trigger names the tree a step judges, change or main, never the moment, and the kind is run, argv through the spawn seam with {message} and {paths} as gates reads them through one shared builder gates::spawnable, or check, a loot-native gate deferred naming #2128 until the checks live where the verb can reach them, and a deferred step is a refusal exiting 1, never a pass. loot pipeline lists and spawns nothing; run judges the working tree by default or, under --version, a scratch tree of a held version written by Workspace::scratch_tree from readable_tree_at so the readability decision precedes any file, holding the version own .lootpipeline, and removed on drop, with the hand-off from Workspace::version_handoff naming the paths whose readable content differs from the first parent; --only narrows to one step and an unknown name is refused naming the declared set; status reads the pipeline/TRIGGER/KIND passes and pipeline/approve admissions trusted keys signed on a version through attester_trust, passes only. A tracked file never runs implicitly: loot new with a run step declared and no .loot/gates line reaches no spawner, pinned. Frozen shapes in ADR 0023 amendment, exit code on the shape. Measured on the release binary: a two-step run 74 ms, run --version 47 ms and a listing 18 ms on a three-file repo; on this repo of 1452 tracked files, run --version HEAD materializes the whole readable tree in 1.2 s against a 0.15 s listing. Found by that measurement, not by thought: under load a Windows scanner held a freshly written scratch file, the one-shot remove_dir_all failed and its swallowed error left plaintext in the temp dir, so ScratchTree drop now retries over half a second and names the path on stderr if it still cannot remove it. Seven censuses moved, each read off its own refusal: the verb tier method count to 387, MACHINE_OUTPUT gains pipeline in sorted position, the usage spells the list leaf as an invocation line, README block and its all 84 verbs sentence, 133 verb lines in three places, the revset placeholder lists take <change|main>, <step> and <id> and SELECTOR_ONLY takes pipeline status, and the site CLI page names the verb; ADR 0066 counts 84 dispatched, 82 in the table, 32 emit machine output with an amendment. CONTEXT.md Pipeline entry says what is built. Nine unit pins plus two in change.rs, five broken once by a named mutation and confirmed red at 0 passed 1 failed then green at 1 passed: a check made a pass, the trigger filter widened, the scratch removal removed, the approval role made a job, and the tracked file run at a finalize. loot-cli and loot-first green across 64 binaries, 2162 passed; the site verb census green. No wire, format or store byte moves, no migration (#2127) fe693773 · dbf3dbe6…diff
  • loot new prints each first-seal tier off the seal the path was sealed under, so a path the same finalize had just published no longer reads internal: the summary printed the .lootattributes resolution seal_gate hands back, a Visibility, which cannot spell published because a published object is Internal plus the @world marker (#481). the tier is now read back off the signed change, seal_visibility and published_marker_to_carry over the address the finalized tree holds at each path, rendered through a new render::tier_label that restore now shares. reading rather than folding the standing rule in, as with_publish_status does for surface, is what makes it right under --no-snapshot, where the finalize signs an earlier capture and the rules may have moved in either direction; a row the finalized tree does not hold is left out, and an unreadable seal prints as a refusal and never as a tier. both directions pinned red first (0 passed and 2 failed): every Tier plus published on a fresh capture, and under --no-snapshot a published seal whose rule was deleted, a restricted seal whose rule was deleted and an internal seal given a publish rule since. red under mutation, counts read each time, each restored green: the row printed again (0 and 2), the marker ignored (0 and 2), the marker taken from the standing rule (1 and 1), seal or standing rule, the overstating repair (1 and 1, late.txt read published), the Visibility taken from the row (1 and 1), internal spelled published (0 and 2), an unreadable seal falling back to the row (2 and 1), a path the change does not hold kept (2 and 1). reproduced through the 0.4.24 binary before and a lane build after. CONTEXT.md, the census row for new_with and the Workspace width move with it. no migration, format byte or wire byte moves, so this owes no deploy. the workspace suite is green (4407 passed over 139 binaries, 13 ignored) (#2219) a4254982 · dbf3dbe6…diff
  • the attestation ledger records what a remote is known to keep rather than what a push put on the wire, the review-sweep fix-up over #2251: a push records rows only for a host whose /info answered, as a relay or as a forge advertising late_attestations, and a host whose /info did not answer is still sent them but has nothing recorded; against a forge without the flag it records what rode with its change, so its left-behind warning counts the late ones and no longer grows; the ledger keeps per forge the tip generation the last recorded push committed at, and a push that reads a lower one sends every attestation over the changes that forge holds again and says it may have been restored, with deleting .loot/attestation-ledger documented as the recovery for a relay and for a restore hidden by later pushes; a ledger that will not read or write warns and never fails a push or skips its deposits, and a record over an unreadable one starts it afresh. the forge misread as a relay the sweep named fails at its unsigned /wants before sending, pinned; the rule stands without it. red first with each fix undone, counts read each time, each restored green: an unanswered /info read as keeping them (0 passed and 2 failed), a forge without the flag recording nothing (0 and 1, left behind 2 where 1), a restored forge unnoticed (0 and 1), an unreadable ledger fatal (0 and 1), an unwritable ledger fatal (0 and 1), the first-seal summary defaulting an unknown change to no rows (0 and 1). also stated: the privacy filter rests on the declared have, a forge holding a head without its ancestry drops a late attestation it is recorded as keeping, a ledger is one clone, late_attestations states the property rather than naming verbs, RemoteSync bound records nothing and its docs are current, the first-seal summary refuses an unknown change and names its tree clone, and the Route doc states where hosting is decided. the ledger stays push-only: store_file_reads is 24 on the gate workload with no move. no format constant, codec byte or migration moves. the workspace suite is green under bash ci/local.sh against Postgres 18 (4430 passed over 139 binaries, 13 ignored; site live suites 7 files passed) (#2355) 9511111e · 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
  • loot show, the deletion rows of loot status and a surface listing name the published tier off the marker the object carries rather than off the .lootattributes on disk, so a published object whose rule was deleted no longer prints internal and a plain one given a rule since no longer prints published: the delta seam reads each row marker in Workspace::rows_of, off the side that carries the row, and keeps the rule for a live side (ADR 0079 section 1) and for a seal it cannot read, while the clobber guards take ResolvedDelta::classes and pay no read; surface, rehome and the pull auto-surface list through the new Workspace::with_sealed_publish_status. the status machine listing is the working tree on disk and keeps the rule. measured over a 400-path tree with the counters, every added read is a memo hit: object_gets moves by one per row with a recorded side (show of a half-edited change 1602 to 1802, status with a third deleted 804 to 938, surface --json 802 to 1203) and object_disk_reads is flat on each (601, 401, 401), a clean status is flat on both, and a hyperfine A/B over 2000 paths reads within noise (show 98.2 vs 97.3 ms, status 93.1 vs 92.6, surface --porcelain 165.4 vs 168.3, status with deletions 130.8 vs 129.8, load 0 to 6 percent). surface_object_reads counts the listing marker read apart from the opens, and the restore pin reads the seals its capture wrote. both directions pinned red first (0 passed and 2 failed with the fix undone), each through the verb: show and status deletion rows, and surface over trees ferried from git commits that delete and add a published rule. red with each piece undone, counts read each time, each restored green: the delta seam on the rule (1 passed and 1 failed), marker or rule, the overstating repair (1 and 1), the new side asked for a deletion (1 and 1), the listing on the rule (1 and 1), the listing as marker or rule (1 and 1), the guard paying the reads (0 and 2 in surface_object_reads). the published values in diff and surface machine output change for such rows and no key or column moves (ADR 0023). no format, wire or migration byte moves, so this owes no deploy. the workspace suite is green (4527 passed over 140 binaries, 13 ignored) (#2352) 0c27bd77 · dbf3dbe6…diff
  • review sweep 15 over the proposal conversation and the published tier: acting on one proposal decides its parties by account as seeing it does, so the withdrawal and decline gates ask propose::sees, the withdrawal author check and the re-proposal parties in admit ask speaks_for, and a rotated tip author whose original key is retired withdraws their proposal with the account live key on a metadata-private repo, where by key it was told the proposal did not exist, and on a public one, where it was told it did not author the tip; a rotated proposer offers a declined proposal again. the #2378 rotation pin now retires both original keys on a Rotated fixture that files the offer before the rotation. the comment-page EXPLAIN pin asks for Sort anywhere in the plan, where its line-start form could never see a nested Sort node. an unread seal answers not published in rows_of and with_sealed_publish_status, the direction that never overstates, where it fell back to the rule; show renders an unread object by address as sealed, so the listing carries the pin. propose.rs, ADR 0095 and CONTEXT.md state which gates are by account as a property, a read of or act on one proposal, and cite #2006 for list, CONTEXT.md scopes the #2352 tier sentence and points at #2381, and append_page refuses a comment repeated within one page. red with each piece undone, counts read each time, each restored green: the withdrawal seeing by key, the withdrawal author by key, admit parties by key (0 passed and 1 failed each), a retired key speaking for nobody (0 and 1 on the rotation pin), a misshapen page index on a throwaway Postgres 18, comment_id before created_at and created_at descending (0 and 1 each, 1 passed restored), the listing falling back to the rule (0 and 1), a repeat within one page taken (0 and 1); the rows_of fallback mutation stays green, since no verb reaches it. bash ci/local.sh is green against Postgres 18 (4530 passed over 139 binaries, 13 ignored). no format constant, codec byte or migration moves; the forge rules change, so this owes a forge deploy (#2382) eceef7eb · dbf3dbe6…diff
  • loot apply-patch names each applied path by the tier its seal records, and loot new --no-snapshot lists the paths the signed change first seals: the apply-patch report printed the .lootattributes resolution, a Visibility, which cannot spell published, so a path this repo publishes read internal while loot show said published, and it now reads each row through Workspace::tiers_as_sealed, the #2219 read generalized from first_seals_as_sealed to any paths of a recorded change, rendered through render::tier_label. the first-seal summary took its set of paths from the disk walk of seal_gate, so under --no-snapshot a .lootattributes the earlier capture first sealed and the disk had since lost was left off; finalize_capturing_over now returns the paths the signed change holds and the anchor the gates judged does not (Workspace::first_seals_of), paths alone, since the tier is the seal. both pinned red first (0 passed and 1 failed each): published, internal and restricted rows through the apply-patch verb, and a --no-snapshot summary listing the lost rules file and neither a path the disk gained since nor one the anchor holds. red with each piece undone, counts read each time, each restored green: the marker ignored, published claimed for every row, the rule resolution printed (0 and 1 each on the apply-patch pin), the set taken from the disk gate, the anchor filter dropped, the anchor read after the finalize (0 and 1 each on the summary pin). reproduced through the 0.4.24 binary before and a lane build after. CONTEXT.md and the Workspace width move with it. no format, wire or migration byte moves, so this owes no deploy. the workspace suite is green (4532 passed over 139 binaries, 13 ignored) (#2353) 22faa0d6 · dbf3dbe6…diff
  • review sweep 16 fix-up over #2382, #2353 and #2358: the test scratch helper hands every path out inside one directory named for the process and claimed once before its first path, so a sibling a fixture derives, the <path>-lanes/ a lane spawns in, is inside what the claim cleared and a reused pid no longer hands a later run the lane an earlier run left, which stacked() in propose.rs took from read_dir; a retired key that wrote a proposal tip is refused the withdrawal in live_account_in words, decided by the retirement rule ADR 0075 already applies to an offer and ADR 0095 to a comment withdrawal, and recorded as an ADR 0075 amendment, with the account live key still withdrawing; the rows_of unread-seal branch is pinned through loot diff --json, which the doc said no verb reached; with_sealed_publish_status refuses a change this position does not hold, sharing held_tree with tiers_as_sealed, where it answered every row unpublished; the speaks_for, sees, rows_of, with_sealed_publish_status and scratch guard docs, CONTEXT.md and ADR 0095 say what the code does, the by-account property scoped to the forge routes. red with each undone, counts read each time and restored: only the handed path cleared (2 passed and 1 failed in scratch_dirs), no retired-key refusal on withdraw (2 passed and 1 failed over the three rotation pins), the decline gate by key through visible_to (0 passed and 1 failed), the rule fallback back in rows_of (0 and 1), and the empty-tree default back in with_sealed_publish_status (0 and 1). bash ci/local.sh is green against Postgres 18, 4606 passed over 142 binaries with 13 ignored and the site live suites at 78 passed. no migration; the withdraw route refuses a retired key now, so this owes a forge deploy (#2386) 6621b15f · 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.