Changes touching this path

  • the shipper gets its writer, its position and the two boundary conditions that would lose data silently, and the position lives in the SAME database as the rows for a reason the code now keeps: a crash between an insert and a position update double counts, silently, because the re-read yields perfectly valid rows - so commitBatch writes both in one transaction rather than the two calls I first wrote, which would have left my own migration comment saying committed alongside them while the code did no such thing. two stores can disagree after a crash; one cannot disagree with itself. the last line is consumed only if it is COMPLETE. nginx appends, so a run landing mid-write sees half a line, and parsing it would refuse it as malformed AND advance past it, so the finished line would never be read - a permanent silent loss of one request that no error would report. everything after the final newline is left for the next run. the boundary is found in the BUFFER before anything is decoded, because the position is a byte offset and user agents are routinely non-ascii, so measuring in characters would shift every offset after a multibyte line; the test carries its own control asserting the fixture really is multibyte, since otherwise it would pass under either implementation. the position is keyed by INODE and not by name, because names rotate - todays access log is tomorrows .log.1 and 1641 made rotation daily and unconditional - and a file SHORTER than our recorded offset was replaced under a reused inode, which logrotate create does routinely, so it is re-read from zero rather than resumed past its opening lines. a refused line still advances the position, or one unparseable line would wedge the shipper behind it forever, and that stall looks exactly like a site with no traffic. and the collision I predicted before starting gets a guard rather than a note: migration numbers are a shared sequential resource and NOTHING was checking them - land refuses a duplicate ADR number under the harbor lock, which is what kept 0074 and 0075 apart when two sessions wrote them the same night, but it knows nothing about site/migrations. two lanes taking 0002 would collide silently and the loser would never run, because the runner records by name and the winner already recorded it. six directory assertions now cover uniqueness, gaplessness, zero padding, and that each file records itself under its OWN name - the copy-paste mistake that makes a table quietly not exist under a green deploy - proved red by planting a duplicate 0002 (#1756) 823ebe57 · dbf3dbe6…
  • the shipper stops being able to ingest without a classifier, and the requirement is the mechanism rather than a note on a ticket: a row can NEVER be reclassified, because 1620 keeps no raw user agent so a later rule cannot revisit it - revisability is bought with provenance and not evidence, and history is never restated. so every row ingested before the shared classify module exists is permanently unjudged, and 1625 default view of class not in bot or internal would count that whole era of bot traffic as ordinary visitors, forever, with nothing in the data saying so. waiting costs NO data and that is what settles it: the logs are retained 30 days, so the bytes sit on disk either way. shipping early does not gain data, it converts recoverable data into rows nobody can ever classify. the type makes omission a compile error and the runtime check makes it an error for a caller that is not typescript, because this guard has to survive the bundler, the entry point, and whoever wires it up months from now - and the refusal says why waiting is free rather than only that it refused, since a message that explains the cost is the difference between someone fixing it and someone deleting the check. the boundary tests pass a real classifier through one helper rather than each supplying its own, so the requirement is stated once and those tests stay about what they are about. two new assertions cover the refusal and its reasoning, both proved red by disabling the guard. this lands the collector core complete and DORMANT: no timer is installed, so nothing runs, and 1756 stays open deliberately rather than being closed over something that does not execute (#1756) c2f0bc87 · dbf3dbe6…diff
  • site/test is type-checked by a project of its own that the site gate already runs, so a test that has drifted against the module it imports refuses a land instead of passing. tsc -b reached src through tsconfig.app.json and vite.config.ts through tsconfig.node.json, and site/test was in neither, so the gate ran those files and never checked them: a type error surfaced there only where it was also a runtime error. site/tsconfig.test.json is referenced from site/tsconfig.json, so npm run typecheck, inside npm run build, inside npm run gate, now reaches them. it is a separate project because vitest runs the tests on node while tsconfig.app.json holds src to an ES2020 browser floor, it includes src because src/routeTree.gen.ts carries the augmentation that types createFileRoute, and it sets allowJs because two tests import tools/budget.mjs; vitest.config.ts joins vite.config.ts in the node project. the first run was a survey and it was not clean: 8 errors over 5 files, every one fixed rather than suppressed, with no ts-expect-error owed and no option loosened. three fake MetricsWriters never learned the saltFor that #1620 added to the interface, private-diff built two outcomes on a LockReason of no-key the union does not contain, private-grants read .reason off a KeyLookup without narrowing to the arm that carries one, and budget-record read an optional reason as a string. proved live: a satisfies number[] on the cli-verbs row list is invisible to the runtime, 7 passed and exit 0 under vitest alone, while npm run gate exits 2 at npm run typecheck before vite build, the suite and the budget ever run. red under mutation: that same error with the new reference dropped is 0 errors and exit 0, saltFor dropped from a fake is 1 error, no-key put back is 2 errors, src dropped from the include is 1 spurious src error, allowJs dropped is 2 errors, the lib put back to ES2020 is 6 errors, and an Array.at added to src is 1 error from the app project, which still decides what src may use. the site gate is green end to end: 643 tests passed and 60 skipped over 52 files, 62 surfaces all under ceiling with nothing recorded. ADR 0071 gains the amendment and a corrected consequence, and CONTEXT.md its site gate line. 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 (3952 passed over 122 binaries, 7 ignored) (#1877) 4290f819 · 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.