Changes touching this path

  • telemetry gets a contract before it gets a sender: ADR 0074 settles what an opt-in loot binary may report, and the alpha promise stops enumerating what leaves your machine because that list could not have absorbed a fifth item anyway - a telemetry report is not experimental in the sense line 3 means, it is us. A report is a fact about the tool and never about the repo: every verb is counted with burn and maroon collapsed to other because each records an incident rather than a feature, timings are refused as repo scale laundered except one bucketed Workspace::open, and the rule that decides future fields is enforceable rather than prose because the report carries no runtime-constructed string except the telemetry id, which forecloses paths, messages, search terms and repo names by construction. machine-id is not reused because the arrival guard and an unlock session compare it, so exporting it would ship a security binding value to a server we operate. The spool is the outbox so show cannot drift from what is sent, the opt-in is a verb and never a first-run prompt because the dominant user of this CLI is a non-interactive agent and an opt-in a machine can trip is not an opt-in, and the relay half splits because loot serve runs from this same binary on a machine somebody owns while relayd and forge would be reporting on third parties who never opted in. What ships is the contract plus the guard behind the rewritten line 3, which sweeps every rs file under a crate src, blanks cfg(test) items by brace depth, and allows six occurrences each carrying a written reason - and it was checked against a planted destination before being trusted (#1626) f2998fea · dbf3dbe6…
  • the run's own signature defect, found inside the file it built to fix it: source_walk said four consumers while the very next land added a fifth, and the sentence is now generated rather than corrected - it walks src and tests through the module's own code mask so a mention in a comment or a string is not a call, groups by enclosing function because the destination census reaches the walk through a use import and a call-site count would miss it entirely, and pins the shape as well as the number by requiring every consumer's file be named, the declaring units equal the consuming units, and every consumer call the discrimination floor first. that last requirement is where this ticket was wrong: it said one consumer skipped the floor and that two others called it, but the crate held exactly two call sites, so three of five skipped it - all five call it now, and the reason is recorded at the verbs site, since its three anchors check that this walk found Workspace's methods while the shared floor checks the walker on the two cases it was written for and this tier has none of. ADR 0074's section 9 stops describing a walk that no longer exists: only the mechanism sentence moves, with a dated amendment quoting the old text verbatim and saying why it was worse than stale, because it named a bug the walk did not have while carrying two it did, while the purpose paragraph and the six-entry allowlist claim are untouched. the trust page's twelve-item enumeration goes, and the durable half is a fourth pinned surface beside install, the ADR and CONTEXT: the positive arm pulls line three out of ADR 0066 itself and requires both pronoun-free halves verbatim rather than typing them, the negative arm forbids a code element inside the alpha section because that is the regrowth shape twice observed, and both were proved red before being trusted. two stale copies this ticket did not name are repointed at the derived header instead of restating a number, and ADR 0066's own amendment turns out to name four things while listing five, which git show against the pre-amendment line settles as five (#1676) c1a195b9 · dbf3dbe6…diff
  • ADR 0074's destination guard was catching one planted shape in three, and the ordinal that a one-word fix left behind stops being a number at all: the census read only a scheme, so a bare relay.millerbyte.com in shipped source and a host assembled at runtime both passed silently while the ADR claimed no hardcoded destination could enter without someone editing the list - the predicate now takes a scheme or two dot-separated labels ending in a known web TLD, with underscore a token character rather than a separator so config.app_name does not read as a host hitting the TLD app, and that widening finds exactly one production line across the whole crates tree, the disclosure address in USAGE, which becomes the seventh allowlisted entry with its reason. every needle in that list is now asserted to still exempt a live line, so a dead entry fails instead of sitting there, and the ADR's own seven-entry sentence is read out of the ADR and compared rather than typed twice, with a stated-exactly-once guard so a vanished sentence fails rather than passing green. the limits that survive the widening are pinned as controls and written into section 9 rather than implied away: a suffix outside the known list, a bare IP, a host built at runtime, and any shipped file that is not rust. and the fifth thing this amendment said ADR 0074 adds becomes one more thing, because the enumeration it counted was deleted by the very change it describes and no referent survives to derive from - a position nobody types cannot fall out of step with a list that moved, which is the second wrong count in that one bullet and the reason for deleting rather than re-numbering. the twice-paid claim beside it gains its predicate too, since under any wrong count in this file the number is at least four and only under a typed count of one of its own lists is it two; and the revset composition #1497 promised turns out to work and is pinned behaviourally at last, the load-bearing half being that a two-change revset draws two nodes and a tilde rather than an off-screen parent (#1680) 37d450f1 · dbf3dbe6…diff
  • 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…diff
  • loot seek is easier to drive: --name <glob> matches a basename at any depth, spelled into the same pathspec as --path three ways, the glob for the root, **/glob for everything below it because the dialect **/ crosses one directory or more and never none, and **/glob/** for what a directory of that name holds because the bare-directory affordance reaches a root-level pattern only, joined by the group any-match rule, because the dialect stops * at a slash and every Rust file was a --path pair agents get wrong, with a glob carrying a separator refused as a path by code; the ambient target resolved is the root lexical absolute path rather than a dot, the same root --in <dir> prints, with no verbatim prefix on Windows, a value that moves where the key does not because a dot was never a location a later call could use, which ADR 0023 says; and loot seek --schema prints the verb machine contract as one JSON document from anywhere, contract first, derived from the code rather than typed: the flags off SPEC and the attached group, the marks and their columns off MARK_COLUMNS, the codes off code::ALL, and three examples the verb renders itself, an answer carrying every optional key, a counted answer and a coded refusal, with --json accepted and any question beside it refused. the codes come in two sets that say which is which, verb_codes off code::ALL and shared_codes off CliError::SHARED defined in error.rs where those slugs are minted, and the tables that are lists are pinned against what the code does: every mark constant read off the file is in MARK_COLUMNS with the arity a rendering under every Detail emits, code::ALL is every pub const in the module read off its own source, SHARED is every slug error.rs mints, and every key Answer::json can write is in the examples, the refusal example rendered by the multi-head raiser itself. the two-axis review before landing renamed the codes key before it froze under a name that read as the whole set, moved the --name refusal ahead of the target open so a bad glob costs a remote no round trip, said that --name is not rebased by the argv door because a basename is not a path and pinned it from a subdirectory, pinned the git-local and relative --in resolved, and corrected the ADR to the spelling the code makes. pinned in the unit tests on a nested fixture and the refusal, on the schema derivation, and through the spawned binary on --name equal to the pair it spells and not to **/ alone, unioned with --path, the ambient resolved absolute and equal to --in <root>, and --schema from a directory that is no repo. red under mutation, counts read each time: --name not spelled at any depth (0 passed, 1 failed), a --name with a separator accepted (0 passed, 1 failed), the ambient resolved staying where the verb ran (0 passed, 1 failed), --in <dir> resolved staying as typed (0 passed, 1 failed), --schema taking a question beside it (0 passed, 1 failed), MARK_COLUMNS forgetting the count row (0 passed, 1 failed), MARK_COLUMNS with an arity wrong (0 passed, 1 failed), code::ALL forgetting a slug (0 passed, 1 failed), the schema example carrying no refresh (0 passed, 1 failed), the schema omitting the bare flags (0 passed, 1 failed), SHARED forgetting a slug (0 passed, 1 failed), the schema omitting the shared codes (0 passed, 1 failed), the schema refusal example not the raiser (0 passed, 1 failed), a --name refusal waiting for the target to open (0 passed, 1 failed), and --schema answering a question instead through the binary (0 passed, 1 failed). 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 (3999 passed over 124 binaries, 7 ignored) (#2115) ca25f385 · dbf3dbe6…diff
  • the forge learns runners and jobs (#2157, ADR 0091, map #2099, first of three slices of #2129): migration 0018 adds the runner and job tables, both repo-scoped, so both join 0014 row-security set and take 0017 forge_is_bound_to_one_repo policy verbatim in shape, and tests/rls.rs ENABLED_TABLES names them, which is the set equality that forces the decision rather than a list nobody maintains. A runner is its OWN keypair under NO account and that is the security property expressed as schema: require_pusher and the proposal door both resolve a signer through account_key, so a runner key is refused at push and propose BY ABSENCE, where the same key on the owner account would have been a full pusher since require_pusher admits any live key of the account; the row is written from an envelope the namespace owner signed, which is a proof needing no browser session, so tests/account_tier.rs is green UNAMENDED. A job identity is the triple version, trigger, kind, so creation is idempotent by the primary key; member and approved are computed in at creation so a later membership change cannot re-authorize queued work; a claim is claimed_by plus a lease the CLAIMANT names, exclusive by FOR UPDATE SKIP LOCKED in the driver and one lock across find-and-write in the reference store; an expired lease returns the job by a READ-TIME predicate, so there is no reaper to fall behind; a verdict is accepted whatever the lease says, because the runner did the work and a bookkeeping deadline must not discard it; a job is born unclaimed and unfinished and a creation carrying either is refused, since those are the two writes that have to be exclusive. Trigger and Kind move from loot-cli to loot_net::pipeline, the one crate the forge and the CLI both already depend on, re-exported so every path reads unchanged: the forge stores what the CLI writes, and two copies of one vocabulary would be a list to keep in step. Capabilities is exactly Kind as a set, and a bit this build cannot name is REFUSED rather than dropped, because reading a newer runner row as covering less would hand it jobs it cannot do. Five conformance cases join the roll call, so both stores answer one contract and neither can name a subset. Measured: bash ci/local.sh green end to end against Postgres 18, 129 test binaries, 0 failed and 0 SKIPPED, which is what proves the driver, the migration and both policies rather than only the reference store; the claim exclusivity and the lease expiry are proved there on real Postgres, and an EXPLAIN plan under contention is NOT measured here and is owed to #2158 where the poll load is. Three refusals found by the run rather than by thought: the destination census flagged a fixture wake-up URL, allowlisted with the reason that it is a value the store round-trips and never an address anything dials, which took the allowlist to ten and moved ADR 0074 spelled count; the shipped-predicate pin read migration 17 alone, so it now reads the migration that CREATED each table rather than recording which came from where; and the binding fixture seeds a runner and a job row per repo, without which its controls were zero and the refusal below them would have passed for the wrong reason. Five pins each broken once by a named mutation, red at 1 failed then green at 0 failed with the count above zero: the claimable predicate widened, the lease made to hold forever, retirement re-dated, the born-claim refusal disabled, and an unknown capability bit accepted. No routes, no wire and no verb here; those are #2158 and #2159. No FORMAT_MAJOR move (#2157) ea4d34a5 · dbf3dbe6…diff
  • ADR 0099 records the move of loot from millerbyte.com to loot.build (map #2412): the site and one-liner at the apex with www redirecting, artifacts at dl.loot.build, the forge at forge.loot.build, security@loot.build through Cloudflare Email Routing with no catch-all, the relay not recreated, and the production Clerk instance on loot.build; and a hard cutover, the operator decision, in which the new names serve beside the old, a release carries them, every clone re-points its forge remote, and the old names are removed with no alias or redirect kept. it states what that breaks for anything made before it, read from the code: an opted-in old binary POSTs telemetry to the old name silently, so the old names must end NXDOMAIN rather than answered by the millerbyte.com wildcard, which would hand those reports to Vercel; old --help links; installers and manifests pinned to dl.millerbyte.com; the crates.io placeholders published with the old homepage, which only a new publish by the operator fixes; and it records the measured costs of the move (a 19.2 s first unlock on the new origin, no forge change because a signed request does not bind the host). ADRs 0037, 0041, 0045, 0049, 0061, 0064, 0066, 0067, 0074 and 0097, whose decisions name a loot host, each gain an amendment pointing here, and a banner where they had none; their bodies keep the names they were written with (#2414) bf2242c5 · 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.