Changes touching this path

  • an unexpected head stops being something the operator can only fold on faith, because `loot heads` lists every live head with what introduced it and how many changes it holds of its own — and since a head is a tip no other head reaches, a count of zero can only mean the head is not live, so #1477s empty head is superseded and the converge it asks for would merge nothing (#1496) 955ec9ff · dbf3dbe6…
  • a verb that takes no positionals stops being able to say so by claiming the opposite, because `NO_ARGS` now sits beside `NO_PATHS` and a census reads every verb invocation shape out of USAGE to find the ones still spelling nothing as open-ended — which is how `loot heads junk` was accepted 88 minutes after the same hole was closed at `loot cat`, and beside it `HEAD~n` ends where the revset lexer already ended it so a range can be typed at all (#1562) fb140e48 · dbf3dbe6…diff
  • a flags value stops being read as a flag, because `FlagSpec::given` asks in flag position the way `positionals` already does and every verb-local scan in both binaries is deleted behind a census that refuses the shape — which is what had `loot tag -m "-d"` signing a retirement, `loot describe -m "--no-snapshot"` silently skipping the capture, and `loot-first land --allow-publish "--skip-tests"` skipping the gate that is its whole job (#1612) b40e1843 · dbf3dbe6…diff
  • the fourth review sweep finds an enumeration asserted as exhaustive for the fifth time in one run, and the repair puts the RULE where the list was: two questions rather than a set of verb names. what does the key HOLD - a key the graph recorded as a change AUTHOR is mailmapped, while an attester, grantor, grantee, custody holder, manifest signer or admitted pusher holds a capability AT THE MOMENT IT IS PRINTED, and an alias there is a display that reads like an authorization claim. and where do the BYTES LAND - a mailmap is local display state, so it may reach a RENDERING and never an artifact whose bytes are hashed or re-ingested as a record. the second clause exists because of a site NEITHER the ticket nor a grep over the helper would have reached: git_mirror author_identity resolves a key the graph recorded as a change author and does not call that helper at all, so question one alone says mailmap it - and that would make a git mirror commit SHAs depend on a LOCAL UNTRACKED DISPLAY FILE, so two machines reading one repo would build two histories. applying the ticket rule mechanically would have INTRODUCED that defect, which is why the rule ships with two clauses and that site is named as its proof. of the four sites the ticket listed, three are mailmapped and tag is NOT: every key handed to that closure is an ATTESTER, the same key attester_trust decides the listing with, and that is the direction where a wrong call is security-shaped, so it stays put with the reason at the site and a pinned positive control. the four were four hand copies of one function body, which is HOW they drifted without anyone choosing to, and the body is now spelled once so there is no ladder left to copy. the grouping table is DELETED rather than narrowed: the enum grows ALL and a name round trip, parse SEARCHES that list and the refusal joins it, so the accepted set and the advertised set are one list read twice and the eighth vacuous pin becomes UNREACHABLE rather than watched - its replacement is pinned against an INDEPENDENT oracle, the hand written usage line read from source in another compilation unit, so a variant the parser accepts and the usage never mentions now reddens. AGENTS.md gains the class and explicitly NO guard, and the no-guard half is EVIDENCED rather than preferred: the census one would naturally write, over that helper call sites, would have caught four of the five instances and MISSED the git mirror - a guard that reads complete and is not would be one more instance of the class it exists to catch (#1832) 0cd1d291 · dbf3dbe6…diff
  • three seams that promised a door nobody walked through are settled on the honest half of each choice, and two of the five findings measured FALSE against the tree before anything was touched. revset::select has three production call sites now, not one, so the ticket count is stale - but the doc claim was still false, because cat, diff, blame and archive reach resolve_selector directly and heads resolves the at-sign a third way through working_id and finalized_anchor, so the line today is THE GRAMMAR and not THE SELECTOR, and the gap is written down at the module that makes the claim rather than left to the reader. loot_revset::evaluate over a string is DELETED and evaluate_ast takes the name, deliberately not the other way round: pointing select at the string entry would have left evaluate_ast callerless and parse production-callerless, which is the #1553 shape where a narrowing comes back THROUGH A NEW DOOR. Selection::versions goes with zero callers outside its own unit test, while the ordering half of that same finding is refuted rather than obeyed - the BTreeSet in history is a membership filter for retain_versions and not an order discard, and the topological order is load-bearing at format_patch numbering, range_diff pairing and grep row order, so the guarantee is ANCHORED on the Set variant instead of withdrawn from it. Group::arguments needs no pin for a second tailed group because a second tailed group now FAILS THE BUILD: Args::groups counts tailed groups and asserts in const, every leaf Args being a const, so the case the comment assumed impossible is unrepresentable rather than assumed - proved by a compile_fail doctest with a byte-identical positive control that reddens quoting the assert own message, which is what stops a typo from reading as the rule. build_heads stops taking eight positionals, two adjacent closures and three adjacent optional ids, and takes a named-field HeadSources: the transposition that used to compile silently was RED at 6 passed 1 failed as a mutation, and the same transposition written at the call site afterwards is simply meaningless at 7 passed 0 failed. the run then caught its own new door - HeadSources was born pub with zero out-of-crate callers, exactly the class this ticket is about - so it and build_heads are pub(crate) with the reason recorded at the type. the PATHSPEC comment on the ticket is STALE and nothing moved there: #1493 wired the group to five production leaves and already narrowed the present-tense claim in delta.rs (#1563) 4834a7ce · dbf3dbe6…diff
  • the first review sweep of the night audits the night OWN three lands, and four of the seven findings were MINTED BY THEM - each fixed at the level that makes the claim true rather than hedged. the wildcard-free match doc said a FOURTEENTH variant would not compile, beside an enum that already had FIFTEEN, so the number is gone and the sentence keeps its point: a hand-written count beside code that can grow is the class AGENTS.md names, and this one was wrong the day it was written. the NO_PATHS sentence and the dispatcher minority sentence disagreed because #1569 narrowed one of them and left the other standing, so the surviving sentence states the SHAPE rather than a frequency - zero declared slots plus an open own list - which is what the #1551 PATHSPEC argument actually rests on, and counting the table shows nearly every was false either way you resolve it: twenty-four literal NO_PATHS and twenty-two NO_ARGS against twenty rows whose spec lives elsewhere. the ADR 0085 note fired TWICE on range-diff, which takes two positionals through the one shared door, and the fix is AT THE DOOR with a latch that catches on HAVING SPOKEN rather than on having been called, because latching on entry would let a first side with nothing to say SILENCE a diverging second one - pinned with a one-positional control, since an equals-one assertion passes against an over-eager latch. the fourth finding is the one with a real choice in it: the note measured the bare pair only, while CONTEXT and two doc surfaces read as though the whole HEAD and HEAD~n pair was covered. so the divergence was BUILT before it was believed - two identities, a converge, one merge tip - and there HEAD~1 as a selector refuses naming both parents while the revset walks the first parent through it, with both bare HEADs equal, so the shipped note was SILENT through it. the MEASURE branch was taken over the narrow one: the note asks the bare pair first and then every depth the AST stands on, with both-walks-exhausted counted as AGREEMENT rather than as a note, and the arm that cannot fire today is ASKED rather than asserted, because that is a fact about two functions and not a thing to write down. prose is narrowed at every surface that read wider than the measurement, the log USAGE line included. the three copies of one census derivation become one function, the ordering contract the shared constant carries for exactly ONE of its three readers is now stated, and the const-only condition under the groups assert is named as what would make it wrong later. five mutations with counts read - and ONE CAME BACK VACUOUS FIRST at zero passed against 1175 filtered out, because the census lives in the bin target and the lib filter reached nothing, caught by reading the COUNT rather than the word (#1882) 5fd6a12a · dbf3dbe6…diff
  • a verb arm now receives the argv door answer instead of the raw slice: VerbRun takes an Admitted value, the rebased tail bound to the spec of the row it was dispatched from, and its readers are the only way in, so argv[0] or argv.first() in an arm fails to compile (both planted, read as E0608 and E0599). spec_of is test-only and its 104 production lookups read through the admitted spec; six of the seven raw-index arms (bundle, grant-status, embargo-status, attest, resolve, completions) read positionals through the door and relay reads its leading word through a named exception; subcommand families resolve their leaf into a new Admitted, and bisect and buoy are handed one ahead of the table. the two named exceptions, leading_word for relay and bisect and pass_through_tail for the bisect run command, plus the one process argv read, are held to a named set of functions by a new census that went red on a planted leading_word read in cmd_bundle, and the source walker consumer header now counts it. refusals and output are unchanged by every suite and by a read of each migrated arm, with one exception found on the way: resolve with a trailing --tool and no command read --tool as the file and now refuses with the usage line, pinned by a new test. CONTEXT.md gains the Admitted argv term; loot-first keeps its own spec_of and DECLARED_READS is untouched (#1929) d92e95f2 · 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
  • review sweep 15 fix-up: the evolog dash is on an empty FIRST LINE, the subject rule now has one home, and the surface prune says plainly that it discards. loot evolog --porcelain dashes its last column when the message first line is empty, which an empty message and a message whose body starts under a blank one both are, and three places said an empty message: the doc above the encoder, the ADR 0023 amendment of 2026-09-17 and CONTEXT.md. The wording moved rather than the bytes, because dashing on an empty message instead is a porcelain byte change for a message that opens with a newline, and a new spawned pin, a_message_whose_first_line_is_empty_is_the_dash_too, puts a run under the sentence: the file reads 5 passed, and with the whole message put back in the column it is 2 passed, 3 failed, the single-line control among the two that stay green. render::subject_line was billed as the one home while six call sites derived that first line inline, the four the ticket named plus the shortlog author rollup and the missing-object listing, so log --oneline, heads, show, range-diff and those two all ask it now, and the near-cousins that each do something more, the note ellipsis, the revert subject and the loot-first PR title, are named beside it rather than routed. The control is the spawned binary: 28 outputs over two repos, one carrying a multi-line message and one a blank first line, are byte-identical before and after, and with subject_line returning the whole message 10 of 11 of them move and the loot-cli lib suite reads 1219 passed, 4 failed, naming the shortlog rollup and the oneline row among them. The surface stale-debt prune keeps the removal error it discards, which #2018 declined and its closing note then reported as fixed, and the doc above it now says the let _ is deliberate, that apply_change_delta propagates where this one does not, and why: the delta writer snapshots, so a refused removal would be recorded as a deletion the disk never took. The removal census in workspace.rs states what its matcher is blind to, a type-annotated binding, a call split over lines and a path derived from a root-joined one, and names disk_entry::drop_empty_parents, whose remove_dir climbs from a dest its caller joined and which the fold cannot reach, because remove_dir takes an empty directory only and a directory holding a file the writer just wrote is not empty; widening the matcher would not have reached that call, so the blindness is stated instead. CONTEXT.md gives that census its crate and spelling scope. migration_serial records that hold blocks and is not re-entrant, and that it serialises migration runs rather than pg_authid, naming the fixed-name CREATE ROLE in tests/rls.rs that writes the shared catalog outside it; Held loses its Option and its Drop impl, since dropping the field is what the compiler already does. The migration census compares a BTreeSet the way the removal census does: with the const reordered it stays green where the Vec compare it replaced goes red (0 passed, 1 failed), and a name dropped from the const reddens it (0 passed, 1 failed). pg/tests.rs cross-references its own source walk and fn finder to source_walk in loot-cli and states where the pair differs. The folds_case helpers in two test files become folds_case_under, so neither shadows the disk_entry rule it asks. The rewrap leftover in account.tsx that #2018 moved rather than fixed is rewrapped with its neighbours, and so is a second one mid-paragraph in CONTEXT.md that the same rewrap reached. The forge suite is green against a throwaway 17.0 cluster (469 passed over nine binaries, no skip note) and its lock case goes red with the session dropped rather than held (0 passed, 1 failed), the site gate is green (643 passed, every surface under its ceiling), and the workspace suite is green (3833 passed) (#2023) c38e3299 · dbf3dbe6…diff
  • a superseded head is listed, not counted: loot log and loot heads stop counting a version superseded under ADR 0032 as a head, so a clean loot move --before no longer prints 2 heads - diverged; finalize then converge for a divergence that does not exist. the rule is spelled once as Liveness::is_superseded, which the head partition drops stale by, loot heads prints its superseded annotation by, and the counts now read: history() routes, counts and sections over the heads that predicate rejects, through a new LogGraph::retain_heads that re-indexes reachability into the kept heads, and the heads header counts the rows whose superseded flag is false and says how many superseded versions follow, still listed under the annotation. the head set itself is untouched - the stale head stays in .loot/heads until a converge retires it. reproduced first through the spawned binary on the lane tree at #1837 exactly as the ticket describes, and measured on move --onto too, where the stale head is not empty (B stays reachable only through it), which is why the rule is superseded and not own == 0. status never counted heads and never marks this with !, pinned rather than assumed. every machine shape is byte-identical modulo ids except the rows that were wrong: log --porcelain loses its two H rows and the working-change * row the fork view printed, log --json goes heads null, and heads --porcelain, heads --json and all three status shapes do not move. red first, four ways: the count rule undone reddens the workspace pin and the spawned reorder pin (0 passed, 1 failed; 1 passed, 1 failed), the header count undone reddens the heads pin and the spawned pin (6 passed, 1 failed; 1 passed, 1 failed), every head uncounted reddens the positive controls while the negative pin stays green (5 passed, 3 failed; 1 passed, 1 failed), and the predicate blinded reddens the partition, the annotation and the count together (6 passed, 1 failed; 0 passed, 2 failed). the #1477 production-shape pin moves to the new header, and ADR 0032 and CONTEXT.md record the amendment. no migration, no wire or format byte moves, and no forge or relay behaviour moves, so this owes no deploy. the workspace suite is green (3887 passed over 122 binaries, 7 ignored) (#1839) 8e6c0841 · dbf3dbe6…diff
  • the two shapes that graduated without a record get their amendments, telemetry status and off carry the contract field, and the comma-joined column gets one home: #1971 carries the ADR 0088 section 4 follow-ups and asks for each premise to be re-verified first, so each was read against the tree — ADR 0023 held no amendment for count-objects (#1523) or telemetry (#1658), telemetry status and off printed no contract field and the string dash where V3 says null, and the Verdict entry in CONTEXT.md still typed 17 of the 68 beside a roster where the dispatch table derives 32 emitting verbs and 51 prose-only ones; the ticket comment correcting item 2 is the later word and is taken as such, telemetry on printing report JSON for the same deliberate reason as show. ADR 0023 gains two dated amendments describing what shipped: the one-metric-per-mark census rows, and the name-keyed telemetry rows with the divergences frozen beside them. status and off lead their JSON with contract now and spell an unresolvable spool null, rendered by status_shape and off_shape, which take values rather than reading the config so all three renderings are assertable; show and on stay exempt because what they print is the report the sender posts, and the exemption is pinned over Report::to_json rather than over a verb, that string being what the endpoint receives. The shared flag column item 3 asks for is verdict::joined_col, the comma join with the dash when empty, and what defines membership is that spelling rather than a roster, so the columns spelled that way are its callers: blame, delta_shape, explain, heads, log, evolog, attestation_shape, refit_shape, seek, tag, both pipeline listings and lanes route through it and no frozen shape pin moved. The cross-shape census is declined with its cost recorded in ADR 0088 section 4, since a census over values needs a pub on each shape that #1553 refuses, one over a spawned binary reads nothing for a verb whose arguments it cannot supply, and its exemption table would be a hand-maintained list asserted as complete. Red under mutation, counts read each time: joined_col joining with a tab (loot-cli 1335 passed and 8 failed), the empty set printing an empty field instead of the dash (1324 passed and 19 failed, and loot-core 647 passed and 1 failed naming lanes_porcelain_rows_are_the_frozen_contract), the contract field taken off status and off (5 passed and 3 failed), the spool null spelled as the string dash again (7 passed and 1 failed), and a contract field added to the report the sender posts (6 passed and 2 failed), each restored. No migration, no wire or format byte moves and no host behaviour moves, but two leaves of client JSON move, so this rides the next release and owes no deploy. The workspace suite is green (4107 passed over 132 binaries, 8 ignored) (#1971) 4ef9c62b · 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.