Changes touching this path
- the opt-in telemetry channel is built, and off means no call because a paired test says so rather than a sentence
loot#1658, building what ADR 0074 specified and loot#1626 shipped only the
guard for. loot telemetry on | off | status | show; an append-only accumulator
that writes one line per dispatched verb, the dispatch-table name, with burn and
maroon collapsed to other AT WRITE TIME so no local trace of an incident exists
either; a sender that runs in main after the verb has printed and decided its
exit code, at most once per 24 hours, behind a 3-second hard timeout, that can
never print, never change the code, and never delay a verb; a spool that IS the
outbox, so show reads the same entry the sender transmits; and a 16-byte id
minted on opt-in and deleted on opt-out, never machine-id.
The guarantee is the pairing. One local listener, the real binary, a sandboxed
config home: init, status, doctor and show with telemetry off make ZERO
connections; on, the same verbs make EXACTLY ONE, and the same verbs again in
the same period make no more; off again makes none. A lone assert-zero passes
when the listener is broken, the binary crashed early, or it pointed at the
wrong port - the exact shape of the logrotate -f check that could never fail.
The endpoint override is https only with the loopback LITERAL the sole
exception, enforced twice, and localhost is refused because what it resolves
to is the resolver business; the refusal happens BEFORE an id is minted, so a
broken override never leaves an identifier that can never be used.
Clause 5 of the field rule is a property of the wire bytes, not a promise:
a test parses every string out of the JSON and requires each to be a
compile-time constant, a member of a fixed array, a dispatch-table name, or
the hex id. The platform is a build-script constant rather than a runtime
assembly from std consts, which is what the rule forbids spelled from constants.
The verb emits machine output - show --json IS the report - so it joins the
emitting tier rather than the prose-only debt list the ceiling forbids growing.
Every count that moved was moved in the documents that state it, because the
censuses read them: 129 verb lines in three sites, 82 dispatched and 80 in the
table and 25 emitting in ADR 0066 with telemetry in the named list, all 82
verbs and the block in the README, the CLI page, and ADR 0074 eight-entry
allowlist - because the endpoint is now the binary ONE destination it contacts
rather than prints, and its ALLOWED row says under what condition.
The destination census flagged three lines that dial nothing: a printed hint
naming http://127.0.0.1 and the two scheme-prefix tests in check_endpoint. They
are respelled rather than exempted - the check splits on the separator and
compares the scheme WORD, same rule, no allowlist row - because a row is a
sentence someone has to be able to defend and these had nothing to defend.
The site half: POST /api/telemetry validates a report against the SAME closed
sets the binary declares, pinned cross-repo by reading the Rust source, and
refuses WHOLE on any field outside them. A valid report becomes source=cli
rows, one per verb invocation under /cli/<verb> plus two bucket rows, all
stamped with the arrival time so no ordering exists to reconstruct; the
telemetry_id rides the row and expires with the 30-day partitions. It sits
behind the same /api/ limit_req the beacon needed, which is why the ADR put it
there. doctor prints on/off, the EFFECTIVE endpoint, last send and the spool.
The notice gains the CLI tier, as ADR 0074 §11 requires: sends nothing unless
you run on, the id links reports and off deletes it, what is never in a report,
show prints it before you decide, and the erasure route - quote your id within
30 days, you hold the key. The test that asserted the page does NOT collect
telemetry is inverted, as it was for the visitor key.
1214 lib and 118 bin tests, 51 suites, 634 site tests, budget and font gates
green, rendered and read.
8a919b01 · dbf3dbe6… - a relay or forge answer that keeps arriving is read whole however long it takes, and one that stops fails on a named budget instead of hanging. reqwest blocking client defaults to a 30 s timeout that wire.rs believed it never set, and bytes() held it over the whole download, so loot clone failed with it did not answer in time while the answer was still arriving. transfers now carry a 30 s silence budget on the client and read the body read by read, so it bounds each wait for bytes and not the download; a probe keeps its deadline as a request timeout over the whole request. a timeout now names the limit that fired, no answer began within, no bytes for, or a probe deadline, claimed only when the failing wait lasted it, and no timeout says the relay is cutting the response. red first, the shipped binary clone through a local proxy throttled to 3 kB/s failed at 30 s with the ticket message; the lane binary cloned it (70 s body) and failed a proxy that stalls mid-body after 30 s naming the budget, and a read-only depth 1 clone of the live relay took its 53.7 MB answer in about 118 s. red under mutation: the body read through bytes() (2 passed, 1 failed), the transfer budget as a request timeout (2 passed, 1 failed), a client with no timeout (1 passed, 2 failed, both hung to the guard), a probe deadline on the client (0 passed, 1 failed), the budget claimed without the wait check (0 passed, 1 failed), and the timeout remedy put back on the cut sentence (0 passed, 1 failed). no wire or format byte moves and no forge or relay byte moves; the client binary change owes a release. the workspace suite is green (3942 passed over 123 binaries, 7 ignored) (#2064)
ef88503d · 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.