Changes touching this path
- 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… - 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 - range-diff pairs by the DURABLE CHANGE ID and by nothing else, which resolves a real tension between two of its own acceptance criteria rather than papering over it: AC1 asks for content similarity and AC6 forbids comparing content across a visibility boundary, and a similarity scorer is EXACTLY the construction AC6 rules out. git scores patches because a git commit has no durable identity - loot RECORDS what git infers, and the handle survives re-snapshot, amend and refit, which is precisely what a rework is. so the pairing is exact, O(n+m) instead of O(n times m) content deltas, and STRUCTURALLY INCAPABLE of comparing content: pair takes two slices of identifier pairs, no Workspace, no keyring, no clock, no tree, and its only production builder reads GraphView, which loot-core documents as excluding anything that touches stored bytes. the evidence that the property is held by the TYPES is that the pairing tests need no repo at all. the verb is the FIFTH RENDERING over the delta seam and builds no differ: each pair body is the seam spec, the seam delta and the seam renderer, byte for byte. what the rule cannot pair it SAYS SO ABOUT rather than guessing - no change id from a legacy or git-bridge ingest, copies, which mint a fresh handle by design, and divergent handles, paired in order with the surplus named. the skip count is argued rather than waved past: its three inputs are change ids that are cleartext on every node, recorded addresses the engine already compares without decrypting, and a fact about THIS READER keys, so the most it can say is that two versions differ in paths you cannot open, which any holder computes from the recorded addresses alone. fifteen mutations, all red with counts read, and AC6 positive control pairs an EMBARGOED change and a readable one in the SAME RUN by the SAME RULE, with only the rendering differing. two findings came from looking at real output rather than reasoning: an amend records the superseded version as a PARENT as well as a predecessor, so a different-bases warning fired on every amended pair until same_base learned it, and a superseded version CANNOT BE NAMED BY A SELECTOR at all, so the revset door is the only way to aim at the left-hand side of an amend - a thing this verb can do that diff cannot (#1533)
c4b0cd67 · 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 - a published speedup that exceeded a ceiling measured three paragraphs below it is WITHDRAWN rather than explained, and the instrument that measured the ceiling is REFUTED BY MEASUREMENT rather than by argument: a discarded second read_graph measures the MARGINAL cost of an extra decode while the pool is still alive, not the first call share - it reads 151.5 ms against a whole region of 148.4 on one after binary and 162.5 against 157.7 on a second, over 100 percent of the quantity it is a fraction of, twice, on separately built binaries. the replacement stops the function instead of doubling the read, and its bands SUM to the region: read_graph plus pool build 154.3 ms at 89.8 percent, walk and splice 16.2, objects and keyring 1.4, against a region of 171.9 - so the ~89 percent decode finding SURVIVES the loss of the instrument that first produced it, and on that pair the change removes 13.9 of the 16.2 ms it could touch, a delta that FITS. the magnitude itself is re-measured across 156 gate runs in one sitting on an idle machine, every run exit 0, discarded 0 batches, carrying a VALUE rather than reading skipped, with the harness own probe at 1 to 9 percent and no exit 3 or 4 anywhere: three independently built before-and-after pairs read minus 13.6, minus 8.1 and minus 10.6 percent at depth 1024, disjoint at both depths in every pair, with graph-load flat across the same invocations - so the answer is published as minus 8 percent conservative and about minus 10 middle, and the spread is the BINARY rather than the machine. the residual is stated and NOT reconciled: the clean pair 22.5 ms exceeds the 16.2 ms band it should sit inside, and the clean pair own band cannot be measured without making it un-clean, with corroborating evidence that the instrument perturbs what it measures - the stop-instrumented after binary reads a read-and-pool band ABOVE its own whole region, an early return costing more than the work it skips, six rounds out of six. what would settle it is named as an exact allocation counter over the region that no half records today, and it is left as instrument work rather than done here. the copy in the fixture now quotes NO figure at all, keeping only the shape, because a figure quoted anywhere else is a copy. the in-loop guard stops checking the OTHER guard than the one its prose names and is asked every rep of the position under measurement - proved by a mutation pair where a no-op ingest is caught RED at 156 passed 2 failed and, with the same guard disabled, GREEN at 158 passed 0 failed, which demonstrates the blindness rather than arguing it. the ADR masthead stops enumerating its own amendments and points at the inline marks that already carry their tickets, the fixture stops claiming the ancestry is the real path when its root is parentless and the walk stop predicate never fires, the Err arm stops asserting a merge as the cause it never established and hands over the selector quoted refusal instead, and the shallow header stops calling a convention mechanical when nothing enforces it (#1888)
dc524dd2 · 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 prose pass narrows claims that read wider than the code, and LineDelta::rendered goes crate-private. ADR 0007, CONTEXT.md and the object_and_key_at doc say the reveal gate is asked at every read through the grant key door, not at every read, since grant_sealed keeps its escrow fallback by design; the Refit enum count, the family list in CONTEXT.md and the refit.rs header, and a stale claim that every planner runs the draft check, now point at the enum and the wildcard-free minted_edges match instead of a count; role_display gets back the blank doc line rustdoc folded into the last bullet, verified in the built HTML, and a record type added to ReservedRecord replaces a third record type; the Landmark entry records the one-line rendering from #1519; the revset named door and the hunkpick PATCH constant state the exceptions a reader finds (grep writing its own refusal, restore spelling -p out under the main.rs census); the ChangeGraph insert doc stops saying the callers do not insert parents-first, names DagRepo::apply_sync for an apply_bundle DagRepo does not have, and says why the ordered ingest_shared_lineage splice stays on insert; ADR 0023 now says what #1870 wrote in the delta_shape header, that the reveal_at split is about the field and not the number, which embargoed@ can carry. nineteen assertion messages lose the run of spaces a rewrap left inside the literal. LineDelta::rendered and Rendered become pub(crate), with a compile_fail probe and a positive control: the probe was red before the narrowing (2 passed, 1 failed), and making the method pub again reddens it (3 passed, 1 failed). items 2, 8 and 14 need no fix here: the #1515 raise is real because #1516 lowered the ceiling between the two raises, #1968 dropped the width narrative, and #1860 withdrew the figures. cargo doc warnings are unchanged for loot-core, loot-codec and loot-cli. no migration, no wire or format byte moves, and no forge or relay byte moves, so this owes no deploy. the workspace suite is green (3913 passed over 123 binaries, 7 ignored) (#1848)
eb966bdb · 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.