Changes touching this path

  • loot-revset: query-algebra crate for selecting sets of changes (#394) cdec28d1 · dbf3dbe6…
  • Rename the Public visibility tier to Internal (ADR 0041 §2, #480) 6969626d · dbf3dbe6…diff
  • Sweep the rust-1.96 clippy debt; document the land-holds-the-binary hazard (#667, #681) 26cfbaa9 · dbf3dbe6…diff
  • the change graph gets one read view, and the two forwarding bands over it retire (#868) 826c3339 · dbf3dbe6…diff
  • loot-revset stops being a finished parser wired to nothing, because `loot log <revset>` and `loot shortlog` now read one door that tries the historic selector shape FIRST and only parses a non-selector word as an expression — which is what keeps `loot log <change-id>` working, since the crate reads bare words as hex while a change id is the letters k-z, so the grammar was never the strict superset its own docs and this ticket both claimed (#1495) dd223bf0 · dbf3dbe6…diff
  • 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
  • HEAD denotes TWO things and that is now a recorded decision rather than a latent trap: the selector HEAD is the dock finalized tip, the revset HEAD is the graph live heads which INCLUDES the unsigned working change, so with WIP present HEAD~1 typed as a selector and HEAD~1 typed inside a revset are off by exactly one - measured on a built 4-change repo, where loot log HEAD~1 answers add f2 and add f1 while the revset arm answers add f3, and the NEGATIVE state built the same way with no WIP has both grammars answer the SAME change, which is what gives the fix its condition instead of a guess. unification is refused in BOTH directions with the callers each break would cost, recorded in ADR 0085 along with four concrete facts that would make the decision wrong later. the legibility lands at revset::select, the ONE argv-to-set door, so all five revset verbs inherit it, and it fires on three conditions rather than on every invocation: the word took the revset arm, so a bare HEAD or HEAD~n stays SILENT because that is the commonest loot log and it already gets the reading every other verb gives; the parsed AST stands on a head, asked of the AST through a new wildcard-free Expr::names_head so a new primary cannot compile without declaring a side and a description pattern spelling HEAD stays silent; and the two grammars ASKED disagree, comparing evaluate against resolve_selector rather than re-deriving is there WIP anywhere, so the note cannot drift from either grammar and the diverged-dock case works without being enumerated. stdout is untouched and the json and porcelain channels are pinned clean. site is NOT involved and that is a MEASUREMENT rather than an assumption - no page under site documents either grammar - with the rule recorded that a page gaining one owes a row. and CONTEXT caught a false claim en route: the selector-vs-revset entry still carried the #1562 reason that HEAD~x is unmistakably the HEAD~n shape with a bad number, refuted by #1562 itself and load-bearing for the shape-first order, so it is corrected in place with the history. seven mutations with counts read, two of them reddening BOTH the unit and the smoke pin, and one control asserting SILENCE when the readings agree (#1568) 68521a66 · 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
  • the open-ended range is typeable, and its meaning is WRITTEN BEFORE IT IS BUILT: x.. is exactly x..HEAD, the ancestors of the revset HEAD minus the ancestors of x, which in words is everything on the current lines of work that x does not already reach - stated in the grammar and mirrored at Expr::Range, at parse_range, in the log USAGE line, in CONTEXT and in the parse-error hint. three things are said explicitly because each is where another tool habit would mislead: it is NOT descendants(x) minus x, since a sibling line reaching a live head is in the range and is not a descendant; it is PLURAL on a diverged dock; and it inherits the ADR 0085 note. it is a DESUGAR rather than a new AST node, so parse of x.. equals parse of x..HEAD and the evaluator, head_depths and the CLI door grow no case and cannot drift from the definition. ..y is REFUSED and the reason is an ASYMMETRY rather than a preference: the two conventions an operator arrives with DISAGREE, git reading ..y as HEAD..y and jj reading it as root()..y which in loot, with no root sentinel, is exactly ancestors(y) - different sets, so either default silently hands half the users the other half answer. the RIGHT endpoint has no such split, git x.. being x..HEAD, jj x.. being x..visible_heads(), and the loot revset HEAD already BEING the live heads, and that asymmetry is the whole argument. secondarily the jj reading is already spelled ancestors(y), so accepting it would mint a second spelling of an existing primary. precedence is PINNED AS TREES rather than as sets, nine shapes including the one that decides the rule - a1..~@ parses as a1.. ~ @, because ~y is not a primary and so the .. before it is open - and open-versus-closed is decided by a wildcard-free starts_primary, so a new token cannot compile until it declares its side. the note behaviour changes DELIBERATELY and is recorded in both places: x.. parses to Range(x, Head), so an expression containing no HEAD token can now print the ADR 0085 note, which is the note doing its job, because nothing in abc123.. hints that its answer includes the working change. two stale claims are corrected where they live, the HEAD~5.. and abc123.. are-errors assertions and the this-ticket-does-not-close-it block, since HEAD~5.. now ANSWERS. seven mutations with counts read, and ONE EXPOSED A BLIND SPOT IN THE NEW PIN ITSELF, left stated rather than implied: the smoke repo has one live head and it IS the working change, so x..@ and x..HEAD denote the same set there and a wrong supplied endpoint leaves the smoke GREEN - which endpoint the grammar fills in is measured in the revset fixture instead, whose graph forks (#1570) ee081e23 · 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.