Changes touching this path

  • the metrics dashboard ships as SIX STATIC PANELS behind an operator allowlist, and the two reviews moved it from a client-fetched page with a 401 to a server-rendered one that cannot be probed: 1623 settled Variant A, the Briefing - one column, one section per question, each caveat as PROSE beside the number it qualifies, which is the structural reason it won, since a caveat there cannot be skipped without skipping its number. the access decision is that being signed in is not the same as being the operator. anyone can sign up to this host and the data is site-WIDE - every visitor path, referrer host and install-funnel count - so the door is a custody list in the 1045 shape: a Clerk id is on it or it is not. it fails CLOSED in every branch, and the proof is that the fail-OPEN spelling was written and run: allowed.length greater than zero AND not includes, then return true, reads as careful and admits the entire internet the moment the list is empty, which is the state a box is in before its first deploy writes one. exactly two tests went red on it. the security review then found the route around that allowlist was the wrong shape twice over. the check sat INSIDE withPrivateSession, which maps an unauthenticated caller to 401 - so a stranger probing the endpoint got a 401 where an unserved path gets 404, and the refusal meant to hide the route confirmed it, while a load-bearing comment three lines up asserted the opposite. and the page itself answered 200 to anyone, rendering a document and only saying not found after a client fetch failed. both collapse into one server function returning null for BOTH refusals, which the loader turns into a real notFound: signed-out, signed-in-not-an-operator and a path we do not serve are now one answer. that rework is also what the ticket asked for and I had not done - the panels render into the HTML from a route loader rather than from a browser round trip, so the acceptance criterion about server-side rendering stops being approximated. the second finding is sharper than it looks: the route declared no headers, and every private route sets private no-store BECAUSE an nginx proxy_cache sits in front. an operator document without it is cacheable at the edge, which is the edge handing one caller a page meant for another. it now carries PRIVATE_HEADERS, and that constant own comment is widened to say it covers two tiers rather than left reading as private-only. one real data bug came out of the same review and no test I had written could see it: ordering a to_char MM-DD label sorts the series as TEXT, so any window crossing new year draws january before december - the sparkline scrambled about thirty days a year on the one chart whose job is a shape over time. grouped and ordered on the timestamp now, formatted on the way out, and pinned by asserting the grouped expression is not a to_char, verified by restoring the bug and watching it go red. built against the PRODUCERS rather than the schema, which is what the prototype was really for: visitor_key is null on every log-sourced row and permanently will be since 1632 took the address out of the log, so there are no uniques and no sessions here at all, and device, browser, os and country have no producer either. the panels that wait on one are rendered, named and marked rather than omitted - uniques on 1757, forge usage on 1758, downloads on 1647 and telemetry on 1658 - because a dashboard that silently drops what it cannot see is how you talk yourself into a wrong conclusion. not prerendered, and that is a security property rather than a build detail: a prerendered page is served as a static FILE with the static route headers, so an operator surface would exist as bytes anyone can fetch with the door never consulted - the same reason private joined that filter in 1043. asserted, and the mutation confirms the assertion bites. it is correspondingly absent from the byte budget, which discovers prerendered surfaces, and its styles stay in the route rather than styles.css because that sheet is eager on all sixty budgeted surfaces and an operator page has no business charging them (#1794) 2c969a0e · dbf3dbe6…
  • the download hop lands as a counted redirect that cannot be steered, and the two things 1647 asks for that do not exist yet are named rather than faked: GET /dl/tag/asset records a start and 302s to R2. the target is CONSTRUCTED from two validated segments and no byte of the request appears in it, because /dl sits on the hostname that also hosts the identity flow and the install one-liner - a redirect an attacker can steer is a phishing primitive wearing our provenance, a link that genuinely starts at our domain and ends wherever they chose. validating and then echoing is one refactor away from that; building from a fixed base plus two matched shapes is not. the segments are read from the RAW pathname rather than decoded route params, so this route decides what decoding means instead of inheriting it. every refusal is 404 rather than 400, because a 400 separates malformed from no-such-thing and telling a prober which guess was closer is free help. sha256.sum and the installer scripts are refused even though they are real files at that prefix: the hop counts download STARTS, and the land-time site gate fetches sha256.sum from R2 on every land - admitting it would make every land a download. ⭐ a mutation found one of my own guards doing nothing. deleting the explicit percent check turned NO test red, because the anchored patterns already reject percent - so the comment claiming it comes first because patterns are the fragile direction was describing a guard by what it looks like rather than by what it does. the code stays as a second fence and the comment now says it is one. unanchoring the tag pattern turns two tests red, which is the anchors earning their place, and the absolute-URL cases stay green under that mutation because the slash check is what catches them - a more precise picture than I had. the write-behind queue is built here because 1647 is blocked on it and it does not exist; 1757 shares it. enqueue is synchronous and never awaits, because this path serves the install one-liner where the caller is a shell script already piped to sh - a database stall there is the most expensive on the site and the least recoverable. bounded, drops the NEWEST so a burst cannot evict what preceded it, counts every drop because a silently discarded row makes the dashboard wrong in the direction that looks like not much traffic, and a failed flush puts the rows BACK rather than losing a batch to a blip. ⚠ NO visitor_key, and that is a deviation stated rather than a gap missed. 1647 asks for one derived from X-Real-IP as the beacon does - but the beacon owns the daily salt and neither exists, and deriving one here would make the privacy notice statement that these records carry no address, no cookie, no key FALSE the day it deploys. downloads-per-day needs no identifier; uniques do, and they arrive with 1757. ⚠ only ONE of the two internal arms is reachable. a request with no X-Real-IP never passed nginx so it is ours by definition, which covers the deploy probes. the edge computes loot_internal for our own hosts but forwards only Host, X-Real-IP, X-Forwarded-For and X-Forwarded-Proto, so install-detect - which runs the real one-liner through the public URL once per release - is counted as an ordinary download. a handful of rows per release rather than a distortion, and naming it beats a comment implying both arms work. EventRow source widens from log to the set migration 0001 actually permits. it said log while the shipper was the only producer, which read as a fact about the schema and was a fact about the caller. /dl joins the prerender deny list, or crawlLinks follows the new links off /install and the BUILD counts a download per platform per land (#1647) db35af90 · dbf3dbe6…diff
  • the drill-down takes the dashboard door and pays for react-table on its own route alone, and ADR 0087 records the metrics pipeline as one document loot#1804 and loot#1636 in one land, because a docs-only land pays the full gate and the drill-down is the last code the ADR describes. The drill-down is /metrics/paths and /metrics/referrers - a react-table over the same rows each bar panel summarises, sortable, bounded at 200 with the distinct count beside it. It is the only interactive escalation and it lives here, not on the dashboard: react-table is imported by this route alone, pinned by a test and MEASURED - the dashboard chunk moved by 80 bytes gzip for its two footer links, the drill-down chunk is 13.1 KB gzip and paid only there, and every other surface grew by ~220 bytes for the route-tree entry, which is the manifest cost loot#1640 predicted. Excluded from prerender by the /metrics prefix rule, METRICS_HEADERS for the dashboard reasons. The door is the hard part and it is the SAME door. operatorReader now lives in operator-door.ts and both the dashboard and the drill-down reach it through a dynamic import inside a handler, returning null for every refusal so the loader raises one notFound - a stranger, a non-operator and an unknown kind are indistinguishable from each other and from a path we do not serve. The kind is refused by the LOADER before the server function runs, and the validator narrows rather than throws, because a thrown validator would surface as a 500, a third distinguishable answer. Two defects were found by the BUILD and the BUDGET with the typecheck green both times, which is why both are pinned as tests rather than remembered. A plain exported function that a route module imports statically is not stripped from the client bundle the way a handler body is, so the first refactor dragged @tanstack/react-start/server into the client and the build refused it. And a VALUE import of two constants from the pg-backed reader put pg into every client bundle - 62 surfaces up by 24.8 KB each - so the constants a route may need now live in lib/metrics-drill.ts with no server dependency in the graph, and read.ts imports them back. ADR 0087 records the pipeline: three collection points and why no one of them can see the surface, the loot_metrics database and its three roles, the visitor key with the two rejected salt constructions, the route-shape rule and its two enforcement points, the account-reference amendment to the map, the retention and rollup boundary, the edge-log posture as the reason uniques need a beacon at all, and the departures and residue - the kept User-Agent, the eager beacon as the answer to the gate hazard, the error log, the out-of-scope vhosts, the shared disk. It is 0087 and not the 0074 the ticket named: telemetry took 0074 the night after this claimed it, and twelve more landed while this waited on its build tickets. Four glossary entries ride the same land - Visitor key, Session, Route-shape path, Marginal rollup - each with the framing it rejects. 624 site tests, published_surfaces gate green, budget green. 984260b2 · dbf3dbe6…diff
  • the dashboard reads the three sources that landed after it, each from where its facts actually live, and no raw identifier is ever selected into a result loot#1940, closing the one gap left on map #1615: /metrics was built against the log, and the beacon, the private tier and the CLI each wrote rows nothing read. People come from the ROLLUP, not from keys. rollup_day is the table built to survive, sessions are already derived there (same key, 30-minute gap, never an id), and its class is the one row rather than the NOT IN spelling because the rollup keeps bot and internal as their own rows. The series ends at the watermark and the panel says so rather than drawing a zero for a day still being counted. Docs by section comes from rollup_section_uniques - per section, never per page, labelled visitor-days because a returning reader counts once per day. Forge usage is the private tier by route shape, which is all its rows hold. The CLI panel counts reports, distinct ids and ids seen on two or more days inside the window, and states the bound ADR 0074 §11 sets: answerable for 30 days and never longer, because the rollup carries no id. Every one of those is an Awaiting state until its source has produced, and a CLI panel that has never received a report reads not measured rather than zero installs - the null-not-zero rule the download panel already keeps. A rule boundary inside the window is named across every headline (loot#1625). The read test list of columns nothing writes SHRANK from seven to one, because six gained a producer; the four that are written but unread stay refused for a different stated reason. The pin that matters is new: telemetry_id may appear COUNTED or GROUPED and never returned - every allowed form is stripped and nothing named telemetry_id may survive, with a control proving the strip removed something. The mutation that returns min(telemetry_id) as a column reddens exactly that pin. The header of read.ts stopped claiming the beacon is unbuilt and visitor_key is null forever, which had been false for a day. WINDOW_DAYS reaches the route from lib/, never as a value from the pg-backed reader (loot#1804). 639 site tests, budget and font gates green, the dashboard chunk 9 to 12 KB with no react-table in it. 6e8987f0 · dbf3dbe6…diff
  • the dashboard review fixes for 1940: every CLI query is under the default view, because the collector writes our own machines reports as internal and a dogfood run read as an opted-in install that keeps running, and returning now counts distinct UTC days like the rollup does; the docs-by-section panel reads only docs sections, since SECTION_SQL buckets every path and the panel titled docs was a site-wide top-8 with the root at its head; the rule-boundary marker is the union of the raw windows rule_version and the rollups own rule_versions array, which migration 0003 put on every rollup table for this read, so the two rollup-fed series carry their boundary too; the stale Forge product usage placeholder that #1949 left below the built panel is deleted and its one true sentence about edge-scrubbed forge paths moves into the built panels caveat. each of the three query fixes is pinned in metrics-read.test.ts and each pin went red under the defect it names. the hand-maintained counts (six panels, the three sources, seven columns and six of them, two stages have no producer) become the property they counted, the last hard-coded 30 days read WINDOW_DAYS, one exported dateOnly in rollup.ts replaces two byte-identical copies, one sinceDay spelling replaces the retyped rollup window and the test counts it, the Awaiting prop is why because it carries reasons rather than ticket numbers, and the dead alias in SparkVals is gone. tsc, the reader and rollup tests, the full suite, the build and the budget are green (#1940) 947fe6f3 · dbf3dbe6…diff
  • the metrics dashboard loads again: the installs-seen-again subquery was aliased returning, a reserved word in Postgres, so the statement never parsed, and because dashboard runs its queries under one Promise.all that one refusal took the whole page down for the operator with every gate green since 1940. the alias is seen_again. what let it through is that metrics-read.test.ts reads the SQL as text and nothing parsed it, so a new metrics-read.pg.test.ts, on the suites existing skip-unless-configured pg convention, runs the real reader as the real metrics_read role over site/migrations on a throwaway cluster: it went red with the production error word for word before the fix and is green after, along with both drill-down kinds and a seeded case that measures what the text pins could only describe, namely that an internal-class report is neither an install nor a return, that only docs sections reach the docs panel, that the rule versions are the union of the raw window and the rollup, and that the read role holds SELECT on every table the page reads. the text tests header now says what it cannot see and to run the pg test before landing SQL. tsc and the full site suite are green (#2010) 60af97d8 · dbf3dbe6…diff
  • a count of people is rounded before the dashboard draws it, because the exemption that keeps this site banner-free has an output condition nothing implemented: 1617s research recorded that the reports an operator reads must hold anonymous statistics only, holding under whatever combination of filters the operator selects, with present to the nearest ten as the recommended measure. that only began to bite when 1940 put people on the page, since before it every panel counted requests. presentPeople is the one place it is applied: a true zero stays zero, 1 to 9 carries no number at all and the page draws under ten rather than a zero over real activity, and anything larger goes to the nearest ten. it is a union rather than a number beside a flag, so an under-ten count has no n to read and a caller that wants a bar height has to ask for a magnitude and cannot print a floor as if it were a measurement; the boundary test proves 1 and 9 are indistinguishable and that no 4 survives into the value, and a floor that carried its count reddens exactly that pin. window totals are summed exactly and rounded once, which a mutation summing the rounded days reddens. what rounds is decided by the unit rather than by a list of panels: a field typed People rounds and a plain number does not, so a panel added later inherits the rule from its type. the rule lives in lib/metrics-drill.ts, not in read.ts, because a value import from the reader puts pg into every client bundle, which is 1804s defect and I had just written it. ADR 0087 records the decision, that under ten deviates from the recommended measure by disclosing that somebody was there, and why that beat a false zero on the operators own page (#1951) 71be502c · dbf3dbe6…diff
  • every compiled-in and current-tense loot host moves to loot.build (map #2412, ADR 0099): loot --help names security@loot.build and https://loot.build/trust, ALPHA_PROMISE_URL is https://loot.build/install and the telemetry DEFAULT_ENDPOINT https://loot.build/api/telemetry, so the next release carries them; the site install one-liners, R2_BASE and HOP_BASE (https://dl.loot.build, https://loot.build/dl), the metrics SITE_SCOPE and own-host referrer, the disclosure links on trust, terms, privacy and known-issues, and the install, quickstart and guides pages follow, with the privacy and terms markers moved to 25 September 2026 and re-pinned since readers see the new address; README, CONTEXT.md (the forge door now forge.loot.build), the release checklist, site CI and test fixtures follow, and the two specs carry a note instead of a partial rewrite. the destination census gains build in WEB_TLDS, without which security@loot.build would be invisible to its bare-host clause, and exempts the two shipped lines that tld makes read as hosts (state.build, r.build()) by their exact text; ADR 0074 section 9 says twelve-entry to match. 37 lines still name millerbyte.com outside ADR bodies, evidence, research and scratch, each kept on purpose: dated history, millerbyte.com the site and its @millerbyte/ui tokens, the two noted specs, and relay-era tooling with no successor host, filed as #2438. census red with build dropped from WEB_TLDS, restored; site gate 819 passed and within budget; workspace suite 4559 passed over 142 binaries, 13 ignored (#2418) c5663115 · 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.