Changes touching this path
- loot count-objects lands, and the constraint it is built under is that its number has to be the number gc acts on rather than a second opinion about it: the unreachable count and the reclaim figure are gc OWN pruner and sweeper called with dry_run, over a keep set extracted out of gc as DagRepo::gc_keep_set the way 1505 pulled fold_onto out of converge, so a census that disagrees with a collection is not a thing that can be written, and the pin measures a store, really collects it, then asserts the two halves and the sum all match. One premise of the ticket was wrong in the direction that saved work: nothing reported how large a store is as a VERB, but the totals half was already factored, since RepoStore::objects_size has been the perf record load-bearing counter since 632, so this adds no third walk of the object directory at all, it adds a caller. The extraction surfaced something gc had been getting away with: its keep set was position-dependent, because the primary own working change is the one root in neither the shared graph file nor the lane registry and verify has been adding it by hand since 1309. gc could not notice, since it refuses from anywhere but the primary, where those oids ride in the loaded graph anyway; a read-only census can run from a lane, so the root moved into the shared function and the answer stopped depending on who asks. Machine output is this verb product rather than a garnish, which is why the porcelain is one row per metric keyed by a leading mark instead of one wide row: ADR 0023 makes a column unaddable, and a census is the shape most likely to be asked for one more number. The anti-vacuity pin is the same fixture reading 1 and then 0 with nothing changed but a change naming the orphan, and the read-only pin fingerprints every file under .loot rather than trusting the op log, which would never have shown a pruned object. On this lane own store it reads 7910 objects at 146.7 MiB with 2330 of them unreachable at 36.9 MiB, which is the 1524 baseline (#1523)
f10ba1d9 · dbf3dbe6… - format-patch stops filing re-seals under a heading that promises the opposite, and its header starts saying in numbers what the body could not carry. the omission list headed itself so that a path left out is never read as a path that did not change, while rung 2 - content is byte-identical, only the seal moved - was filed under it, so the closing N path(s) omitted added withheld paths and re-seals together and neither reader could recover their own number. there are now two headed lists and two closing counts, and patch_omission returns which list a row belongs on rather than a bare reason string; the bytes-differ-but-lines-do-not row stays on the withheld side, because something really changed there and this patch cannot carry it. the header gains omitted, omitted-reasons, unchanged and lossy, always present and 0 or none when empty so that nothing was left out and this writer does not say stop being one observation, all read off a single PatchFidelity the body's own classifier produces rather than a second walk that could call a patch complete while the rendering withheld three paths. PATCH_FORMAT stays 1: the rows are additive and the format had zero consumers, so there was no reader a bump could protect, and that reasoning expires the day 1513 ships. included stanzas deliberately carry no tier - it would have to ride in git's extended-header region, the one place that can cost the git apply promise, and a row's visibility is today's standing .lootattributes policy rather than the version's recorded marker, so exporting it would ship the sending repo's policy as if it were a property of the change. lossy is measured from the included stanzas' own bytes rather than declared, and the end-to-end smoke shows it firing on a real crlf file whose rebuilt bytes are lf. the git apply promise is pinned at last by a test that shells out to real git and skips with a printed reason where git is absent, and the mutation proving it non-vacuous found something worth recording: git apply is lenient about line numbers - shifting every hunk start by one left it perfectly happy - so the strict in-tree applier sees a defect this test cannot, and neither is redundant. beside that: converge gains merge's N path(s) need resolution summary from a shared helper, since the fold a no-remote repo reaches was the one printing conflict rows and then converged onto one line with no next move; hunk_body's comment stops claiming to be the only place file bytes reach a terminal, which patch_hunks made false the day it landed; the fourth-versus-second rendering count is settled at fourth, which is what Rendering's own members count; and the census seam records that a census run from a lane roots the primary's working change only through the working-change blob, so a torn one over-reports unreachable while costing nothing, the run being dry and a real gc re-rooting those oids from the primary (#1786)
e41bae33 · dbf3dbe6…diff - packed object storage lands its READ half, and the decision that could not wait for the writer is what a pack is ALLOWED TO GROUP: membership is the address first byte, order is the address order, and the reader REFUSES both violations rather than the packer promising them. a pack adds structure over addresses and that structure sits OUTSIDE the ciphertext, so a packer grouping by grant list or visibility tier would make the pack boundary BE the set of objects a reader cannot open - an authorization-set disclosure produced by a storage layout, which no encryption below it helps. the rule is safe structurally rather than by good behaviour: addresses are blake3 over nonce and ciphertext (ADR 0004), so bucketing by addr[0] is provably uncorrelated with custody and a packer CANNOT group everything one identity can open. the stronger rule, no loose object in a packed bucket, is rejected as unimplementable, since one object arriving after a repack would make every store refused; the residual packed-or-loose bit is an arrival-order fact mtime already discloses. FORMAT_MAJOR goes 13 to 14 at the READER and not at the writer, because the number should mean written by a binary that can read packs, and deferring it to 1525 leaves a window where some binaries read packs and some do not and all report 13. what the bump buys is a named refusal instead of a silent lie: pack/ is not a 64 character hex name, so a v13 walk SKIPS it and reports every packed object MISSING, referenced by change and by path, where v14 answers UnsupportedFormat found 14 supported 13. v14 is the first major in this history that moves no wire layout at all, measured rather than argued - the two frozen parity vectors moved by their marker byte and every other frozen vector beside them is byte identical. two findings beyond the criteria. packing breaks ADR 0038 burn SILENTLY: destroy_objects_loose deletes a file, cannot reach a span in a pack, and would not fail either, the already-destroyed arm swallowing it while the caller records a tombstone over LIVE ciphertext - it now refuses, and the guard asks the DISK rather than the live index, because the index version was vacuously green with burn having removed the address before the save runs. and a packed read must re-hash where a loose read need not, since a wrong offset yields a DIFFERENT VALID object under the wrong address rather than garbage. the membership pin was vacuous on its first writing too, filtering with the same function the code bucketed with, so it asserted only that the two agreed (#1524)
eb753b9f · dbf3dbe6…diff - loot verify --unreachable lands the dangling report and closes the packing family, and the thing it does NOT do is walk: it answers from gc_keep_set, so the whole new computation is a SET DIFFERENCE over the scan the integrity check was already doing - no third reachability walk and no second directory pass either. 1523 refused to write the second one and this refuses to write the third, which matters because a report that could disagree with the collection it names as the remedy is worse than no report. the two directions deliberately take DIFFERENT root sets and that is the subtle half: verify own node list stays the roots for MISSING, because it carries the referencing change and path that a bare oid set cannot, while the keep set is the roots for UNREACHABLE, because it additionally holds the loaded graph and it DROPS burned oids under ADR 0038 - so using it for missing would hide deliberate destruction, and reporting a burned object as missing damage is exactly the inversion burn exists to avoid. the primary own working change is seeded once in each, by the code that already seeded it. the exit rule is structural rather than a renderer discipline: is_clean does not read unreachable at all, so garbage alone cannot fail a verify however the report is rendered, and the process pin deletes an object the listing did NOT name, chosen by subtraction, so its missing half is a positive control on its unreachable half rather than a second assertion of the same thing. size is the SPAN length for a packed object and the file length for a loose one, never plaintext, which loot cannot know without keys - and the two halves are reported APART rather than summed, because that is what keeps each one checkable against its own collector: the packed half is GcReport packed_orphans by construction and the loose half is the census unreachable figure, and the census must go on excluding packed garbage to keep the promise it is pinned to. ObjectScan now carries how each present object is stored, which costs ZERO extra syscalls because both arms already held both facts at the instant they graded an address. one residual is documented rather than hidden: an address stored both loose and packed, the window inside a repack, is attributed once to its loose copy. and the empty case prints that every stored object is referenced by a change - the exact sentence 1525 had to qualify at gc as scope drift - where here it is NOT drift, because the enumeration behind it is scan_objects and that sees packed spans too; the asymmetry is pinned as a test rather than asserted in prose. the verbs census moved to 345 and its sentence moved with it, the first run in four where that did not go stale (#1526)
061af7f3 · dbf3dbe6…diff - the second review sweep of this run finds gc --pack crediting packing with the PRUNE bytes and staying silent about it, and the repair is a NARROWER SIGNATURE rather than a wider condition: size_note took the before and after totals and returned nothing whenever the store shrank, so on this repo own store, 2330 unreachable objects against roughly 250 KB of table, it would print 146.7 MiB falling to 110 MiB and say NOTHING - the exact misreading ADR 0083 warns about in its own text, in the verb written to honour that warning. packing_note now takes the REPORT and cannot see the totals at all, so no combined direction is able to suppress it, and it fires on buckets_repacked. the figure is measured by the packer rather than derived from the pair: overhead_of is header plus table, encode sizes its first body offset FROM it, and the report carries the table a rewritten bucket now holds LESS the one it replaced, computed above the dry-run bail so a dry run reports what a real run does. the pin the attribution actually rests on is new and runs a real repack over a store holding a loose orphan AND a packed one, asserting that before minus pruned minus dropped plus table equals after with every term from its own producer and the sum checked against a census none of them took, 11012 - 4141 - 4141 + 275 = 3005, and asserting the two directions genuinely disagree, which is the defect in miniature on real bytes. the pin that encoded the WRONG rule is deleted rather than preserved. four weak pins have now been found in one run and the last two were invisible to the mutation sweeps, because a sweep only tests the pins you AIM it at and therefore cannot find a pin that tests nothing - the count rule of 1812 proves a pin is LIVE, not that it is aimed at anything, and that limit is now written down. two mutations make the point by experiment rather than argument: under a copy-instead-of-rename and under a helper that unlinks a bucket without writing its pack, the OLD tests stay GREEN. one proposed fix is refused with its reason, that routing a reader fixture through the writer would assert only that the two agree and go on agreeing if both move together, which is the same vacuity the membership pin was written to avoid and which eight reader tests depend on not having; the real complaint is fixed by asserting a structural post-condition instead. the walk census contradicted itself inside one commit and the count is now stated ONCE in CONTEXT.md with the code referring to it, choosing live set as the load-bearing word because verify own node list is a ROOT SET FOR ABSENCE that is never consulted about deletion and deliberately KEEPS burned oids where a live set drops them. the commit record of c6b1cae carries the wrong version and cannot be fixed, so CONTEXT.md records that too (#1823)
907d2a9d · 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.