Changes touching this path
- 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… - 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 two arms of a pathspec compare one spelling now, a .lootignore subtree line spelled with a backslash stops ignoring nothing, and the symptom the ticket reported is measured as unreachable through the CLI. delta::Pathspec::matches read its bare-directory prefix arm off the pattern text as typed while its glob arm read a normalized one, so at the library door --path docs\adr kept docs/adr and nothing beneath it; and Pathspec::new trimmed a trailing / off the raw argument, so docs\ was neither trimmed nor matched by either arm and kept nothing at all. both arms ask policy::unix_separators now, which is where the rule lives, and Pattern::normalized is borrowed off the compiled pattern of the glob rather than stored beside it, so the text a reader compares and the glob that matches it are one string rather than a third value to keep in step. the headline of the ticket is FALSE at the CLI, and that is the main finding: PATHSPEC declares --path a path flag with a Slot::Path tail, the argv door rebases every such token (#1330), and that rebase ends in treepath::store_key, so a pathspec reaching the matcher from a real process is /-separated already on Windows and on POSIX alike, and the one route that skips the rebase, no repo above the cwd, ends in the not-a-loot-repo refusal of the verb itself before any path is matched. measured through the spawned binary on this Windows machine over status, diff, the positional form and a run from a subdirectory: every spelling already selected identically. so no separator hint is added to refuse_unmatched, because a hint naming a cause that cannot be the cause is worse than none; what the refusal does name now is the pattern in the spelling it is compared in, since Pathspec::new normalizes before the trim it always applied. the reachable instance is the one the acceptance criteria sent me to look for: Ignore::parse_recorded read its trailing-slash subtree affordance off the line as typed, so build\ missed strip_suffix and compiled to the glob build/, which matches no path at all, and the line ignored NOTHING where build/ prunes - fail-OPEN, the files staying in the snapshot and sealing internal, the tier a relay reads by design. .loot/view is correct and is pinned rather than claimed: View::matches is a glob match and nothing else, so it has no second arm to disagree with. red first on the tree as it stood: the delta pin fails at the bare-directory arm (0 passed, 1 failed), and reproducing the reported symptom through a process takes the library and the door together - with treepath::store_key dropped from normalize_rel and Pathspec put back, status --path docs\adr refuses where the slash twin narrows, while either half alone leaves the process pin green, which is the measurement that says the CLI was never broken. mutations: normalized returning the text as typed reddens the Patterns pin (26 passed, 1 failed, left docs\adr right docs/adr); the trim taken off the normalized spelling reddens the trailing-separator arm (41 passed, 1 failed); the subtree affordance read off the raw line reddens the ignore pin (25 passed, 1 failed, left false right true at build/a.o); and a second spelling of the rule, in delta.rs or in policy.rs, reddens the locality census (1 failed each). that census asserts at most one spelling rather than exactly one, because rewriting the normalizer without that literal keeps every behaviour pin green (34 passed) and an exactly-once census would tax a refactor instead of guarding against a second home; a not-gone-blind guard sits beside it. CONTEXT.md carries both halves, the store_key spelling of the rebase as the reason the pathspec defect was inert and the .lootignore separator as the fail-open one that was not. no migration, and no forge or site byte moves, so this owes no deploy. the workspace suite is green (3852 passed over 119 binaries, 7 ignored) (#1859)
67f8adf1 · dbf3dbe6…diff - test scratch directories are named by one shared helper, common::scratch, from the process id and a per-process counter rather than the clock, so two tests asking for one tag at once are no longer handed one directory that the second caller empties and refills (the #2258 mechanism): 19 test files under crates/*/tests named a temp_dir path from SystemTime nanoseconds in 21 statements and now call fresh_dir or fresh_path, loot-cli files reaching it through mod common and loot-first exit_codes compiling the same std-only file by path, and revset_everywhere and plaintext_equality_census, which already counted, call it too. scratch_dirs.rs holds the #2258 pin, moved from revset_everywhere and aimed at the shared helper, red under the clock naming in 13 runs of 13 (0 passed and 1 failed, 1 to 16 of 400 directories handed twice), and a guard that walks every .rs file under crates/*/tests and refuses a temp_dir statement that reads the clock, red over the unconverted tree naming the 19 files (1 passed and 1 failed), red with buoy_exit put back (1 and 1) and red when the walk finds nothing (0 and 1), each restored green. no other test changes what it asserts. the workspace suite is green (4533 passed over 140 binaries, 13 ignored, from 4532 over 139: the guard is new and the pin moved into its own binary). test-only, so it owes no deploy (#2358)
6dd1e05b · 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.