Changes touching this path

  • SDK: inject transport/runner seams + map binary error codes (#432, #433, #434) Three architecture-review deepenings that make the two LootRepo adapters' decision logic testable without a live relay or the real binary, and replace stderr regex-scraping with the binary's coded error channel. #432 — RelayTransport seam. A narrow dumb-pipe (`post`) + default HttpRelayTransport, injected via `connectRelay(url, id, { transport })`. All interpretation stays adapter-side: response classification (401→AuthError+pubkey, non-2xx/connection-fail→TransportError) is a pure helper, and the push visibility-resolution + GuardError enforcement is extracted to a pure `resolvePushVisibilities`. New relay.unit.test.ts proves error classification, path-scoping, decode, and compose/guard against a fake transport — the WASM core exposes no bundle encoder, so decode/path-scoping replay golden `/fetch` bytes captured from a real relay (test/fixtures, regenerate with gen-relay-fixtures.mjs after a format bump). Relay integration trimmed to the read + write round-trip smokes (read.behavior/write.behavior); push-errors.behavior deleted. #433 — LootRunner seam. `run` (buffered, never throws on non-zero) + `spawn` (streaming) + default SubprocessRunner, injected via `openRepo(path, { runner })`. Physical error-mapping, arg composition, and pull streaming are unit-tested against a fake runner (physical.unit.test.ts); physical integration trimmed to the read + write round-trip smoke. #434 — map binary error codes → LootErrorCode. physical.ts reads `error.code` from the binary's `{"error":{"code","message"}}` under --json and maps it in one place (demotion/mis_seal/seal_wip→guard; unsupported_format/no_repo/unknown_flag →setup; not_found→not-found; else generic); all stderr prose regexes dropped. `run`/`pull` append --json, so the CLI's `new`/`describe` verbs now accept --json (not --porcelain — no consumer) to emit coded failures. loot's engine has no conflict-family slug (it accumulates forks rather than rejecting), so conflict stays deferred/generic — ConflictError remains exported for when a slug lands. e75ba364 · dbf3dbe6…
  • the sdk suite hands push a positional url again: --remote means a name now (#880) f8caca6b · dbf3dbe6…diff
  • the readiness waits over a spawned binary in sdk stop being budgets and start ending on the host itself, and the reason they were never seen to fire is now written where a reader meets them: every behaviour suite that stands a relay up polled a real loot serve behind Date.now() plus 20 seconds, which is a SMALLER budget than the 30 seconds that already lost in #1693 over a LARGER startup, and the 60 second beforeAll hook outside it sat inside the same measured spread, so raising the inner number alone would have left the effective bound where it was. the new sdk/test/spawned-host.ts has three endings and only the last is a clock: the probe succeeding, which is the condition these suites actually need since it proves the host ANSWERS rather than that it printed a line; the child exiting, reported with its code instead of polled at for the rest of the wait, seeded from the childs recorded state as well as its future exit event so a host already gone is not waited on; and a backstop carrying the same 600 seconds tutorial.rs carries, off the same saturated measurement and for the same reason, with the hook timeout derived strictly larger so the named refusal wins the race. the fixture generator imports that module rather than restating it, which node does by stripping the types itself. THE BEHAVIOUR SUITES CANNOT PIN ANY OF THIS AND THE CONTROL SAYS SO: with the condition deleted outright the whole sdk suite still read 11 files passed, because an idle machine has the relay up before the next await, so a dedicated pin over a spawned node child carries it instead. red under mutation, counts read each time: the exit ending deleted failed two of the three pins on vitests own timeout (2 failed and 1 passed, both at 5000ms, the wait running on to the backstop), the already-gone seed dropped failed the third alone (1 failed and 2 passed), and the probe discarded so the wait returns on the first look failed all three (3 failed and 0 passed, asked 1 against 3 and two promises resolving instead of rejecting), each restored to 3 passed and the sdk suite to 129 passed over 12 files. the gate question is NOT answered here and #2080 still owns it, but the sdk README now states what decides it and gives the grep that checks it rather than listing the workflows, and tutorial.rs stops naming budgets that no longer exist. no migration, no wire or format byte moves and no host behaviour moves, so this owes no deploy. the workspace suite is green (4178 passed over 133 binaries, 9 ignored) (#1914) 2cac70f9 · dbf3dbe6…diff
  • the figure the #1890 verdict rests on is now a column in the table it was missing from, taken the way that table was taken: the pre-#1572 clone spelling put back and the ignored sweep run once per arm, which reads the splice band at 41.3, 39.2, 38.0 and 37.2 percent of its own region on the before binary against 11.2, 6.2, 3.4 and 1.3 shipped, so the 37 percent the conclusion turned on is readable from the tree instead of from a session transcript, and the re-take reproduced every before and after cell already there to within one allocation. THE VERDICT IS NARROWED TO WHAT THE COUNT SHOWS: withdrawing the band ceiling and confirming the clean delta are separate acts and only the first was done, because a count does not convert to milliseconds - what is retired is a contradiction between two readings rather than the spread among the timings, and the published magnitude stays where they left it. two precision defects in the #2242 retraction go with it: the move over that size range is about 4.8x in the call and about 3.4x as a process and the sentence now names which, and rests on one reading is withdrawn because #2223 records no repetition count for its whole-verb rows, so what is known is that the figure does not reproduce and not how it was taken. the sweep doc had its axes inverted against the code under it and now states the property instead, that the shapes fall into runs holding one axis while the other moves, and the list class is answered for the third time in this run by replacing the two named untimed controls with the questions that decide membership. the duplicated in-loop guards are extracted: prove_the_position_has_not_ingested and prove_the_tip_was_spliced are asked by the timing and the count alike, each refusal written once and true of both. the named positive control is refused rather than built, because an in-tree knowingly worse arm means a wrong body in production code, and the before column now published stands in its place. sdk records the node type-stripping floor its .ts import imposes in engines, where npm reads it. red under mutation, counts read each time: the position control inverted failed all three allocation pins (0 passed and 3 failed, naming a position holding 1 change), and the splice control fed a false answer failed all three on its new text (0 passed and 3 failed), each restored to 3 passed. no migration, no wire or format byte moves and no host behaviour moves, so this owes no deploy. the workspace suite is green (4179 passed over 133 binaries, 9 ignored) (#2247) c8b11725 · dbf3dbe6…diff
  • the tutorial interrupt red #1916 read as a removal that lied is a tree made again after the sweep: on the linux runner std remove_dir_all answers success only once the root is gone, the captured transcript prints the first prompt ahead of the handler line, and walk, still running on the main thread beside the handler, opened with a create_dir_all over alice that minted the root back before ask beat the heartbeat into it. two delays injected into that sequencing reproduced the red and its alice, heartbeat remnant on this desktop with confirm_gone in place, so that check alone would not have closed it; Sandbox::create now makes alice before the handler is armed, the same two delays pass, and a unit pin drives the sweep, the walk and the beat in that order. what stays open is said at the fix: other writers, the relay thread and the loot subprocesses among them, can still put a path back mid-step. the CI run recorded the two readings and not the sequencing, so the mechanism is established by reading and by the reproduction rather than observed there, and workflow.md stops calling the report and the look one moment. the loot-s3 client keeps its 60 s budget for want of any measured rate to its bucket, but a request that runs out now names it and what it covers, where reqwest said error sending request or error decoding response body with no word of a deadline. the sdk doc stops claiming the native policy: the formula is copied, native allows the send budget between answer chunks where the sdk allows idleMs, the rounding differs, wire.rs now points back at the copy, and the unit test reads the floor from its constant. smaller: the engine.rs verdict compares the band against the band, the measure.rs refusals state a property instead of counting callers, the fixture generator import note sits at the import, and transportFailure takes a role rather than a string. red under mutation, counts read each time: create_dir_all put back in walk (11 passed and 1 failed, holding alice and heartbeat), the s3 timeout naming removed (12 passed and 2 failed), the sdk upload rounded down (6 passed and 1 failed), each restored to 12, 14 and 7 passed. no migration and no wire or format byte moves; the forge and relay deployables word a timed out object store request differently once next deployed, and no code in the tree matches on that text, so this owes no deploy. the workspace suite is green (4192 passed over 133 binaries, 9 ignored) and the sdk suite is green (137 passed over 13 files) (#2254) bdeb6a0c · dbf3dbe6…diff
  • the browser SDK head derivation skips a superseded version: the WASM core ChangeView, the JSON WasmBundle.changesJson renders, gains predecessors as hex ids, an empty list when a change supersedes none, and snapshot() in sdk/src/repo.ts drops any id some returned change names as a predecessor before folding the heads, the engine within_depth_of_heads rule, so heads() and the parents a push builds on no longer name a superseded version under unboundedRead against a host that sends one. the golden relay bundles are regenerated with the first change pushed, amended and pushed again, so the meta bundle holds a superseded version nothing names as a parent; the amend is a loot squash rather than the loot edit the ticket named, because an edit finalize records the superseded version as a parent as well as a predecessor, measured, which the old derivation already skipped. pinned in relay.unit.test.ts: the golden holds that shape, and heads() names the amend alone while list() does not show draft.md, the path only the superseded version holds; the shared parity check_bundle pins the empty list. red first against the old golden (20 passed and 2 failed). red under mutation, counts read each time: the predecessor filter dropped from snapshot (20 passed and 2 failed), the core rendering no predecessors (19 passed and 3 failed), the field left out of the JSON (parity 0 passed and 1 failed), each restored to green. no format byte and no migration moves and no host changes, so this owes no deploy. the SDK suite is green in the lane (139 passed over 13 files), the site gate is green (678 passed and 62 skipped over 62 files, 62 surfaces) with no ceiling moved, and the workspace suite is green (4323 passed over 137 binaries, 12 ignored) (#2137) a9fd3357 · 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.