Changes touching this path

  • TS SDK slice 6: physical mode openRepo over the shared LootRepo interface (#428) The second backend: openRepo(path) drives an on-disk .loot/ checkout by shelling out to the installed loot binary, returning the IDENTICAL LootRepo the in-memory mode defines — so calling code is backend-agnostic. The binary owns all crypto/codec; physical mode adds none (no WASM). - CLI (sanctioned tiny machine-output addition, #428): `loot surface --porcelain`/`--json` emit the current readable tree as path+visibility (loot-core `verdict::surface_{porcelain,json}`), so `list()` never scrapes human text. An empty repo is an empty tree, not an error. - sdk/src/physical.ts: openRepo → PhysicalRepo via child_process. list() parses `surface --json`; read() streams the materialized file (a real byte stream) → NotFound on ENOENT; edit/remove write the working copy (capture-first) and record a client-side overlay so status/diff report kinds (added/modified/removed) against a committed baseline captured at open + refreshed on push — loot folds a described change into the current tree, so surface alone can't tell add from modify. describe/push shell out (`describe -m`, `new`); guards map to --allow-demote. Errors map to the shared taxonomy (missing binary → setup error; parent-moved → ConflictError; non-repo → NotFoundError). - Seam: `runReadContract` extracted to sdk/test/read-contract.ts and now runs VERBATIM against BOTH backends (connectRelay and openRepo) — the proof they are interchangeable behind one interface. physical.behavior.test.ts adds a write round-trip + error surface. 32 SDK tests; loot-core/loot-cli green. Deferred (documented): physical private-visibility authoring (a .lootattributes rule) and pull-with-remote behavior — public content covers the AC and the in-memory backend covers private. Refs #428, #422. 9d12a388 · 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.