Changes touching this path
- the beacon counts PEOPLE where the log can only count requests, and the notice that describes it was rewritten in the same change because deploying one without the other publishes a falsehood
loot#1757, over loot#1620 and loot#1617. POST /api/beacon takes one short
message per view and derives SHA-256(daily_salt || ip || ua || site) truncated
to 16 bytes, in process, discarding both inputs. It is canonical for uniques and
sessions and for nothing else: the log stays canonical for volume, because it
sees the ~53 prerendered pages, the cache hits and curl, none of which run any
JavaScript. Two sources counting volume would be two numbers to reconcile.
The key is length-prefixed per field rather than concatenated, and that is a
real defect closed rather than a flourish. One of the fields is the User-Agent,
which the CALLER chooses: with plain concatenation ip=1.2.3.4 ua=5 and
ip=1.2.3.45 ua= hash identically, so a visitor could be merged onto a neighbour.
The mutation that drops the framing reddens exactly that pin and nothing else.
Two decisions are recorded rather than defaulted. NO SALT, NO ROW: a beacon row
without a key adds to a count of beacon rows while contributing nothing to the
only two things this source is canonical for, so it would trade what we came for
against a number competing with the log. And the module is EAGER, which is the
answer to the ticket first hazard - ADR 0071 weighs the document plus eager
assets, so a deferred chunk is paid by every visitor and counted by nobody.
Measured at ~450 B on each of 62 surfaces and RECORDED, and loot#1640 is the
precedent that makes this more than taste: it measured a lazy route at 581 bytes
against 270 eager.
The edge half is new and had to be, because this is the site first
unauthenticated row-writing endpoint and the site vhost had no rate limiting at
all. limit_req at the /api/ PREFIX, not at /api/beacon, so ADR 0074 telemetry
arrives protected rather than silently exposed. Idempotence is remove-then-
reinsert between markers, and loot#1647 install-detect arm is closed in the same
patch since it needed the same only-if-absent vhost step. Its ordering is
load-bearing: the blanket header insert runs while only hand-written blocks
exist, which makes a duplicate unrepresentable instead of guarded against.
Found by RUNNING it, which is the whole argument for the fixture: the marker
ended in (generated), which awk read as a GROUP, so the strip silently never
fired - the second run appended a second /api/ block while grep -v tore the
limit_req line out of the first, leaving a vhost that would have failed nginx -t
on the box. Pinned now, with a control proving the predicate can say no.
The notice had to move with the code. Five published statements would have gone
false, the worst being that these records carry no key and nothing links two
requests to the same person. Rewritten to lead with the key, say the secret is
DESTROYED rather than merely rotated, and disclose that a visitor spanning
midnight is counted twice.
FOUR more contradictions were then found only by RENDERING the page, which is
the third time that has been the only thing that worked. Objecting still said
the log is the only thing we collect from, so this control has nothing to
suppress - three paragraphs after the new text says the browser sends nothing
when you object. Erasure and Your rights both still claimed nothing is keyed to
you. And JSX drops a newline beside a tag, so the page shipped visitorkey and
notstored as single words. The font gate then caught a star glyph absent from
the shipped subset, which would have rendered as tofu.
A test that asserted we do NOT collect a visitor key survived all of this green,
because its regex matched one verb phrasing the new prose never uses. It is
inverted now: the page MUST name the key, MUST say destroyed, MUST disclose the
midnight double-count. Leaving it would have let a later edit delete the
disclosure and stay green.
532 site tests, 322 scripts tests, budget green with the notice raise on the
record.
3c22dcae · dbf3dbe6…
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.