diff --git a/.gitignore b/.gitignore index ff1f05b4..426c13cf 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,3 @@ title-recordings/ .jedit-text.edict-lawpack-build.lock .obsidian/ .claude/ -src/generated/jedit/structural-history-replace-text-range.wesley.generated.ts diff --git a/AGENTS.md b/AGENTS.md index 7d70f31f..06d7e1de 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,42 +33,26 @@ These are hard repo rules, not suggestions: ## Structure - `ARCHITECTURE.md` is the canonical repo architecture doctrine. -- `docs/BEARING.md` records the current execution gravity. +- `docs/jim-component-ownership.md` owns the Jim/Jedit/Edict/Echo target + ownership and causal model. +- `README.md` (*Current posture*) records current truth, the roadmap toward the + `Jim.edict` goalpost, and the hard gates; *Where Jim is going* records the + product direction. - `docs/method/process.md` is the canonical cycle workflow. - `docs/method/durable-decisions.md` owns the durable decision policy and the canonical-owner register. +- `docs/method/documentation-lifecycle.md` owns when documentation is kept, + rewritten, or deleted. - `docs/method/roadmap-planning.md` defines release-gate, roadmap, slice, and proof policy for multi-cycle planning. +- `docs/method/ci.md` describes what CI runs for a change. - `docs/design/TEMPLATE.md` is the required template for full cycle designs. -- `docs/design/0034-design-cycle-template-and-lifecycle.md` records the policy - decision that made executable design docs official. -- `docs/design/0024-jedit-powered-by-echo-release-gate.md` is the completed - baseline plan for the first thirty slices proving jedit has an installed - package/evidence path while Echo remains generic. -- `docs/design/0025-echo-application-hosting-pattern.md` is the completed - post-release-pressure ten-slice plan for proving the reusable Echo - application-hosting pattern before applying it to Graft, Think, or other apps. -- `docs/design/0026-echo-hosting-hardening-first-twenty.md` is the completed - hardening plan for slices 41-60. Keep track of our progress in that plan doc - by checking off slices just before you make the commit for that slice. -- `docs/design/0027-echo-hosted-production-cutover.md` is the active production - cutover plan for slices 61-80. Keep track of progress in that plan doc by - checking off slices just before you make the commit for that slice. -- `docs/BEARING.md` is the active plan for the powered-by-Echo completion - budget after slice 80. Keep track of progress there by checking off slices - just before you make the commit for that slice. -- `docs/design/0032-jedit-echo-reading-cache-and-fallback-boundaries.md` - records the local package for slices 101-110. -- `docs/design/0033-echo-authoritative-recovery-gate-b.md` records the current - local companion plan for consuming Echo recovery truth through jedit-owned - ports. Keep track of progress there and in `docs/BEARING.md` by checking off - slices just before you make the commit for that slice. - `scripts/quality-gate.mjs` is the current enforceable quality ratchet. - `quality-baseline.json` is temporary debt tracking, not permission to add more debt. - Keep it empty when the ratchet is clean. + Lower an entry when the debt shrinks, and remove it when the debt is gone. -Keep track of our progress in the plan doc by checking off slices just before -you make the commit for that slice. +When a cycle has a plan doc with a slice checklist, check off each slice just +before you make the commit for that slice. ## Durable Decision Discipline @@ -82,9 +66,9 @@ Chat transcripts, Think memories, pull-request prose, and review threads may motivate a decision; none of them is its repository home. Treat missing or stale canonical decision documentation as incomplete -engineering work, not optional polish. Historical design documents remain -evidence of their cycle; when durable current architecture changes, update the -current owning doctrine rather than relying on an old retrospective. +engineering work, not optional polish. When durable current architecture +changes, update the current owning doctrine. Obsolete documents are deleted, not +kept as history; follow `docs/method/documentation-lifecycle.md`. ## Design Cycle Workflow @@ -99,21 +83,25 @@ current owning doctrine rather than relying on an old retrospective. software surface: package API, runtime behavior, rendered output, scripted app flow, command behavior, schema validation, lower-mode output, or CI/tooling behavior. -- Design-doc assertions are allowed only as evidence-ledger checks. They cannot - be the only acceptance test for product, runtime, UI, or tooling work. +- Tests never read documentation. No spec, test, or gate may read a document's + content or assert its wording, so a docs change never changes a check's + result; see + [documentation-lifecycle.md](docs/method/documentation-lifecycle.md). - Fill in the design doc retrospective before marking the PR ready. - Create GitHub issues for deferred work instead of hiding follow-on debt in prose. ## Current Reality -The repo is still converging toward the full architecture doctrine, but the -enforceable quality ratchet is currently clean. +The repo is still converging toward the full architecture doctrine. -- `scripts/quality-gate.mjs` currently enforces no `any`, no `unknown`, and no - TypeScript file over 500 lines. -- `quality-baseline.json` should stay empty unless temporary ratcheted debt is - deliberately introduced and documented. +- `scripts/quality-gate.mjs` enforces the rules it prints (`npm run quality`), + including no `any`, no `unknown`, no enums, no type assertions, function, + parameter, import, complexity, and line-length limits, and a 500-line file + limit that also covers specs and tests. +- `quality-baseline.json` records the remaining ratcheted debt: line counts for + a few oversized spec and test files. A change may lower an entry, never raise + one. ## Delivery Workflow diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index b8d9f940..e16bf6e0 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -20,8 +20,8 @@ The broader project doctrine is written down in Ports describe typed runtime contracts. They do not decode raw payloads. - `src/adapters` - Concrete implementations for filesystem, MCP, Bijou integration, persistence, and process boundaries. - Raw strings, JSON, bytes, terminal events, and MCP payloads are decoded here and re-encoded here. + Concrete implementations for the filesystem, the native Echo host process, Graft, Bijou integration, and other process boundaries. + Raw strings, JSON, bytes, terminal events, and host payloads are decoded here and re-encoded here. - `src/ui` Presentation and input mapping. @@ -232,17 +232,21 @@ Why the boundary exists: - Graft's `StructuredBuffer` surface is an immutable parsed snapshot over `path + content`, which is excellent for language intelligence but not a substitute for an editor runtime. -- `jedit` still needs a lawful text-edit kernel with explicit tick-grounded - history, stable anchors, and eventually a persistent piece-rope worldline. +- Editor truth needs a lawful text-edit kernel with tick-grounded history and + stable anchors. The persistent rope is `jedit.text` law hosted in Echo's + graph (see `docs/design/0159-edict-rope-representation.md`), not a Graft + concern. - Structural projections and causal text truth are related, but they are not the same layer. The intended stack is: -- `jedit` core owns editing interaction and buffer lifecycle over causal text - frontiers +- `Jim.edict` owns editing interaction and buffer lifecycle over causal text + frontiers; today TypeScript and the native host hold this as compatibility + authority - Graft provides structural intelligence and parser-backed projections -- Echo / `echo-text` owns the native causal text substrate +- Echo owns generic admission, scheduling, graph state, receipts, and + recovery; it hosts the rope as application law, not as a built-in text engine - Echo persistence owns durable causal history - filesystem remains a working projection boundary - Git remains an ecosystem projection and compatibility export @@ -251,8 +255,9 @@ The intended stack is: implementation may use Echo internally, but `jedit` should not have to route canonical editor truth through Graft to reach its own causal substrate. -The transport used to reach Graft is not architectural truth. The current MCP -path is an implementation detail, not a long-term ownership claim. +The transport used to reach Graft is not architectural truth. The current +direct Graft API session (`src/adapters/graft-api-session.ts`) is an +implementation detail, not a long-term ownership claim. ## Testing Rule diff --git a/CHANGELOG.md b/CHANGELOG.md index 18cb40d2..1d854cfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,33 @@ ## Unreleased +- Folded `VISION.md` and `docs/BEARING.md` into `README.md`. *Current posture* + now holds current truth, the authority and artifact boundaries, the roadmap + toward `Jim.edict`, and the hard gates; *Where Jim is going* holds the product + promise, boundary doctrine, product goalposts, and non-goals. The README's + Vim-parody introduction is unchanged. Every reference now points at the + README sections. + +- Removed obsolete documentation: completed or abandoned design cycles whose + rules now live in code, specs, or canonical owners; documents for retired + interfaces (the TypeScript text runtime, optic session, WASM transport, and + structural-history generation); dated audit snapshots; the invalidated + `v0.1.0` release material; the method backlog, retrospective, and graveyard + directories; and five closed Edict probes. Still-binding rules moved into + their owners, live ideas became GitHub issues, and links were repaired. + `docs/method/documentation-lifecycle.md` now owns the rule that Git history + is the archive, `docs/method/ci.md` documents CI planning, and `AGENTS.md`, + `ARCHITECTURE.md`, `README.md`, `VISION.md`, `CODE_STANDARDS.md`, BEARING, + the ownership map, and the Echo guides were corrected where they had drifted. + Tests no longer read documentation at all: the specs that asserted Markdown + wording (`audit-docs`, `design-cycle-policy`, `guide-path-references`, + `echo-application-hosting-guide`, `rope-fact-inspector-design`, the Vim + command-line teardown check, and the design-doc ledger half of + `replace-range-law-cycle`) and the quality gate's `identity-doctrine-links` + rule were removed, along with the now-empty `docs-release` CI shard, so a + docs-only change runs build and quality but no test shard. Behavioural checks + were kept, including the lawpack digest sidecars and the cutover guard. + - CI now runs ShellCheck (`scripts/ci/shellcheck.sh`, in the `quality` job) over every tracked shell script and over the pre-commit and pre-push launchers that `scripts/install-hooks.sh` generates, installed into a throwaway repository. diff --git a/CODE_STANDARDS.md b/CODE_STANDARDS.md index f84c7229..05209a2b 100644 --- a/CODE_STANDARDS.md +++ b/CODE_STANDARDS.md @@ -79,7 +79,9 @@ For cross-realm values, normalize through adapters/boundaries and construct vali --- -## Strict Code Limits (Enforced) +## Strict Code Limits + +`scripts/quality-gate.mjs` enforces these: - **File size**: ≤ **500 lines** - **Source line length**: ≤ **160 characters** @@ -89,9 +91,12 @@ For cross-realm values, normalize through adapters/boundaries and construct vali nesting level) - **Cyclomatic complexity**: ≤ **8** - **Parameters**: ≤ **5** (use a named options class/object otherwise) +- Max 12 imports per file + +Review enforces these: + - **Class size**: ≤ **400 lines**, ≤ **15 public methods** - One primary domain concept per file -- Max 12 imports per file --- @@ -137,38 +142,11 @@ must be named before comparison. --- -## Sample ESLint Rules - -```json -{ - "rules": { - "max-lines": ["error", 500], - "max-len": ["error", { "code": 160 }], - "max-lines-per-function": ["error", { "max": 35, "skipBlankLines": true, "skipComments": true }], - "max-depth": ["error", 4], - "max-params": ["error", 5], - "complexity": ["error", 8], - "max-statements": ["error", 25], - - "@typescript-eslint/no-explicit-any": "error", - "@typescript-eslint/no-restricted-types": [ - "error", - { - "types": { - "unknown": "Use a concrete type instead of unknown" - } - } - ], - "@typescript-eslint/no-unsafe-assignment": "error", - "@typescript-eslint/no-unsafe-member-access": "error", - "@typescript-eslint/no-unsafe-return": "error", - "@typescript-eslint/no-unsafe-call": "error", - "@typescript-eslint/only-throw-error": "error", - "@typescript-eslint/switch-exhaustiveness-check": "error", - "@typescript-eslint/no-floating-promises": "error" - } -} -``` +## Enforcement + +The repository does not use ESLint. `scripts/quality-gate.mjs` implements the +enforced limits, the banned-language list, and the magic-literal ratchet above; run `npm run quality` to see the full +rule list and any ratcheted debt in `quality-baseline.json`. --- diff --git a/GUIDE.md b/GUIDE.md index f4f142e8..925d95fb 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -26,6 +26,16 @@ workspace launches that trusted Rust host as a child process. Set host is missing or exits, text operations fail closed. Jim does not fall back to a local text runtime. +### Startup flags + +`jedit --version` (or `-V`) prints `jedit `, where the version is +`package.json`'s, and exits. `jedit --help` (or `-h`) prints that line, the +usage `jedit [--version|-V] [--help|-h]`, and the two options, and exits. Both +return before the workspace module is loaded, so they never start the terminal +UI or the native Echo host. A flag counts only as the sole argument; any other +arguments start the editor. `src/adapters/jedit-startup-cli.ts` implements this +and `spec/jedit-startup-cli.spec.mjs` pins it. + Build the app: ```sh @@ -71,8 +81,8 @@ Jim command ``` The implemented surface is intentionally narrow: create/open a buffer, -single-range replace/insert/delete, and bounded text-window observation. Other -operations return typed obstructions. Edict will replace the transitional Rust +single-range replace/insert/delete, checkpoint declaration, and bounded +text-window observation. Other operations return typed obstructions. Edict will replace the transitional Rust operation law and invocation seam operation by operation; do not widen this compatibility path merely to regain feature parity. diff --git a/README.md b/README.md index 4e765c6a..f73d4c13 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ No, [get outta here](https://github.com/flyingrobots/echo#is-this-just-git). ### How Vim-like is Jim? -See `docs/vi_diff.txt` when available, along with the design docs and parity notes, for differences from Vim. +See `docs/vi_diff.txt` for differences from Vim. ### Should I use Jim? @@ -35,7 +35,7 @@ Probably not yet, unless you enjoy living near the active edge of a weird — bu That said, I have started dogfooding it and pushing it toward daily-driver territory. Jim is especially useful for editing programs and other plain text where trust, auditability, and recoverability matter. All core commands use ordinary keyboard characters. The editing surface is meant to stay quiet, direct, and fast. The editor should not scream just because the runtime underneath it knows more than most editors dare to remember. -Jim aims to remain lightweight at the surface even as the machinery beneath it becomes causally explicit. The production text path is now Echo-hosted: a trusted native process registers a Wesley-generated compatibility package, submits generated EINT envelopes through Echo's WAL-backed app capability, and consumes scheduler receipts plus bounded readings. Echo owns admission, runtime lifecycle, scheduling, graph state, receipts, and recovery. Jim currently supports only create/open, single-range editing, and bounded text reads through that path; unsupported operations fail closed. Edict will replace the narrow compatibility package when its native invocation corridor is ready. That split is not decorative. Jim should know editor truths, not substrate coordinates. +Jim aims to remain lightweight at the surface even as the machinery beneath it becomes causally explicit. The production text path is now Echo-hosted: a trusted native process registers a Wesley-generated compatibility package, submits generated EINT envelopes through Echo's WAL-backed app capability, and consumes scheduler receipts plus bounded readings. Echo owns admission, runtime lifecycle, scheduling, graph state, receipts, and recovery. Jim currently supports only create/open, single-range editing, checkpoint declaration, and bounded text reads through that path; unsupported operations fail closed. Edict will replace the narrow compatibility package when its native invocation corridor is ready. That split is not decorative. Jim should know editor truths, not substrate coordinates. Jim grows out of the `jedit` repository. The product arc is Jim. The repository, packages, contracts, release gates, and internal APIs remain `jedit` until the Echo-backed proof and compatibility plan make a public rename safe. The rename should be earned the same way the rest of the editor is earned: through real product pressure, not theater. @@ -57,7 +57,7 @@ npm run build node dist/main.js ``` -The build and witness tooling live in the repository and the `scripts/` directory. Read `GUIDE.md` for operational guidance, `ARCHITECTURE.md` for layer rules and dependency posture, `ADVANCED_GUIDE.md` for the render and authority path, and `docs/BEARING.md` for the compact statement of current truth. +The build and witness tooling live in the repository and the `scripts/` directory. Read `GUIDE.md` for operational guidance, `ARCHITECTURE.md` for layer rules and dependency posture, and `ADVANCED_GUIDE.md` for the render and authority path. [Current posture](#current-posture) below is the statement of current truth. Running the editor builds and launches the trusted native Echo host: @@ -71,9 +71,9 @@ binary, and `JEDIT_ECHO_WAL_DIR` may select its filesystem WAL directory. ## Installation -See the quickstart materials under `docs/releases/` for the current release-gate path. +See [Build And Startup](docs/jedit-echo-end-to-end.md#build-and-startup) for building the native Echo host and launching the editor. -At the moment, the quickstart is aimed less at “install this polished public editor� and more at “prove this Echo-backed edit/read path is real, bounded, and honest.� This is not a bug in the README. The product should earn its myths. +At the moment, setup is aimed less at “install this polished public editor� and more at “prove this Echo-backed edit/read path is real, bounded, and honest.� This is not a bug in the README. The product should earn its myths. ## Documentation @@ -82,36 +82,185 @@ Start here: - `GUIDE.md` — how to run, build, validate, and inspect the Echo cutover posture. - `ADVANCED_GUIDE.md` — how the visible editor, projections, and Echo authority fit together. - `ARCHITECTURE.md` — the layer rules, dependency graph, and product vocabulary. -- `docs/BEARING.md` — compact current truth, active roadmap anchors, and non-negotiables. -- `docs/design/` — living design specs for each major cycle. +- `docs/jim-component-ownership.md` — who owns what across Jim, Jedit, Edict, and Echo, now and in the target. +- `docs/design/` — active design documents and accepted doctrine. - `docs/design/echo-identity-doctrine.md` — canonical Echo identity, scope, and transport doctrine. -- `docs/method/` — process, roadmap, release, and proof policy. +- `docs/method/` — process, roadmap, documentation, CI, and proof policy. - `docs/jedit-echo-end-to-end.md` — the current jedit-plus-Echo proof path. Inside the editor, the command surface continues to grow. The roadmap is not “become all of Vim and then add lore.� The roadmap is accountable editing through a product loop with teeth: explain, preview, admit, recover. ## Current posture +This section is the repository's statement of current truth and of the order of work. Keep it current when execution gravity changes; historical implementation claims belong in Git history. + +Current bearing: keep the real Wesley compatibility corridor honest, author Jim's first operation as real Edict source, and converge on `Jim.edict` as an Echo-realized active observer. Do not add editor vocabulary to Echo or move Jim's semantic state machine into a generated TypeScript client. + What you get right now includes: - Vim-shaped editing with Normal and Insert behavior, plus a growing command surface. -- A real native Echo host for buffer creation, single-range editing, bounded - observation, scheduler receipts, and restart recovery. -- Typed obstruction for save/export, checkpoints, `:why`, causal gutter - readings, multi-range editing, and undo/redo until those paths are Echo-owned. +- A trusted native Rust host, `jedit-echo-host`, linked to Echo. Production startup launches it; there is no TypeScript text runtime or generic WASM facade in the product text path. +- Buffer open/create, insert, replace, delete, checkpoint declaration, bounded text-window reads, scheduler receipts, and restart recovery. +- Typed obstruction for multi-range editing, save/export, range `:why`, causal line-diff, and undo/redo until those paths are Echo-owned. - No local history drawer or undo stack; those surfaces remain unavailable until they can read retained, basis-pinned Echo evidence. - Graft-backed syntax highlighting, outlines, diagnostics, and structural projections where available. - Witness scripts and JSON-reporting evidence tools for CI, agents, and release-gate work. - Agent-oriented interfaces for bounded, inspectable editing workflows. +How the text path works today: + +- `contracts/jedit/echo-text.graphql` declares buffer creation, single-range replacement, checkpoint declaration, and bounded text-window observation. +- Echo's `echo-wesley-gen --contract-host` output supplies canonical EINT codecs, operation identities, registry evidence, generated rules, and the query observer plan under `native/jedit-echo-host/src/generated/`. +- The native host registers that package, submits EINT envelopes through Echo's WAL-acknowledged app capability, asks Echo's trusted host to derive installed-operation admission evidence, runs scheduler-owned ticks, and returns opaque receipt and reading identities. +- Buffer authority is an immutable graph rope stored in Echo's worldline graph. Narrow edits path-copy touched nodes and retain untouched subtree identity. +- Restart reconstructs witnessed submissions, graph state, and receipts from Echo's filesystem runtime WAL. The recovered host can continue editing. +- TypeScript currently owns the JSONL process adapter, request/result mapping, coordinate branding, and disposable UI projections. Its request mapping is explicit migration debt: in the target corridor TypeScript normalizes canonical events and transports artifacts, but has zero semantic authority to interpret commands, choose operations, derive ranges, advance Jim state, or optimistically mutate visible text. +- Jim owns `RopeCheckpointDeclared` semantics. Echo admits and schedules the generated declaration, persists its Jim fact in the graph/WAL history, and returns the opaque receipt and tick identities. Declaration validates that its basis head belongs to the stated Jim buffer worldline and does not mint a text head, rewrite, diff, or causal anchor. A Jim checkpoint declaration and an Echo causal anchor remain separate propositions; no anchor association is created automatically. +- The current package is explicitly `0.1.0-wesley-compat`. Its authored Rust operation law and process invocation seam are transitional until Edict can install and invoke the corresponding generated operations. +- Checkpoint reason remains a transitional GraphQL `String` because the pinned Wesley contract-host enum emitter produces Rust that does not compile for this enum shape. The installed native Jim contract still admits exactly `manual-save`, `autosave`, `retention-boundary`, `export`, and `import`; an arbitrary string is not an admitted checkpoint proposition. +- The full-snapshot runtime, local graph-rope executor, local admission loop, locally manufactured receipts, fake production transports, and optimistic text mutation path remain deleted. +- Test doubles are permitted only under test code and only through explicit injection. The production cutover guard scans TypeScript, executable scripts, and native host Rust for forbidden local authority. + The current wedge is not “more editor.� It is accountable editing. Jim is the product shape I am using to apply pressure to a broader causal computing vision. What sets it apart is that it is trying to do one thing most editors barely attempt: explain what happened in terms stronger than “because the buffer changed.� That is where `:why`, historical basis preview, proposal strands, and strand/braid/worldline UX are headed. The editor should not merely let you act. It should be able to account for the act afterwards. This does not mean Jim currently claims full causal omniscience. It does not. Some parts of the story already exist. Some are actively being proven. Some are still roadmap. The weirdness here is intentional, but it is not supposed to be fake. +### Authority boundary + +The accepted production mutation corridor is: + +```text +Jim command +-> Jim-owned validated request +-> Echo host process port +-> Wesley-generated EINT and installed package +-> Echo WAL-acknowledged submission +-> Echo-owned installed-operation admission +-> Echo scheduler-owned tick +-> Jim graph-rope facts + opaque Echo receipt +-> Echo bounded query observation +-> disposable Jim UI projection +``` + +In the target Edict corridor, Jedit normalizes physical input into one canonical event envelope with stable event, source, ordering, normalized-input, and admission coordinates. Echo admits and transports the envelope without inspecting Jim or Jedit fields. Only `jim.core`, authored from `Jim.edict`, interprets editor meaning. [Jim: Components, Responsibilities, and Ownership](docs/jim-component-ownership.md) holds the frozen ownership and causal-settlement contract. + +```text +terminal bytes +-> Jedit adapter emits one canonical event envelope +-> Echo realm admits and delivers it opaquely under an exact JimRelease +-> jim.core interprets the event and durably retains any command attempt +-> jim.core requests jedit.text TextWindow.edict +-> Echo returns a basis-bound Reading +-> jim.core composes jedit.text ReplaceRange.edict +-> Echo privately evaluates one combined Jim-and-buffer candidate +-> one realm and epoch atomically settles Jim, Buffer, result, and evidence + or retains a distinct CandidateSettlementRejected outcome +-> Jedit renders one declared causal view basis +``` + +A generated client may encode events, install or address verified packages, transport readings/outcomes/receipts, and decode typed projections. It is a syscall stub, not Jim. A direct generated-client invocation of `ReplaceRange` is permitted only in an explicitly test-only operation conformance harness. + +### Artifact boundaries + +These artifacts are intentionally not interchangeable: + +| Artifact | Role | +| --- | --- | +| `jedit.text.schema@1` | Application fact shapes, codecs, and identity rules | +| `jedit.text.ReplaceRange.oracle@1` | Independent expected-behavior evidence | +| `ReplaceRange.edict` | `jedit.text`-authored operation semantics composed by `jim.core` | +| Echo Target IR and verified package | Compiler-produced generic executable meaning | +| Echo receipt | Evidence of one admitted execution against one basis | + +The oracle is never a program. Echo must not synthesize an evaluator or package from the schema or oracle. + +Runtime identity follows [the Echo identity doctrine](docs/design/echo-identity-doctrine.md). Jim must not copy Echo identity domains, admission policy, scheduler behavior, WAL evidence, or support-policy logic. + +### Roadmap + +The active goalpost is [Jim.edict](https://github.com/flyingrobots/jedit/issues/295). In order: + +1. Keep the narrow create/replace/checkpoint/read corridor green against Echo-owned WAL, admission, scheduling, graph state, receipts, and restart recovery. +2. Avoid restoring broad editor feature parity through transitional APIs. +3. Author the persistent-rope `ReplaceRange.edict` in `jedit.text`, with typed outcomes. The flat-text reference is already authored, built through the pinned Edict package chain, and verified in Echo; it is the logical-text reference for the persistent-rope differential gate, not graph admission or recovery evidence. +4. Build it through Edict's public application-build boundary and let the first honest compiler or target-profile failure route work to its owning repo. +5. Extend Echo only for generic bounded-program capabilities proven necessary by the compiler-produced package; prove the result against the independent Jedit oracle. +6. Author `TextWindow.edict`, then the smallest `Jim.edict` active observer. +7. Move production Jedit to canonical event submission and disposable rendering; make frontend operation orchestration and the Wesley/native planner route unreachable, then delete them. +8. Migrate create/open and checkpoint lawpacks under the same ownership model. +9. Add optional causal-anchor association as a proposition separate from checkpoint declaration only when a concrete consumer requires it. +10. Add save/export through Jim-authored operations, then derive undo/redo candidates from retained Echo history and invoke generated inverse operations through basis-pinned Echo observations. +11. Delete the remaining compatibility host package and semantic JSONL glue; retain only raw event/artifact transport required by the final membrane. + +### Hard gates + +- Do not reintroduce an in-process text authority to make the TUI usable. +- Do not mutate visible text before an Echo-backed observation returns. +- Do not call local file writes a save when no Echo basis was exported. +- Do not manufacture Echo receipts, ticks, admissions, anchors, or identities. +- Do not make the UI claim causal evidence that Echo cannot return. +- Do not treat a cache, WAL mirror, queue, map, or materialization as semantic authority beside Echo history. +- Do not widen the handwritten compatibility protocol for feature parity. +- Do not describe the Wesley compatibility package as the final Edict design. +- Do not put `ReplaceRange`, rope operations, `Buffer`, or `TextWindow` semantics in Echo production code. +- Do not let TypeScript map commands to operations in final production composition. + _There is no file. Only witnessed causal history and lawful, bounded optics._ +## Where Jim is going + +Jim must earn this promise: a modal editor for people and agents who need edits to be explainable, recoverable, and reviewable. The editing surface stays quiet while runtime truth becomes causally explicit, so every meaningful edit, read, projection, and future undo path can be explained by deterministic runtime evidence. + +The user should experience a fast keyboard-first editor, clean text and Markdown workflows, minimal chrome, strong Vim-shaped editing semantics, structural intelligence when it helps, and reliable answers to "what am I seeing?" and "why did this edit happen?" + +The stack should provide contract-shaped edits, deterministic admission, evidence-bearing readings, bounded observation apertures, reproducible transport boundaries, undo as authored counter-history rather than deletion, and debug surfaces that can explain the causal path. Users still experience ordinary undo semantics: the causal model exists to preserve explainability and replayability below the product boundary, not to make editing feel like operating a ledger. + +Jim's owned lane is accountable editing: edits that can be inspected, replayed, explained, previewed, and safely admitted. Its signature product loop is: + +```text +explain -> preview -> admit -> recover +``` + +### Product pressure + +Product pressure determines architecture truth. The stack advances only when a real editor constraint forces a seam to become honest, and new runtime abstractions emerge from witnessed editor requirements, not speculative protocol expansion. That is why the first serious proof was small (`createBuffer -> replaceRange("hello") -> textWindow(0..5)`): one witnessed editor story is worth more than a generalized protocol that no product path has forced into existence. + +### Boundary doctrine + +Jim is the consumer, not the substrate. App-facing code never knows worldline ids, basis refs, ticks, strands, scheduler mechanics, Echo root derivation, or other runtime-internal coordinates; those stay below the production text session and the native host boundary. It may know buffers, ranges, selections, modes, panes, panels, lenses, product-shaped readings such as `TextWindowReading`, and opaque head identities returned by Jim, carried as a reading's basis. App code replays an opaque head identity; it never derives, inspects, or mints one. + +Echo owns causal substrate truth. Jim submits intent and observes readings without reaching around Echo into runtime internals, and the Echo boundary should eventually feel boring: a versioned package, a documented byte ABI, explicit scheduler, materialization, and session-bootstrap behavior, and a named basis on every reading. + +Jim's application law is authored in Edict and compiled through Edict's public build into verified generic Echo packages, replacing the Wesley compatibility package operation by operation. Jim does not invent protocol shapes beside either, because doing so makes drift invisible. + +Graft provides structural intelligence, not editing truth: syntax spans, outlines, fold regions, structural selection, diagnostics, rename previews, structural diffs, and semantic summaries. Jim owns the editing experience that composes those engines into a coherent product. + +### Product goalposts + +Product work is ordered by these goalposts: + +1. **Editor Trust Gate**: prove open, edit, save, quit, search, dirty-state, and disk-output behavior before leaning on causal UI. +2. **Command Provenance And `:why`**: expose why representative Vim edits changed text, which basis they used, which range they touched, and what receipt or result reading proves the outcome. +3. **Historical Basis Preview**: preview history through a bounded basis view while clearly preserving the current head. +4. **Search Sets And Substitute Strand Preview**: let search create basis-bound result sets, let `:%s` preview proposal strands, and let `:admit` admit all or selected rows. +5. **Historical Yank And Register Provenance**: reuse retained historical material without moving the current head. +6. **Vim Power Core**: deepen Vim parity through the causal system, prioritizing visual mode, registers, semantic repeat, macros, marks, structural text objects, and range commands. +7. **Agent-Safe Editing**: require agent edits to arrive as accountable proposal strands with basis, range, rationale, evidence, and admission paths. + +### Non-goals + +- No full editor feature set before the causal seam is real. +- Echo does not learn Jim product nouns, and Jim does not learn Echo substrate coordinates. +- No packages published just because the witness ritual works, and no public editor release until the product has a credible demo path for accountable editing. +- No hand-authored protocol shapes beside the generated contract or the Edict packages. +- No Continuum to bless an unproven boundary; it comes in only after the local Jim/Echo boundary is proven enough to publish without speculative ontology. +- No collaboration before one local causal file history is honest. +- Not a CRDT research toy, a blockchain editor, an IDE framework, a protocol-first product, or a distributed-systems demo pretending to be an editor. + +A Jim reading is legitimate when the app can show useful text and the stack can explain the basis, law, aperture, and evidence that made the reading true. Plainly: the user sees text, and the runtime can explain why that text is the right text to show. + ## Copying Jim is currently under active development. See `LICENSE` for the current terms. @@ -134,7 +283,7 @@ Bug reports, design feedback, and causal UX ideas are welcome through GitHub iss ## Information -Latest news, design notes, and witness surfaces live in the repository. For deeper dives into provenance, worldlines, history, Echo hosting, and command explanation, start in `docs/design/` and `docs/BEARING.md`. +Latest news, design notes, and witness surfaces live in the repository. For deeper dives into provenance, worldlines, history, Echo hosting, and command explanation, start in `docs/design/` and `docs/jim-component-ownership.md`. ### Useful entry points diff --git a/VISION.md b/VISION.md deleted file mode 100644 index 8ddd4253..00000000 --- a/VISION.md +++ /dev/null @@ -1,272 +0,0 @@ -# jedit Vision - -`jedit` is a terminal-first editor whose editing surface stays quiet while its -runtime truth becomes causally explicit. - -The product goal is not to build an IDE-shaped terminal app. The goal is an -editor that feels direct and small at the surface, while every meaningful edit, -read, projection, and future undo path can be explained by deterministic -runtime evidence. - -## North star - -`jedit` should make causal editing usable. - -The product promise Jim must earn is: - -```text -Jim is a modal editor for people and agents who need edits to be explainable, -recoverable, and reviewable. -``` - -The user should experience: - -- a fast keyboard-first editor -- clean text and Markdown workflows -- minimal chrome -- strong Vim-shaped editing semantics -- structural intelligence when it helps -- reliable answers to "what am I seeing?" and "why did this edit happen?" - -The stack should provide: - -- contract-shaped edits -- deterministic admission -- evidence-bearing readings -- bounded observation apertures -- reproducible transport boundaries -- undo as authored counter-history, not deletion -- debug surfaces that can explain the causal path - -Users should still experience ordinary undo semantics. The causal model exists -to preserve explainability and replayability below the product boundary, not to -make editing feel like operating a ledger. - -Jim should not try to win by being a larger Vim, a terminal IDE clone, a generic -AI chat surface, or full modal-editor parity alone. Those lanes make the product -interchangeable. Jim's owned lane is accountable editing: edits that can be -inspected, replayed, explained, previewed, and safely admitted. - -The signature product loop is: - -```text -explain -> preview -> admit -> recover -``` - -## Product pressure - -Product pressure determines architecture truth. - -The stack advances only when a real editor constraint forces a seam to become -honest. `jedit` exists to apply that pressure. New runtime abstractions should -emerge from witnessed editor requirements, not speculative protocol expansion. - -This is why the first serious proof is small: - -```text -createBuffer --> replaceRange("hello") --> textWindow(0..5) -``` - -One witnessed editor story is worth more than a generalized protocol that no -product path has forced into existence. - -## Current checkpoint - -The first cross-stack truth was Stack Witness 0001: - -```text -createBuffer --> replaceRange("hello") --> textWindow(0..5) --> ReadingEnvelope + QueryBytes("hello") --> TextWindowReading -``` - -This is intentionally small. It proves the first editor/runtime seam without -turning the repo into protocol theater. - -The next checkpoint is stronger: jedit is now the release gate for Echo -`v0.1.0`. Echo is not considered ready to build with until this repository can -run a real Echo witness for a contract-backed edit, scheduler-owned tick, -observed outcome, bounded text reading, retained evidence, and replay. - -The current stack posture is: - -- Wesley publishes the fixture artifact shape. -- Echo hosts the fixture runtime path and owns the WASM package export boundary. -- jedit consumes the seam through a fake transport and an opt-in real Echo WASM - witness. -- jedit now keeps read coordinates behind `TextBufferOptic` and an opaque - `ReadBasisHandle`. -- Continuum remains intentionally untouched until the local product/runtime seam - is proven enough to publish as a shared protocol family. - -The opt-in real Echo WASM witness now preserves the required authority split: -application code submits and observes, while trusted host code owns scheduler -control. The witness also reports inline reading evidence, missing durable -retention posture, and replay obstruction posture. The next pressure is not -tick authority; it is replacing those honest obstructions with generic retained -refs, durable replay, and a jedit-owned generated contract path. - -## Boundary doctrine - -`jedit` is the consumer, not the substrate. - -App-facing jedit code should not know about: - -- worldline ids -- basis refs -- heads -- ticks -- strands -- scheduler mechanics -- Echo root derivation -- fixture-only runtime coordinates - -Those belong below the optic/session adapter boundary. - -App-facing jedit code may know about: - -- buffers -- ranges -- selections -- modes -- panes -- panels -- lenses -- `TextBufferOptic` -- `ReadBasisHandle` -- product-shaped readings such as `TextWindowReading` - -The durable direction is: - -```text -open buffer/session --> receive TextBufferOptic --> request bounded text window through its opaque read basis handle --> receive product-shaped reading plus evidence-bearing runtime envelope -``` - -The handle is not the basis. `TextBufferOptic` is the app-facing capability; -`ReadBasisHandle` is an opaque supporting token that lets the session resolve -the correct basis below the app boundary. - -## Echo relationship - -Echo owns causal substrate truth. - -`jedit` should submit intent and observe readings. It should not reach around -Echo into runtime internals. - -The Echo boundary should eventually feel boring: - -- package is versioned -- byte ABI is documented -- scheduler/materialization behavior is explicit -- session bootstrap is explicit -- optics own basis resolution -- app code never derives root worldline lore - -The current real WASM witness is a necessary bridge, not a public contract. It -exists to keep pressure on the byte ABI until Echo provides a durable package -and session bootstrap. It may report `missing_retention` or -`durable_replay_unavailable`; those are release-gate blockers, not acceptable -v0.1.0 end states. - -## Wesley relationship - -Wesley owns deterministic contract artifact generation. - -The current Stack Witness fixture uses human-readable fixture bytes so the seam -can be inspected. Those bytes must not fossilize into doctrine. - -The durable target is Wesley-generated binary codecs shared by Rust and -TypeScript, plus generated helpers for intent and observation shapes. - -`jedit` should consume generated helpers when they are ready. It should not -invent parallel protocol shapes because doing so makes drift invisible. - -## Graft relationship - -Graft provides structural intelligence, not editing truth. - -Graft should help with: - -- syntax spans -- outlines -- fold regions -- structural selection -- diagnostics -- rename previews -- structural diffs -- semantic summaries - -Echo should own causal text history. - -`jedit` owns the editing experience that composes those engines into a coherent -product. - -## Execution sequence - -Near-term product work should stay narrow and ordered by goalposts: - -1. **Editor Trust Gate**: prove open, edit, save, quit, search, dirty-state, and - disk-output behavior before leaning on causal UI. -2. **Command Provenance And `:why`**: expose why representative Vim edits - changed text, which basis they used, which range they touched, and what - receipt or result reading proves the outcome. -3. **Historical Basis Preview**: preview history through a bounded basis view - while clearly preserving the current head. -4. **Search Sets And Substitute Strand Preview**: let search create basis-bound - result sets, let `:%s` preview proposal strands, and let `:admit` admit all - or selected rows. -5. **Historical Yank And Register Provenance**: reuse retained historical - material without moving the current head. -6. **Vim Power Core**: deepen Vim parity through the causal system, prioritizing - visual mode, registers, semantic repeat, macros, marks, structural text - objects, and range commands. -7. **Agent-Safe Editing**: require agent edits to arrive as accountable proposal - strands with basis, range, rationale, evidence, and admission paths. - -Runtime work still follows product pressure: - -- Keep Echo app/host authority split intact. -- Keep witness reports honest about inline evidence, missing retained refs, and - replay obstruction. -- Move remaining fixture-only basis lore below durable session boundaries. -- Replace hand-authored fixture assumptions with Wesley-generated helpers. -- Add editor semantics only when pulled by the causal seam. -- Bring Continuum in only after the local jedit/Echo boundary is proven enough - to publish without speculative ontology. - -## Non-goals right now - -- Do not build a full editor feature set before the causal seam is real. -- Do not make Echo know jedit product nouns. -- Do not make jedit know Echo substrate coordinates. -- Do not publish packages just because the witness ritual works. -- Do not prepare a public editor release until the product has a credible demo - path for accountable editing. -- Do not route around Wesley with permanent hand-authored protocol shapes. -- Do not bring Continuum in to bless an unproven boundary. -- Do not implement collaboration before one local causal file history is honest. - -## What jedit is not - -- Not a CRDT research toy. -- Not a blockchain editor. -- Not an IDE framework. -- Not a protocol-first product. -- Not a distributed-systems demo pretending to be an editor. -- Not a place for runtime abstractions to look impressive before the product has - forced them to be useful. - -## Operating sentence - -A jedit reading is legitimate when the app can show useful text and the stack -can explain the basis, law, aperture, and evidence that made the reading true. - -Plainly: the user sees text, and the runtime can explain why that text is the -right text to show. diff --git a/docs/BEARING.md b/docs/BEARING.md deleted file mode 100644 index 3b2f4995..00000000 --- a/docs/BEARING.md +++ /dev/null @@ -1,191 +0,0 @@ -# BEARING - -Current bearing: keep the real Wesley compatibility corridor honest, author -Jim's first operation as real Edict source, and converge on `Jim.edict` as an -Echo-realized active observer. Do not add editor vocabulary to Echo or move -Jim's semantic state machine into a generated TypeScript client. - -This document records current repository truth. Historical implementation -claims belong in git history and design retrospectives. - -## Current Truth - -- Production startup launches `jedit-echo-host`, a trusted native Rust process - linked to Echo. There is no TypeScript text runtime or generic WASM facade in - the product text path. -- `contracts/jedit/echo-text.graphql` declares buffer creation, single-range - replacement, checkpoint declaration, and bounded text-window observation. -- Echo's `echo-wesley-gen --contract-host` output supplies canonical EINT - codecs, operation identities, registry evidence, generated rules, and the - query observer plan under `native/jedit-echo-host/src/generated/`. -- The native host registers that package, submits EINT envelopes through - Echo's WAL-acknowledged app capability, asks Echo's trusted host to derive - installed-operation admission evidence, runs scheduler-owned ticks, and - returns opaque receipt and reading identities. -- Buffer authority is an immutable graph rope stored in Echo's worldline graph. - Narrow edits path-copy touched nodes and retain untouched subtree identity. -- Restart reconstructs witnessed submissions, graph state, and receipts from - Echo's filesystem runtime WAL. The recovered host can continue editing. -- TypeScript currently owns the JSONL process adapter, request/result mapping, - coordinate branding, and disposable UI projections. Its request mapping is - explicit migration debt: in the target corridor TypeScript normalizes - canonical events and transports artifacts, but has zero semantic authority - to interpret commands, choose operations, derive ranges, advance Jim state, - or optimistically mutate visible text. -- Buffer open/create, insert, replace, delete, checkpoint declaration, and - bounded text-window reads are implemented. Multi-range edit, save/export, - `:why`, causal line-diff, and undo/redo return typed obstructions. -- Jim owns `RopeCheckpointDeclared` semantics. Echo admits and schedules the - generated declaration, persists its Jim fact in the graph/WAL history, and - returns the opaque receipt and tick identities. Declaration validates that - its basis head belongs to the stated Jim buffer worldline and does not mint a - text head, rewrite, diff, or causal anchor. -- A Jim checkpoint declaration and an Echo causal anchor remain separate - propositions. No anchor association is created automatically. -- The current package is explicitly `0.1.0-wesley-compat`. Its authored Rust - operation law and process invocation seam are transitional until Edict can - install and invoke the corresponding generated operations. -- Checkpoint reason remains a transitional GraphQL `String` because the pinned - Wesley contract-host enum emitter produces Rust that does not compile for - this enum shape. The installed native Jim contract still admits exactly - `manual-save`, `autosave`, `retention-boundary`, `export`, and `import`; an - arbitrary string is not an admitted checkpoint proposition. -- The full-snapshot runtime, local graph-rope executor, local admission loop, - locally manufactured receipts, fake production transports, and optimistic - text mutation path remain deleted. -- Test doubles are permitted only under test code and only through explicit - injection. The production cutover guard scans TypeScript, executable scripts, - and native host Rust for forbidden local authority. - -## Authority Boundary - -The accepted production mutation corridor is: - -```text -Jim command --> Jim-owned validated request --> Echo host process port --> Wesley-generated EINT and installed package --> Echo WAL-acknowledged submission --> Echo-owned installed-operation admission --> Echo scheduler-owned tick --> Jim graph-rope facts + opaque Echo receipt --> Echo bounded query observation --> disposable Jim UI projection -``` - -The target Edict corridor is: - -Jedit normalizes physical input into one canonical event envelope with stable -event, source, ordering, normalized-input, and admission coordinates. Echo -admits and transports the envelope without inspecting Jim or Jedit fields. -Only `jim.core`, authored from `Jim.edict`, interprets editor meaning. See -[Jim: Components, Responsibilities, and Ownership](jim-component-ownership.md) -for the frozen ownership and causal-settlement contract. - -```text -terminal bytes --> Jedit adapter emits one canonical event envelope --> Echo realm admits and delivers it opaquely under an exact JimRelease --> jim.core interprets the event and durably retains any command attempt --> jim.core requests jedit.text TextWindow.edict --> Echo returns a basis-bound Reading --> jim.core composes jedit.text ReplaceRange.edict --> Echo privately evaluates one combined Jim-and-buffer candidate --> one realm and epoch atomically settles Jim, Buffer, result, and evidence - or retains a distinct CandidateSettlementRejected outcome --> Jedit renders one declared causal view basis -``` - -A generated client may encode events, install or address verified packages, -transport readings/outcomes/receipts, and decode typed projections. It is a -syscall stub, not Jim. A direct generated-client invocation of `ReplaceRange` -is permitted only in an explicitly test-only operation conformance harness. - -## Artifact Boundaries - -These artifacts are intentionally not interchangeable: - -| Artifact | Role | -| --- | --- | -| `jedit.text.schema@1` | Application fact shapes, codecs, and identity rules | -| `jedit.text.ReplaceRange.oracle@1` | Independent expected-behavior evidence | -| `ReplaceRange.edict` | `jedit.text`-authored operation semantics composed by `jim.core` | -| Echo Target IR and verified package | Compiler-produced generic executable meaning | -| Echo receipt | Evidence of one admitted execution against one basis | - -The oracle is never a program. Echo must not synthesize an evaluator or package -from the schema or oracle. - -Runtime identity follows -[the Echo identity doctrine](design/echo-identity-doctrine.md). Jim must not -copy Echo identity domains, admission policy, scheduler behavior, WAL evidence, -or support-policy logic. - -## Immediate Roadmap - -- [x] Execute compiler-produced flat-text replacement against literal UTF-8 - cases, then range, UTF-8, no-op and resource refusals. This is the logical-text - reference for the persistent-rope differential gate, not graph admission or - recovery evidence. - -- [x] Make the pinned Edict package-chain harness discover Cargo's actual - executable when its output is redirected. Preserve producer pins and verify - the emitted pure package in Echo; this does not complete the authored rope - operation or its stateful runtime path. - -1. Keep the narrow create/replace/checkpoint/read corridor green against - Echo-owned WAL, admission, scheduling, graph state, receipts, and restart - recovery. -2. Avoid restoring broad editor feature parity through transitional APIs. -3. Check in Jim-owned `ReplaceRange.edict` with its complete lawpack closure. -4. Build it through Edict's public application-build boundary and let the first - honest compiler or target-profile failure route work to its owning repo. -5. Extend Echo only for generic bounded-program capabilities proven necessary - by the compiler-produced package; prove the result against the independent - Jedit oracle. -6. Author `TextWindow.edict`, then the smallest `Jim.edict` active observer. -7. Move production Jedit to canonical event submission and disposable - rendering; make frontend operation orchestration and the Wesley/native - planner route unreachable, then delete them. -8. Migrate create/open and checkpoint lawpacks under the same ownership model. -9. Add optional causal-anchor association as a proposition separate from - checkpoint declaration only when a concrete consumer requires it. -10. Add save/export through Jim-authored operations, then derive undo/redo - candidates from retained Echo history and invoke generated inverse - operations through basis-pinned Echo observations. -11. Delete the remaining compatibility host package and semantic JSONL glue; - retain only raw event/artifact transport required by the final membrane. - -## Hard Gates - -- Do not reintroduce an in-process text authority to make the TUI usable. -- Do not mutate visible text before an Echo-backed observation returns. -- Do not call local file writes a save when no Echo basis was exported. -- Do not manufacture Echo receipts, ticks, admissions, anchors, or identities. -- Do not make the UI claim causal evidence that Echo cannot return. -- Do not treat a cache, WAL mirror, queue, map, or materialization as semantic - authority beside Echo history. -- Do not widen the handwritten compatibility protocol for feature parity. -- Do not describe the Wesley compatibility package as the final Edict design. -- Do not put `ReplaceRange`, rope operations, `Buffer`, or `TextWindow` - semantics in Echo production code. -- Do not let TypeScript map commands to operations in final production - composition. - -## Verification - -Use: - -```sh -npm run check -``` - -For the narrow real Echo corridor: - -```sh -npm run echo:test -JEDIT_DIST_PREBUILT=1 node --test spec/workspace-production-echo-wiring.spec.mjs -node scripts/jedit-production-cutover-guard.mjs -npm run witness:echo -``` diff --git a/docs/audits/documentation-readme-audit-2026-06-28.md b/docs/audits/documentation-readme-audit-2026-06-28.md deleted file mode 100644 index 518529ed..00000000 --- a/docs/audits/documentation-readme-audit-2026-06-28.md +++ /dev/null @@ -1,99 +0,0 @@ -# Documentation & README Audit (Completeness Check) — `jedit` / "Jim" - -**Date:** 2026-06-28 -**Role:** Technical Writer & Senior Developer Advocate -**Scope:** `README.md` validated against the codebase, plus the supporting doc set (`GUIDE.md`, `ADVANCED_GUIDE.md`, `ARCHITECTURE.md`, `CODE_STANDARDS.md`, `AGENTS.md`, `VISION.md`, `CHANGELOG.md`, `docs/`). -**Verdict:** Recommendation **A — incremental updates.** The doc set is unusually rich and mostly accurate; the problems are *targeted*: one wrong function reference, a missing "how do I open a file" path, an inconsistent run incantation, and four absent standard files. - ---- - -## 1. Accuracy & Effectiveness Assessment - -### 1.1 Core Mismatch (the single most critical inaccuracy) - -**`ADVANCED_GUIDE.md:41` documents a function that does not exist where or how it claims.** - -> "Opening a file eventually calls `loadEditor(filePath)` in `src/main.ts`." - -Verified against the code, this is wrong on three counts: - -- **Wrong location.** `loadEditor` is defined in `src/app/workspace/editor-session.ts:46`, not `src/main.ts`. `src/main.ts` contains no reference to `loadEditor` at all. -- **Wrong signature.** The real signature is `loadEditor(filePath: string, editorFile: EditorFilePort)` — it requires an injected port; the docs show a one-arg call. -- **Wrong control flow.** `src/main.ts` routes `--version`/`--help` and otherwise calls `runJeditWorkspace()`, which **ignores `process.argv`** (`src/main-workspace.ts:26`). So the documented "open a file" entry path through `main.ts` does not exist. - -This is the most critical inaccuracy because it is the *one place the docs try to explain the file-open lifecycle* — the editor's most fundamental operation — and it sends a new engineer to the wrong file with the wrong signature for a flow that isn't wired the way described. - -### 1.2 Audience & Goal Alignment - -**Primary audience (as written): contributors / proof-auditors**, not end users. The README is candid about this ("the quickstart is aimed less at 'install this polished public editor' and more at 'prove this Echo-backed edit/read path is real'"). That is a legitimate choice for the project's stage. Measured against that audience's top 3 questions: - -| Question | Addressed? | Evidence | -|---|---|---| -| **"What is this and should I use it?"** | ✅ Strong | README "What is Jim?" + "Should I use Jim?" are clear, honest, and well-written. | -| **"How do I build, run, and validate it?"** | ⚠� Partial | Build/validate steps exist (README "Compiling", GUIDE "Run/Validate"), but **how to actually open and edit a file is documented nowhere** (see 1.3). | -| **"How do I contribute (rules, process, security)?"** | ⚠� Partial | `CODE_STANDARDS.md`, `AGENTS.md`, `ARCHITECTURE.md` cover doctrine, but there is **no `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, or `SECURITY.md`** (see 2.2). | - -The end-user audience the README *gestures at* ("I have started dogfooding it … especially useful for editing programs") is **not** served: a dogfooding user has no documented way to open their file. - -### 1.3 Time-to-Value (TTV) Barrier - -**The single biggest bottleneck: after building, no document tells you how to open a file.** README "Compiling" ends at `node dist/main.js`; GUIDE "Run The App" ends at `npm run dev`. Both launch an empty workspace rooted at `cwd`, and because argv is ignored, `node dist/main.js myfile.txt` does nothing with the file. No doc mentions an in-editor `:e`/`:edit`, a file picker, or a CLI argument — grep across README/GUIDE/ADVANCED_GUIDE/`vi_diff.txt` finds zero "open a file" instructions. A new developer reaches a blank editor and is stranded at the exact moment they expected to start editing. - -A secondary, smaller barrier: **two inconsistent start incantations.** README says `npm ci` → `npm run build` → `node dist/main.js`; GUIDE says `npm install` → `npm run dev`. Neither cross-references the other, so a reader can't tell which is canonical. - ---- - -## 2. Required Updates & Completeness Check - -### 2.1 README.md Priority Fixes (top 3 to reach accuracy) - -1. **Add a "Opening and editing a file" section.** Document the real way to open a file today (in-editor command and/or the CLI arg once it exists), and the basic save command. This closes the 1.3 TTV gap and the 1.2 end-user question. *(If the CLI file-arg is not yet implemented, say so explicitly rather than implying `node dist/main.js ` works.)* -2. **Reconcile the run instructions with `GUIDE.md`.** Pick one canonical quickstart (`npm ci && npm run build && npm start`, or `npm install && npm run dev`) and make README + GUIDE agree, noting that `npm run dev` uses `tsx` for source iteration while `npm run build` + `start` runs compiled `dist/`. -3. **Fix/clarify the docs index.** The README "Documentation" list omits `VISION.md` and `CODE_STANDARDS.md` (both present at repo root) and points readers to `docs/releases/` for a "quickstart" that is actually a release-gate proof. Align the index with what each file really delivers. - -### 2.2 Missing Standard Documentation - -Confirmed absent at repo root (and, per repo scaffolding policy for `flyingrobots` repos, expected): - -- **`SECURITY.md`** — *required by policy and high-value here.* The project executes external binaries resolved via `PATH` (graft/colorful) and reads/writes user files; there must be a documented vulnerability-reporting channel and a statement of the runtime trust model. -- **`CONTRIBUTING.md`** — doctrine lives in `CODE_STANDARDS.md`/`AGENTS.md`, but there is no single "how to propose a change, run the gate, and open a PR" entry point for a human contributor. -- **`NOTICE`** — required alongside the Apache-2.0 `LICENSE` for an Apache-licensed project (attribution notices). Present: `LICENSE`. Missing: `NOTICE`. -- **`CODE_OF_CONDUCT.md`** — standard for a public GitHub project; currently absent. - -### 2.3 Supplementary Documentation (one undocumented complex area) - -**The file-load/encoding/fingerprint boundary in `src/adapters/editor-file.ts` is under-documented and the one doc that describes it (`ADVANCED_GUIDE.md` "Loading A Buffer") is partly wrong (1.1).** This is a genuinely subtle area: null-byte binary detection, lossy `toString('utf8')` decode, `EditorFileFingerprint` generation, and the `EditorFileLoadResult` variants (`directory`/`missing`/`obstructed`/binary/text). None of the port methods carry JSDoc, and the durability/encoding guarantees are unstated. This area deserves a corrected, dedicated write-up because it is exactly where correctness/data-integrity bugs hide. - ---- - -## 3. Final Action Plan - -### 3.1 Recommendation Type — **A. Incremental updates.** - -The documentation is extensive, well-written, and largely accurate; a full rewrite would destroy real value. The defects are specific and individually small: one wrong function reference, one missing file-open story, one inconsistent run command, and four missing standard files. - -### 3.2 Deliverable — Generated prompt (Incremental: apply 2.1 fixes + create 2.2 files) - -> **Prompt:** `Update the jedit documentation for accuracy and completeness without rewriting it wholesale.` -> -> `README.md: (1) Add an "Opening and editing a file" section describing how to actually open a file today and how to save; if no CLI file argument exists yet, state that explicitly instead of implying 'node dist/main.js ' opens a file. (2) Reconcile the quickstart with GUIDE.md so both agree on one canonical run path, noting npm run dev (tsx/source) vs npm run build + npm start (compiled dist). (3) Correct the "Documentation" index to include VISION.md and CODE_STANDARDS.md and to describe docs/releases/ accurately as the release-gate proof path, not a user quickstart.` -> -> ADVANCED_GUIDE.md: Fix the stale runtime-shape references, not only the "Loading A Buffer" section. EditorState lives in `src/app/workspace/editor/model.ts`, not `src/main.ts`. loadEditor lives in `src/app/workspace/editor-session.ts` (signature loadEditor(filePath: string, editorFile: EditorFilePort)), not `src/main.ts`. commitMutation lives in `src/app/workspace/editor-editing-core.ts`, not `src/main.ts`. The app/runtime loop lives in `src/app/workspace/runtime.ts` with composition through `src/main-workspace.ts`, and `src/main.ts` only remains the process entrypoint for startup CLI routing. Bijou-facing rendering helpers live under `src/ui/workspace-render.ts` plus workspace viewer modules, not as a monolithic `src/main.ts` app. Describe the real load path through loadEditorFile in `src/adapters/editor-file.ts`, including null-byte binary detection, UTF-8 decoding, and fingerprinting. -> -> `Create the missing standard files at repo root, consistent with the Apache-2.0 license and the project's flyingrobots scaffolding policy: SECURITY.md (vulnerability-reporting channel + a short runtime trust model covering PATH-resolved external binaries and local file I/O), CONTRIBUTING.md (how to set up, run npm run check, follow the non-negotiables in CODE_STANDARDS.md/ARCHITECTURE.md, and open a PR), NOTICE (Apache-2.0 attribution), and CODE_OF_CONDUCT.md (a standard template). Cross-link the new files from README.` -> -> `Add JSDoc to EditorFilePort methods in src/ports/editor-file.ts documenting encoding, durability, and failure semantics, and add a focused docs/topics/file-loading.md explaining the editor-file.ts load/encoding/fingerprint boundary. Do not change any code behavior in this task; documentation and comments only. Verify every file path and function reference you write against the actual source before committing.` - -### 3.3 Mitigation Prompt (ready to execute) - -> Act as a technical writer hardening the jedit docs for accuracy. Step 1: verify each claim by reading the referenced source (`src/main.ts`, `src/main-workspace.ts`, `src/app/workspace/editor/model.ts`, `src/app/workspace/editor-session.ts`, `src/app/workspace/editor-editing-core.ts`, `src/app/workspace/runtime.ts`, `src/ui/workspace-render.ts`, `src/adapters/editor-file.ts`, `package.json` scripts). Step 2: apply the README and ADVANCED_GUIDE corrections in 3.2, fixing all stale Advanced Guide runtime references, the loadEditor location/signature error, and the file-open + canonical-run sections. Step 3: create SECURITY.md, CONTRIBUTING.md, NOTICE, and CODE_OF_CONDUCT.md at repo root and link them from README. Step 4: add JSDoc to EditorFilePort and a docs/topics/file-loading.md. Constraints: documentation only, no behavior changes; every file path / function name you write must be confirmed against the current source; keep the project's honest, plain-spoken tone. Finish by listing every claim you verified and the file:line you verified it against. - ---- - -### Evidence Basis - -- Wrong runtime references: `ADVANCED_GUIDE.md` still points core editor state, `loadEditor`, mutation, and Bijou app ownership at `src/main.ts`; actual anchors include `src/app/workspace/editor/model.ts` (`EditorState`), `src/app/workspace/editor-session.ts:46` (`loadEditor(filePath: string, editorFile: EditorFilePort)`), `src/app/workspace/editor-editing-core.ts:380` (`commitMutation`), `src/app/workspace/runtime.ts` (`createWorkspaceRuntime`), `src/ui/workspace-render.ts` (rendering helpers), `src/main-workspace.ts` (workspace boot), and `src/main.ts` only remains the process entrypoint / startup CLI switch. -- No file-open instructions: grep for `:e`/`:edit`/`open a file` across README/GUIDE/ADVANCED_GUIDE/`docs/vi_diff.txt` returns none. -- Run-command inconsistency: `README.md:53-54` (`npm ci` / `npm run build`) vs `GUIDE.md:13,19` (`npm install` / `npm run dev`). -- Missing standard files (confirmed absent at root): `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`, `NOTICE`. Present: `LICENSE`, `CHANGELOG.md`, `ARCHITECTURE.md`, `CODE_STANDARDS.md`, `AGENTS.md`, `VISION.md`. -- Doc index gaps: README "Documentation" list omits root-level `VISION.md` and `CODE_STANDARDS.md`. diff --git a/docs/audits/ready-to-ship-assessment-2026-06-28.md b/docs/audits/ready-to-ship-assessment-2026-06-28.md deleted file mode 100644 index 935d00bb..00000000 --- a/docs/audits/ready-to-ship-assessment-2026-06-28.md +++ /dev/null @@ -1,214 +0,0 @@ -# Ready-to-Ship Assessment (Exhaustive Mode) — `jedit` / "Jim" - -**Date:** 2026-06-28 -**Role:** Senior Principal Software Auditor (long-term maintenance risk + deployment feasibility) -**Scope:** Full repository at `flyingrobots/jedit`, `main`. Terminal-first modal editor + Echo-backed causal-editing harness. 330 `.ts` files, ~51k LOC, 166 specs, strict `tsc`, no ESLint. -**Headline:** Internals are exceptionally clean; the **host file-write adapter is not crash-safe, the legacy save branch is not conflict-safe, and the process lacks a crash guard**, which is disqualifying for a tool whose thesis is *trust, auditability, and recoverability*. - ---- - -## 1. Quality & Maintainability Assessment (Exhaustive) - -### 1.1 Technical Debt Score — **3 / 10** (1 = Excellent, 10 = Unmaintainable) - -Low debt, and that is an evidence-backed claim: **1 `any` (in a comment), 12 `unknown`, 0 `@ts-ignore`, 1 TODO, 0 stray `console.*`** across 51k LOC, under a strict `tsconfig` (`noUncheckedIndexedAccess`, `noPropertyAccessFromIndexSignature`, `noImplicitOverride`). The three patterns that keep it from a 1–2: - -1. **Doctrine enforced by custom tooling, not ESLint.** Every "non-negotiable" (<=500 LOC, no `any`, no magic strings, inward dependencies) lives in `ARCHITECTURE.md`, reviewer vigilance, and the repo-owned quality gate. There is no ESLint config, but `scripts/quality-gate.mjs` is wired through `npm run quality`, `.github/workflows/ci.yml` has a dedicated quality job, and the aggregate `check` job fails unless quality succeeds. The clean numbers are protected by a custom gate, but not by a standard lint ecosystem or dependency-audit gate. -2. **LOC-cap fragmentation.** Ten files sit at 490–499 LOC against the hard 500 cap (`viewer-content.ts` 499, `jedit-echo-optic-codec.ts` 499, `workspace-chrome.ts` 498, `jedit-contract-runtime.ts` 496). The metric is met *numerically*; the risk is artificial splits and inter-file coupling the line count cannot see. `src/app/workspace` alone holds 102 files. -3. **Build-coupled feedback loop.** `test:all` = `npm run build && JEDIT_DIST_PREBUILT=1 node --test … spec/**/*.spec.mjs`, single-concurrency, against compiled `dist/`. Every test run pays a full Wesley-gen + `tsc`. Slow loops are a long-term maintenance tax. - -### 1.2 Readability & Consistency - -**Issue 1 — Public port methods carry no contract docs.** `src/ports/editor-file.ts` declares `saveEditorFile(filePath, lines): void` with no JSDoc stating durability guarantees, encoding, or failure mode (it throws, but nothing says so). A new engineer cannot tell from the type whether the save is atomic or whether errors are returned or thrown. - -> **Mitigation Prompt 1:** `Add JSDoc to every method on the EditorFilePort interface in src/ports/editor-file.ts. For saveEditorFile, document: the file is written UTF-8; whether the write is atomic; that it throws on I/O failure (and which error shapes); and any preconditions (e.g. readOnly buffers must not call it). Match the documentation density of the obstruction mappers. Do not change signatures.` - -**Issue 2 — Production save and legacy save have different safety levels.** Ctrl-S and `:write` dispatch through `saveWorkspace`, and an opened production text authority takes the `saveProductionText` path (`src/app/workspace/workspace-save-key.ts:31-74`). That path exports through `exportWorkspaceText` (`src/app/workspace/workspace-text-commands.ts:345`) and runs `materializationPreflightIssue(request)` before writing. The legacy/non-opened fallback still calls `saveEditor` (`src/app/workspace/editor-session.ts:105`) directly and bypasses that drift preflight. The trap is not normal production save; it is retaining a fallback branch with weaker safety semantics. - -> **Mitigation Prompt 2:** `Either retire the legacy saveEditor fallback or route it through the same materialization preflight posture as the production save path. Keep Ctrl-S and :write on saveProductionText for opened production text authorities. Add specs proving production save still calls materializationPreflightIssue and the legacy/non-opened branch cannot silently overwrite a stale host file.` - -**Issue 3 — Duck-typed Node error decoding inlined per adapter.** `nodeErrorCode` in `src/adapters/editor-file.ts:58` reaches into `'code' in cause && typeof cause.code === 'string'`. This idiom is re-derived across adapters instead of being a shared, named boundary decoder, so error-handling consistency depends on each author repeating it correctly. - -> **Mitigation Prompt 3:** `Create a single shared helper (e.g. src/adapters/node-error.ts) exporting nodeErrorCode(cause: Error): string | undefined with a named Error-specific code guard. Keep non-Error thrown values at the catch boundary and convert them before calling the helper, so the src/ quality gate does not gain any explicit unknown annotations. Replace the inline duck-typing in editor-file.ts and any sibling adapters with it. Add a unit spec covering an ENOENT Error, a non-Error thrown value, and an Error with no code.` - -### 1.3 Code Quality Violations (SRP / unnecessary complexity) - -**Violation 1 — `loadEditorFile` does five jobs in one function** (`src/adapters/editor-file.ts:17-47`): path classification (dir / non-file), I/O, binary detection, UTF-8 decode, fingerprinting, *and* error-to-result mapping. - -Original (abridged): - -```ts -export function loadEditorFile(filePath: string): EditorFileLoadResult { - try { - const stat = statSync(filePath); - if (stat.isDirectory()) return directoryEditorFile(filePath); - if (!stat.isFile()) return obstructedEditorFile(filePath, NON_FILE_MESSAGE); - const bytes = readFileSync(filePath); - const fingerprint = editorFileFingerprintFromBytes(bytes); - if (bytes.includes(NULL_BYTE)) { - return { lines: [BINARY_FILE_MESSAGE], readOnly: true, fingerprint }; - } - return { lines: normalizeLines(bytes.toString(UTF8_ENCODING)), readOnly: false, fingerprint }; - } catch (cause) { /* maps ENOENT vs other */ } -} -``` - -Simplified Rewrite — separate *classification*, *decoding*, and *error mapping*: - -```ts -export function loadEditorFile(filePath: string): EditorFileLoadResult { - try { - return classifyAndDecode(filePath); - } catch (cause) { - return loadErrorResult(filePath, cause); - } -} - -function classifyAndDecode(filePath: string): EditorFileLoadResult { - const stat = statSync(filePath); - if (stat.isDirectory()) return directoryEditorFile(filePath); - if (!stat.isFile()) return obstructedEditorFile(filePath, NON_FILE_MESSAGE); - return decodeRegularFile(readFileSync(filePath)); -} - -function decodeRegularFile(bytes: Buffer): EditorFileLoadResult { - const fingerprint = editorFileFingerprintFromBytes(bytes); - return bytes.includes(NULL_BYTE) - ? { lines: [BINARY_FILE_MESSAGE], readOnly: true, fingerprint } - : { lines: normalizeLines(bytes.toString(UTF8_ENCODING)), readOnly: false, fingerprint }; -} - -function loadErrorResult(filePath: string, cause: Error): EditorFileLoadResult { - const code = nodeErrorCode(cause); - return code === NODE_ERROR_NOT_FOUND - ? missingEditorFile(filePath) - : obstructedEditorFile(filePath, cause.message, code); -} -``` - -> **Mitigation Prompt 4:** `Refactor loadEditorFile in src/adapters/editor-file.ts by extracting classifyAndDecode, decodeRegularFile, and loadErrorResult as shown, so each function has one responsibility. Keep behavior and the public signature identical; the existing editor-file specs must still pass unchanged. Keep the file under 500 LOC and introduce no magic strings.` - -**Violation 2 — Imperative, mutation-based option assembly in the Graft process runner** (`src/adapters/graft-source-highlighter.ts:138-167`): a mutable `options` object is conditionally patched three times before `spawnSync`. - -Original: - -```ts -const options: SpawnSyncOptionsWithStringEncoding = { cwd: request.cwd, encoding: PROCESS_RUNNER_ENCODING, shell: false }; -if (request.stdin != null) options.input = request.stdin; -if (request.timeoutMs != null) options.timeout = request.timeoutMs; -if (request.maxBufferBytes != null) options.maxBuffer = request.maxBufferBytes; -const result = spawnSync(request.command, request.args, options); -``` - -Simplified Rewrite — pure construction via conditional spread: - -```ts -const options: SpawnSyncOptionsWithStringEncoding = { - cwd: request.cwd, - encoding: PROCESS_RUNNER_ENCODING, - shell: false, - ...(request.stdin != null && { input: request.stdin }), - ...(request.timeoutMs != null && { timeout: request.timeoutMs }), - ...(request.maxBufferBytes != null && { maxBuffer: request.maxBufferBytes }), -}; -const result = spawnSync(request.command, request.args, options); -``` - -> **Mitigation Prompt 5:** `In createGraftSourceHighlighterProcessRunner (src/adapters/graft-source-highlighter.ts), replace the mutable options object and its three conditional assignments with a single immutable declaration using conditional spreads, so options is built once and never mutated. Confirm the highlighter specs still pass.` - -**Violation 3 — `saveEditor` couples policy (readOnly guard + dirty-flag state) with the durability decision it cannot see** (`src/app/workspace/editor-session.ts:105-116`). It returns a clean (`dirty: false`) state *before knowing the bytes are durably on disk*, because `saveEditorFile` is fire-and-return with a non-atomic write underneath. - -Original: - -```ts -export function saveEditor(editor: EditorState, editorFile: EditorFilePort): EditorState { - if (editor.readOnly) return editor; - editorFile.saveEditorFile(editor.path, editor.lines); - return { ...editor, dirty: false }; -} -``` - -Simplified Rewrite — make durability a returned outcome, not an assumption: - -```ts -export function saveEditor(editor: EditorState, editorFile: EditorFilePort): SaveEditorOutcome { - if (editor.readOnly) return { kind: SaveOutcomeKinds.Skipped, editor }; - const result = editorFile.saveEditorFile(editor.path, editor.lines); // now returns SaveResult - return result.kind === SaveResultKinds.Persisted - ? { kind: SaveOutcomeKinds.Persisted, editor: { ...editor, dirty: false } } - : { kind: SaveOutcomeKinds.Obstructed, editor, issue: result.issue }; -} -``` - -> **Mitigation Prompt 6:** `Change EditorFilePort.saveEditorFile to return a discriminated SaveResult (Persisted | Obstructed{issue}) instead of void, and update saveEditor in editor-session.ts to only clear the dirty flag on Persisted, surfacing Obstructed to the caller. Keep the buffer dirty when a save fails. Add specs for the readOnly-skip, persisted, and obstructed branches.` - ---- - -## 2. Production Readiness & Risk Assessment (Exhaustive) - -### 2.1 Top 3 Ship-Stopping Risks ("Hard No") - -**Risk 1 — Non-atomic file save can corrupt user data. [CRITICAL]** `src/adapters/editor-file.ts:50-52` - -```ts -export function saveEditorFile(filePath: string, lines: readonly string[]): void { - writeFileSync(filePath, joinLines(lines), UTF8_ENCODING); -} -``` - -This writes directly over the target path. A crash, `SIGKILL`, full disk, or power loss *mid-write* leaves the user's file truncated or partially written — total data loss. This is doubly indefensible because the repo **already has** the safe pattern elsewhere: `src/adapters/jedit-wsc-workspace-store.ts` writes a temp file and uses `rmSync(tempPath, { force: true })` cleanup around an atomic swap. The editor's headline promise is recoverability; its save path is the least recoverable code in the tree. - -> **Mitigation Prompt 7:** `Make saveEditorFile in src/adapters/editor-file.ts crash-safe: write to a sibling temp file in the same directory (so rename is atomic on the same filesystem), fsync the file descriptor, rename() over the target, then fsync the parent directory after rename so the directory entry is durable on Unix filesystems; clean up the temp file on failure. Preserve the original file's mode/permissions. Mirror the temp-write discipline already used in jedit-wsc-workspace-store.ts. Add specs that assert the original file is intact when the write step throws and that the parent-directory fsync path is exercised after a successful rename.` - -**Risk 2 — Legacy/non-opened save can still blind-overwrite host changes. [HIGH]** `src/app/workspace/editor-session.ts:105` → `saveEditorFile`. The production opened-text path used by Ctrl-S and `:write` checks `materializationPreflightIssue` before writing, so it is not the normal two-instance overwrite path. The remaining risk is the legacy/non-opened fallback: it writes `editor.path` without checking whether the host file changed since load. Keeping that branch around makes the save model easy to misunderstand and leaves a weaker path for future call sites. - -> **Mitigation Prompt 8:** `Close or harden the legacy/non-opened save path. If saveEditor remains callable, thread the load-time fingerprint through it; before writing, re-stat/re-fingerprint the on-disk file and compare to the fingerprint captured at open. If they differ, obstruct with a recovery message ("file changed on disk; reload or force-overwrite") instead of writing. Add an explicit force path for the user. Cover changed-on-disk and unchanged cases with specs.` - -**Risk 3 — No top-level crash guard leaves the terminal wrecked. [HIGH]** No `process.on('uncaughtException'…)` or `'unhandledRejection'` handler exists anywhere in `src/` (grep returns only a comment). The app enters raw mode + mouse reporting via `run(app, { mouse: … })` (`src/main-workspace.ts:45`). Any uncaught throw (162 `throw` sites, 57 `catch`) on the render/input path crashes the process with the terminal still in raw/alt-screen/mouse mode — the user's shell is left unusable and any unsaved buffer is gone with no diagnostic. - -> **Mitigation Prompt 9:** `Add a top-level safety net in src/main.ts (or a dedicated bootstrap adapter) that registers uncaughtException and unhandledRejection handlers which: restore the terminal (exit raw mode, disable mouse reporting, leave alt-screen) via the Bijou TUI teardown, flush a structured crash diagnostic, attempt an emergency swap-file save of dirty buffers, and exit non-zero. Verify the terminal is restored by simulating a thrown error in an integration spec.` - -### 2.2 Security Posture - -> Note up front: **command injection is NOT present.** Every external process call uses `shell: false` with array args (`graft-source-highlighter.ts:145`, `graft-diagnostics-adapter.ts:178`, `execFileSync('git', ['rev-parse'…])`). That is the correct posture. The two findings below are subtler and genuinely overlooked. - -**Vulnerability 1 — PATH-based resolution of external binaries (supply-chain / PATH hijack). [MEDIUM]** The Graft/colorful runtimes are invoked by *name* (`request.command`) resolved through the inherited `PATH` (`graft-source-highlighter.ts:157`, `node-echo-recovery-command.ts:26`, `graft-diagnostics-adapter.ts:160`). If Jim is launched from a directory or environment where an attacker controls an earlier `PATH` entry (or a `./`-on-PATH shell), a malicious `graft`/`colorful` executable runs with the user's privileges on every file open. There is no pinned absolute path, checksum, or signature check. - -> **Mitigation Prompt 10:** `Harden external runtime resolution. Resolve graft/colorful to an absolute path once at startup (configurable via an explicit env var or settings key), reject relative or cwd-local resolutions, and record the resolved path + version in the startup diagnostic. Document the trust assumption in docs/. Optionally verify a known version string before first use and degrade to plain projection if it cannot be verified.` - -**Vulnerability 2 — Lossy/undetected non-UTF-8 content becomes silent data corruption on save. [MEDIUM]** `loadEditorFile` flags only files containing a NULL byte as binary (`editor-file.ts:30`); everything else goes through `bytes.toString('utf8')` (`editor-file.ts:38`), which **replaces** invalid byte sequences with U+FFFD. A latin-1/shift-JIS file with no null bytes loads as mangled text, is editable, and on `:w` is written back UTF-8 — silently corrupting the user's file. For an auditability-first editor this is an integrity failure, not a cosmetic one. - -> **Mitigation Prompt 11:** `In loadEditorFile, detect invalid UTF-8 (not just null bytes) — e.g. decode with fatal/strict semantics or scan for U+FFFD after decode — and mark such buffers readOnly with an explicit "non-UTF-8 / unsupported encoding" obstruction instead of loading lossy text. Never write a buffer back in a different encoding than it was read. Add specs for a valid UTF-8 file, a null-byte binary, and an invalid-UTF-8 file.` - -### 2.3 Operational Gaps (production) - -> Framing: Jim is an interactive TUI, not a long-running service, so classic health-check/uptime probes are partly N/A. The gaps below are the operationally meaningful ones for *this* artifact. - -- **Gap 1 — No crash telemetry / structured error reporting sink.** With 0 `console.*` and no `uncaughtException` handler, a field crash produces nothing actionable: no log file, no diagnostic bundle, no buffer-recovery trail. The witness/JSON tooling exists for CI but is not wired to runtime failures. -- **Gap 2 — No autosave / swap-file / crash recovery for in-memory buffers.** Dirty buffers live only in process memory (`EditorState.lines`); a crash or kill loses unsaved work entirely. Vim's `.swp` recovery is exactly the table-stakes feature a "recoverability" editor must ship. -- **Gap 3 — No release-artifact provenance / supply-chain attestation in CI.** `ci.yml` builds and shards tests but produces no signed build, SBOM, or dependency-audit gate (notably for the pre-1.0, fast-moving `@flyingrobots/graft 0.10.1` on the highlight critical path). Nothing blocks a compromised or yanked transitive dep from reaching a "release-gate" build. - ---- - -## 3. Final Recommendations & Next Step - -### 3.1 Final Ship Recommendation — **NO (as-is).** - -Not because the codebase is low quality — it is, by the metrics, excellent. The blocker is specific and narrow: **the shared host file-write adapter is not crash-safe (Risk 1), the legacy/non-opened save branch is not conflict-safe (Risk 2), and the process has no crash guard (Risk 3).** For a general-purpose editor that markets *trust, auditability, and recoverability*, shipping a write adapter that can truncate the user's file on a mid-write crash is a contradiction of the product's core promise. This becomes a **"YES, BUT…"** the moment Risks 1–3 are fixed and covered by tests; none of the three is large. - -### 3.2 Prioritized Action Plan - -- **Action 1 (High Urgency):** Make host writes atomic and close the legacy conflict gap — implement temp-write + file fsync + rename + parent-directory fsync in `saveEditorFile`, keep production export on `materializationPreflightIssue`, and either retire `saveEditor` or thread the load-time fingerprint into it for drift detection (**Mitigation Prompts 7 & 8**). This closes the two data-loss ship-stoppers and reuses a pattern already in the repo. -- **Action 2 (Medium Urgency):** Add the top-level crash guard with terminal restore + emergency dirty-buffer swap-save, plus a structured crash diagnostic sink (**Mitigation Prompt 9** + Operational Gaps 1–2). Protects the user's shell and unsaved work in the field. -- **Action 3 (Low Urgency):** Armor the doctrine and the encoding boundary — keep the existing `scripts/quality-gate.mjs` / `npm run quality` / CI quality job path, add a strict ESLint flat config with boundary + max-lines rules as a complementary standard lint surface, and tighten non-UTF-8 handling (**Mitigation Prompt 11**). Prevents quality regression and silent corruption over the long maintenance tail. - ---- - -### Evidence Basis - -- Save path: `src/adapters/editor-file.ts:50` (`writeFileSync` direct), `src/app/workspace/workspace-save-key.ts:31-74` (Ctrl-S / `:write` production route), `src/app/workspace/editor-session.ts:105` (legacy `saveEditor` fallback), `src/app/workspace/workspace-text-commands.ts:361` (export save with preflight). -- Atomic pattern already present: `src/adapters/jedit-wsc-workspace-store.ts` (temp + `rmSync force`). -- External process exec (all `shell: false`, array args): `graft-source-highlighter.ts:157`, `graft-diagnostics-adapter.ts:160/178`, `node-echo-recovery-command.ts:26`, `graft-api-session.ts:284`. -- Crash safety: no `uncaughtException`/`unhandledRejection`/`process.on` handler in `src/`; raw-mode launch at `src/main-workspace.ts:45`. -- Encoding: NULL-byte-only binary detection + lossy `toString('utf8')` at `src/adapters/editor-file.ts:30,38`. -- Type discipline: 1 `any` (comment), 12 `unknown`, 0 `@ts-ignore`, 0 `console.*`, 1 TODO; strict `tsconfig.json`; no ESLint; `scripts/quality-gate.mjs` runs through `npm run quality`; CI `.github/workflows/ci.yml` includes a quality job and the aggregate `check` job requires quality success. diff --git a/docs/audits/two-phase-assessment-2026-06-28.md b/docs/audits/two-phase-assessment-2026-06-28.md deleted file mode 100644 index c2f6e2c4..00000000 --- a/docs/audits/two-phase-assessment-2026-06-28.md +++ /dev/null @@ -1,125 +0,0 @@ -# Two-Phase Assessment — `jedit` / "Jim" - -**Date:** 2026-06-28 -**Reviewer perspectives:** Senior Developer Advocate (DX), Senior Architect & Auditor (IQ), Strategic Lead (synthesis) -**Codebase type:** Terminal-first modal editor + Echo-backed causal-editing proof harness (TypeScript, hexagonal). 330 source files, ~51k LOC, 166 spec files, strict `tsc`, no ESLint. Remote: `flyingrobots/jedit`. - ---- - -## 0. Executive Report Card (Strategic Lead) - -| Metric | Score | Recommendation | -|---|---|---| -| **Developer Experience (DX)** | **4 / 10** | **Best of:** Structured, recoverable error model — every obstruction carries `code` + `message` + `recovery` (`src/adapters/jedit-mutation-obstruction-mappers.ts`). | -| **Internal Quality (IQ)** | **9 / 10** | **Watch Out For:** No ESLint despite a mandate for maximal lint strictness — the entire "non-negotiable" doctrine (≤500 LOC, no `any`, no magic strings) is enforced by convention + review, not tooling. One inattentive merge erodes it. | -| **Overall** | **THUMBS UP** | **Justification:** As an internal proof harness and design lab it is among the most disciplined codebases audited; as a *consumable* editor it is honestly pre-alpha, which the README itself admits. | - -> The DX score is low **by design** — the project is not yet pitched as installable. It is scored as a tool a developer must adopt, because that is what the template measures. - ---- - -## 1. DX: Ergonomics & Interface Clarity (Advocate) - -### 1.1 Time-to-Value — 3 / 10 -TTV path is `npm ci → npm run build → node dist/main.js` (README "Compiling"). The single biggest boilerplate killer is not build steps — it is that **there is no installed binary and no file argument**. `src/main.ts` slices `process.argv`, but `jeditStartupCliAction` returns non-null for *exactly one* arg (`--version`/`--help`) and `runJeditWorkspace()` (`src/main-workspace.ts:26`) **ignores argv entirely** — it boots a workspace rooted at `cwd`. So `node dist/main.js README.md` silently does nothing with the file. - -- **Action Prompt (TTV):** `In src/main.ts and src/main-workspace.ts, add a CLI port that parses positional file arguments. Introduce a JeditStartupInvocation type carrying { files: readonly string[]; flags } decoded at the adapter boundary (jedit-startup-cli.ts), and thread an initialOpenPaths option through createWorkspaceApp so 'node dist/main.js path/to/file' opens that file in a buffer on boot. Add a package.json "bin" entry mapping 'jedit' to dist/main.js. Cover argv parsing with a spec under spec/.` - -### 1.2 Principle of Least Astonishment -Directly follows 1.1 and is the **single biggest POLA violation**: a self-described "Vim-shaped editor" does not honor `vim file.txt`. Every Vim user's first reflex (`jedit foo.ts`) is a no-op. They intuitively expect the named file to open; instead they get an empty workspace and must discover `:e` from inside. - -- **Action Prompt (Interface):** `Make the jedit binary accept one or more file paths as positional arguments matching Vim's invocation contract (jedit [options] [file...]). Opening multiple files should create one buffer per file with the first focused. Update GUIDE.md and the --help text (STARTUP_CLI_USAGE in jedit-startup-cli.ts) to document 'jedit ' as the primary entry point.` - -### 1.3 Error Usability -Internally this is a **strength**, not a weakness: `envelopeDecodeObstructedResponse` returns `{ code, message, recovery }` where `recovery` is a literal next action ("resubmit the intent using a valid EINT mutation envelope"). The gap is the *missing link layer* — recovery strings reference internal protocol nouns ("EINT mutation envelope", "register the worldline session via the optic client") with no pointer to where a human/agent learns those terms. - -- **Action Prompt (Error Handling):** `In src/adapters/jedit-mutation-obstruction-mappers.ts, extend the obstruction shape with an optional 'docs' field (a stable doc anchor, e.g. docs://obstructions/JEDIT_MUTATION_ENVELOPE_INVALID). Generate a docs/topics/obstructions.md catalog keyed by obstruction code from a single source of truth, and add a spec asserting every exported *_CODE constant has a catalog entry, so recovery strings always resolve to documentation.` - ---- - -## 2. DX: Documentation & Extendability (Advocate) - -### 2.1 Documentation Gap -Documentation *volume* is high (GUIDE, ADVANCED_GUIDE, ARCHITECTURE, BEARING, design/, method/). The missing piece is a **"First 5 minutes as a user" quickstart** — every doc is written for a contributor/proof-auditor. `docs/releases/` is described as "prove this Echo-backed path is real," not "edit your first file." There is no `:command` reference for the editor surface a daily-driver would reach for. - -- **Action Prompt (Docs):** `Create docs/quickstart.md aimed at a Vim user who wants to edit one real file: install/build, open a file, the supported Normal/Insert subset, how to save, and how to invoke :why and the history drawer. Cross-link it from README "Should I use Jim?". Generate a command-surface reference (docs/topics/commands.md) from the runtime command registry rather than hand-authoring it.` - -### 2.2 Customization — 6 / 10 -Strongest extension point: the **ports/adapters seam** — capabilities (Graft highlighting, Echo transport, filesystem, MCP) are injected into app services, so swapping an implementation needs no core edits (`ARCHITECTURE.md` Dependency Rule). Weakest/most fragile: **keybindings & command surface** are wired in code (`src/app/workspace/vim-command-executor.ts`, `vim-chord-syntax.ts`, `command-completion.ts`) with no external config/registration path — extending the command set means editing core source, the exact thing customization should avoid. - -- **Action Prompt (Extension):** `Introduce a command-registration port that lets adapters contribute commands/chords without editing vim-command-executor.ts. Define a JeditCommandDescriptor (id, chord, handler, provenance source) and a registry the executor consults, then migrate existing commands onto it. This turns the command surface into a composition point and prepares for user-supplied keymaps.` - ---- - -## 3. Internal Quality: Architecture & Maintainability (Architect) - -### 3.1 Technical Debt Hotspot -No single file is *bad* — but the **cluster of ten files at 490–499 LOC** is the debt signal. With a hard "no file over 500 LOC" non-negotiable, `src/app/workspace/viewer-content.ts` (499), `src/adapters/jedit-echo-optic-codec.ts` (499), `src/ui/workspace-chrome.ts` (498), `src/app/jedit-contract-runtime.ts` (496) are pressed against the ceiling. The cap is being satisfied *numerically*, which risks artificial splits and growing internal coupling that the metric cannot see. `src/app/workspace` alone holds 102 files — the highest concentration of orchestration. - -- **Action Prompt (Debt):** `Audit the ten src files between 490–499 LOC. For each, decide whether it is one cohesive responsibility (raise the doctrine cap with justification in ARCHITECTURE.md) or two responsibilities hugging the limit (extract along the seam into a named collaborator). Do not change public interfaces; add no new magic strings. Record the decision per file in docs/code-standards-audit.md.` - -### 3.2 Abstraction Violation -The codebase is notably clean on SoC — boundary decode is genuinely pushed to adapters. The closest real violation is `src/main.ts` performing **I/O (`writeSync` to fd 1)** *and* invocation routing inline. It is small, but it is app/transport concern leaking into the entry shim and is exactly where the swallowed-argv bug lives. - -- **Action Prompt (SoC):** `Extract main.ts's stdout writing and startup routing into a StartupPresenter (ui/) plus a StartupRouter (app/) behind an OutputPort, leaving main.ts as a thin composition root that wires ports to adapters and delegates. Add a spec that drives the router with fake argv + a fake OutputPort, asserting --version/--help and file-open routing without touching real stdout.` - -### 3.3 Testability Barrier -The primary barrier is the **test execution model**: `test:all` runs `npm run build && JEDIT_DIST_PREBUILT=1 node --test ... spec/**/*.spec.mjs` — specs are `.mjs` exercising **compiled `dist/` output**, single-concurrency. There is no fast TS-level unit path; every test run pays a full `tsc` build, and tests bind to emitted JS rather than source. That discourages tight red-green loops despite the otherwise injectable architecture. - -- **Action Prompt (Testability):** `Add a fast unit lane that runs specs against TypeScript via tsx/node --import without a full dist build (e.g. npm run test:unit), reserving the dist-prebuilt lane for integration/witness specs. Keep test:all as the gate. Verify a representative domain spec passes in both lanes to prove source/dist parity.` - ---- - -## 4. Internal Quality: Risk & Efficiency (Auditor) - -### 4.1 The Critical Flaw -**Doctrine enforced by humans, not machines.** The "Non-Negotiables" (≤500 LOC, no `any`, no `unknown`, no magic strings, no stringly state machines) are real and currently *honored* — the audit found **1 `any` (in a comment), 0 `@ts-ignore`, 1 TODO** across 51k LOC, which is exceptional. But there is **no ESLint config**, so nothing mechanically blocks regression. `tsconfig` is excellent (strict + `noUncheckedIndexedAccess` + `noPropertyAccessFromIndexSignature`), yet it cannot enforce LOC caps, magic-string bans, or import-direction rules. The doctrine is one inattentive merge from erosion. - -> Per repo policy this is flagged, not fixed — it conflicts with the global "maximize linter strictness" mandate; awaiting confirmation before any change. - -- **Action Prompt (Risk Mitigation):** `Add an ESLint flat config with the strictest TypeScript ruleset (typescript-eslint strict-type-checked + stylistic), promote all warnings to errors, ban any/unknown via no-explicit-any and a custom rule, and add eslint-plugin-boundaries to encode the hexagonal dependency rule (ui→app→domain/ports, adapters→ports). Add a max-lines rule at 500. Wire 'npm run lint' into the CI static/build job and a pre-commit hook in scripts/hooks/.` - -### 4.2 Efficiency Sink -The structural risk is the **build-coupled feedback loop** (see 3.3) rather than a hot-path algorithm: every `dev`, `build`, and `test` re-runs Wesley contract generation (`gen:contract:structural-history:wesley`) before `tsc`. For a 330-file project this serializes generation → full compile → asset copy on every iteration, single-concurrency tests on top. - -- **Action Prompt (Optimization):** `Make Wesley contract generation incremental/cached: skip regeneration when contracts/jedit/*.graphql and the generator are unchanged (hash-gate the .wesley-cache outputs). Enable tsc incremental builds (composite/tsBuildInfoFile). Measure cold vs warm 'npm run build' and record the delta.` - -### 4.3 Dependency Health -Dependencies are few and first-party-heavy: core `@flyingrobots/bijou` packages are exact-pinned to `7.0.0`, `@flyingrobots/graft` is exact-pinned to `0.10.1`, and `@flyingrobots/bijou-i18n` and its tools use `^7.0.0`. The watch item is still **Graft at 0.10.1 (pre-1.0) with a visibly churning surface** — the CHANGELOG shows multiple Graft bumps (0.10.0→0.10.1, "colorful 0.2.1 numeric IR identifiers") in the unreleased window alone. A pre-1.0 dependency on the syntax/highlight critical path is the highest-volatility external risk even though it is already exact-pinned. No GPL/AGPL contamination observed; no CVE-bearing package surfaced. - -- **Action Prompt (Dependency):** `Keep @flyingrobots/graft exact-pinned at 0.10.1, add a CHANGELOG/compat note documenting the minimum colorful IR version it requires, and add a smoke spec that asserts the Graft highlight adapter degrades gracefully (no crash, plain projection) when the expected parser runtime or colorful version is absent on PATH. Separately decide whether the ranged @flyingrobots/bijou-i18n and bijou-i18n tool packages should stay ranged for lockstep patch intake or be exact-pinned with the rest of the Bijou runtime surface.` - ---- - -## 5. Strategic Synthesis & Action Plan (Strategist) - -### 5.1 Combined Health Score — 7 / 10 -World-class internals dragged down by deliberate pre-alpha consumability. The engineering *discipline* is a 9; the *adoptability* is a 4. Weighted to a 7: this is a healthy, honest codebase that has chosen depth before reach. - -### 5.2 Strategic Fix (highest leverage, improves DX **and** IQ) -**Implement real CLI invocation: `jedit [file...]`.** It is the highest-leverage single move because it simultaneously: - -- **DX:** fixes the #1 TTV blocker (1.1) *and* the #1 POLA violation (1.2) — `jedit file.txt` finally does the obvious thing. -- **IQ:** forces resolution of the swallowed-argv SoC leak in `main.ts` (3.2) by introducing a proper startup-invocation port/adapter, replacing inline `writeSync` routing with a testable seam (3.3). - -One change closes the worst usability gap and the worst structural shortcut at the editor's front door. - -### 5.3 Mitigation Prompt (Strategic Priority) - -- **Action Prompt:** `Implement first-class file-open invocation for jedit, addressing both usability and structure. (1) Decode argv at the adapter boundary in jedit-startup-cli.ts into a JeditStartupInvocation { files: readonly string[]; printAction?: ... }, supporting 'jedit [--version|--help] [file...]'. (2) Replace the inline writeSync routing in src/main.ts with a thin composition root that wires an OutputPort adapter and a StartupRouter, eliminating the I/O+routing mixing flagged in SoC review. (3) Thread initialOpenPaths through runJeditWorkspace → createWorkspaceApp so named files open as buffers (first focused) on boot. (4) Add a package.json "bin": { "jedit": "dist/main.js" } entry. (5) Add specs covering argv parsing (version/help/files/none) against a fake OutputPort, and an integration spec asserting a named file is opened. (6) Update README "Compiling", GUIDE.md, and --help text to document 'jedit ' as the primary entry point. Honor the non-negotiables: no any/unknown, no new magic strings, keep every touched file under 500 LOC.` - ---- - -## Reviewer Notes - -- **Strongest signal:** 51k LOC with effectively zero type escapes and a coherent hexagonal boundary is rare. The doctrine works — it just is not *armored* (4.1). -- **Flagged, not fixed (per flyingrobots policy):** the missing-ESLint finding (a conflict with the "maximize linter strictness" mandate) and the Graft pre-1.0 dependency risk both await confirmation before any change. - -### Evidence basis - -- Type discipline: 1 `: any`/`as any` (a comment), 12 `unknown`, 0 `@ts-ignore`/`@ts-expect-error`, 1 TODO across 330 `.ts` files / ~51k LOC. -- LOC cap: largest source file is 499 LOC; ten files sit in 490–499. -- `tsconfig.json`: `strict`, `noUncheckedIndexedAccess`, `noPropertyAccessFromIndexSignature`, `noImplicitOverride`, `noUnusedLocals/Parameters`. -- Entry path: `src/main.ts` → `jeditStartupCliAction` (1-arg version/help only) → `runJeditWorkspace()` ignores argv. -- Error model: `src/adapters/jedit-mutation-obstruction-mappers.ts` (`code`/`message`/`recovery`). -- CI: single `.github/workflows/ci.yml` with sharded test planning; no lint job. diff --git a/docs/code-standards-audit.md b/docs/code-standards-audit.md deleted file mode 100644 index fbf04f93..00000000 --- a/docs/code-standards-audit.md +++ /dev/null @@ -1,234 +0,0 @@ -# Code Standards Audit - -Date: 2026-05-13 - -This audit records the gap between the current executable quality ratchet and -the full project standard in `CODE_STANDARDS.md`. It is intentionally a planning -artifact: no runtime behavior is changed here. - -## Inputs - -- Repository head: `e501ea9` (`main`, after PR #16) -- Enforced gate: `npm run quality -- --json` -- Additional measurement: TypeScript AST scan over `src/**/*.ts` -- Scope: hand-authored and generated TypeScript under `src` - -## Executive Summary - -The enforceable ratchet is clean: - -| Rule | Status | Evidence | -| :--- | :--- | :--- | -| No `any` | Clean | quality gate reports `0` regressions | -| No `unknown` | Clean | quality gate reports `0` regressions | -| Max 500 lines per TypeScript file | Clean | quality gate reports `0` regressions | - -The broader standard is not yet fully enforced. The largest gaps are function -size, cyclomatic complexity, import fan-in, parameter count, and the project-wide -ban on type assertions. These should be treated as tracked debt, not permission -to add more. - -## Metric Snapshot - -| Metric | Current | -| :--- | ---: | -| TypeScript files scanned | 105 | -| Total TypeScript lines scanned | 15,822 | -| Files at or above 425 lines | 7 | -| Files over 500 lines | 0 | -| Files over 12 imports | 8 | -| Functions over 35 lines | 38 | -| Functions over nesting depth 4 | 1 | -| Functions over complexity 8 | 32 | -| Functions over 5 parameters | 9 | -| Classes over 400 lines | 0 | -| Classes over 15 public methods | 0 | -| Type assertions, including `as const` | 84 | -| `enum` declarations | 0 | -| `throw new Error(...)` in `src` | 0 | -| Direct host API touches measured | 8 | - -The AST scan is conservative and should be converted into an executable ratchet -before these counts are used as hard CI policy. It is good enough to identify -the first cleanup sequence. - -## Near File-Size Limit - -These files are compliant today but close enough to the 500-line limit that new -work should avoid growing them: - -| File | Lines | -| :--- | ---: | -| `src/adapters/jedit-echo-optic-codec.ts` | 500 | -| `src/ui/title-scene.ts` | 496 | -| `src/app/jedit-contract-runtime.ts` | 495 | -| `src/app/workspace/editor-editing-helpers.ts` | 476 | -| `src/ui/title-screen.ts` | 449 | -| `src/ui/theme-builder.ts` | 428 | - -Priority: prevent growth immediately, then split when touching these areas. - -## Import Fan-In - -`CODE_STANDARDS.md` sets a maximum of 12 imports per file. Current offenders: - -| File | Imports | -| :--- | ---: | -| `src/app/workspace/key-bindings.ts` | 30 | -| `src/app/workspace/viewer.ts` | 25 | -| `src/adapters/workspace-app.ts` | 23 | -| `src/app/workspace/runtime.ts` | 23 | -| `src/app/workspace/file-tree.ts` | 17 | -| `src/app/workspace/model.ts` | 16 | -| `src/app/workspace/editor-session.ts` | 14 | -| `src/app/workspace/init.ts` | 13 | - -Primary concern: workspace orchestration modules still aggregate too many -responsibilities. This is a better refactor target than mechanical import -rewriting. - -## Function Size and Complexity - -Largest functions over the current standard: - -| Function | Location | Lines | Params | Depth | Complexity | -| :--- | :--- | ---: | ---: | ---: | ---: | -| `updateFromKey` | `src/app/workspace/key-bindings.ts:99` | 185 | 6 | 5 | 56 | -| anonymous update body | `src/app/workspace/runtime.ts:64` | 144 | 1 | 2 | 21 | -| anonymous reducer body | `src/app/workspace/runtime.ts:83` | 122 | 2 | 2 | 20 | -| `renderWorkspace` | `src/app/workspace/viewer.ts:88` | 106 | 1 | 1 | 11 | -| `createEchoTransportJeditOpticClient` | `src/adapters/jedit-echo-optic-client.ts:71` | 94 | 1 | 1 | 9 | -| `previewMarkdownLines` | `src/ui/markdown-preview.ts:30` | 90 | 1 | 2 | 16 | -| `updateGraftDrawerFromKey` | `src/app/workspace/graft-drawer.ts:17` | 87 | 3 | 2 | 19 | -| `updateTreeFromKey` | `src/app/workspace/file-tree.ts:34` | 66 | 4 | 2 | 10 | -| `sceneSampleAt` | `src/ui/title-screen.ts:168` | 63 | 10 | 2 | 7 | -| `updateInsertMode` | `src/app/workspace/editor-editing.ts:165` | 62 | 5 | 1 | 17 | - -The first cleanup target should be `updateFromKey`: it violates line count, -parameter count, nesting depth, and complexity in one place. - -## Type Assertions - -The AST scan found 84 type assertions in `src`, including many `as const` -token declarations and generated-code constants. - -Recommended classification: - -| Bucket | Policy | -| :--- | :--- | -| Generated files under `src/generated` | Track separately; do not hand-edit generated output. | -| Boundary casts in adapters | Replace with parser/constructor validation where practical. | -| `as const` runtime token tables | Convert to explicit runtime objects, classes, or `Object.freeze` values with named types when touched. | -| Generic model casts in app helpers | Replace with narrower model interfaces or returned concrete model types. | - -High-signal source files to inspect first: - -- `src/app/source-highlight-session.ts` -- `src/adapters/echo-wasm-kernel.ts` -- `src/adapters/title-scene-loader.ts` -- `src/adapters/title-bunny-mesh.ts` -- `src/app/jedit-observer-spec.ts` -- `src/app/workspace/editor/key.ts` -- `src/app/workspace/workspace-key.ts` -- `src/ui/jedit-theme.ts` - -## Host API Touches - -Measured direct host APIs: - -| API | Location | Initial classification | -| :--- | :--- | :--- | -| `Date.now` | `src/adapters/workspace-app.ts:45` | Adapter injection default, acceptable. | -| `Math.random` | `src/adapters/workspace-app.ts:46` | Adapter injection default, acceptable. | -| `process.env` | `src/adapters/workspace-app.ts:90` | Adapter boundary, should be injected/configured later. | -| `process.cwd` | `src/main.ts:8` | Process entry point, acceptable. | -| `process.env` | `src/main.ts:27` | Process entry point, acceptable. | -| `Date.now` | `src/ui/feedback.ts:75` | UI helper fallback; should be made explicit through caller/capability. | - -The likely fixes are small: remove default `Date.now` from app logic and keep -host capabilities in adapters or process entry points. - -## Architecture Observations - -- The `src/main.ts` split is successful; the process entry point is now small. -- Workspace input, runtime update, and rendering remain orchestration hot spots. -- Title rendering is close to size limits and has several high-parameter helper - functions. Any TUI/title visual work should include local decomposition. -- Codec and contract runtime files are still near the file-size ceiling; future - contract work should prefer new focused modules over adding to these files. -- Generated files need an explicit policy before broad type-assertion rules are - enforced against them. - -## Remediation Backlog - -### Must Fix Before New Feature Work - -1. Split `src/app/workspace/key-bindings.ts`. - - Extract scene picker handling. - - Extract title screen key handling. - - Extract editor command dispatch. - - Replace the six-parameter `updateFromKey` with a named context object or - injected command environment. - -2. Split workspace runtime dispatch. - - Replace anonymous 100+ line update bodies with named message handlers. - - Keep `WorkspaceMessageTypes` as the central runtime truth. - -3. Add a second quality ratchet script or extend `scripts/quality-gate.mjs`. - - Start with reporting-only JSON for function length, params, imports, - complexity, and assertions. - - Only fail CI once baselines are explicit and shrinking. - -### Should Fix Before TUI Landing Work - -1. Port only the small `tui` commits first. - - `dbdc946` floor fade hit fix. - - `821d24d` ASCII inactive color fix. - - `b12cffe` help copy scope fix. - -2. Keep `/Users/james/git/jedit-rays` read-only during the port. - - The worktree has an untracked `docs/data-model.md` and an old branch shape. - - Replaying selected commits onto fresh `main` is safer than merging `tui`. - -3. Treat the Flying Robots logo work as a separate visual PR. - - It adds a Braille text asset and a new renderer module. - - It should include screenshot or surface-level verification. - -4. Re-design the Think-style notice change against current `src/ui/feedback.ts`. - - Do not cherry-pick `9d94a30` directly. - - It predates the current notification-token and runtime-issue toast work. - -### Ratchet Later - -1. Type assertion policy by bucket. -2. Import count enforcement. -3. Function length and parameter count enforcement. -4. Complexity enforcement. -5. Host API placement enforcement. - -## Proposed PR Sequence - -1. `chore(quality): add code standards audit` - - Adds this audit only. - -2. `refactor(workspace): split key binding dispatch` - - High value because it removes the single worst standards violation. - -3. `refactor(workspace): split runtime message handlers` - - Reduces long anonymous functions and import fan-in. - -4. `chore(quality): report extended standards metrics` - - Adds reporting-only metrics for currently unenforced rules. - -5. `fix(title): port low-risk tui rendering fixes` - - Replays the three small `tui` fixes onto current `main`. - -6. `feat(title): port Flying Robots logo band` - - Separate visual PR with focused verification. - -## Decision Record - -Do not start new feature work until the audit is merged and the first workspace -dispatch cleanup is either complete or explicitly deferred. The repository is -green, but the standards gap is real enough that new feature work should not -increase the current hot spots. diff --git a/docs/design/0001-replace-range-contract/replace-range-contract.md b/docs/design/0001-replace-range-contract/replace-range-contract.md deleted file mode 100644 index 2db69b66..00000000 --- a/docs/design/0001-replace-range-contract/replace-range-contract.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: "replace-range-contract" -legend: "none" -cycle: "0001-replace-range-contract" -source_backlog: "docs/method/backlog/asap/replace-range-contract.md" ---- - -# replace-range-contract - -Source backlog item: `docs/method/backlog/asap/replace-range-contract.md` -Legend: none - -## Sponsors - -- Human: Backlog operator -- Agent: Implementation agent - -These labels are abstract roles. In this design, `user` means the served -perspective, like in a user story, not a literal named person or -specific agent instance. - -## Hill - -Turn `ReplaceRange` into the first explicit, executable seam of the future -Echo-backed text kernel by locking the contract between prose, tests, and -runtime stub. At the end of this cycle, `jedit` should have a design packet, -executable spec, and minimal green implementation that make three claims -concrete: - -1. inserting a fragment satisfies the materialization law -2. deleting text is just replacement by the empty fragment -3. replacing a range with identical logical text is a no-op - -This cycle is complete when those claims are named in this design, expressed in -tests, and satisfied by the initial runtime contract implementation. This cycle -still does not require persistent rope storage, anchors, strands, or -admission. - -## Playback Questions - -### Human - -- [ ] ReplaceRange is named as the first kernel seam in this cycle. -- [ ] This cycle pins down insert/materialization, delete-by-empty-fragment, - and logical no-op. -- [ ] This cycle limits scope to the minimal ReplaceRange seam. -- [ ] This cycle makes accessibility, localization, and agent inspectability - explicit. - -### Agent - -- [ ] ReplaceRange insertion satisfies the materialization law. -- [ ] ReplaceRange deletion is replacement by the empty fragment. -- [ ] ReplaceRange returns the same root and no receipt for a logical no-op. -- [ ] The runtime contract stays a minimal ReplaceRange seam rather than a full - rope engine. -- [ ] The workspace satisfies build, quality, and the ReplaceRange contract - suite. - -## Accessibility and Assistive Reading - -- Linear truth / reduced-complexity posture: the cycle should remain readable as - plain text. The contract is expressed as short invariant-style statements plus - direct red tests rather than diagram-heavy explanation. -- Non-visual or alternate-reading expectations: playback must be inspectable - through file reads and test output alone. No claimed result depends on a - visual demo or terminal animation. - -## Localization and Directionality - -- Locale / wording / formatting assumptions: the contract uses stable English - engineering nouns such as `fragment`, `range`, and `receipt`. It should avoid - idioms that would make future localization harder. -- Logical direction / layout assumptions: the contract is phrased in logical - range terms (`start`, `end`) and does not depend on left/right UI metaphors. - -## Agent Inspectability and Explainability - -- What must be explicit and deterministic for agents: the exact public contract - types and the three expected behaviors must be visible in source and asserted - in tests. Agents should not need to infer hidden intent from chat. -- What must be attributable, evidenced, or governed: the green implementation - must be attributable back to these playback questions and the contract tests - they produced. This cycle's witness is the passing contract suite plus the - minimal runtime implementation. - -## Non-goals - -- [ ] Implementing persistent piece-rope storage. -- [ ] Implementing anchor transforms. -- [ ] Implementing strands or admission. -- [ ] Refactoring the current Bijou UI around the future text kernel. - -## Backlog Context - -Turn the Echo-backed text-kernel direction into a real cycle centered on the `ReplaceRange` primitive. The immediate deliverable is an explicit design hill plus playback questions that align with the existing red contract tests for insertion/materialization law, deletion by empty fragment, and logical no-op behavior. - -## Later Evolution - -WF-0154 (2026-07-12) removed the module-global root-id counter this cycle's -minimal runtime shipped with: `createBufferRoot`, `createTextFragment`, and -`emptyFragment` now take explicit ids, `replaceRange` takes the next root id, -and tick admission threads `nextRootId` as chain state -(`spec/root-identity-determinism.spec.mjs`). The behavioral laws in this -document (materialization, deletion by empty fragment, logical no-op) are -unchanged. diff --git a/docs/design/0002-anchor-transform-semantics/anchor-transform-semantics.md b/docs/design/0002-anchor-transform-semantics/anchor-transform-semantics.md deleted file mode 100644 index bddfb1cc..00000000 --- a/docs/design/0002-anchor-transform-semantics/anchor-transform-semantics.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -title: "anchor-transform-semantics" -legend: "none" -cycle: "0002-anchor-transform-semantics" -source_backlog: "docs/method/backlog/asap/anchor-transform-semantics.md" ---- - -# anchor-transform-semantics - -Source backlog item: `docs/method/backlog/asap/anchor-transform-semantics.md` -Legend: none - -## Sponsors - -- Human: Backlog operator -- Agent: Implementation agent - -These labels are abstract roles. In this design, `user` means the served -perspective, like in a user story, not a literal named person or -specific agent instance. - -## Hill - -Turn point-anchor transform semantics into the next explicit seam after -`ReplaceRange` by locking the contract between prose, tests, and a runtime -contract. At the end of this cycle, `jedit` should have a design packet, -executable spec, and minimal green implementation that make four claims -concrete: - -1. a left-biased point anchor stays before inserted text at its byte -2. a right-biased point anchor moves after inserted text at its byte -3. a point anchor after a replacement shifts by the replacement byte delta -4. a point anchor inside a deleted span collapses to the replacement start - -This cycle is complete when those claims are named in this design, expressed in -tests, and satisfied by the initial runtime contract implementation. This cycle -does not implement interval anchors, anchor persistence, rope-maintenance -semantics, or editor UI integration. - -## Playback Questions - -### Human - -- [ ] Anchor transforms are defined in terms of logical ReplaceRange deltas - rather than rope maintenance. -- [ ] This cycle pins down left-bias, right-bias, forward shift, and collapse - semantics for point anchors. -- [ ] This cycle limits scope to point anchors over ReplaceRange deltas. -- [ ] This cycle makes accessibility, localization, and agent inspectability - explicit. - -### Agent - -- [ ] A left-biased point anchor stays before inserted text at its byte. -- [ ] A right-biased point anchor moves after inserted text at its byte. -- [ ] A point anchor after a replacement shifts by the replacement byte delta. -- [ ] A point anchor inside a deleted span collapses to the replacement start. -- [ ] The runtime contract stays a minimal point-anchor seam rather than a full - anchor system. -- [ ] The workspace satisfies build, quality, and the anchor transform contract - suite. - -## Accessibility and Assistive Reading - -- Linear truth / reduced-complexity posture: the contract stays linear and - point-based. The cycle talks about byte positions, deltas, and bias without - requiring a visual editor demo. -- Non-visual or alternate-reading expectations: playback must be inspectable - through file reads and test output. No claimed behavior depends on cursor - animation or viewport state. - -## Localization and Directionality - -- Locale / wording / formatting assumptions: the contract uses stable English - engineering nouns such as `anchor`, `bias`, `delta`, and `replacement - delta`, and avoids idiomatic prose. -- Logical direction / layout assumptions: left/right in this cycle refers only - to bias semantics at a logical point. Position transforms are phrased in byte - offsets and replacement ranges rather than screen coordinates. - -## Agent Inspectability and Explainability - -- What must be explicit and deterministic for agents: the point-anchor runtime - surface, the bias constants, and the four expected transform behaviors must - be visible in source and in tests. Agents should not need to infer anchor - rules from chat. -- What must be attributable, evidenced, or governed: the green implementation - must be attributable back to these playback questions and the anchor-transform - contract suite. - -## Non-goals - -- [ ] Implementing interval-anchor semantics. -- [ ] Implementing anchor persistence or serialization. -- [ ] Treating rope-maintenance events as author-facing anchor semantics. -- [ ] Wiring the anchor contract into the current Bijou editor UI. - -## Backlog Context - -Define the first executable contract for point-anchor transform semantics over ReplaceRange. The cycle should pin down how point anchors behave when text is inserted at the anchor, before it, after a replacement, and inside a deletion, while keeping rope maintenance out of author-facing semantics. diff --git a/docs/design/0003-echo-backed-rope-worldline-contract/echo-backed-rope-worldline-contract.md b/docs/design/0003-echo-backed-rope-worldline-contract/echo-backed-rope-worldline-contract.md deleted file mode 100644 index 2993b926..00000000 --- a/docs/design/0003-echo-backed-rope-worldline-contract/echo-backed-rope-worldline-contract.md +++ /dev/null @@ -1,350 +0,0 @@ ---- -title: "echo-backed-rope-worldline-contract" -legend: "none" -cycle: "0003-echo-backed-rope-worldline-contract" -source_backlog: "docs/method/backlog/asap/echo-backed-rope-worldline-contract.md" ---- - -# echo-backed-rope-worldline-contract - -Source backlog item: `docs/method/backlog/asap/echo-backed-rope-worldline-contract.md` -Legend: none - -## Sponsors - -- Human: Backlog operator -- Agent: Implementation agent - -These labels are abstract roles. In this design, `user` means the served -perspective, like in a user story, not a literal named person or -specific agent instance. - -## Hill - -Turn the causal text-runtime direction into the first explicit contract packet -for the future Echo-backed editor kernel. At the end of this cycle, `jedit` should -have a design packet that makes five claims concrete: - -1. the canonical editable truth is witnessed causal history rather than an AST - snapshot, filesystem artifact, or Git export -2. causal history, lawful readings, and materialized projections have explicit - ownership boundaries -3. Graft owns structural readings over rope heads rather than the - editor kernel itself -4. save acts as a checkpoint rather than a reset of editor truth -5. causal history retention is tiered across tick receipts, ticks, edit - groups, and checkpoints/admissions rather than "keep everything forever" or - "discard everything on save" - -This cycle is complete when those claims are named in this design, aligned with -the causal runtime strata note, and turned into explicit playback questions for -the next executable seams. This cycle is intentionally design-first: it does -not implement Echo bindings, a rope runtime, or new editor UI. - -## Playback Questions - -### Human - -- [ ] The cycle clearly says witnessed causal history is canonical, AST - structure is derived, and Git commits are ecosystem exports rather than the - cadence of editor truth. -- [ ] The cycle makes the causal-history / reading / projection ownership split - explicit across `jedit`, Echo, Graft, filesystem, and Git adapters. -- [ ] The cycle explains save as a checkpoint rather than a reset. -- [ ] The cycle names a tiered retention model for tick receipts, ticks, edit - groups, and checkpoints/admissions. -- [ ] The cycle limits scope to the runtime contract rather than pretending to - implement the substrate. - -### Agent - -- [ ] The packet names the causal runtime truths the future rope-worldline must - expose: ticks, tick receipts, anchors, and parser-independent editing truth. -- [ ] The packet names the Graft reading responsibilities: syntax - spans, folds, diagnostics, node lookup, structural selection, rename - preview, diff, and semantic summary. -- [ ] The packet names filesystem and Git projection/export responsibilities. -- [ ] The packet makes explicit that Graft's current `StructuredBuffer` shape - is projection-oriented rather than the canonical editor kernel. -- [ ] The packet leaves the next executable seams obvious: rope contract, - structural-reading adapter contract, retention policy, and - checkpoint-to-export bridge. - -## Accessibility and Assistive Reading - -- Linear truth / reduced-complexity posture: this cycle should remain readable - as a short architecture packet. It should prefer explicit ownership and truth - classes over diagrams or metaphors that require prior Continuum knowledge. -- Non-visual or alternate-reading expectations: playback must be inspectable - through plain markdown reads alone. No claim in this cycle depends on visual - editor demos or interactive runtime screenshots. - -## Localization and Directionality - -- Locale / wording / formatting assumptions: the packet should use stable - engineering nouns such as `rope-worldline`, `tick`, `edit-group`, - `checkpoint`, and `witness`, and should avoid idioms that make later - localization harder. -- Logical direction / layout assumptions: causal history, readings, and - projections are ownership terms, not visual layout. The packet should avoid - left/right or top/bottom metaphors when describing causal ownership. - -## Agent Inspectability and Explainability - -- What must be explicit and deterministic for agents: the ownership split and - truth classes must be visible directly in repo docs so future agent work does - not infer editor-kernel behavior from chat or stale assumptions. -- What must be attributable, evidenced, or governed: the packet must be - attributable to current repo truth in `README.md`, `ARCHITECTURE.md`, - `docs/design/runtime-temperatures.md`, and the existing text-runtime design - notes rather than free-floating discussion. - -## Contract - -Detailed node, edge, and rewrite expectations for the future Echo-backed causal -text reading model now live in -[../jedit-echo-graph-model.md](../jedit-echo-graph-model.md). -The dynamic footprint law for those rewrites now lives in -[../0004-dynamic-footprint-binding-contract/dynamic-footprint-binding-contract.md](../0004-dynamic-footprint-binding-contract/dynamic-footprint-binding-contract.md). - -### Core law - -- Witnessed causal history is canonical. -- Rope-worldline, AST, file, pane, and diff shapes are readings or - materialized projections over that history. -- Git commits are ecosystem exports, not the cadence or authority of editor - truth. - -`jedit` therefore must not wait for `git commit` before live editor truth, -syntax surfaces, or structural context catch up. - -### Runtime strata - -`jedit` should treat its causal runtime as strata: - -- causal history - admitted transitions, frontiers, receipts, checkpoints, strands, braids, and - retained witness -- lawful readings - text windows, snapshots, syntax spans, diagnostics, searches, diffs, and - proposal previews -- materialized projections - viewport caches, filesystem working trees, Graft parse caches, exported Git - commits, and CI snapshots - -The same noun must not silently slide between these strata. - -### Causal history truths - -The causal history layer is the editor-native truth. - -It must own: - -- `BufferWorldline` -- `RopeRoot` -- ticks as the canonical causal-history boundary -- tick receipts as the fine-grained transition witness surface -- anchors -- future strands and admissions - -It must remain lawful when: - -- the buffer is dirty -- the buffer does not parse -- the language is unsupported -- the editor has not saved yet -- the repo is not a Git repo - -This layer is where `ReplaceRange`, anchor transforms, and tick admission -ultimately become witnessed history. - -`jedit` may layer edit groups and undo groups over ticks, but those groupings -must not be mistaken for the canonical worldline boundary. - -### Reading truths - -The reading layer is an interpretation of causal history. - -It must own: - -- syntax spans -- fold regions -- parser-backed diagnostics -- node lookup -- structural selections -- rename preview -- structural diff and semantic summary -- anchor-affinity style snapshot mapping - -These readings follow available frontiers, rope heads, or tick heads. They are -allowed to be partial when parsing fails and must degrade honestly for -unsupported languages. - -Readings are not allowed to masquerade as canonical text truth. - -### Projection and export truths - -Materialized projections are useful, portable surfaces over causal history. - -They include: - -- filesystem working trees -- exported Git commits -- CI snapshots -- public archive formats -- compatibility mirrors - -These projections may lag behind live editing truth. They are not allowed to -define when truth exists inside the editor. - -## Ownership - -### `jedit` - -`jedit` owns: - -- product behavior -- modes -- panes, panels, and lenses -- save and open flows -- focus and interaction policy -- rendering policy - -`jedit` does not own parser semantics or durable causal history storage. - -### Echo / jedit contract host - -Echo is the intended generic host of causal rope-worldline truth. jedit-owned -contracts and generated host adapters own the rope vocabulary and text law. - -That means: - -- persistent piece-rope storage modeled through the jedit contract -- scheduler-owned ticks and tick receipts emitted by Echo -- anchors and transformable positions defined by jedit contract law -- future strands and admissions - -Echo is not the owner of UI behavior, panel lifecycle, structural parser -projection semantics, or built-in rope/string manipulation. - -`jedit` is the right place for edit-group and undo policy layered over Echo -ticks. - -### Graft - -Graft owns structural intelligence over causal text history. - -That means: - -- interpreting current in-memory content -- producing parser-backed projections -- remaining truthful about partial parses and unsupported languages - -Graft's current `StructuredBuffer` shape is already a strong structural -reading surface, but it is still projection-oriented. It is not the canonical -editable buffer runtime. - -### Filesystem and Git adapters - -The filesystem owns working projections. Git and `git-warp` own optional -ecosystem export, import, mirroring, public hosting, CI, and compatibility -surfaces. - -They should export or mirror editor projections later. They should not decide -the live update cadence or reality history of the editor. - -## Save and retention - -### Save - -Save is a checkpoint, not a reset. - -Saving may: - -- create a checkpoint -- materialize the current head to disk -- emit or prepare ecosystem export artifacts - -Saving must not: - -- destroy causal history -- discard undoable editor truth by default -- redefine when the editor's truth started to exist - -### Retention tiers - -Retention should be tiered: - -- tick receipts - short-horizon, compactable, not forever by default -- ticks - canonical causal history that survives saves -- edit groups - medium-lived, human-meaningful history layered over one or more ticks -- checkpoints and admissions - durable long-horizon history - -The contract should permit compaction of fine-grained tick-receipt history -without destroying higher-level tick, edit-group, or checkpoint truth. - -## Immediate executable seams - -This cycle should leave the next implementation seams obvious: - -1. `echo-backed-rope-worldline-contract` - the causal text-runtime contract itself -2. `graft-hot-structural-projections-over-rope-heads` - legacy-named backlog slug - the structural reading adapter contract -3. `causal-history-retention-and-compaction-policy` - the retention law -4. `save-checkpoints-and-cold-witness-bridge` - legacy-named backlog slug - the checkpoint-to-export bridge - -This packet is successful if those seams become more precise rather than more -poetic. - -The first executable seam in this cycle is save-checkpoint semantics, because -it pins down one of the most user-visible consequences of the causal rope model -without requiring the full runtime to exist yet. - -The next executable seam after save-checkpoint semantics is scheduler-owned -admission semantics: a lawful `ReplaceRange` should become jedit contract work -that Echo may decide during a tick and witness with a tick receipt, while a -logical no-op should not mint a new tick. - -The executable seam after tick-admission semantics is edit-group semantics: -`jedit` should be able to group one or more known ticks into a human-meaningful -edit group without redefining the canonical tick boundary. - -The executable seam after edit-group semantics is an app-facing causal-runtime -port and a truthful in-memory adapter: `jedit` should be able to compose -ReplaceRange, tick admission, edit-group policy, and checkpointing without -pretending that Echo is already embedded in-process. - -## Backlog Context - -Define the causal text-truth substrate for `jedit`. - -Context: - -- `jedit` needs a canonical editable truth that updates with live editing, - not Git commit cadence. -- Echo is already the causal runtime in the broader Continuum model and already - has WASM-facing posture that makes it plausible as the native substrate. -- Graft is now strong enough to own structural readings, which sharpens the - need for a separate causal text-runtime contract. - -This note should answer: what exactly is the rope-worldline, what is its -primitive edit law, how do ticks and tick receipts fit, and how do anchors and -edit groups fit without collapsing into parser or Git concerns. - -## Non-goals - -- Implementing an Echo crate, WASM guest, or TypeScript bindings in this cycle. -- Implementing the rope runtime itself. -- Replacing Graft with Echo or collapsing the two into one undifferentiated - engine. -- Designing every long-term Echo retention or ecosystem export detail. -- Treating Git commit cadence as the live update cadence of the editor. diff --git a/docs/design/0004-dynamic-footprint-binding-contract/dynamic-footprint-binding-contract.md b/docs/design/0004-dynamic-footprint-binding-contract/dynamic-footprint-binding-contract.md deleted file mode 100644 index 20c26e6e..00000000 --- a/docs/design/0004-dynamic-footprint-binding-contract/dynamic-footprint-binding-contract.md +++ /dev/null @@ -1,529 +0,0 @@ ---- -title: "dynamic-footprint-binding-contract" -legend: "none" -cycle: "0004-dynamic-footprint-binding-contract" -source_backlog: "docs/method/backlog/asap/dynamic-footprint-binding-contract.md" ---- - -# dynamic-footprint-binding-contract - -Source backlog item: `docs/method/backlog/asap/dynamic-footprint-binding-contract.md` -Legend: none - -## Sponsors - -- Human: Backlog operator -- Agent: Implementation agent - -These labels are abstract roles. In this design, `user` means the served -perspective, like in a user story, not a literal named person or specific -agent instance. - -## Hill - -Turn the `jedit` causal text reading model into the first explicit contract for -dynamic, honest rewrite footprints. At the end of this cycle, `jedit` should have a -design packet that makes five claims concrete: - -1. rewrite footprints are static at the level of slots, bindings, derivation - grammar, and capability surface -2. rewrite bindings are dynamic at the level of concrete worldline/head/range - values and runtime materialized readings -3. `ReplaceRangeAsTick` can bind a dynamic rope/anchor focus without gaining - arbitrary causal-history or reading reach -4. `CreateCheckpoint` can stay narrow without borrowing the `ReplaceRange` - shape by accident -5. compile-time honesty failures and runtime binding failures are distinct and - both necessary - -This cycle is complete when those claims are explicit in repo truth, grounded -in `jedit`'s real causal-text nouns, and illustrated with concrete rewrite -examples rather than generic placeholder entities. - -## Playback Questions - -### Human - -- [ ] The packet clearly states that footprint schema is static while concrete - bindings are dynamic. -- [ ] The packet uses `jedit`'s real nouns and rewrite families rather than - abstract `Foo`/`Bar` stand-ins. -- [ ] The packet includes at least one detailed `ReplaceRangeAsTick` example. -- [ ] The packet distinguishes compile-time and runtime failure classes. -- [ ] The packet stays focused on footprint law rather than drifting into full - runtime implementation. - -### Agent - -- [ ] The packet names the minimum vocabulary needed for honest dynamic - rewrites: slots, binding sources, closures, create/update surfaces, and - forbidden surfaces. -- [ ] The packet shows how `ReplaceRangeAsTick` may dynamically derive its - touched rope path while remaining statically bounded. -- [ ] The packet shows how `CreateCheckpoint` stays narrower than - `ReplaceRangeAsTick`. -- [ ] The packet states what Wesley should prove at compile time and what Echo - should enforce at runtime. -- [ ] The packet leaves the next executable seam obvious: Wesley directive - grammar plus one proof-slice rewrite compilation. - -## Accessibility and Assistive Reading - -- Linear truth / reduced-complexity posture: this packet should remain readable - as direct prose plus one proposed GraphQL footprint shape. It should avoid - requiring a diagram to understand the law. -- Non-visual or alternate-reading expectations: all claims should be - inspectable from markdown alone. No argument depends on visual rope diagrams - or UI mockups. - -## Localization and Directionality - -- Locale / wording / formatting assumptions: the packet uses stable nouns such - as `slot`, `binding`, `closure`, `ReplaceRangeAsTick`, and `Checkpoint`. - It should avoid idioms that would make future localization harder. -- Logical direction / layout assumptions: the packet speaks in logical range, - basis, and closure terms rather than left/right or screen-space metaphors. - -## Agent Inspectability and Explainability - -- What must be explicit and deterministic for agents: the rewrite capability - boundary must be visible in repo docs so future generator/runtime work does - not infer honesty rules from chat alone. -- What must be attributable, evidenced, or governed: the proposed footprint - shape must be attributable to the existing causal text reading model and text - edit algebra rather than free-floating compiler folklore. - -## One Sentence - -`jedit` should treat a rewrite footprint as a statically declared slot-and- -closure grammar whose concrete worldline, head, rope, and anchor instances are -bound dynamically at runtime. - -## Why This Exists - -The current simplified proof slice is enough to prove one thing: - -- Wesley can generate a bounded Rust capability surface from a declared - footprint. - -It is not enough for `jedit`, because `jedit`'s real causal-text rewrites are -not static object updates over pre-known nodes. `ReplaceRangeAsTick` needs: - -- a runtime `worldlineId` -- a runtime `baseHeadId` -- a runtime byte range -- a dynamically discovered touched rope path -- optionally a dynamically discovered affected-anchor set - -If the footprint model cannot express that honestly, it will either: - -- become too weak and allow dishonest arbitrary traversal -- or become too rigid and fail to model the editor's real rewrite law - -This packet defines the middle path. - -The first authored GraphQL home for that contract now lives in -[../../../contracts/jedit/hot-text-runtime.graphql](../../../contracts/jedit/hot-text-runtime.graphql). - -## Core Law - -The core split is: - -- **static footprint schema** - what kinds of things the rewrite may bind, derive, create, update, or forbid -- **dynamic footprint binding** - which concrete nodes or closures satisfy those bindings for a particular - invocation - -This means the compiler must prove: - -- the implementation can only act through declared slots and declared closure - operators -- the implementation cannot reach undeclared causal-history or reading surfaces - -And the runtime must prove: - -- the supplied ids and arguments resolve lawfully -- the derived closures are valid for this invocation -- the resulting rewrite satisfies materialization and admission law - -## Minimum Footprint Vocabulary - -The current flat `reads` / `writes` lists are not enough for `jedit`. - -The minimum honest vocabulary is: - -### 1. Slots - -Named logical bindings for specific contract nouns. - -Examples: - -- `worldline: BufferWorldline` -- `baseHead: RopeHead` -- `checkpoint: Checkpoint` - -### 2. Binding sources - -How a slot gets its concrete runtime binding. - -Minimum binding modes: - -- from explicit mutation args -- from the current canonical relation of an already-bound slot -- from a declared derivation over an already-bound slot -- from creation inside the rewrite - -### 3. Closures - -A declared derived focus over causal text readings rather than a single fixed -node. - -For `jedit`, the important closures are things like: - -- rope-range closure over a `RopeHead` plus `[startByte, endByte]` -- affected-anchor closure over a `BufferWorldline`, a `basisHead`, and a - receipt transform window - -The closure operator itself must be named in the footprint contract, not -invented ad hoc inside Rust. - -### 4. Create surfaces - -Which node kinds the rewrite may mint. - -For example: - -- `TextBlob` -- `RopeLeaf` -- `RopeBranch` -- `RopeHead` -- `Tick` -- `TickReceipt` -- `Checkpoint` - -### 5. Update surfaces - -Which bound slots may be updated and which logical fields/relations they may -change. - -For example: - -- `BufferWorldline.CANONICAL_HEAD` -- tick-chain membership - -### 6. Forbidden surfaces - -Which noun families are explicitly out of bounds even if they are available -elsewhere in the wider product stack. - -For `jedit` causal-text rewrites, the important forbidden surfaces are: - -- AST state -- diagnostics -- Git export history -- UI state - -## Compile-Time vs Runtime - -This split is non-negotiable. - -### Compile-time honesty failures - -These should be static failures or unavailable methods: - -- a `ReplaceRangeAsTick` implementation tries to read AST state -- a checkpoint rewrite tries to create a `Tick` -- a causal text rewrite tries to inspect Git export history -- a rewrite tries to use a closure operator that was not declared - -### Runtime binding failures - -These are real invocation-time failures: - -- `worldlineId` does not resolve -- `baseHeadId` does not belong to that worldline -- `[startByte, endByte]` is invalid for that head -- a declared closure resolves to no result or ambiguous results where the - contract required exactly one -- the logical replacement is a no-op and therefore must not mint a tick - -## Proposed GraphQL Footprint Shape - -This is illustrative, not frozen syntax, but it is concrete enough to drive -Wesley and Echo work. - -```graphql -directive @wes_footprint( - slots: [WesFootprintSlot!]! - closures: [WesFootprintClosure!] - creates: [WesFootprintCreate!] - updates: [WesFootprintUpdate!] - forbids: [String!] -) on FIELD_DEFINITION - -input WesFootprintSlot { - slot: String! - kind: String! - bindFromArg: String - bindFromSlot: String - bindRelation: String - access: [WesAccess!]! - cardinality: WesCardinality = ONE -} - -input WesFootprintClosure { - slot: String! - fromSlot: String! - operator: String! - argBindings: [String!] - reads: [String!]! - cardinality: WesCardinality = MANY -} - -input WesFootprintCreate { - slot: String! - kind: String! - cardinality: WesCardinality = ONE -} - -input WesFootprintUpdate { - slot: String! - fields: [String!]! -} - -enum WesAccess { - READ - WRITE - DELETE -} - -enum WesCardinality { - ONE - OPTIONAL - MANY -} -``` - -The important point is not the exact spelling. The important point is that the -contract names: - -- what gets bound directly -- what gets derived as a closure -- what may be created -- what may be updated - -without pretending the compiler already knows the concrete node IDs. - -## `ReplaceRangeAsTick` - -This is the real center. - -### Dynamic input - -`ReplaceRangeAsTick` takes runtime values such as: - -- `worldlineId` -- `baseHeadId` -- `startByte` -- `endByte` -- inserted fragment or text - -### Static contract - -The rewrite should still have a statically honest footprint like: - -```graphql -type Mutation { - replaceRangeAsTick( - worldlineId: ID! - baseHeadId: ID! - startByte: Int! - endByte: Int! - insertText: String! - ): ReplaceRangeAsTickResult! - @wes_op(name: "replaceRangeAsTick") - @wes_footprint( - slots: [ - { - slot: "worldline" - kind: "BufferWorldline" - bindFromArg: "worldlineId" - access: [READ, WRITE] - } - { - slot: "baseHead" - kind: "RopeHead" - bindFromArg: "baseHeadId" - access: [READ] - } - ] - closures: [ - { - slot: "touchedRope" - fromSlot: "baseHead" - operator: "ropeRangeClosure" - argBindings: ["startByte", "endByte"] - reads: ["RopeBranch", "RopeLeaf", "TextBlob"] - cardinality: MANY - } - { - slot: "affectedAnchors" - fromSlot: "worldline" - operator: "anchorsIntersectingEditWindow" - argBindings: ["baseHead", "startByte", "endByte"] - reads: ["Anchor"] - cardinality: MANY - } - ] - creates: [ - { slot: "newBlob", kind: "TextBlob", cardinality: OPTIONAL } - { slot: "newLeaves", kind: "RopeLeaf", cardinality: MANY } - { slot: "newBranches", kind: "RopeBranch", cardinality: MANY } - { slot: "nextHead", kind: "RopeHead" } - { slot: "tick", kind: "Tick" } - { slot: "receipt", kind: "TickReceipt" } - ] - updates: [ - { slot: "worldline", fields: ["canonicalHead"] } - ] - forbids: ["AstState", "Diagnostics", "GitWitness", "UiState"] - ) -} -``` - -### What this lets the compiler prove - -Wesley can then generate a bounded capability surface such that the rewrite -implementation may only: - -- inspect the bound `worldline` -- inspect the bound `baseHead` -- inspect the declared `touchedRope` closure -- inspect the declared `affectedAnchors` closure -- create the listed causal-text nouns -- update the allowed worldline relation - -It cannot: - -- ask for arbitrary causal-history or reading traversal -- inspect AST state -- mutate diagnostics -- perform Git export operations -- touch UI state - -### What runtime still must do - -Echo still needs to: - -- bind `worldlineId` -- bind `baseHeadId` -- derive the rope-range closure -- derive the affected-anchor closure -- reject stale or invalid basis -- enforce no-op discipline -- enforce materialization law - -That is correct. The runtime is supposed to own those instance-level truths. - -One important v1 note: reading `affectedAnchors` here does not mean the rewrite -is authorized to persist anchor updates in-place. In the current `jedit` -contract, that closure exists so anchor transform can remain a derived function -of the emitted receipt until persistence is explicitly widened. - -## `CreateCheckpoint` - -This second example matters because it proves the model is not just a range -editing trick. - -The rewrite can stay much narrower. In the current authored GraphQL contract it -is also intentionally canonical-only: it binds the checkpoint target from the -worldline's current `CANONICAL_HEAD` relation instead of letting the caller -name an arbitrary `headId`. - -```graphql -type Mutation { - createCheckpoint( - worldlineId: ID! - kind: String! - label: String - ): Checkpoint! - @wes_op(name: "createCheckpoint") - @wes_footprint( - slots: [ - { - slot: "worldline" - kind: "BufferWorldline" - bindFromArg: "worldlineId" - access: [READ] - } - { - slot: "currentHead" - kind: "RopeHead" - bindFromSlot: "worldline" - bindRelation: "CANONICAL_HEAD" - access: [READ] - } - ] - creates: [ - { slot: "checkpoint", kind: "Checkpoint" } - ] - updates: [] - forbids: ["RopeBranch", "RopeLeaf", "TextBlob", "Tick", "TickReceipt"] - ) -} -``` - -This means the generated Rust surface for checkpoint creation should not expose: - -- rope-edit closures -- blob creation -- tick creation -- receipt creation - -If the implementation tries to do any of those things, it should fail -statically. - -If later product needs bookmark-like or admission-like retained markers on -non-canonical heads, that should arrive as an explicit widening such as -`CreateCheckpointAtHead`, not as a silent broadening of this rewrite. - -## What This Means For `jedit` - -The causal text rewrite boundary can now be stated precisely: - -- `ReplaceRangeAsTick` is allowed a dynamic rope-local and anchor-local focus - over a statically declared causal-text closure -- `CreateCheckpoint` is not -- later rewrites such as `RegisterAnchor` and strand/braid admission can be - added with the same slot/binding/closure model instead of inventing a new - honesty system each time - -This is exactly the missing bridge between: - -- `jedit`'s causal text reading model -- Wesley's compile-time honesty goal -- Echo's runtime binding and admission law - -## Immediate executable seams - -The next useful seams are now clearer: - -1. define the first actual Wesley directive grammar for slot and closure - footprints -2. compile one `ReplaceRangeAsTick` proof slice into a bounded Rust surface -3. prove that AST/diagnostic/Git/UI access is unavailable from that generated - surface -4. bind the resulting surface in Echo against a real runtime focus closure - -## Backlog Context - -`jedit` already knows the text-history nouns it needs. What it lacked was the -honest bridge between static footprint law and dynamic runtime binding. - -This packet defines that bridge. It should now guide both: - -- Wesley footprint grammar work -- Echo runtime focus-binding work - -without weakening either side into vague capability theater. diff --git a/docs/design/0005-jedit-observer-spec/jedit-observer-spec.md b/docs/design/0005-jedit-observer-spec/jedit-observer-spec.md deleted file mode 100644 index f658c687..00000000 --- a/docs/design/0005-jedit-observer-spec/jedit-observer-spec.md +++ /dev/null @@ -1,133 +0,0 @@ -# Jedit Observer Spec - -Status: design sketch - -Purpose: define the first lawful app-owned observer shape for `jedit` without -pretending that a GraphQL query alone is the whole observer. - -This note is the detailed companion to: - -- [../../src/app/jedit-observer-spec.ts](../../src/app/jedit-observer-spec.ts) -- [../../contracts/jedit/hot-text-runtime.graphql](../../contracts/jedit/hot-text-runtime.graphql) -- [../jedit-echo-graph-model.md](../jedit-echo-graph-model.md) - -## One Sentence - -`jedit` should author observers in app code as lawful `ObserverSpec` objects -that Wesley can compile and Echo can host generically, beginning with a -memoryless canonical-head `worldlineSnapshot` observer. - -## Why This Exists - -The current integration posture is optic-shaped: - -- app-authored mutations define the set side -- Echo admits generic substrate intents and returns deterministic result and - receipt envelopes -- later readings come from observers over sliced holographic truth - -That means the get side needs a real authoring surface of its own. - -The important correction is: - -- a GraphQL query shape is not automatically a full observer -- a full observer has static law and runtime state -- the app must author the static part legally without handing Echo arbitrary - callbacks - -## Observer Layers - -This packet keeps three layers distinct. - -### 1. ObserverSpec - -App-authored, mostly static, and lawful. - -For `jedit`, the first observer spec declares: - -- canonical-worldline aperture -- `jedit` causal-text basis -- memoryless state shape -- replace-with-latest-slice update law -- snapshot-reading emission law -- author-visible rights with canonical-text-only revelation - -### 2. ObserverInstance - -Runtime object hosted by Echo. - -Even the memoryless case is still a runtime object in principle. It may have a -trivial state, but it is still distinct from the authored spec. - -### 3. Reading - -Observer-relative emitted output for one frontier or hologram. - -For the first `jedit` proving slice, that reading is the contract -`worldlineSnapshot` result. - -## Current First Observer - -The first `jedit` observer is intentionally narrow: - -- name: `worldlineSnapshot` -- aperture: one canonical worldline slice -- basis nodes: - - `BufferWorldline` - - `RopeHead` - - `Checkpoint` -- derived surface: - - `text` -- history window: - - canonical head only -- state mode: - - memoryless - -This is the degenerate observer case where `M` is trivial and the update law is -almost identity-like. - -That is acceptable because it proves the authored/compiled/runtime split -without pretending `jedit` already needs the full observer zoo. - -## Why Memoryless First - -The first `worldlineSnapshot` observer is a safe proving target because it lets -us prove: - -- app code can author an observer lawfully -- the observer is not the same object as the GraphQL query itself -- the observer spec can name aperture, basis, state, update, emit, budgets, - and rights explicitly -- the emitted reading can still be the same generated contract family used by - the rest of the app - -Later `jedit` observers should become accumulative where it earns real value, -for example: - -- retained cursor or anchor context -- retained edit-group awareness -- retained provenance or receipt windows -- conflict or settlement-aware editor lenses - -## Current Rule - -`jedit` must not define observers by handing Echo arbitrary host callbacks. - -The app may define: - -- lawful observer specs in app code -- app-owned reading families -- app-owned observer rights and exposure policy - -But those must lower into compiler-produced and runtime-legal observer plans. - -## Immediate Next Step - -The next step after this note is not to widen `worldlineSnapshot`. - -It is to: - -1. let Wesley compile the first `ObserverSpec` into an `ObserverPlan` -2. let Echo host that plan through a generic Observer API -3. keep the resulting reading envelope distinct from the original mutation - result and receipt envelope diff --git a/docs/design/0006-optic-backed-file-model/optic-backed-file-model.md b/docs/design/0006-optic-backed-file-model/optic-backed-file-model.md deleted file mode 100644 index 663e42c7..00000000 --- a/docs/design/0006-optic-backed-file-model/optic-backed-file-model.md +++ /dev/null @@ -1,420 +0,0 @@ ---- -title: "optic-backed-file-model" -legend: "none" -cycle: "0006-optic-backed-file-model" -source_backlog: "conversation: echo-optic-read-write-planning" ---- - -# optic-backed-file-model - -Source backlog item: `conversation: echo-optic-read-write-planning` -Legend: none - -## Sponsors - -- Human: Backlog operator -- Agent: Implementation agent - -These labels are abstract roles. In this design, `user` means the served -perspective, like in a user story, not a literal named person or specific -agent instance. - -## Hill - -Turn the emerging Echo Optic idea into a concrete `jedit` planning packet and -backlog cut. At the end of this cycle, `jedit` should have a design that makes -six claims explicit: - -1. an open file is a focused causal view, not a whole string in memory -2. an Optic read is a bounded observation at an Echo coordinate -3. an Optic write is an Intent submission, never a direct setter -4. text windows, inverse ticks, and braid projections are contract-owned - `jedit` semantics compiled through Wesley -5. Echo owns the generic Optic, coordinate, dispatch, admission, and reading - substrate -6. `jedit` can prepare now with a fake Echo Optic harness while waiting for the - real Echo API - -This cycle is complete when those claims are visible in repo docs and broken -into backlog items that can be executed independently. - -## Playback Questions - -### Human - -- [ ] The packet clearly states that all file mutations happen by submitting - Intents through Echo. -- [ ] The packet makes `read` and `write` optic behavior concrete without - implying direct substrate mutation. -- [ ] The packet explains how bounded viewport reads replace full-file editor - loading. -- [ ] The packet keeps `jedit` text semantics app-owned and Echo substrate - semantics generic. -- [ ] The packet cuts the plan into backlog tasks with acceptance criteria. - -### Agent - -- [ ] The packet names the current repo seam in - `src/ports/jedit-optic-client.ts` and the future seam through - `EchoWasmKernelTransport`. -- [ ] The packet gives enough GraphQL-shaped examples for future Wesley schema - work. -- [ ] The packet specifies how inverse-tick undo appends history rather than - deleting history. -- [ ] The packet specifies how sequential braid edits project current file - state. -- [ ] The packet leaves an executable first slice: fake Echo Optic tests over - bounded text-window reads and Intent-only writes. - -## Accessibility and Assistive Reading - -- Linear truth / reduced-complexity posture: this packet should be readable as - direct prose plus small GraphQL examples. No argument should depend on a - diagram. -- Non-visual or alternate-reading expectations: all examples use named - coordinates, ranges, and receipts rather than visual screen positions. - -## Localization and Directionality - -- Locale / wording / formatting assumptions: the packet uses stable nouns such - as `Optic`, `Intent`, `Reading`, `Coordinate`, `Braid`, `Tick`, and - `Receipt`. -- Logical direction / layout assumptions: `before`, `after`, `start`, and - `end` refer to logical text order, not visual left/right screen layout. - -## Agent Inspectability and Explainability - -- What must be explicit and deterministic for agents: the read/write boundary - must be documented so future agents do not reintroduce whole-file strings as - the editor's canonical model. -- What must be attributable, evidenced, or governed: the plan must tie back to - the authored GraphQL contract, the existing optic client seam, and the Echo - doctrine that app nouns stay out of Echo core. - -## Core Decision - -`jedit` should treat an open editable file as an Echo-backed Text File Optic: - -```text -TextFileOptic = focus + coordinate + bounded read family + write Intent family -``` - -The Optic is not the file itself. The file is a causal projection over -witnessed history. The Optic is the capability-scoped way the editor focuses on -that history and emits bounded readings from it. - -This means: - -- `read` means observe a bounded projection at a causal coordinate -- `write` means submit an Intent against the focused projection -- the returned result is a tick, receipt, reading, obstruction, or later - settlement signal -- direct setters are not part of the model - -## Non-Goals - -- Implementing the real Echo Optic API inside `jedit`. -- Making Echo core know about files, text ranges, Graft, or `jedit`. -- Removing `worldlineSnapshot` before a bounded read family exists. -- Solving every strand, braid, and wormhole retention rule in this packet. -- Replacing the current editor UI in one cycle. - -## Current Repo Starting Point - -The repo already has a useful first seam: - -- [src/ports/jedit-optic-client.ts](../../../src/ports/jedit-optic-client.ts) -- [src/app/jedit-optic-client.ts](../../../src/app/jedit-optic-client.ts) -- [spec/jedit-optic-client.spec.mjs](../../../spec/jedit-optic-client.spec.mjs) - -That seam is GraphQL-shaped, but it is not Echo-shaped yet. The current -implementation directly maps generated operation names to the legacy in-memory -`HotTextRuntimePort`. That is acceptable as a proving slice, but the next step -should make the seam transport-shaped: - -```text -jedit UI - -> TextFileOptic client - -> encoded contract query or mutation - -> EchoWasmKernelTransport - -> fake or real Echo contract host - -> reading, tick receipt, or obstruction -``` - -The fake host may use the in-memory runtime internally. The public app seam -must still look like Echo: bytes in, bytes out, with decoding only at the -adapter boundary. - -## Optic Law - -An Echo Optic should obey four rules. - -### 1. Coordinate-Anchored Reads - -Every read is tied to an Echo coordinate or a named frontier. A reading is not -just "current text"; it is "this projection as observed from this causal -position." - -### 2. Bounded Projections - -Reads must have explicit budgets. For source painting, the normal read is a -text window around the viewport and cursor, not the whole file. - -### 3. Intent-Only Writes - -All writes submit Intents. The Optic can help construct the Intent, but it does -not bypass admission. - -### 4. Receipts Over Mutation Return Values - -The editor should advance from receipts and readings, not from local mutation -assumptions. A write may be accepted, rejected, obstructed, transformed, or -settled later. - -## App Model - -The editor-facing open file model should become: - -```ts -type OpenTextFile = { - opticId: string; - cursor: TextCursor; - viewport: TextViewport; - lastReadingCoordinate: EchoCoordinate; -}; -``` - -The editor owns cursor, viewport, panels, selection presentation, and keyboard -mode. Echo owns causal history, coordinates, admission, and receipt identity. -The `jedit` contract owns text semantics such as ranges, line -windows, anchors, inverse text operations, and braid projection rules. - -## Ideal GraphQL Shape - -This is a planning target, not a claim that the current generated schema -already supports it. - -```graphql -type TextFileOptic { - opticId: ID! - worldlineId: ID! - braidId: ID - coordinate: EchoCoordinate! - capabilities: [OpticCapability!]! -} - -type EchoCoordinate { - worldlineId: ID! - strandId: ID - braidId: ID - tickId: ID -} - -type TextCursor { - line: Int! - column: Int! -} - -type TextLineReading { - lineNumber: Int! - text: String! - startByte: Int! - endByte: Int! -} - -type TextWindowReading { - opticId: ID! - readingId: ID! - coordinate: EchoCoordinate! - startLine: Int! - lineCount: Int! - totalLineCount: Int! - lines: [TextLineReading!]! - hasMoreBefore: Boolean! - hasMoreAfter: Boolean! -} - -input OpenTextFileOpticInput { - worldlineId: ID! - braidId: ID - coordinate: EchoCoordinateInput -} - -input TextWindowInput { - opticId: ID! - cursor: TextCursorInput! - beforeLines: Int! - afterLines: Int! - maxBytes: Int! -} - -type Query { - textWindow(input: TextWindowInput!): TextWindowReading! -} - -type Mutation { - openTextFileOptic(input: OpenTextFileOpticInput!): TextFileOptic! -} -``` - -The read example for the editor is: - -```graphql -query ReadViewport($input: TextWindowInput!) { - textWindow(input: $input) { - opticId - coordinate { - worldlineId - strandId - braidId - tickId - } - startLine - lineCount - totalLineCount - hasMoreBefore - hasMoreAfter - lines { - lineNumber - text - startByte - endByte - } - } -} -``` - -## Intent Writes - -The write shape should keep the base coordinate visible: - -```graphql -input ReplaceTextRangeInput { - opticId: ID! - baseCoordinate: EchoCoordinateInput! - range: TextRangeInput! - replacement: TextFragmentInput! - author: String -} - -type TextEditResult { - accepted: Boolean! - coordinate: EchoCoordinate - tick: Tick - receipt: TickReceipt - obstruction: TextEditObstruction -} - -type Mutation { - replaceTextRange(input: ReplaceTextRangeInput!): TextEditResult! -} -``` - -That operation is still an Intent. If the editor has a stale base coordinate, -the result should be an obstruction rather than a silent local overwrite. - -## Inverse Tick Undo - -Undo should append inverse history. It should not delete old ticks. - -Example: - -```text -C0 = add "h" -C1 = add "e" -C2 = add "l" -C3 = add "l" -C4 = add "o" - -projection = "hello" -``` - -Unapplying `C2` should admit a new inverse operation: - -```text -C5 = inverse(C2) - -projection = "helo" -history = [C0, C1, C2, C3, C4, C5] -``` - -The GraphQL-shaped operation should make that explicit: - -```graphql -input UnapplyTickInput { - opticId: ID! - baseCoordinate: EchoCoordinateInput! - targetTickId: ID! - author: String -} - -input UnapplyTickSequenceInput { - opticId: ID! - baseCoordinate: EchoCoordinateInput! - targetTickIds: [ID!]! - author: String -} - -type Mutation { - unapplyTick(input: UnapplyTickInput!): TextEditResult! - unapplyTickSequence(input: UnapplyTickSequenceInput!): TextEditResult! -} -``` - -## Braid Projection - -The initial braid model for normal editing should be sequential: - -```text -baseline + S0 = projection 1 -(baseline + S0) + S1 = projection 2 -((baseline + S0) + S1) + S2 = projection 3 -``` - -Each next strand forks from the current projection frontier, not from a -separate local patch list. The braid projection is the current file state. - -The first useful `jedit` contract should support: - -- opening an optic over a worldline alone -- opening an optic over a worldline plus active braid -- reading a bounded text window from the projected braid -- submitting the next edit Intent against the braid frontier -- rejecting or obstructing edits whose base coordinate is no longer admissible - -## Preparation Plan - -The plan splits into seven executable slices: - -1. define the Text File Optic contract surface in GraphQL -2. add a fake Echo Optic transport harness for tests -3. add bounded `textWindow` readings before changing editor rendering -4. route editor mutations through Intent-shaped optic writes -5. add inverse tick and inverse sequence operations -6. model braid-backed file projections -7. cut over from fake/direct clients to generated Wesley/Echo clients later - -## Backlog Cut - -The backlog cards for this packet are: - -- [text-file-optic-contract-surface](../../method/backlog/asap/text-file-optic-contract-surface.md) -- [fake-echo-optic-transport-harness](../../method/backlog/asap/fake-echo-optic-transport-harness.md) -- [bounded-text-window-optic-reader](../../method/backlog/asap/bounded-text-window-optic-reader.md) -- [intent-only-editor-mutation-routing](../../method/backlog/asap/intent-only-editor-mutation-routing.md) -- [inverse-tick-unapply-intents](../../method/backlog/asap/inverse-tick-unapply-intents.md) -- [braid-backed-file-projection-optic](../../method/backlog/asap/braid-backed-file-projection-optic.md) -- [optic-client-generation-cutover](../../method/backlog/asap/optic-client-generation-cutover.md) - -## Open Questions - -- Is an Optic persistent causal metadata, a session-scoped capability handle, - or both? -- Which coordinate fields are Echo substrate fields versus contract projection - fields? -- How should Wesley declare bounded reading budgets so Echo can enforce them - generically? -- Which inverse operations can be generated from receipts, and which require - contract-authored inverse logic? -- How much braid projection admission belongs in Echo generic substrate versus - the `jedit` text contract? diff --git a/docs/design/0007-jedit-v1-experience/jedit-v1-experience.md b/docs/design/0007-jedit-v1-experience/jedit-v1-experience.md deleted file mode 100644 index ca83e49a..00000000 --- a/docs/design/0007-jedit-v1-experience/jedit-v1-experience.md +++ /dev/null @@ -1,462 +0,0 @@ ---- -title: "jedit-v1-experience" -legend: "none" -cycle: "0007-jedit-v1-experience" -source_backlog: "conversation: jedit-v1-feel-and-causal-features" ---- - -# jedit-v1-experience - -Source backlog item: `conversation: jedit-v1-feel-and-causal-features` -Legend: none - -## Purpose - -Define how `jedit` v1 should feel, what product promises it should make, and -which causal features deserve explicit design work. - -This packet is product-facing. It gives the Echo, Optic, rope-worldline, and -Wesley contract work a user-facing reason to exist. - -## Design Lineage - -This document takes inspiration from the Bijou project documentation, -especially: - -- `docs/strategy/bijou-vision.md` -- `docs/strategy/bijou-ux-doctrine.md` -- `docs/strategy/humane-shell.md` -- `docs/strategy/content-guide.md` -- `docs/design-system/foundations.md` -- `docs/design-system/patterns.md` -- `docs/invariants/focus-owns-input.md` -- `docs/invariants/visible-controls-are-a-promise.md` -- `docs/invariants/docs-are-the-demo.md` -- `docs/strategy/ai-explainability-standard.md` - -The inheritance is not visual imitation. The important standards are: - -- calm over noise -- explicit ownership over hidden magic -- focus as input ownership -- visible controls as operational truth -- shell and chrome as product surfaces -- density with rhythm -- AI as governed assistance -- documentation as a proving surface - -## One Sentence - -`jedit` v1 should feel like a quiet terminal editor that happens to understand -causality. - -## Product Stance - -`jedit` is a terminal-native editor for people who want their working surface -to stay calm while the system underneath remains precise, inspectable, and -causal. - -It should not become a browser IDE in a terminal. - -It should not fill the screen with permanent panels to prove that it is -powerful. - -It should make power available as focused views, drawers, lenses, Optics, and -reviewable proposals. The central editor should remain quiet by default. - -## What `jedit` Is - -`jedit` is: - -- a keyboard-first terminal editor -- a calm source-editing workspace -- an Echo-ready causal editing surface -- a proving ground for Optic-backed file interaction -- a humane shell over source, search, diagnostics, tests, suggestions, and - history -- an editor where the user can understand what owns input and what changed - -`jedit` is not: - -- a terminal clone of VS Code -- a pile of panes around a text area -- a chat app with an editor attached -- a Git UI pretending to be the source of editor truth -- an AST workbench that only works when code parses -- an editor that hides mutation behind auto-applied suggestions - -## Users - -The primary user is a developer working inside a real repository. - -They want to open files quickly, edit without friction, search and navigate -with confidence, understand diagnostics without being shouted at, preview -suggestions before accepting them, and trust undo, save, and dirty state. - -The secondary user is a future agent, plugin, or integration that needs to -interact with editor state without relying on folklore. - -They need declared Optics, bounded readings, causal coordinates, Intent-only -mutations, receipts, checkpoints, proposals, and deterministic surfaces that -can be tested. - -## The Feeling Promise - -`jedit` should feel: - -- quiet -- fast -- deliberate -- spatially stable -- honest about focus -- forgiving without being vague -- powerful without visual pressure - -It should not feel: - -- noisy -- tutorialized all the time -- covered in permanent panels -- clever at the cost of trust -- dependent on hidden background mutation -- afraid to show consequences when the user asks - -## Product Principles - -### 1. The Text Surface Is Sacred - -The main editor is the primary surface. Everything else is a lens, drawer, -pane, rail, or temporary layer over the user's current task. - -### 2. Focus Owns Input - -The active region owns local controls. Footer hints, help, and visible controls -must follow the same truth. - -### 3. Visible Controls Are A Promise - -If `jedit` shows a key hint, that key should work right now for the active -layer or region. Missing hints are acceptable. Dead hints are not. - -### 4. Power Appears On Demand - -Search, help, diagnostics, suggestions, tests, Git context, history, and -settings should appear as focused surfaces with clear entry and exit. - -### 5. Density Requires Rhythm - -Terminal density is useful. It still needs air. Rows, gutters, panes, and -footer hints should read as intentional, not compressed. - -### 6. Causality Should Clarify - -The user should not have to learn Echo to edit a file. Causal features should -answer practical questions: - -- what changed? -- why is this stale? -- what would happen if I apply this? -- can I preview the earlier state? -- which checkpoint am I ahead of? - -### 7. Suggestions Are Proposals - -Completions, AI edits, format operations, and refactors are proposed changes. -Small completions may stay lightweight. Larger changes should become -reviewable proposals with basis, scope, and accept or reject paths. - -### 8. Save Is A Checkpoint - -Save should record a checkpoint. It should not erase editor causality. Dirty -state means the current projection differs from the last save checkpoint or -durable Echo frontier. - -### 9. Large Files Are Normal - -Opening a large file should not require eager full-file thinking. The normal -read should be a bounded window around the viewport and cursor. - -### 10. AI Must Be Governed - -AI-mediated output must be marked, explainable, and actionable. It should -present proposals, evidence, and next actions instead of silently mutating -files. - -## Shell Anatomy - -The shell should be sparse, but not vague. - -- **Main editor** - Shows text, cursor, selection, optional gutter cues, and minimal local - markers for diagnostics, search, or suggestions. It avoids permanent - explanatory copy, large inline AI blocks, and noisy diagnostic prose. - -- **Footer** - Carries operational truth: mode, focused region, working controls, dirty or - checkpoint posture, and short status after meaningful events. It is not a - command encyclopedia. - -- **File drawer** - Helps navigation and orientation. It is easy to open and dismiss. It is not - required for normal editing once a file is open. - -- **Command palette** - Acts as the front door for rare actions. It should be fast, searchable, and - honest about scope. - -- **Help** - Is discoverable, not omnipresent. Short hints teach the next few actions. - Full help explains the active layer and its controls. - -- **Drawers** - Hold sidecar inspection surfaces: diagnostics, search results, file tree, - Graft structure, proposal details, test output, and notification history. - Inactive drawers stop advertising controls. - -- **Panes** - Are focused Optic views, not layout clutter. A pane may show another file - region, a definition peek, a checkpoint comparison, a proposal preview, test - output, or generated structure. - -- **Modals** - Are only for decisions that must stop the user: discard work, apply a broad - proposal, resolve an obstruction, or quit with unsaved checkpoint state. - -## Common Feature Stance - -- **Buffer switching** - Avoid permanent tab clutter. Prefer a recent-buffer stack, file switcher, and - compact footer identity. - -- **Search** - Search is a lens. Matches are navigable, coordinate-aware, and dismissible. - Project search belongs in a drawer or palette-backed result surface. - -- **Replace** - Replace is a proposed edit group. Replace-all should show scope and - consequence before committing, and obstruct on stale bases. - -- **Completion** - Completion is quiet by default: a small candidate surface or ghost - suggestion first, details only on request or dwell. - -- **AI assistance** - AI operates through proposal strands. The user can inspect affected region, - basis, rationale, evidence, and effect before accepting. - -- **Diagnostics** - Diagnostics use quiet editor markers and a drawer for explanation. Inline - diagnostic text appears on focus, dwell, or command. - -- **Definition and references** - Peek first. Jump second. A target opens as a temporary pane or drawer view - that can be pinned, jumped to, or dismissed. - -- **Splits** - Splits are intentional Optic views with clear subjects and coordinates. The - default remains one editor. - -- **Undo and redo** - Primitive ticks are runtime truth. User-facing undo groups typing bursts, - paste, format, AI proposals, and refactors into understandable events. - -- **Git and diff** - Git is an ecosystem projection, not editor truth. Diffs compare coordinates: - current vs save checkpoint, exported Git HEAD, proposal, or earlier tick. - -- **Tests and tasks** - Test results carry a basis. If the user edits after a run, `jedit` knows the - results may be stale. - -- **Multi-cursor** - Multi-cursor editing is an edit cohort over anchors. The UI shows count and - scope before broad edits. - -- **Macros** - Macros become replayable Intent sequences. Replay previews or obstructs when - context changed. - -- **Settings** - Settings are local, inspectable, and calm. Prefer project config and command - palette changes before a large preferences UI. - -## Causal Feature Plan - -### 1. Causal Undo And Time Rail - -Most editors expose undo as a hidden stack. `jedit` should expose meaningful -events when useful: - -- typing burst -- paste -- delete -- format -- proposal accept -- refactor -- save checkpoint - -The user should be able to undo the last event, preview a prior coordinate, -unapply a specific tick, or compare now with then. - -Design doc to write: `causal-undo-and-time-rail`. - -### 2. Suggestion As Proposal Strand - -Suggestions and AI edits often mutate attention before they mutate text. -`jedit` should treat non-trivial suggestions as proposed causal strands. - -The user should be able to preview, inspect basis and affected range, accept -all, accept part, reject, or keep the proposal as a temporary fork. - -Design doc to write: `suggestion-as-proposal-strand`. - -### 3. Save Checkpoints And Dirty Truth - -Dirty state is often vague. `jedit` should say exactly what changed relative to -the last save checkpoint or durable Echo frontier. - -The user should be able to save as checkpoint, compare current to last save, -inspect unsaved causal events, and understand whether save wrote to disk, -created a checkpoint, or both. - -Design doc to write: `save-checkpoints-and-dirty-truth`. - -### 4. Causal Panes And Optic Views - -Most split panes are layout mechanics, not semantic views. `jedit` should model -panes as Optics over causal subjects: - -- same file, different viewport -- same file, earlier checkpoint -- definition peek -- proposal preview -- test output tied to a coordinate - -Design doc to write: `causal-panes-and-optic-views`. - -### 5. Causal Anchors In The Editor - -Cursors, selections, diagnostics, search hits, and AI target ranges drift when -text changes. `jedit` should model them as anchors with lawful transform -behavior. - -Design doc to write: `causal-anchors-editor-integration`. - -### 6. Causal Search And Replace - -Replace-all often applies to a stale or poorly understood basis. `jedit` should -make search results coordinate-aware and replace operations previewable as -causal edit groups. - -Design doc to write: `causal-search-and-replace`. - -### 7. Causal Diagnostics And Tasks - -Diagnostics and test output age quickly while the editor keeps moving. `jedit` -should carry the coordinate that produced each result and show stale posture -calmly. - -Design doc to write: `causal-diagnostics-and-tasks`. - -## Recommended First Design Docs - -The first three documents should be: - -1. `causal-undo-and-time-rail` -2. `suggestion-as-proposal-strand` -3. `causal-panes-and-optic-views` - -They define the clearest product differences: - -- time is inspectable -- suggestions are governed -- panes are causal views, not layout clutter - -## v1 User Story - -A user opens `jedit` in a repository. - -The screen is quiet. The file drawer may be visible, but the editor owns the -center. The footer shows the mode, the focused region, and only the controls -that work now. - -The user opens a large file. The editor paints visible text quickly because the -normal read path is a bounded window, not a full-file demand. The file remains -a causal object underneath, but the user does not have to think about that to -type. - -They edit. Typing feels ordinary. Underneath, meaningful changes become ticks -and edit groups. The footer can acknowledge important events without becoming -a log. - -They search. Search opens as a lens. Matches are navigable. Replace shows what -will change before it commits. - -They peek a definition. A temporary pane opens with the target. They can pin -it, jump to it, or dismiss it. - -They receive a suggestion. A small completion may appear near the cursor. A -larger AI or refactor suggestion appears as a proposal with scope, basis, and -actions. It does not silently rewrite the file. - -They see diagnostics. The editor marks them quietly. The drawer explains them -when asked. If the file changes after diagnostics were produced, `jedit` knows -they are stale. - -They save. Save records a checkpoint. The editor can explain what is ahead of -that checkpoint and what has been written to disk. - -They undo. Undo steps through meaningful events. Later, the time rail can show -the sequence, preview earlier coordinates, and unapply targeted ticks. - -They leave and return. The editor remembers useful working context, but the -first feeling is still quiet text and honest controls. - -## v1 Feature Bar - -v1 should support: - -- calm terminal-native editor shell -- file drawer and fast file switching -- large-file-friendly read path -- normal editing with keyboard-first ergonomics -- contextual footer and help -- search and replace lens -- basic diagnostics drawer -- definition peek or pinned pane model -- save checkpoint and dirty-state semantics -- grouped undo foundation -- proposal UX for larger suggestions -- Graft-backed structure where available -- graceful absence where structure is unavailable - -v1 may defer: - -- full multi-user collaboration -- full visual time rail -- complete braid UI -- full AI assistant chat -- complete settings surface -- full macro recorder -- rich Git workbench - -## Acceptance Bar - -This direction is working when: - -- the editor feels calmer after features are added, not busier -- every visible hint works for the active layer -- the user can recover from search, drawers, proposals, and panes with clear - dismiss behavior -- suggestions and AI edits are reviewable before broad mutation -- save, dirty state, and undo can be explained in causal terms -- large files do not force eager full-file thinking into the main interaction -- docs, tests, and UI vocabulary use the same product nouns - -## Non-Goals - -- Designing the final Echo API. -- Replacing the Optic-backed file model packet. -- Specifying exact keybindings for every feature. -- Turning the v1 story into a marketing page. -- Making every advanced causal feature mandatory for v1. diff --git a/docs/design/0008-fake-echo-causal-ux-demo/fake-echo-causal-ux-demo.md b/docs/design/0008-fake-echo-causal-ux-demo/fake-echo-causal-ux-demo.md deleted file mode 100644 index 8b123410..00000000 --- a/docs/design/0008-fake-echo-causal-ux-demo/fake-echo-causal-ux-demo.md +++ /dev/null @@ -1,756 +0,0 @@ ---- -title: "fake-echo-causal-ux-demo" -legend: "none" -cycle: "0008-fake-echo-causal-ux-demo" -source_backlog: "conversation: fake-echo-causal-ux-demo" ---- - -# fake-echo-causal-ux-demo - -Source backlog item: `conversation: fake-echo-causal-ux-demo` -Legend: none - -## Purpose - -Define the first fake Echo demo that lets `jedit` test causal editor UX before -the real Echo Optic API is ready. - -This packet is not a shortcut around Echo. It is a way to make the app boundary -honest early, so the human can judge the editor's feel while the runtime -substrate catches up. - -The demo should let us test: - -- bounded source reading -- Intent-shaped editing -- receipt and obstruction posture -- save as checkpoint -- proposal as strand -- causal panes as Optic views -- calm footer and drawer behavior around causal state - -The goal is a usable feedback loop, not a polished feature checklist. - -## Design Lineage - -This packet continues the direction set by: - -- [optic-backed-file-model](../0006-optic-backed-file-model/optic-backed-file-model.md) -- [jedit-v1-experience](../0007-jedit-v1-experience/jedit-v1-experience.md) -- [runtime-temperatures](../runtime-temperatures.md) - -It also inherits Bijou standards already adopted in the v1 packet: - -- focus owns input -- visible controls are a promise -- density requires rhythm -- the shell is a product -- AI surfaces must explain -- docs are a proving surface - -The design stance is calm and strict: - -- the central editor stays quiet -- causal truth stays inspectable -- advanced state appears only where it helps the user's next decision -- fake runtime machinery does not leak into the product surface - -## One Sentence - -Build a fake Echo causal editing demo that is fake underneath but Echo-shaped at -the `jedit` boundary. - -## Hill - -At the end of this cycle, a user should be able to run `jedit`, open a file, -edit it, checkpoint it, receive a proposed edit, preview the proposal in a -causal view, and accept or reject it while every file mutation routes through -an Intent-shaped fake Echo transport. - -The demo is successful when the human can give product feedback on the feel of -the causal editor, not only on the implementation architecture. - -## Playback Questions - -### Human - -- [ ] Does the editor still feel zen by default? -- [ ] Does causal state clarify without turning into a debug console? -- [ ] Does the footer say enough about checkpoint and obstruction posture? -- [ ] Does a proposal feel like a governed change instead of a hidden edit? -- [ ] Does previewing a proposal or checkpoint feel spatially stable? -- [ ] Does the user know what owns input in every demo state? -- [ ] Does dismissing a pane, drawer, proposal, or notice feel predictable? - -### Agent - -- [ ] The app-facing demo path talks to a fake Echo transport, not to a direct - mutable text runtime. -- [ ] Reads are bounded readings with basis and budget. -- [ ] Writes are Intent submissions with base coordinates. -- [ ] Accepted writes advance from receipts and follow-up readings. -- [ ] Stale writes return obstructions with a calm user-facing path. -- [ ] Save produces checkpoint posture, not Git authority. -- [ ] Proposal preview and admission use strand-like vocabulary. -- [ ] UI tests can exercise the path without needing the real Echo repo. - -## Current Starting Point - -`jedit` already has three important pieces: - -- a calm terminal editor shell -- a large-file fix that removed the old eager-load cap -- a GraphQL-shaped `jedit` Optic client seam - -That is enough to begin the demo, but not enough to prove the future model. - -The current risk is that we make the editor nicer while leaving the authority -model local and string-shaped. That would make the later Echo cutover harder. - -The design pass should pull the opposite way: - -```text -real jedit UI - -> real app ports - -> TextFileOptic client - -> EchoWasmKernelTransport-shaped adapter - -> fake Echo jedit contract host - -> temporary in-memory causal text runtime -``` - -Only the last box is fake. The app boundary should already feel like Echo. - -## Core Decision - -The demo should be fake in implementation and real in architecture. - -Fake means: - -- the contract host may live inside `jedit` -- the host may materialize full text internally when needed -- ticks, coordinates, strands, and checkpoints may use simple local identity -- persistence may be session-only -- no real Wesley compilation is required for the first pass - -Real means: - -- the editor does not mutate canonical text directly -- every user-facing file write is an Intent-shaped submission -- every source paint uses a reading-shaped result -- every result carries basis, receipt, obstruction, or checkpoint posture -- every proposal is modeled as a strand-like candidate, not as a hidden patch -- decoding happens at the adapter boundary -- the future real Echo adapter can replace the fake without redesigning the UI - -## Demo Honesty Rules - -### 1. The UI Does Not Know The Runtime Is Fake - -The UI should not branch on fake runtime details. It should know about product -objects: - -- open file -- text window reading -- cursor -- viewport -- receipt -- obstruction -- checkpoint -- proposal -- pane - -The fake host can cheat internally. The editor cannot. - -### 2. Reads Are Observations - -A source read is not "give me the file string." - -It is: - -```text -observe this optic, from this basis, with this cursor, viewport, and budget -``` - -The normal paint path should consume a `TextWindowReading`. - -### 3. Writes Are Intents - -Typing, paste, delete, replace, checkpoint, proposal acceptance, and targeted -unapply all enter the file model as Intents. - -The demo may group many keystrokes into one edit event for feel. It must not -turn that group into a direct setter. - -### 4. Receipts Drive Confidence - -The editor should advance its causal posture from receipts, not from optimism. - -After an edit: - -```text -Intent submitted - -> receipt accepted - -> reading refreshed - -> footer posture updates -``` - -If the basis is stale: - -```text -Intent submitted - -> obstruction returned - -> editor keeps current reading - -> footer gives one calm recovery path -``` - -### 5. Git Is Not In The Demo Spine - -Git may appear later as export or ecosystem context. It should not define save, -dirty state, undo, proposal state, or history in this demo. - -The demo spine is Echo-shaped: - -```text -edit = tick or edit group -save = checkpoint -proposal = strand -comparison = reading over two coordinates -acceptance = admission -file = projection -Git commit = export, outside this spine -``` - -## First Demo Spine - -The first demo should prove this path: - -```text -Open - -> Read Window - -> Edit - -> Receipt - -> Checkpoint - -> Proposal - -> Preview - -> Accept -``` - -This is intentionally narrow. It covers the product concepts that need human -feedback while avoiding a broad feature sweep. - -### Open - -Opening a file creates a `TextFileOptic` focus. - -The UI should receive: - -- file identity -- optic identity -- coordinate or named frontier -- capability posture - -The first screen should still feel like opening an ordinary editor. - -### Read Window - -The editor asks for visible lines plus a small margin. - -The reading should include: - -- basis coordinate -- start line -- line count -- total line count -- line text -- line spans -- before and after continuation flags - -Large files should feel normal in this path. - -### Edit - -A typed burst or paste becomes an Intent with a base coordinate. - -For the demo, it is acceptable to coalesce typing into humane edit groups. The -grouping should serve undo and explanation, not runtime convenience alone. - -### Receipt - -The host returns an accepted receipt or obstruction. - -The happy path should feel invisible. The footer may briefly acknowledge the -accepted edit group, then return to ordinary mode and checkpoint posture. - -### Checkpoint - -Save creates a checkpoint and may materialize the filesystem projection. - -The user-facing posture should be: - -```text -saved at checkpoint C12 -ahead by 0 edits -``` - -After a later edit: - -```text -checkpoint C12 -ahead by 1 edit -``` - -The footer must not imply Git authority. - -### Proposal - -A larger suggestion appears as a proposal strand. - -The first version can be local and deterministic: - -- wrap selected text -- rename a repeated local token in a small fixture -- apply a formatting-like text transform -- insert a short suggested block - -The proposal should have: - -- basis coordinate -- affected range -- summary -- preview reading -- accept action -- reject action - -### Preview - -Preview should use a causal pane, not a permanent IDE split. - -Good first previews: - -- current vs proposal -- current vs checkpoint -- affected range only - -The preview pane owns input while focused. The footer changes with it. - -### Accept - -Accepting a proposal submits an admission Intent. - -The editor should advance from the resulting receipt and reading. - -Rejecting a proposal should dismiss it without mutating the file. - -## UX Surface Model - -### Main Editor - -The editor remains the default surface. - -It shows: - -- text -- cursor -- selection -- optional quiet markers -- no permanent causal log - -Causal data should not occupy the main text area unless it is directly tied to -the region being edited. - -### Footer - -The footer carries operational truth. - -It can show: - -- mode -- focused region -- checkpoint posture -- short receipt or obstruction status -- one or two working controls - -It should avoid: - -- tick spam -- long coordinate strings -- Git-shaped dirty language -- controls for covered or inactive panes - -### Notice - -Use a short notice for transient receipt or obstruction feedback. - -Examples: - -```text -Edit accepted -Checkpoint C12 -Edit obstructed: file changed since this reading -``` - -The notice should not become an activity stream in the first demo. - -### Proposal Surface - -The proposal surface should be compact. - -It should answer: - -- what will change? -- where? -- from what basis? -- what are the choices? - -It should not read like an AI chat transcript. - -### Causal Pane - -A causal pane is an Optic view with a subject and basis. - -First subjects: - -- proposal preview -- checkpoint comparison -- same file, different viewport - -The pane is useful when it gives the user a decision surface. It is not a -layout decoration. - -### Drawer - -The drawer is for inspection, not for proving the demo exists. - -It may show: - -- proposal details -- checkpoint events -- obstruction explanation -- coordinate details when explicitly requested - -The default demo should not open with the drawer. - -## GraphQL-Shaped Demo Contract - -The fake does not need final Echo bytes yet, but it should be shaped like the -future Wesley-authored contract. - -### Query A Text Window - -```graphql -query TextWindow($input: TextWindowInput!) { - textWindow(input: $input) { - opticId - readingId - coordinate { - worldlineId - strandId - braidId - tickId - } - startLine - lineCount - totalLineCount - hasMoreBefore - hasMoreAfter - lines { - lineNumber - text - startByte - endByte - } - } -} -``` - -### Submit A Text Edit Intent - -```graphql -mutation ReplaceTextRange($input: ReplaceTextRangeIntentInput!) { - replaceTextRange(input: $input) { - outcome - receipt { - tickId - coordinate { - worldlineId - strandId - braidId - tickId - } - editGroupId - summary - } - obstruction { - reason - basisCoordinate { - worldlineId - tickId - } - currentCoordinate { - worldlineId - tickId - } - recovery - } - } -} -``` - -### Create A Checkpoint - -```graphql -mutation CreateCheckpoint($input: CreateCheckpointIntentInput!) { - createCheckpoint(input: $input) { - outcome - checkpoint { - checkpointId - coordinate { - worldlineId - braidId - tickId - } - label - } - receipt { - tickId - summary - } - } -} -``` - -### Create And Preview A Proposal - -```graphql -mutation CreateTextProposal($input: CreateTextProposalIntentInput!) { - createTextProposal(input: $input) { - outcome - proposal { - proposalId - basisCoordinate { - worldlineId - tickId - } - proposalCoordinate { - worldlineId - strandId - tickId - } - affectedRange { - startByte - endByte - } - summary - } - } -} - -query ProposalPreview($input: ProposalPreviewInput!) { - proposalPreview(input: $input) { - proposalId - basisReadingId - previewReadingId - diffReadingId - affectedStartLine - affectedLineCount - } -} -``` - -### Admit A Proposal - -```graphql -mutation AdmitProposal($input: AdmitProposalIntentInput!) { - admitProposal(input: $input) { - outcome - receipt { - tickId - coordinate { - worldlineId - braidId - tickId - } - summary - } - obstruction { - reason - recovery - } - } -} -``` - -These examples are planning targets. The fake host can implement only the -fields required by the first demo, but the names should keep the future shape -visible. - -## Demo Scenarios - -### Scenario 1: Large File Opens Calmly - -The user opens a large file. - -Expected feel: - -- first paint is quick -- scrolling requests more windows -- the footer remains ordinary -- there is no "loading whole file" anxiety - -Implementation proof: - -- the public read result is bounded -- tests assert that source paint does not need a full-file string - -### Scenario 2: Edit Accepted - -The user types into the file. - -Expected feel: - -- typing feels normal -- footer does not chatter for every keystroke -- after a grouped event, checkpoint posture updates - -Implementation proof: - -- edit submits an Intent with a base coordinate -- receipt advances editor posture -- follow-up reading paints the changed window - -### Scenario 3: Stale Edit Obstructed - -The fake host advances a file behind the current reading. - -The user submits an edit against the old basis. - -Expected feel: - -- the edit is not silently lost -- the editor explains the obstruction in one calm line -- the user has a clear recovery path - -Implementation proof: - -- stale basis returns an obstruction -- UI keeps its current reading until a recovery action refreshes or reapplies - -### Scenario 4: Save Creates Checkpoint - -The user saves. - -Expected feel: - -- save feels familiar -- the footer says checkpoint truth -- disk write is a projection detail, not the whole story - -Implementation proof: - -- save submits checkpoint Intent -- checkpoint identity is returned -- dirty posture compares current coordinate to checkpoint coordinate - -### Scenario 5: Proposal As Strand - -The user asks for or receives a larger suggestion. - -Expected feel: - -- the text is not rewritten without consent -- proposal scope is obvious -- preview is focused -- accept and reject are both cheap - -Implementation proof: - -- proposal has a basis coordinate -- proposal preview is a reading -- accept submits an admission Intent -- reject only dismisses the proposal - -### Scenario 6: Causal Pane - -The user previews current vs checkpoint or current vs proposal. - -Expected feel: - -- the pane appears only when useful -- focus ownership is obvious -- dismissing returns to the editor cleanly - -Implementation proof: - -- pane content is an Optic reading -- footer hints change while the pane owns input -- no inactive pane advertises controls - -## Build Sequence - -1. Fake Echo Optic transport harness -2. Bounded text-window reader -3. Intent-only editor mutation routing -4. Fake causal demo spine -5. Checkpoint footer posture -6. Proposal strand demo -7. Causal Optic pane demo - -This sequence keeps the implementation honest. The early tasks prove the -boundary. The later tasks create the surfaces the human can judge. - -## Backlog Cut - -Existing foundation cards: - -- [fake-echo-optic-transport-harness](../../method/backlog/asap/fake-echo-optic-transport-harness.md) -- [bounded-text-window-optic-reader](../../method/backlog/asap/bounded-text-window-optic-reader.md) -- [intent-only-editor-mutation-routing](../../method/backlog/asap/intent-only-editor-mutation-routing.md) -- [inverse-tick-unapply-intents](../../method/backlog/asap/inverse-tick-unapply-intents.md) -- [braid-backed-file-projection-optic](../../method/backlog/asap/braid-backed-file-projection-optic.md) - -New demo cards from this pass: - -- [fake-echo-causal-ux-demo-spine](../../method/backlog/asap/fake-echo-causal-ux-demo-spine.md) -- [checkpoint-footer-posture](../../method/backlog/asap/checkpoint-footer-posture.md) -- [proposal-strand-demo](../../method/backlog/asap/proposal-strand-demo.md) -- [causal-optic-pane-demo](../../method/backlog/asap/causal-optic-pane-demo.md) - -## Human Feedback Targets - -This demo should make it easy to answer product questions: - -- Is the causal footer too quiet, too loud, or just right? -- Should checkpoints appear as labels, counts, or short status text? -- Does obstruction recovery feel helpful or accusatory? -- Does proposal preview need a pane, drawer, inline marker, or palette action? -- How much proposal basis should be visible by default? -- Does accepting a proposal feel like editing or like approving a patch? -- Do causal panes feel like editor power or layout clutter? -- Does the editor preserve the current zen feeling after these features exist? - -The first pass should favor less chrome. If the human asks "where did it go?" -we can reveal more. If the human asks "why is the editor yelling?" we already -added too much. - -## Acceptance Bar - -This design is working when: - -- the demo can be built before real Echo lands -- the app boundary is already Echo-shaped -- the central editor remains calm -- every file mutation in the demo submits an Intent-shaped request -- every visible state has a user-facing reason -- proposal and checkpoint flows can be judged by feel -- the fake can be deleted later without changing the product model -- tests describe the boundary, not fake runtime internals - -## Non-Goals - -- Implementing real Echo persistence. -- Implementing real Wesley compilation inside this repo. -- Designing the full causal time rail. -- Designing complete multi-strand merge UI. -- Making Git part of the demo's source of truth. -- Turning the demo into a debug inspector. -- Solving every large-file caching policy. diff --git a/docs/design/0009-title-floor-material-contrast/title-floor-material-contrast.md b/docs/design/0009-title-floor-material-contrast/title-floor-material-contrast.md deleted file mode 100644 index a25fe516..00000000 --- a/docs/design/0009-title-floor-material-contrast/title-floor-material-contrast.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: "title-floor-material-contrast" -legend: "ui" -cycle: "0009-title-floor-material-contrast" -source_backlog: "conversation: jedit-title-scene-light-theme-checkerboard" ---- - -# title-floor-material-contrast - -Source backlog item: `conversation: jedit-title-scene-light-theme-checkerboard` -Legend: UI - -## Sponsored Users - -- A developer using the title screen while switching between dark and light - editor themes. -- A future agent adjusting title-scene materials without accidentally making - semantic theme tokens stand in for physical scene materials. - -## Hills - -1. A user can switch between built-in light and dark themes and still read the - title floor as the same checkerboard, with dark tiles darker than light - tiles. -2. A maintainer can explain that the checker floor uses theme-derived material - colors, not hard-coded post-processing and not raw semantic token order. -3. An agent can add future lighting effects without reintroducing the light - theme inversion. - -## Playback Questions - -1. For every built-in theme, does the title scene expose a floor-light material - whose luminance is greater than its floor-dark material? -2. Does the rendered scene still use the theme's source/accent colors for - spheres and logo materials? -3. Does the floor remain part of the shader/material model instead of a - post-render color rewrite? - -## Requirements - -- Add a title-scene material palette seam that names floor dark/light colors. -- Derive floor dark/light ordering by luminance from the theme's title-scene - near/far tokens. -- Keep theme token lookups symbol-based. -- Do not add `setRGB()` or surface post-processing loops. -- Keep sphere and logo material color lookup behavior unchanged. - -## Acceptance Criteria - -- RED test proves the title scene material palette is missing or does not - guarantee floor-light luminance greater than floor-dark luminance. -- GREEN test proves all built-in themes maintain the floor contrast contract. -- `npm run build` passes. -- `npm run test -- spec/title-screen.spec.mjs` passes. -- `npm run quality` passes. -- `git diff --check` passes. - -## Accessibility / Assistive Reading Posture - -The checkerboard is decorative spatial context. This cycle improves visual -consistency but does not make the floor carry editor information. - -## Localization / Directionality Posture - -No localized text or directional layout is affected. - -## Agent Inspectability / Explainability Posture - -The palette seam should let agents answer the user's question directly: yes, -the inversion came from theme semantics, and the fix is to derive explicit -floor material roles before lighting. - -## Implementation Outline - -1. Add a failing title-screen spec for floor material luminance ordering across - built-in themes. -2. Export a small title-scene material palette function from - `src/ui/title-screen.ts`. -3. Use the ordered floor material colors in floor shading and floor - reflections. -4. Record drift, playback, and retrospective in this design packet. - -## Tests To Write First - -- `title scene keeps checker floor material contrast stable across built-in themes` - -## Drift Check - -- RED observed: - `npm run test -- spec/title-screen.spec.mjs` failed because - `titleSceneMaterialColors` did not exist. -- GREEN observed: - `node --test spec/title-screen.spec.mjs` passed with 6 tests. -- Full suite observed: - `npm run test` passed with 112 tests. -- Build observed: - `npm run build` passed. -- Quality observed: - `npm run quality` passed with no regressions. -- Whitespace drift: - `git diff --check` passed. - -## Playback - -1. The title-screen spec now checks every built-in theme and asserts - `floorLight` has greater luminance than `floorDark`. -2. The palette seam answers the diagnosis directly: the old behavior came from - using semantic theme token order as physical checker material order. -3. Floor shading now uses explicit dark/light material colors for both - checker parities, and reflections sample the same material roles. - -## Retrospective - -The light theme did not need a post-render color correction. The scene needed -material roles that survive theme polarity changes. Sorting the title-scene -near/far colors by luminance keeps the shader theme-native while making the -checkerboard's dark/light meaning stable. diff --git a/docs/design/0010-title-scene-shadows-caustics/title-scene-shadows-caustics.md b/docs/design/0010-title-scene-shadows-caustics/title-scene-shadows-caustics.md deleted file mode 100644 index faab86c7..00000000 --- a/docs/design/0010-title-scene-shadows-caustics/title-scene-shadows-caustics.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: "title-scene-shadows-caustics" -legend: "ui" -cycle: "0010-title-scene-shadows-caustics" -source_backlog: "conversation: jedit-title-scene-caustics-and-shadows" ---- - -# title-scene-shadows-caustics - -Source backlog item: `conversation: jedit-title-scene-caustics-and-shadows` -Legend: UI - -## Sponsored Users - -- A developer seeing the jedit title scene as the editor's first visual tone. -- A future agent adding title-scene lighting without returning to broad - post-render color hacks. - -## Hills - -1. A user can see floor shadows and subtle caustic-style highlights as part of - the raytraced scene, not as a color remap after rendering. -2. A maintainer can test floor light effects as numeric material facts before - they become terminal cells. -3. An agent can tune future scene effects through named helpers and constants - instead of hidden shader branches. - -## Playback Questions - -1. Does a floor point under a sphere report reduced key-light visibility? -2. Does a floor point near a reflective sphere report nonzero caustic strength? -3. Does a far floor point stay unshadowed and free of caustics? -4. Does the rendered title scene still pass the existing material color, - reflection, and deterministic rendering specs? - -## Requirements - -- Add a pure floor-light-effect helper that returns shadow and caustic facts. -- Shadowing must come from scene geometry and the key light direction. -- Caustics must be bounded and based on reflective sphere proximity. -- Apply the effects inside the shader material color path. -- Do not add post-render `setRGB()` loops or hard theme-color remapping. - -## Acceptance Criteria - -- RED test proves the floor-light-effect helper is missing. -- GREEN test proves shadow, caustic, and far-field behavior. -- `node --test spec/title-screen.spec.mjs` passes. -- `npm run build` passes. -- `npm run test` passes. -- `npm run quality` passes. -- `git diff --check` passes. - -## Accessibility / Assistive Reading Posture - -The effects are decorative and must not carry editor state. They should remain -subtle enough not to reduce title logo legibility. - -## Localization / Directionality Posture - -No localized text or directional layout is affected. - -## Agent Inspectability / Explainability Posture - -The effect helper should make the shader explainable: a floor sample first -gets theme-derived material color, then a shadow multiplier and caustic -strength, then lighting composition. - -## Implementation Outline - -1. Add a failing title-screen spec for floor light effects. -2. Export a small floor-light-effect helper from `src/ui/title-screen.ts`. -3. Apply shadow and caustic effects to floor material shading and reflected - floor color. -4. Record drift, playback, and retrospective in this design packet. - -## Tests To Write First - -- `title floor light effects expose sphere shadows and caustics` - -## Drift Check - -- RED observed: - `node --test spec/title-screen.spec.mjs` failed because - `titleFloorLightEffectsAt` did not exist. -- GREEN observed: - `node --test spec/title-screen.spec.mjs` passed with 7 tests. -- Full suite observed: - `npm run test` passed with 113 tests. -- Build observed: - `npm run build` passed. -- Quality observed: - `npm run quality` passed with no regressions. -- Whitespace drift: - `git diff --check` passed. - -## Playback - -1. `title floor light effects expose sphere shadows and caustics` proves a - floor point under a sphere has reduced key-light visibility. -2. The same spec proves a nearby reflective sphere contributes nonzero caustic - strength. -3. The far-field assertion proves distant floor points stay unshadowed and - free of caustics. -4. Existing title-screen specs still pass for material colors, reflections, - floor contrast, and deterministic rendering. - -## Retrospective - -The useful boundary was a small numeric effect helper rather than another -rendering mode. The shader now composes material color, shadow multiplier, and -caustic strength before the Braille cell is produced, which keeps the effect in -the raytraced scene instead of pushing it into terminal post-processing. diff --git a/docs/design/0011-title-logo-cell-overlay/title-logo-cell-overlay.md b/docs/design/0011-title-logo-cell-overlay/title-logo-cell-overlay.md deleted file mode 100644 index dd3b464c..00000000 --- a/docs/design/0011-title-logo-cell-overlay/title-logo-cell-overlay.md +++ /dev/null @@ -1,121 +0,0 @@ ---- -title: "title-logo-cell-overlay" -legend: "ui" -cycle: "0011-title-logo-cell-overlay" -source_backlog: "conversation: jedit-title-logo-smaller-non-braille" ---- - -# title-logo-cell-overlay - -Source backlog item: `conversation: jedit-title-logo-smaller-non-braille` -Legend: UI - -## Sponsored Users - -- A developer evaluating the title screen's visual balance on first launch. -- A future agent adjusting logo placement without coupling logo rendering to - the raytraced scene shader. - -## Hills - -1. A user sees the jedit logo at roughly 40% of its previous width, centered - horizontally and visually anchored around the lower two-thirds of the title - screen. -2. A user sees the logo rendered with solid and fading hatch glyphs, not - Braille cells. -3. A maintainer can explain that the logo is an intentional cell-resolution - overlay above the raytraced background, not a post-render color repair pass. - -## Playback Questions - -1. Does the title logo bounds helper center the logo horizontally? -2. Does the title logo bounds helper place the logo center near two-thirds of - the available height? -3. Are bold logo cells non-Braille glyphs? -4. Does the logo retain themed gradient material color? - -## Requirements - -- Render the raytraced scene independently from the logo. -- Paint the logo as a cell-resolution overlay using solid/hatch glyphs. -- Use coverage sampling from the existing logo mask to choose glyph density. -- Keep the logo themed through the existing title logo/source colors. -- Do not add color post-processing loops. - -## Acceptance Criteria - -- RED tests prove the current logo is still Braille and the cell-bounds helper - is missing. -- GREEN tests prove non-Braille logo glyphs and lower-two-thirds placement. -- `node --test spec/title-screen.spec.mjs` passes. -- `npm run build` passes. -- `npm run test` passes. -- `npm run quality` passes. -- `git diff --check` passes. - -## Accessibility / Assistive Reading Posture - -The title logo remains decorative. The first interactive editor screen still -needs usable controls without relying on the logo's shape. - -## Localization / Directionality Posture - -No localized text or directional layout is affected. - -## Agent Inspectability / Explainability Posture - -The bounds helper and glyph chooser should make the logo experiment easy to -audit: placement is a named ratio, and glyph choice follows mask coverage. - -## Implementation Outline - -1. Add failing specs for logo bounds and non-Braille logo glyphs. -2. Render the scene without the logo inside the Braille shader. -3. Paint the logo overlay at cell resolution from sampled mask coverage. -4. Record drift, playback, and retrospective in this design packet. - -## Tests To Write First - -- `title logo bounds center the smaller logo in the lower two thirds` -- `title screen renders the logo as a non-Braille themed glyph layer` - -## Drift Check - -RED drift matched the design: the pre-change title surface still marked logo -cells as bold Braille glyphs, and no cell-bounds helper existed for direct -placement assertions. - -Implementation drift is intentional and bounded: - -- The logo is now painted after the raytraced Braille scene, but this is a - decorative content layer rather than a color correction pass. -- The overlay uses `surface.set` for the logo cells only, so it does not - mutate raytraced colors after rendering. -- The logo scale is expressed as 40% of the previous 80% width ratio, yielding - a 32% screen-width target. - -## Playback - -Playback answers: - -1. The exported bounds helper centers the logo horizontally within one cell. -2. The bounds helper places the logo center near two-thirds of the available - height, clamping only when the screen is too short. -3. Bold logo cells render with solid and hatch glyphs instead of Braille. -4. Logo foreground color still uses the existing accent-to-info title gradient, - while the raytraced background keeps natural lighting and material colors. - -Validation: - -- `node --test spec/title-screen.spec.mjs` passed. -- `npm run build` passed. -- `npm run quality` passed with no regressions. -- `npm run test` passed 114 tests. -- `git diff --check` passed. - -## Retrospective - -This split made the logo easier to reason about. The raytraced scene owns -material lighting, reflection, shadow, and Braille resampling; the logo owns -cell placement and mask coverage. That separation should also make it easier to -remove or revise the experiment later without disturbing the shader path. diff --git a/docs/design/0012-title-camera-spring-controls/title-camera-spring-controls.md b/docs/design/0012-title-camera-spring-controls/title-camera-spring-controls.md deleted file mode 100644 index b175f62f..00000000 --- a/docs/design/0012-title-camera-spring-controls/title-camera-spring-controls.md +++ /dev/null @@ -1,138 +0,0 @@ ---- -title: "title-camera-spring-controls" -legend: "ui" -cycle: "0012-title-camera-spring-controls" -source_backlog: "conversation: jedit-title-camera-bijou-springs" ---- - -# title-camera-spring-controls - -Source backlog item: `conversation: jedit-title-camera-bijou-springs` -Legend: UI - -## Sponsored Users - -- A developer on the title screen using arrow keys to inspect the raytraced - scene. -- A future maintainer tuning title-screen motion without editing the full app - reducer. -- A future agent verifying that jedit consumes Bijou v5 motion primitives for - real UI behavior, not only theme metadata. - -## Hills - -1. A user presses left or right on the title screen and the camera eases toward - the new orbit angle instead of stepping instantly. -2. A user presses up or down on the title screen and the camera radius eases - toward the new zoom distance, keeping the existing minimum radius. -3. A maintainer can inspect a small title-camera session module and see that - Bijou spring animation commands, critically damped physics, and stale-frame - guards drive the camera. - -## Playback Questions - -1. Does an arrow-key camera update change the target immediately while leaving - the visible angle/radius to be animated by spring frames? -2. Does the spring config use critical damping for its stiffness and mass? -3. Does a stale spring frame from an older key press fail to overwrite the - newest camera motion? -4. Does the main reducer render the title screen from the animated camera - value rather than the target value? - -## Requirements - -- Use Bijou's exported animation/spring facilities for title camera motion. -- Preserve existing left/right angle and up/down radius deltas. -- Preserve the minimum camera radius. -- Keep repeated arrow presses target-relative so input remains responsive while - an earlier animation is still in flight. -- Ignore stale animation frames by motion id. -- Keep title camera behavior outside the large main reducer where practical. - -## Acceptance Criteria - -- RED tests fail because no title-camera spring session exists and the main - reducer still steps camera values immediately. -- GREEN tests prove target-relative arrow updates, critical damping, stale-frame - guards, and non-terminal spring frame values. -- `node --test spec/title-camera-session.spec.mjs` passes. -- `npm run build` passes. -- `npm run test` passes. -- `npm run quality` passes. -- `git diff --check` passes. - -## Accessibility / Assistive Reading Posture - -The arrow keys remain the same. Motion is decorative and should not hide editor -functionality because it only runs before a file is open. - -## Localization / Directionality Posture - -No text or localized layout is affected. - -## Agent Inspectability / Explainability Posture - -Camera motion should have named constants for deltas, spring physics, axis -tags, and message tags. Tests should cover the reducer seam directly so a -future agent can tune the motion without launching the app. - -## Implementation Outline - -1. Add a failing title-camera session spec. -2. Implement a small app-level camera session using Bijou `animate` with a - critically damped spring config. -3. Wire `src/main.ts` to store animated camera state, delegate title-screen - arrow keys, and apply spring frame messages. -4. Record drift, playback, and retrospective in this design packet. - -## Tests To Write First - -- `title camera arrow keys move targets through spring commands` -- `title camera spring config is critically damped` -- `title camera ignores stale spring frames` -- `title camera spring command emits interpolated frames before target` - -## Drift Check - -RED drift matched the design: the session module did not exist, so the focused -spec failed before any app wiring could claim spring-driven camera behavior. - -Implementation drift is limited to the app shell boundary: - -- The main reducer keeps the same title-screen-only arrow-key affordance but - delegates the target math and spring command creation to - `src/app/title-camera-session.ts`. -- `src/main.ts` stores a single `titleCamera` object instead of separate - `camAngle` and `camRadius` fields. -- Existing `renderTitleScreen` still receives plain numeric angle and radius - values, so the raytracer stays independent of Bijou command scheduling. - -## Playback - -Playback answers: - -1. Arrow-key updates change `angleTarget`/`radiusTarget` immediately while the - visible `angle`/`radius` wait for spring frame messages. -2. `TITLE_CAMERA_SPRING` sets damping to - `2 * sqrt(stiffness * mass)`, so the configured motion is critically - damped. -3. `reduceTitleCameraMotion` ignores stale frame messages whose motion id no - longer matches the active axis. -4. `renderViewer` passes `model.titleCamera.angle` and - `model.titleCamera.radius` into `renderTitleScreen`, leaving targets as - reducer state rather than render inputs. - -Validation: - -- `node --test spec/title-camera-session.spec.mjs` passed. -- `npm run build` passed. -- `npm run quality` passed with no regressions. -- `npm run test` passed 118 tests. -- `git diff --check` passed. - -## Retrospective - -The app already used Bijou `animate` for the clock, so the right fix was not a -custom easing loop. Pulling the title camera into a small session module made -the behavior testable without importing the top-level app, and motion ids avoid -the common overlapping-animation bug when users press arrows repeatedly. diff --git a/docs/design/0013-editor-inspired-themes/editor-inspired-themes.md b/docs/design/0013-editor-inspired-themes/editor-inspired-themes.md deleted file mode 100644 index 630abdb5..00000000 --- a/docs/design/0013-editor-inspired-themes/editor-inspired-themes.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: "editor-inspired-themes" -legend: "ui" -cycle: "0013-editor-inspired-themes" -source_backlog: "conversation: jedit-more-custom-themes" ---- - -# editor-inspired-themes - -Source backlog item: `conversation: jedit-more-custom-themes` -Legend: UI - -## Sponsored Users - -- A developer who wants jedit to feel familiar when cycling themes. -- A user evaluating whether title-screen materials, source tokens, markdown, - drawers, and cursor styles remain coherent across very different palettes. -- A future theme author looking for more examples than one dark and one light - theme. - -## Hills - -1. A user can cycle through several built-in themes inspired by familiar editor - palettes, not only the existing graphite and morning themes. -2. A user sees each added theme use the full jedit theme token system so source, - markdown, chrome, title-scene, and surface tokens remain complete. -3. A maintainer can add future palettes without duplicating variable binding - boilerplate for every theme. - -## Playback Questions - -1. Do built-in theme names include editor-inspired dark and light options? -2. Does every built-in theme still expose the canonical variable names needed - by existing token assertions? -3. Are the added palettes distinct enough that cycling themes is visually - meaningful? -4. Does the implementation keep a single token application path? - -## Requirements - -- Add multiple built-in themes inspired by well-known editor themes. -- Keep existing `graphite` and `morning` themes and their order. -- Use the current `defineJeditTheme`/`applyThemeTokens` pipeline. -- Keep canonical variables: ink, muted, accent, info, warning, success, surface, - surface.raised, and surface.muted. -- Do not add a separate theme runtime or ad hoc rendering branch. - -## Acceptance Criteria - -- RED tests fail because the new built-in theme names are missing. -- GREEN tests prove the added names exist, built-ins have unique names, each - theme exposes canonical variables, and added surface palettes are distinct. -- `node --test spec/theme-switch.spec.mjs` passes. -- `npm run build` passes. -- `npm run test` passes. -- `npm run quality` passes. -- `git diff --check` passes. - -## Accessibility / Assistive Reading Posture - -The themes should preserve foreground/background pairs for workspace, drawer, -footer, source, markdown, title scene, and cursor tokens. Contrast auditing is -out of scope for this cycle but should be easier with more representative -palettes. - -## Localization / Directionality Posture - -Theme names are stable ASCII identifiers and do not affect localized content or -directional layout. - -## Agent Inspectability / Explainability Posture - -Palettes should be declared as data and then adapted once into the theme -builder. Future agents should inspect a small palette list rather than diffing -repeated token-assignment blocks. - -## Implementation Outline - -1. Add failing specs for the desired theme names and palette completeness. -2. Factor the existing theme variable construction into a palette adapter. -3. Add editor-inspired palettes through the existing token application path. -4. Record drift, playback, and retrospective in this design packet. - -## Tests To Write First - -- `built-in jedit themes include editor-inspired palettes` -- `built-in jedit themes keep unique complete palettes` - -## Drift Check - -RED drift matched the design: the existing theme switch spec could prove the -current two-theme system, but the requested editor-inspired names were absent. - -Implementation drift is positive and contained: - -- Existing `graphite` and `morning` themes were preserved in order. -- Theme construction now flows through a palette adapter before the existing - `applyThemeTokens` function, reducing duplication without changing token - semantics. -- The added palettes are inspiration-level jedit palettes rather than a new - runtime theme format. - -## Playback - -Playback answers: - -1. Built-ins now include `monokai`, `solarized-dark`, `solarized-light`, - `dracula`, `nord`, and `catppuccin`. -2. Every built-in theme exposes the canonical variable names required by the - existing token assertions. -3. Workspace surface backgrounds are unique across built-ins, so theme cycling - has visible palette movement. -4. All palettes pass through `definePaletteTheme`, `paletteVariables`, and the - existing `applyThemeTokens` path. - -Validation: - -- `node --test spec/theme-switch.spec.mjs` passed. -- `npm run build` passed. -- `npm run quality` passed with no regressions. -- `npm run test` passed 120 tests. -- `git diff --check` passed. - -## Retrospective - -The key cleanup was factoring variables into palette data before adding more -themes. That kept the feature from becoming a copy-paste block and creates a -natural place for the later generated light/dark companion-theme work. diff --git a/docs/design/0014-light-dark-theme-companions/light-dark-theme-companions.md b/docs/design/0014-light-dark-theme-companions/light-dark-theme-companions.md deleted file mode 100644 index 7fa76cc7..00000000 --- a/docs/design/0014-light-dark-theme-companions/light-dark-theme-companions.md +++ /dev/null @@ -1,140 +0,0 @@ ---- -title: "light-dark-theme-companions" -legend: "ui" -cycle: "0014-light-dark-theme-companions" -source_backlog: "conversation: jedit-generated-and-authored-theme-variants" ---- - -# light-dark-theme-companions - -Source backlog item: `conversation: jedit-generated-and-authored-theme-variants` -Legend: UI - -## Sponsored Users - -- A developer who likes a palette but wants the opposite light/dark mode - without manually choosing a different theme. -- A theme author who wants to provide a carefully tuned light or dark companion - when generated inversion is not good enough. -- A future agent validating that generated companions and authored overrides - use the same runtime theme object shape. - -## Hills - -1. A user can ask jedit for the opposite light/dark companion of the current - theme and receive a usable generated theme when no authored companion exists. -2. A user gets the hand-authored Solarized light/dark pair instead of a - generated approximation when toggling between Solarized modes. -3. A maintainer can inspect the theme metadata and see each theme's mode, - family, companion name, and whether it was authored or generated. - -## Playback Questions - -1. Does an unpaired dark theme produce a generated light companion with a - lighter workspace background? -2. Does toggling a generated companion return to the original theme? -3. Does an authored light/dark companion override the generated fallback? -4. Does the settings drawer expose light/dark mode as a first-class appearance - control? - -## Requirements - -- Add explicit theme mode metadata for light and dark themes. -- Add explicit metadata for authored versus generated variants. -- Generate an opposite palette from any current theme when no authored - companion is registered. -- Allow authored companion themes to override generated companions by name. -- Preserve existing theme cycling and existing built-in theme order. -- Add a settings row that toggles the current theme to its light/dark companion. - -## Acceptance Criteria - -- RED tests fail because theme mode metadata, companion generation, authored - overrides, and the settings row do not exist yet. -- GREEN tests prove generated companions, authored Solarized override behavior, - and settings-row exposure. -- `node --test spec/theme-switch.spec.mjs spec/settings-session.spec.mjs` - passes. -- `npm run build` passes. -- `npm run test` passes. -- `npm run quality` passes. -- `git diff --check` passes. - -## Accessibility / Assistive Reading Posture - -Generated companions should prioritize swapping surface/ink contrast over -preserving exact hue. Full contrast auditing remains future work, but the -feature should keep all canonical style tokens populated. - -## Localization / Directionality Posture - -The mode labels are short UI labels in the settings drawer. No directional -layout behavior changes. - -## Agent Inspectability / Explainability Posture - -Mode, family, variant source, and companion name should be plain theme metadata. -The generated path should be deterministic and testable without launching the -terminal UI. - -## Implementation Outline - -1. Add failing theme-switch specs for generated companions and authored - overrides. -2. Add failing settings-session expectations for a light/dark row. -3. Extend the theme type/builder with mode and variant metadata. -4. Implement generated opposite palette fallback and authored companion lookup. -5. Wire settings activation to `oppositeJeditTheme`. -6. Record drift, playback, and retrospective in this design packet. - -## Tests To Write First - -- `jedit generates opposite light and dark companion themes` -- `authored light and dark variants override generated companions` -- `jedit settings rows expose light dark theme mode` - -## Drift Check - -RED drift matched the design: theme objects had no explicit mode or variant -source metadata, no companion resolver existed, and the settings drawer exposed -only theme cycling rather than mode toggling. - -Implementation drift is bounded: - -- Generated companions are not added to the installed theme cycle. They are - produced on demand by `oppositeJeditTheme`. -- The existing built-in theme order is unchanged. -- Hand-authored override behavior is demonstrated by the Solarized light/dark - pair through companion names on the theme metadata. - -## Playback - -Playback answers: - -1. `graphite` produces a generated `graphite-light` companion with a lighter - workspace background. -2. Toggling that generated companion returns to the original `graphite` theme - through its `companionThemeName`. -3. `solarized-dark` resolves to the authored `solarized-light` theme, and the - reverse path resolves back to `solarized-dark`. -4. The settings drawer now exposes a `Light/dark` choice row and activation - calls the host's mode-toggle handler. - -Validation: - -- `node --test spec/theme-switch.spec.mjs spec/settings-session.spec.mjs` - passed. -- `node --test spec/settings-drawer.spec.mjs spec/theme-switch.spec.mjs - spec/settings-session.spec.mjs` passed. -- `npm run build` passed. -- `npm run quality` passed with no regressions. -- `npm run test` passed 122 tests. -- `git diff --check` passed. - -## Retrospective - -Adding metadata to the theme object was the right substrate for this feature: -renderers still receive the same token maps, while settings and theme selection -can reason about family, mode, variant source, and companion name. Keeping -generated companions out of the installed cycle avoids turning one palette list -into a doubled theme picker. diff --git a/docs/design/0015-randomized-title-scene/title-scene-randomization.md b/docs/design/0015-randomized-title-scene/title-scene-randomization.md deleted file mode 100644 index da8b2467..00000000 --- a/docs/design/0015-randomized-title-scene/title-scene-randomization.md +++ /dev/null @@ -1,136 +0,0 @@ ---- -title: "randomized-title-scene" -legend: "ui" -cycle: "0015-randomized-title-scene" -source_backlog: "conversation: jedit-random-camera-and-non-overlapping-geometry" ---- - -# randomized-title-scene - -Source backlog item: `conversation: jedit-random-camera-and-non-overlapping-geometry` -Legend: UI - -## Sponsored Users - -- A developer returning to the title screen who wants the raytraced scene to - feel alive without flickering between frames. -- A user moving the camera around the title scene and noticing more than the - same three fixed spheres every time. -- A future maintainer validating that procedural scene generation never spawns - overlapping objects. - -## Hills - -1. A user starts jedit and sees the title camera begin from a seeded random - orbit angle and radius instead of a fixed frontal placement. -2. A user sees a deterministic mixed scene with varied material colors, sizes, - spheres, and column-like objects. -3. A maintainer can test the scene generator directly and prove generated - object footprints do not overlap. - -## Playback Questions - -1. Does a fixed scene seed produce the same camera placement and object layout? -2. Do different scene seeds produce different camera placements? -3. Does the scene include multiple shape kinds, sizes, reflectivity values, and - material colors? -4. Are all generated object footprints separated by at least the required - margin? -5. Does the title shader render the generated objects without changing the - post-processing/color philosophy? - -## Requirements - -- Generate title-scene camera placement from a scene seed. -- Generate title-scene objects from a scene seed and current theme material - colors. -- Include at least one sphere and at least one column-like shape. -- Use deterministic seeded pseudo-randomness after startup. -- Reject or avoid overlapping object footprints. -- Preserve interactive arrow-key camera controls after the seeded placement. -- Keep raytraced material colors and lighting natural. - -## Acceptance Criteria - -- RED tests fail because no title scene generator exists and the title camera - always starts from fixed values. -- GREEN tests prove deterministic generation, seed variation, mixed shape - kinds/materials/sizes, and non-overlap. -- `node --test spec/title-scene.spec.mjs spec/title-screen.spec.mjs` passes. -- `npm run build` passes. -- `npm run test` passes. -- `npm run quality` passes. -- `git diff --check` passes. - -## Accessibility / Assistive Reading Posture - -The title scene remains decorative and appears only before editing. Camera -randomization must not alter editor controls or file-opening behavior. - -## Localization / Directionality Posture - -No text or localized layout changes. - -## Agent Inspectability / Explainability Posture - -Scene generation should be isolated in a testable module with named shape tags, -seeded random helpers, and explicit footprint checks. - -## Implementation Outline - -1. Add failing specs for seeded camera/object generation and non-overlap. -2. Implement a deterministic title-scene generation module. -3. Extend the title shader to render generated sphere and column objects. -4. Seed the initial app title camera and pass the scene seed into rendering. -5. Record drift, playback, and retrospective in this design packet. - -## Tests To Write First - -- `title scene generation is deterministic and seed-sensitive` -- `title scene generation creates varied non-overlapping objects` -- `initial title camera state can use a seeded scene placement` - -## Drift Check - -RED drift matched the design: there was no scene-generation seam, no seeded -camera placement, and the title shader still built a fixed three-sphere scene -inline. - -Implementation drift is intentional and bounded: - -- Startup uses `Math.random()` once to choose a scene seed; generated scene data - is deterministic after that seed so frames do not flicker. -- The shader now consumes generated scene objects but still applies the same - material lighting, reflection, shadows, caustics, and Braille resampling. -- Column objects are rendered as finite vertical cylinder sides; caps are left - out of scope for this cycle. - -## Playback - -Playback answers: - -1. A fixed scene seed produces stable camera placement and identical generated - objects. -2. Different seeds produce different camera placements and object layouts. -3. The generator creates at least six objects with sphere and column shape tags, - varied material colors, radii, and reflectivity values. -4. Tests check every object footprint pair against - `TITLE_SCENE_OBJECT_MARGIN`. -5. `renderTitleScreen` now receives the scene seed and renders generated - objects without post-render color mutation. - -Validation: - -- `node --test spec/title-scene.spec.mjs spec/title-screen.spec.mjs - spec/title-camera-session.spec.mjs` passed. -- `npm run build` passed. -- `npm run quality` passed with no regressions. -- `npm run test` passed 125 tests. -- `git diff --check` passed. - -## Retrospective - -Keeping generation in `src/ui/title-scene.ts` kept `title-screen.ts` under the -500-line rule while making non-overlap directly testable. The floor-shadow -regression caught during playback was useful: shadow rays can begin inside a -shape, so sphere intersection now uses the positive exit root when needed. diff --git a/docs/design/0016-structural-history-replace-text-range-metadata/replace-text-range-wesley-metadata.md b/docs/design/0016-structural-history-replace-text-range-metadata/replace-text-range-wesley-metadata.md deleted file mode 100644 index 86a2a451..00000000 --- a/docs/design/0016-structural-history-replace-text-range-metadata/replace-text-range-wesley-metadata.md +++ /dev/null @@ -1,153 +0,0 @@ ---- -title: "structural-history-replace-text-range-metadata" -legend: "contracts" -cycle: "0016-structural-history-replace-text-range-metadata" -source_backlog: "docs/method/backlog/asap/optic-client-generation-cutover.md" ---- - -# structural-history-replace-text-range-metadata - -Source backlog item: -`docs/method/backlog/asap/optic-client-generation-cutover.md` -Legend: contracts - -## Sponsored Users - -- A maintainer moving buffer-history authority out of transitional TypeScript - and into the structural-history GraphQL contract. -- A developer reviewing whether `replaceTextRange` now has generated Wesley - operation identity instead of another hand-authored string. -- A future agent cutting over more structural-history operations without - widening the runtime storage migration. - -## Hills - -1. A maintainer can inspect the structural-history SDL and see - `replaceTextRange` declared as a Wesley operation whose identity comes from - generated metadata. -2. A developer can run the normal build and test paths from a clean checkout - and have the ignored `replaceTextRange` descriptor generated before - TypeScript imports it. -3. A future runtime slice can call the hot-buffer replace boundary and observe - generated `replaceTextRange` operation identity while preserving existing - tick, no-op, and open edit-group behavior. - -## Playback Questions - -1. Does the structural-history SDL mark `replaceTextRange` with `@wes_op`? -2. Does the structural-history generator emit the Wesley operation descriptor - from `contracts/jedit/structural-history.graphql`? -3. Is the extracted descriptor ignored generated output rather than a second - committed source of truth? -4. Does the app boundary import generated operation metadata instead of naming - `replaceTextRange` by hand? -5. Does routing through that boundary preserve replace admission, logical - no-op behavior, and open edit-group membership? - -## Requirements - -- Keep `contracts/jedit/structural-history.graphql` as the authored domain - contract for structural history. -- Mark `replaceTextRange` as a Wesley operation in that SDL. -- Generate the structural-history Wesley TypeScript artifact during build and - test without requiring a sibling Wesley checkout. -- Extract only the `replaceTextRange` operation descriptor needed by this - slice. -- Ignore the extracted descriptor so generated metadata does not become a - committed peer authority. -- Route the hot-buffer replace boundary through the generated descriptor. -- Preserve the existing in-memory runtime as the executor for this slice. - -## Acceptance Criteria - -- RED tests fail because the structural-history SDL is not yet consumed by any - generated adapter-facing metadata. -- GREEN tests prove SDL annotation, generation, ignored descriptor posture, - app-boundary consumption, and preserved hot-buffer tick behavior. -- `node --test spec/structural-history-contract-readiness.spec.mjs - spec/structural-history-replace-text-range-metadata.spec.mjs` passes. -- `npm run build` passes. -- `npm run test` passes. -- `npm run quality` passes. -- `git diff --check` passes. - -## Accessibility / Assistive Reading Posture - -This cycle changes contract authority and adapter metadata, not the visible -editor surface. It must not alter editing controls, footer language, focus -behavior, or screen-reader-relevant text. - -## Localization / Directionality Posture - -No localized strings or layout direction rules change in this cycle. - -## Agent Inspectability / Explainability Posture - -The generated route should be explainable from plain repo reads: - -- SDL declares the operation. -- Package scripts run generation before build and tests need the descriptor. -- The adapter imports generated metadata at one boundary. -- Specs prove the descriptor is ignored and mirrors Wesley output. - -## Implementation Outline - -1. Add structural-history SDL authority for text-history operations. -2. Add a build-local structural-history Wesley generation script. -3. Extract the `mutationReplaceTextRangeOperation` descriptor into - `src/generated/jedit`. -4. Ignore that descriptor and document that it is build output. -5. Add a small app boundary that returns generated `replaceTextRange` - operation identity while delegating execution to the current runtime port. -6. Update the hot-buffer session to use the boundary. -7. Record drift, playback, and retrospective in this design packet. - -## Tests To Write First - -- `structural history SDL marks replaceTextRange as a Wesley operation` -- `structural history generation path emits replaceTextRange metadata` -- `generated replaceTextRange descriptor is ignored and mirrors Wesley metadata` -- `replace/tick adapter consumes generated replaceTextRange operation identity` -- `replaceTextRange metadata route preserves hot buffer tick behavior` - -## Drift Check - -RED drift matched the design: structural-history authority existed as a -direction, but no generated structural-history artifact was consumed by an app -boundary, and `replaceTextRange` execution still had no generated operation -identity at the session boundary. - -Implementation drift is intentional and bounded: - -- The generator extracts one descriptor rather than committing the full - structural-history TypeScript output. -- The generated descriptor is ignored and recreated by build/test. -- Runtime storage, persistent history, and generated payload-shape cutover stay - out of scope. - -## Playback - -Playback answers: - -1. `replaceTextRange` is declared in the structural-history SDL with - `@wes_op(name: "replaceTextRange")`. -2. `npm run gen:contract:structural-history:wesley` emits the Wesley output and - extracts `mutationReplaceTextRangeOperation`. -3. `.gitignore` excludes the extracted descriptor, and tests prove it is not - tracked. -4. `src/app/structural-history-replace-text-range.ts` imports the generated - descriptor and exposes the generated operation name. -5. The hot-buffer session still admits replace ticks, preserves no-op behavior, - and includes admitted ticks in open edit groups. - -Validation: - -- `npm run check` passed. -- `git diff --check` passed. - -## Retrospective - -Keeping this as a one-operation metadata slice made the authority shift -reviewable. The generated operation name is now real runtime evidence at the -app boundary, while the broader storage and generated-payload migration remains -deferred to a later cycle. diff --git a/docs/design/0017-real-echo-release-gate/real-echo-release-gate.md b/docs/design/0017-real-echo-release-gate/real-echo-release-gate.md deleted file mode 100644 index 1c45efcf..00000000 --- a/docs/design/0017-real-echo-release-gate/real-echo-release-gate.md +++ /dev/null @@ -1,118 +0,0 @@ -# Real Echo Release Gate - -Status: active cross-repo gate. - -Echo `v0.1.0` is delayed until jedit works on Echo. This document records what -that means from the jedit side. - -## Claim - -jedit proves Echo is buildable when a clean jedit checkout can run a documented -real Echo witness that uses jedit-owned contracts and generated artifacts: - -```text -jedit-authored structural-history SDL --> Wesley generated artifacts --> Echo package install --> jedit app submits canonical edit intent --> trusted Echo host stages work and authorizes scheduler opportunities --> Echo scheduler emits tick receipts --> jedit observes applied, rejected, or obstructed outcome --> jedit queries bounded text reading --> retained receipt and reading evidence can be inspected --> replay reproduces the same result -``` - -The test must run from this repository. Echo's in-repo hot-text-shaped fixture -proves generic mechanics, but it does not prove the external product seam. - -## Product Model - -The app-facing boundary is `TextBufferOptic`, not raw Echo coordinates. -`ReadBasisHandle` is an opaque supporting token issued through that optic. The -release witness should preserve the current data-model rule: - -```text -The app may hold the optic. -The app may invoke the optic. -The app may not inspect the optic's runtime coordinates. -``` - -Runtime-facing handlers may use worldline ids, head ids, and scheduler -coordinates below the optic boundary. App-facing jedit code may not. - -## Current Blocker - -The current opt-in real Echo WASM witness now has a local app/host split. The -current witness report also inventories inline reading evidence and returns -typed postures for missing durable retention and replay. The next blocker is to -move from the old stack-witness fixture shape toward a jedit-owned generated -contract path with real retained evidence and durable replay. - -The previous rejection remains important doctrine: Echo should reject scheduler -`start` / `until_idle` control through app-facing dispatch. jedit must preserve -that authority boundary while improving the witness. - -## Required Authority Split - -jedit application code may: - -- submit canonical intent bytes; -- observe intent outcomes; -- request bounded readings through opaque handles; -- render product-shaped readings and evidence summaries. - -Trusted Echo host code may: - -- install generated contract packages; -- stage ticketed runtime ingress; -- record trusted runtime-control commands such as Start, Stop, cadence, or - drain policy; -- run scheduler passes; -- choose until-idle or cadence policy; -- recover faulted heads or runtime posture. - -jedit application code must not: - -- tick Echo; -- start or stop Echo through app intent dispatch; -- send scheduler control through app dispatch; -- access worldline ids, heads, or scheduler internals; -- treat raw transport arrival as semantic Echo history; -- forge read basis handles. - -## Passing Witness - -The first passing real Echo witness should prove: - -- one edit-like mutation with non-trivial vars; -- one bounded text reading; -- `TextBufferOptic` or its generated successor as the app-facing capability; -- product-shaped text result plus Echo `ReadingEnvelope` evidence; -- retained receipt and reading evidence; -- replay of the same result; -- at least one non-happy path such as unsupported operation, lawful rejection, - obstruction, residual reading, or missing retention. - -The current intermediate witness is allowed to report `missing_retention` and -`durable_replay_unavailable` so the gap is machine-readable. Those postures do -not satisfy the final release gate. - -## Non-Goals - -- Do not build the full editor on Echo in this slice. -- Do not make Echo know jedit product nouns. -- Do not make jedit app code know Echo substrate coordinates. -- Do not remove the fake transport harness before the real witness is stable. -- Do not route around Wesley with a permanent hand-authored protocol. -- Do not bring Continuum into the local witness. - -## Immediate Work - -1. Keep the fake Echo-shaped harness as the stable app-facing contract. -2. Keep the real Echo witness path on separate app and trusted-host adapters. -3. Replace the current `missing_retention` witness posture with generic retained - receipt and reading refs from Echo. -4. Add an agent-friendly CLI witness before adding an MCP wrapper. -5. Replace the current `durable_replay_unavailable` posture with replay proof - before accepting the gate. diff --git a/docs/design/0018-echo-wasm-host-transport-authority/echo-wasm-host-transport-authority.md b/docs/design/0018-echo-wasm-host-transport-authority/echo-wasm-host-transport-authority.md deleted file mode 100644 index 96fbab51..00000000 --- a/docs/design/0018-echo-wasm-host-transport-authority/echo-wasm-host-transport-authority.md +++ /dev/null @@ -1,128 +0,0 @@ -# Echo WASM Host Transport Authority - -Status: local transport boundary implemented. - -This design packet records the jedit side of the Echo `v0.1.0` authority split. -The matching Echo packet is -`docs/design/wasm-trusted-runtime-host-control-boundary.md` in the Echo -repository. - -## Claim - -jedit's real Echo WASM path has two transport surfaces: - -```text -jedit application adapter --> submit canonical intent bytes --> observe bounded readings --> inspect scheduler status as metadata - -trusted Echo host adapter --> request runtime lifecycle policy --> dispatch packed Echo control intent bytes below the lifecycle port -``` - -The application adapter cannot tick Echo and cannot call the raw trusted control -export. The trusted host adapter may call Echo's raw -`dispatch_control_intent_trusted(...)` export so the opt-in release witness can -request Echo's internal run loop until idle without tunneling trusted runtime -lifecycle control through application dispatch. - -## Why This Exists - -The old real WASM witness sent Echo scheduler `start` / `until_idle` control -through `submitIntentBytes(...)`. Current Echo correctly rejects that as a -forbidden control intent. jedit should not weaken that boundary. It should -model the real product split: - -```text -application product capability --> app-safe intent/observe transport - -trusted host/runtime owner --> trusted runtime lifecycle port --> raw control transport below the adapter -``` - -The fake Echo-shaped transport remains useful for default tests. The real WASM -transport is opt-in because it depends on a sibling Echo checkout and generated -WASM package. - -## Implemented Surface - -`src/ports/echo-kernel-transport.ts` now defines: - -- `EchoWasmKernelTransport`, the app-safe surface; -- `EchoTrustedHostControlTransport`, the trusted host-control surface; -- `EchoWasmKernelHostTransport`, which bundles the two without merging their - authority. -- `TrustedEchoRuntimeLifecyclePort`, the trusted lifecycle vocabulary that wraps - raw control bytes for host-owned code. - -`src/adapters/echo-wasm-kernel.ts` now exports: - -- `createEchoWasmKernelTransport(...)`, which returns only the app-safe - transport for existing callers; -- `createEchoWasmKernelHostTransport(...)`, which returns `{ app, trustedHost }` - for release witnesses and host-owned integration. - -The app-safe object deliberately has no `dispatchControlIntentBytes(...)` -method. The trusted host object deliberately has no submit or observe methods. -The lifecycle port deliberately exposes `requestRunUntilIdle(...)`, not `tick`, -`stepTick`, or any externally injected tick API. - -The agent witness runner follows the same port/adapter rule: - -- `scripts/ports/echo-witness-runner.mjs` owns orchestration over an abstract - witness runner adapter; -- `scripts/adapters/node-echo-witness-runner.mjs` owns filesystem paths, - sibling Echo checkout resolution, process spawning, and witness-report reads; -- `scripts/jedit-echo-witness.mjs` is only CLI argument parsing and summary - emission. - -Echo build paths and host process execution are therefore adapter concerns, not -application or witness-orchestration logic. - -## Agent Surface - -The immediate agent interface should be a CLI, not an MCP server: - -```sh -ECHO_WARP_WASM_DIR=/path/to/echo/crates/warp-wasm \ - node scripts/jedit-echo-witness.mjs --json -``` - -That command emits a machine-readable summary plus a witness report naming the -app/host authority split, fixture operation ids, generated jedit contract -metadata, observed reading identity, artifact hash, residual posture, observer -basis, product-shaped text, retained-evidence inventory, and replay posture. -With `--replay`, the summary includes the report replay posture. The current -posture is `durable_replay_unavailable`, which is honest obstruction rather -than a durable proof. A later MCP server can wrap the same command once replay -output is strong enough to expose through a protocol. The MCP should not be the -first authority boundary; it would add protocol surface before the shell witness -is trustworthy. - -## Evidence - -- `echo wasm kernel transport stays byte-oriented and substrate-generic` -- `echo wasm kernel host transport keeps trusted control off the app surface` -- `echo wasm trusted host transport requires the raw trusted control export` -- `trusted Echo lifecycle port requests run-until-idle without exposing tick injection` -- `trusted Echo lifecycle port keeps app transport out of lifecycle authority` -- `jedit Echo witness CLI emits a dry-run JSON plan for agents` -- direct JSON CLI run includes a witness report with `ReadingEnvelope` posture -- direct JSON CLI run cites generated `hot-text-runtime` operation metadata -- direct JSON CLI run names inline retained evidence and missing-retention - posture -- `--replay` reports the typed replay posture without app tick authority -- `real Echo WASM requires an installed observer before jedit textWindow can materialize` - -## Non-Goals - -- No Echo ticks through app dispatch. -- No externally injected host tick stream. -- No app access to Echo worldline ids or scheduler internals. -- No high-level product API in this slice. -- No MCP server before the shell witness is green and useful. -- No removal of the fake transport harness. diff --git a/docs/design/0019-echo-runtime-control-release-slices/echo-runtime-control-release-slices.md b/docs/design/0019-echo-runtime-control-release-slices/echo-runtime-control-release-slices.md deleted file mode 100644 index 3daf43ca..00000000 --- a/docs/design/0019-echo-runtime-control-release-slices/echo-runtime-control-release-slices.md +++ /dev/null @@ -1,151 +0,0 @@ -# Echo Runtime Control And Release-Gate Slices - -Status: design plan for the next jedit/Echo release-gate batch. - -This packet records the jedit-side consequence of Echo's trusted -runtime-control doctrine: - -```text -Start/Stop are trusted runtime-control history. -Start/Stop are not jedit contract intents. -Start/Stop request Echo runtime lifecycle policy; they do not create ticks. -TickReceipt remains Echo scheduler-owned execution evidence. -``` - -jedit may expose Start/Stop/cadence controls in a product shell or local host -CLI. Those controls must flow through a trusted Echo host adapter. They must not -be encoded as `replaceTextRange`, structural-history mutations, or any other -jedit-authored domain operation. - -## Authority Split - -| Surface | Allowed | Forbidden | -| :--- | :--- | :--- | -| jedit app/product adapter | Submit edit intents, observe outcomes, request bounded readings, render product evidence. | Tick Echo, start/stop Echo, drain Echo, inspect worldline/head/scheduler internals. | -| jedit trusted Echo host adapter | Install packages, call trusted Echo control, choose cadence/drain policy, run witness loops. | Expose raw trusted control to app code or mutate jedit product state directly. | -| Echo scheduler | Select work, attempt ticks, emit receipts, roll back failed attempts. | Treat jedit product commands as scheduler control. | - -`Start(tickFrequency = 1/60)` is a trusted host policy command. It asks Echo -to run its own internal loop under host cadence. It is not a request from the -editor contract or host adapter to run one externally supplied tick now. - -## Design Consequences - -- The release witness may record Start/Stop/cadence evidence in its report. -- The app-facing witness summary must keep runtime-control evidence separate - from edit intent evidence. -- Replay may use runtime-control history to explain pending gaps or running - posture. -- Replay must not sleep to reproduce wall-clock cadence. It should replay - logical control epochs and scheduler receipts. -- Stopping the host must not interrupt a half-committed tick. - -Current implementation note: jedit now has -`TrustedEchoRuntimeLifecyclePort.requestRunUntilIdle(...)`. The real Echo WASM -witness uses that port instead of calling raw trusted-control bytes directly. -The port still delegates to Echo's trusted control export below an adapter. - -## Next Ten Slices From jedit's Side - -The matching Echo plan is -`docs/design/v0.1.0-jedit-next-ten-slices.md` in the Echo repository. - -### 1. Release-Gate Doctrine Cleanup - -Update jedit docs so the current proof starts from -`contracts/jedit/structural-history.graphql` and `replaceTextRange`. -`TextBufferOptic`, if retained, is a jedit product capability, not an Echo noun. -Start/Stop belong to the trusted host adapter. - -Witness: docs grep shows no claim that Echo owns editor/text-buffer concepts. - -### 2. Witness Retained-Evidence Inventory - -Extend the real Echo witness report with receipt refs, reading refs, package -identity, reading identity, artifact hash, and missing-retention posture. - -Witness: `node scripts/jedit-echo-witness.mjs --json` reports retained evidence -without leaking scheduler internals. - -Current implementation note: the report now records inline `QueryBytes` and -`ReadingEnvelope` evidence and names durable receipt/payload/envelope refs as -`missing_retention`. Real Echo retained refs remain a later replacement for -that posture. - -### 3. Echo Retained Evidence Ref Surface Check - -Coordinate with Echo if the WASM/API surface does not expose enough generic -retained evidence refs. jedit should consume generic refs only through its -adapter. - -Witness: jedit can report evidence refs without private Echo runtime access. - -Current implementation note: the current Echo WASM witness exposes enough -inline observation evidence to report the gap, but not enough durable retained -refs to satisfy the release gate. No jedit code should fabricate those refs. - -### 4. Adapter Consumes Echo Retained Refs - -Map Echo retained refs into jedit's product witness report below the adapter -boundary. - -Witness: product-facing report stays about edits, readings, receipts, and -evidence. - -### 5. Replay Witness Shell - -Add a replay phase to the witness CLI. Replay should compare outcome or reading -identity, or return a typed replay obstruction when durable replay is not yet -available. - -Witness: CLI replay does not require app-facing tick authority. - -Current implementation note: `--replay` now returns the report replay posture. -Until durable replay exists, the posture is `durable_replay_unavailable`. - -### 6. Product-Facing Intent Outcome Consumption - -Consume Echo's app-safe outcome API once polished: unknown, pending, applied, -rejected, obstructed. - -Witness: jedit observes outcome without trusted control. - -### 7. Generated Structural-History Request Path - -Use generated structural-history operation metadata and codecs for -`replaceTextRange` instead of the old stack-witness fixture shape. - -Witness: the real Echo mutation path is generated-contract backed. - -### 8. Generated Package Install Path - -Install the jedit-generated package through Echo's generic installed-package -boundary. - -Witness: unsupported op/query is rejected at package boundary and no jedit noun -enters Echo. - -### 9. Real Mutation And Query Round Trip - -Submit `replaceTextRange`, let the trusted host enable/drain scheduler -opportunities, observe the outcome, and query a bounded text reading. - -Witness: real report includes non-trivial vars, scheduler-owned receipt, -bounded reading, retained refs, and app/host split. - -### 10. Non-Happy Path And Release-Gate Report - -Add one honest failure path: unsupported op/query, missing retention, residual -reading, lawful rejection, or obstruction. - -Witness: one documented command emits the happy path, non-happy path, retained -evidence, replay result, and authority-boundary checks. - -## Non-Goals - -- Do not make Start/Stop jedit contract mutations. -- Do not expose Echo trusted control on the app transport. -- Do not make app dispatch synchronous with Echo execution. -- Do not make wall-clock cadence semantic history. -- Do not move jedit product nouns into Echo. -- Do not remove the fake transport until the real witness is stable. diff --git a/docs/design/0020-trusted-echo-runtime-lifecycle-port/trusted-echo-runtime-lifecycle-port.md b/docs/design/0020-trusted-echo-runtime-lifecycle-port/trusted-echo-runtime-lifecycle-port.md deleted file mode 100644 index 15636f81..00000000 --- a/docs/design/0020-trusted-echo-runtime-lifecycle-port/trusted-echo-runtime-lifecycle-port.md +++ /dev/null @@ -1,164 +0,0 @@ -# Trusted Echo Runtime Lifecycle Port - -Status: implemented local boundary. - -## Claim - -jedit trusted host code may request Echo runtime lifecycle policy, but Echo -owns the internal run loop, every logical tick boundary, and every -`TickReceipt`. - -The lifecycle port exists so product code and witness code stop talking in raw -trusted-control bytes. It is still a host-only surface. It is not a jedit -contract operation and not an application capability. - -## Authority Boundary - -| Surface | Allowed | Forbidden | -| :--- | :--- | :--- | -| jedit app/product code | Submit canonical intent bytes, observe bounded readings, render product evidence. | Start Echo, stop Echo, request run-until-idle, inject ticks, inspect scheduler internals. | -| jedit trusted Echo host adapter | Request start with scheduler cadence policy, request run-until-idle, request stop, decode trusted lifecycle responses. | Expose raw trusted control to app code, choose individual tick boundaries, mutate product state. | -| Echo runtime | Own the run loop, choose scheduler work, emit tick receipts, report lifecycle status. | Treat jedit product operations as trusted runtime control. | - -## Implemented Shape - -The source boundary is: - -```text -src/ports/echo-runtime-lifecycle.ts -src/adapters/echo-runtime-lifecycle.ts -``` - -The current port exposes: - -```text -TrustedEchoRuntimeLifecyclePort.requestStart({ tickIntervalSeconds }) -TrustedEchoRuntimeLifecyclePort.requestRunUntilIdle({ cycleLimit }) -TrustedEchoRuntimeLifecyclePort.requestStop() -``` - -The current TypeScript field name is `tickIntervalSeconds` for compatibility -with the merged port. Read it as scheduler cadence policy, not as authority to -inject or choose individual ticks. - -The adapter requires: - -```text -EchoTrustedHostControlTransport -+ EchoRuntimeLifecycleCodec --> TrustedEchoRuntimeLifecyclePort -``` - -That split is deliberate. The lifecycle port owns host authority vocabulary. -The codec owns the current Echo control-byte representation. The witness can -continue using its current CBOR fixture codec without making that fixture a -product API. - -## Tick Authority Rule - -The lifecycle port must not grow methods named or shaped like: - -- `tick`; -- `stepTick`; -- `nextTick`; -- `advanceTick`; -- `runOneTick`. - -`requestStart` means: - -```text -trusted host asks Echo to begin its own internal run loop using host cadence -policy -``` - -It does not mean: - -```text -trusted host supplies a discrete tick -trusted host chooses individual tick boundaries -wall-clock cadence becomes semantic history -``` - -`requestRunUntilIdle` means: - -```text -trusted host asks Echo to run its own scheduler loop until idle, bounded by a -cycle-limit guardrail -``` - -It does not mean: - -```text -trusted host supplies a tick stream -trusted host chooses Tick N -application callback timing becomes causal history -``` - -`requestStop` means: - -```text -trusted host asks Echo to suspend future scheduler opportunities at a safe -boundary -``` - -It does not mean: - -```text -trusted host interrupts a half-committed tick -application code cancels execution -``` - -## Witness Integration - -The real Echo WASM stack witness now routes its until-idle control through the -trusted lifecycle port: - -```text -createEchoWasmKernelHostTransport(...) --> { app, trustedHost } --> createTrustedEchoRuntimeLifecyclePort({ trustedHost, codec }) --> lifecycle.requestRunUntilIdle({ cycleLimit }) --> lifecycle.requestStop(), when the host is shutting down or suspending the - scheduler -``` - -The app transport remains separate: - -```text -app.submitIntentBytes(...) -app.observeBytes(...) -``` - -No app-facing jedit optic client receives the lifecycle port. - -## Evidence - -- `trusted Echo lifecycle port requests run-until-idle without exposing tick injection` -- `trusted Echo lifecycle port requests stop through trusted control only` -- `trusted Echo lifecycle port keeps app transport out of lifecycle authority` -- `real Echo WASM witness control intent honors configured cycle limit` -- `real Echo WASM witness stop control stays on trusted lifecycle vocabulary` -- `real Echo WASM requires an installed observer before jedit textWindow can materialize` - -## Non-Goals - -- No app-controlled tick. -- No host-injected discrete tick. -- No product-facing Start/Stop UI in this slice. -- No durable replay in this slice. -- No retained evidence implementation in this slice. -- No jedit nouns in Echo. - -## Next Work - -This boundary is the prerequisite for making the interactive jedit product path -Echo-backed. The next implementation should use this lifecycle port while -routing a real product edit/read path through Echo: - -```text -jedit edit intent --> app-safe Echo transport --> trusted lifecycle request --> Echo-owned tick receipt --> bounded text reading -``` diff --git a/docs/design/0021-echo-powered-text-buffer-optic-session/echo-powered-text-buffer-optic-session.md b/docs/design/0021-echo-powered-text-buffer-optic-session/echo-powered-text-buffer-optic-session.md deleted file mode 100644 index f45d19f0..00000000 --- a/docs/design/0021-echo-powered-text-buffer-optic-session/echo-powered-text-buffer-optic-session.md +++ /dev/null @@ -1,120 +0,0 @@ -# Echo-Backed TextBufferSession Port - -Status: implemented local boundary. - -## Claim - -jedit can expose a `TextBufferSessionPort` that returns app-facing -`TextBufferOptic` buffer capabilities while keeping the trusted Echo lifecycle -port behind adapters. - -This slice is a local integration step toward the release-gate sentence: - -```text -jedit is powered by Echo. -``` - -It does not claim that every interactive editor action is already backed by -real Echo. It proves the product-facing session boundary can be wired as: - -```text -TextBufferSessionPort --> TextBufferOptic mutation --> app-safe jedit/Echo optic client --> trusted host loop may drain Echo independently --> later bounded read -``` - -## Implemented Shape - -The app-facing port is: - -```text -src/ports/text-buffer-session.ts -``` - -The reusable app implementation is: - -```text -src/app/text-buffer-session.ts -createTextBufferSession(client) -``` - -The Echo-backed adapter is: - -```text -src/adapters/echo-backed-text-buffer-session.ts -createEchoBackedTextBufferSession({ - client, -}) -``` - -Mutation methods call only the app-safe client: - -- `openTextBuffer`; -- `createBufferWorldline`; -- `replaceRangeAsTick`; -- `createCheckpoint`. - -Read methods also remain app-safe and do not request lifecycle control: - -- `worldlineSnapshot`; -- `textWindow`. - -## Authority Rule - -The returned `TextBufferSessionPort` and `TextBufferOptic` do not expose: - -- `requestRunUntilIdle`; -- `tick`; -- raw trusted control bytes; -- scheduler status internals. - -The lifecycle object stays in the host-owned adapter layer and is not called by -app-facing dispatch. Application code still sees only the product capability. - -## Why This Is Transitional - -The current `JeditOpticClient` still returns mutation results synchronously for -the fake Echo-shaped transport and the transitional app-owned runtime. Real Echo -will eventually separate: - -```text -accepted intent --> trusted host loop drains Echo independently --> outcome observation -``` - -This slice does not pretend that product-facing outcome observation is finished. -It keeps the lifecycle boundary outside app-facing dispatch so the next slices -can replace fixture behavior without changing the app authority model. - -## Evidence - -- `Echo-backed TextBufferSession port does not request lifecycle during app-facing dispatch` -- `trusted Echo lifecycle port requests run-until-idle without exposing tick injection` -- `transport-backed optic client exercises the fake Echo host through encoded bytes` - -## Non-Goals - -- No app-facing lifecycle method. -- No direct Echo tick method. -- No durable replay. -- No retained evidence lookup. -- No interactive TUI cutover in this slice. -- No jedit nouns in Echo. - -## Next Work - -The next integration step is now recorded in -`../0022-agent-echo-powered-session-witness/agent-echo-powered-session-witness.md`. -It binds this powered session into a host-owned runtime path that can be -exercised from an agent/CLI command: - -```text -create buffer --> submit replace-range --> request lifecycle --> observe text window --> report outcome + reading evidence -``` diff --git a/docs/design/0022-agent-echo-powered-session-witness/agent-echo-powered-session-witness.md b/docs/design/0022-agent-echo-powered-session-witness/agent-echo-powered-session-witness.md deleted file mode 100644 index caa2b86c..00000000 --- a/docs/design/0022-agent-echo-powered-session-witness/agent-echo-powered-session-witness.md +++ /dev/null @@ -1,95 +0,0 @@ -# Agent Echo-Powered Session Witness - -> **Historical design note:** CR-03 removed `currentReadBasis()` from the -> product optic. Current reads carry an explicit Jim `basisHeadId` and branded -> UTF-8 byte range while the optic retains the opaque transport capability. - -## Claim - -Agents can exercise the jedit `TextBufferOptic` product path through a -command-line witness without receiving Echo tick authority or raw runtime -coordinates. - -This is a host-owned smoke path. It proves the product-facing capability shape: - -```text -agent command --> host constructs Echo-shaped transport --> host constructs trusted lifecycle port --> host constructs Echo-backed TextBufferSessionPort --> create buffer --> apply replace-range intent --> observe text window --> trusted stop request --> JSON witness report -``` - -## Boundary - -The command is: - -```sh -npm run witness:echo:session -``` - -or directly: - -```sh -node scripts/jedit-echo-powered-session.mjs --json --dry-run -``` - -The emitted report names: - -- the app-facing session port (`TextBufferSessionPort`); -- the app-facing buffer capability (`TextBufferOptic`); -- the transport posture (`fake-echo-shaped`); -- the fact that app code cannot tick; -- the fact that app-facing dispatch does not request lifecycle drain; -- trusted stop requested by the host command; -- the resulting receipt id, reading id, text window lines, and truncation - posture. - -## Authority - -The CLI is not an app API. It is a host/agent witness command. - -The app-facing object remains `TextBufferOptic`. It exposes: - -- `applyIntent(...)`; -- `textWindow(...)`; -- `openedTextBasis`. - -It does not expose: - -- `requestRunUntilIdle`; -- `tick`; -- `dispatchControlIntentBytes`; -- raw worldline coordinates. - -## Why Fake Echo-Shaped Transport Remains Here - -The real Echo WASM witness remains the opt-in substrate proof: - -```sh -ECHO_WARP_WASM_DIR=/path/to/echo/crates/warp-wasm \ - node scripts/jedit-echo-witness.mjs --json --replay -``` - -This slice adds the product-session command around the same app-facing -capability boundary. It is intentionally fast, deterministic, and local to -jedit's default test suite. It does not replace the real Echo WASM witness. - -## Witnesses - -- `Echo-powered session CLI reports app capability, lifecycle, and reading evidence` -- `Echo-powered session CLI rejects invalid cycle limits as JSON failures` -- `Echo-backed TextBufferSession port does not request lifecycle during app-facing dispatch` - -## Not In This Slice - -- Real Echo WASM package publishing. -- Durable retained evidence lookup. -- Durable replay. -- Interactive TUI cutover. -- MCP server wrapping the product command. -- Application-controlled runtime lifecycle. diff --git a/docs/design/0023-trusted-echo-host-shutdown-witness/trusted-echo-host-shutdown-witness.md b/docs/design/0023-trusted-echo-host-shutdown-witness/trusted-echo-host-shutdown-witness.md deleted file mode 100644 index 0beb650a..00000000 --- a/docs/design/0023-trusted-echo-host-shutdown-witness/trusted-echo-host-shutdown-witness.md +++ /dev/null @@ -1,82 +0,0 @@ -# Trusted Echo Host Shutdown Witness - -## Claim - -jedit host code can request Echo shutdown through the trusted lifecycle port -after an Echo-powered product session runs, without turning shutdown into an -application intent or app-visible tick control. - -## Implemented Shape - -The host helper is: - -```text -src/app/trusted-echo-runtime-host.ts -``` - -It exposes: - -```text -stopTrustedEchoRuntime(lifecycle) -``` - -which calls: - -```text -TrustedEchoRuntimeLifecyclePort.requestStop() -``` - -and returns a small shutdown report that explicitly carries: - -- `accepted`; -- `lastRunCompletion`; -- `appCanTick: false`. - -The agent session witness now runs: - -```text -create buffer --> apply replace-range --> trusted run-until-idle requests --> observe text window --> trusted stop request --> JSON witness report -``` - -## Authority - -Stop is trusted host lifecycle control. It is not: - -- a jedit application intent; -- a generated Wesley mutation; -- an app-facing `TextBufferOptic` method; -- an external tick interruption; -- user undo. - -`Stop` suspends future scheduler opportunities at a safe Echo boundary. It must -not imply half-tick interruption or hidden rollback. - -## Why This Is Not SIGTERM Yet - -This slice adds the deterministic primitive that a future process-signal -adapter should call. It does not install Node signal handlers yet because the -current interactive workspace still needs a broader host lifecycle owner for: - -- Echo startup policy; -- Echo package location; -- real WASM package loading; -- process shutdown ordering; -- final retained evidence flush. - -## Witnesses - -- `Echo-powered session CLI reports app capability, lifecycle, and reading evidence` -- `trusted Echo lifecycle port requests stop through trusted control only` - -## Not In This Slice - -- Node `SIGTERM` or `SIGINT` signal handlers. -- Long-running fixed-cadence host loop. -- App-facing stop controls. -- Durable runtime-control history. -- Durable retained evidence flush. diff --git a/docs/design/0024-jedit-powered-by-echo-release-gate.md b/docs/design/0024-jedit-powered-by-echo-release-gate.md deleted file mode 100644 index d1af459e..00000000 --- a/docs/design/0024-jedit-powered-by-echo-release-gate.md +++ /dev/null @@ -1,1136 +0,0 @@ -# jedit Powered By Echo Release Gate - -Status: slices 1-30 closed locally; release-gate evidence recorded. - -After slice 30, release pressure was deliberately removed. The active -post-release-pressure continuation lives in -[`0025-echo-application-hosting-pattern.md`](0025-echo-application-hosting-pattern.md) -and supersedes the earlier release-shaped slice 31-40 plan below. Keep this file -as the historical baseline for slices 1-30. - -This plan defines the local release gate for the sentence: - -```text -jedit is powered by Echo. -``` - -That sentence is true only when the primary headless jedit text edit/read -workflow uses Echo as the runtime authority for submission, admission, -scheduler-owned execution, receipt production, query observation, and evidence -retention, while all jedit-specific nouns remain in jedit contracts, generated -adapters, or jedit ports. - -Echo must not know what a `TextBufferOptic`, rope, pane, cursor, text window, or -editor command is. Echo sees generic package identities, operation ids, query -ids, handlers, observers, receipts, readings, retained evidence, and -obstructions. - -## Progress Protocol - -Agents must keep this file current. Before committing a slice, check off that -slice's checklist items in this file. Do not mark later slices complete early. -If a slice is split, add the split under the original slice rather than -silently changing the release bar. - -## Release Gate Definition - -jedit is powered by Echo when this clean-checkout flow exists: - -```text -trusted host starts Echo runtime policy --> jedit installs its generated contract package --> app creates or opens a TextBufferOptic --> app submits a replace-range intent through jedit-owned adapter code --> Echo accepts/adjudicates generic contract work --> trusted host lets Echo run its scheduler-owned loop --> app observes the intent outcome --> app queries textWindow through a jedit-owned query observer --> app receives TextWindowReading plus evidence --> host can inspect retained receipt/reading posture --> trusted host stops Echo cleanly -``` - -## Authority Bar - -- Application code cannot tick Echo. -- Application code cannot call trusted Echo lifecycle control directly. -- Application dispatch does not execute synchronously. -- `TextBufferOptic` is a jedit capability, not an Echo noun. -- jedit text/rope semantics live in jedit contracts, generated adapters, and - jedit-owned handler/observer code. -- Mutation handlers run only during Echo scheduler-owned execution. -- Query observers are read-only. -- `AdmissionTicket` is not `TickReceipt`. -- Conflict/rejection for one attempt is final for that attempt. -- Retry is a new explicit causal act, not hidden runtime behavior. - -## Slice 01 - Plan And Bearing Signposts - -User story: As a contributor or agent, I can open one plan and immediately know -the twenty-slice route to proving jedit is powered by Echo without contaminating -Echo with jedit nouns. - -Work: - -- Create this release-gate plan. -- Reference it from `AGENTS.md`. -- Create/update `docs/BEARING.md` so the current repo gravity points here. -- State the progress protocol that slices are checked off just before their - commits. - -Test plan: - -- `git diff --check` -- Text search for this plan path from `AGENTS.md` and `docs/BEARING.md`. - -Checklist: - -- [x] Plan document exists. -- [x] `AGENTS.md` references the plan. -- [x] `docs/BEARING.md` references the plan. -- [x] Progress protocol is explicit. - -## Slice 02 - jedit Contract Package Descriptor - -User story: As the trusted host adapter, I can describe the jedit contract -package as an opaque installable artifact without teaching Echo editor nouns. - -Work: - -- Add a jedit-owned package descriptor module. -- Bind package identity, schema identity, artifact identity, codec identity, - supported mutation operation names, supported query operation names, and - observer plan identities. -- Consume existing Wesley-generated operation metadata. -- Keep the descriptor in jedit code, not Echo. - -Test plan: - -- Unit test descriptor identity and operation membership. -- Assert mutation/query operation sets come from generated Wesley metadata. -- Assert descriptor docs/code do not require Echo to know `TextBufferOptic`. -- `npm run build` -- Focused descriptor test. - -Checklist: - -- [x] Descriptor module exists. -- [x] Descriptor includes package/schema/artifact/codec identity. -- [x] Descriptor lists supported mutations from generated metadata. -- [x] Descriptor lists supported queries from generated metadata. -- [x] Descriptor has focused tests. - -## Slice 03 - Package Install Preflight - -User story: As the trusted host adapter, I can preflight a jedit package install -locally and reject unsupported operations before they look runtime-visible. - -Work: - -- Add a jedit-owned package preflight module. -- Validate duplicate operation/query names. -- Validate required mutations and queries are present. -- Classify unsupported mutation/query requests with typed results. -- Keep this as adapter/package boundary logic, not app-facing text behavior. - -Test plan: - -- Unit test happy preflight. -- Unit test missing required mutation. -- Unit test missing required query. -- Unit test unsupported mutation request. -- Unit test unsupported query request. -- `npm run build` -- Focused preflight test. - -Checklist: - -- [x] Preflight module exists. -- [x] Required mutations are validated. -- [x] Required queries are validated. -- [x] Unsupported mutations are rejected before runtime work. -- [x] Unsupported queries are rejected before observer execution. -- [x] Preflight has focused tests. - -## Slice 04 - Echo Package Install Adapter - -User story: As a trusted host adapter, I can translate the jedit package -descriptor into Echo's generic package-install API without app code seeing -runtime internals. - -Work: - -- Add the first jedit adapter that targets Echo's generic installed package - boundary shape. -- Pass only generic package/operation/query/observer identity to Echo. -- Preserve app/host split: package install is trusted host work. -- Return typed install posture to jedit-side code. - -Test plan: - -- Adapter test with fake generic Echo package port. -- Unsupported operation remains preflighted before runtime-visible work. -- App-facing session has no install method. -- `npm run build` - -Checklist: - -- [x] Generic Echo package port shape exists in jedit. -- [x] Trusted adapter installs descriptor through that port. -- [x] App-facing API cannot install packages. -- [x] Install posture is typed. -- [x] Tests prove no app install authority. - -## Slice 05 - Mutation Handler Registration - -User story: As the trusted host adapter, I can register jedit-owned mutation -handlers so Echo can call them during scheduler-owned execution. - -Work: - -- Add jedit-owned handler registration for `createBufferWorldline`, - `replaceRangeAsTick`, and `createCheckpoint`. -- Decode vars through generated/jedit-owned surfaces. -- Run existing jedit contract runtime logic behind the handler boundary. -- Keep handlers unavailable from app dispatch. - -Test plan: - -- Handler registration test with fake Echo contract host port. -- Mutation handler cannot be called through app-facing `TextBufferOptic`. -- Handler receives decoded generated vars. -- Handler returns typed generic result bytes/posture. - -Checklist: - -- [x] Mutation handler registry exists in jedit adapter layer. -- [x] `createBufferWorldline` handler registered. -- [x] `replaceRangeAsTick` handler registered. -- [x] `createCheckpoint` handler registered. -- [x] App dispatch cannot call handlers directly. - -## Slice 06 - Query Observer Registration - -User story: As the trusted host adapter, I can register jedit-owned query -observers so Echo can materialize bounded readings through generic QueryView. - -Work: - -- Register `worldlineSnapshot` and `textWindow` query observers. -- Decode query vars through generated/jedit-owned surfaces. -- Return generic query payload bytes and observer plan identity. -- Keep observer context read-only. - -Test plan: - -- No observer means unsupported query. -- Registered observer returns payload bytes. -- Observer cannot mutate runtime. -- Observer cannot request lifecycle/ticks. -- jedit adapter decodes `TextWindowReading`. - -Checklist: - -- [x] Query observer registry exists in jedit adapter layer. -- [x] `worldlineSnapshot` observer registered. -- [x] `textWindow` observer registered. -- [x] Observer context is read-only. -- [x] Unsupported query remains unsupported without registration. - -## Slice 07 - Installed Package TextBufferOptic Headless Flow - -User story: As an app caller, I can create a text buffer, apply an edit, and read -a text window through `TextBufferOptic`, while Echo remains the generic runtime. - -Work: - -- Wire `TextBufferOptic` to the installed package/handler/observer transport - path for one headless flow. -- Keep trusted host lifecycle outside app-facing API. -- Replace the fake transport in this witness only. This slice proves the - jedit-owned package boundary path; later slices bind that path to the real - Echo WASM package install surface when it is available. - -Test plan: - -- Create buffer. -- Apply `replaceRange`. -- Trusted host drains/runs Echo. -- Query `textWindow`. -- Assert resulting `TextWindowReading` contains edited text. -- Assert app-facing objects expose no tick/lifecycle/install methods. - -Checklist: - -- [x] Headless flow uses installed jedit package transport path. -- [x] `TextBufferOptic` creates/opens buffer. -- [x] `replaceRange` goes through the installed mutation handler path. -- [x] `textWindow` goes through the installed query observer path. -- [x] App surface has no runtime authority. - -## Slice 08 - Trusted Host Runtime Loop - -User story: As a trusted local host, I can start and stop Echo runtime policy -without giving app code per-tick control. - -Work: - -- Add a trusted host lifecycle runner with start/stop posture. -- Treat cadence as host policy, not application semantic history. -- Prevent stop from interrupting half-committed work. -- Keep run-until-idle as a trusted testing/drain primitive. - -Test plan: - -- App-facing code cannot call start/stop. -- Trusted host can start with cadence policy. -- Trusted host can stop cleanly. -- Submitted work is eventually decided under host loop. -- Stop never exposes half-tick state. - -Checklist: - -- [x] Trusted host start posture exists. -- [x] Trusted host stop posture exists. -- [x] App-facing API has no start/stop/tick authority. -- [x] Cadence is host policy. -- [x] Stop is clean and typed. - -## Slice 09 - Intent Outcome Observation - -User story: As app code, I can distinguish accepted, pending, applied, -rejected, obstructed, and unknown intent outcomes. - -Work: - -- Add jedit-side outcome observation types. -- Correlate jedit app operations to Echo generic intent/submission/ticket/receipt - evidence where available. -- Stop treating dispatch acceptance as application. - -Test plan: - -- Accepted but not ticked is not applied. -- Applied mutation maps to receipt. -- Unsupported operation maps to obstruction. -- Conflict/rejection remains final for that attempt. - -Checklist: - -- [x] Outcome type exists. -- [x] Accepted/pending/applied distinction exists. -- [x] Rejection/obstruction are represented. -- [x] Receipt correlation is exposed through app-safe handles. -- [x] Tests cover non-applied accepted submission. - -## Slice 10 - Retained Evidence Lookup - -User story: As a host or diagnostic tool, I can inspect retained evidence for a -jedit edit/read flow without raw Echo internals. - -Work: - -- Add jedit-side retained evidence refs for receipt, reading envelope, payload, - package identity, and replay posture. -- Keep CAS byte identity separate from semantic reading identity. -- Return missing retention as typed obstruction. - -Test plan: - -- Reading payload hash is not query identity. -- Missing material returns obstruction. -- Retained refs include semantic coordinate. -- Host can produce evidence inventory. - -Checklist: - -- [x] Retained evidence ref type exists. -- [x] Receipt ref posture exists. -- [x] Reading envelope/payload posture exists. -- [x] Missing retention is typed. -- [x] Semantic and byte identities are distinct. - -## Slice 11 - Agent CLI Real Echo Path - -User story: As an agent, I can run one command that exercises the real -Echo-backed jedit path and returns JSON evidence. - -Work: - -- Extend the existing witness CLI to use the real package path. -- Report package install, submitted intent, lifecycle posture, outcome, reading, - retention posture, and replay posture. -- Keep dry-run mode. - -Test plan: - -- CLI dry-run reports plan. -- CLI real mode reports structured evidence. -- CLI errors are typed JSON. -- CLI does not require app tick authority. - -Checklist: - -- [x] CLI real path uses installed package flow. -- [x] CLI JSON includes install/outcome/reading evidence. -- [x] CLI dry-run stays stable. -- [x] CLI typed errors stay machine-readable. -- [x] Agent-facing docs updated. - -## Slice 12 - MCP Adapter For Agents - -User story: As an MCP agent, I can invoke the jedit Echo witness without shell -parsing and receive structured evidence. - -Work: - -- Add or extend MCP-facing adapter for the witness. -- Keep filesystem/process operations behind adapters. -- Return typed payloads matching CLI JSON. - -Test plan: - -- MCP adapter dry-run works. -- MCP adapter real witness call works when configured. -- Adapter cannot expose trusted lifecycle to app code. - -Checklist: - -- [x] MCP adapter exists or is extended. -- [x] Adapter delegates to witness port. -- [x] JSON schema matches CLI evidence. -- [x] No raw lifecycle/tick method leaks. - -## Slice 13 - Conflict And Rejection Path - -User story: As app code, I can see a lawful rejection or obstruction as an -honest outcome, not as a retry or internal fault. - -Work: - -- Add one deterministic non-happy path to the real Echo-backed jedit flow. -- Prefer unsupported operation/query first, then conflict when Echo exposes the - needed blocker evidence. -- Document retry as new causal input. - -Test plan: - -- Non-happy path returns typed outcome. -- No hidden retry occurs. -- Healthy later work can still proceed. - -Checklist: - -- [x] Non-happy path selected. -- [x] Outcome is typed. -- [x] No hidden retry. -- [x] Docs explain explicit retry doctrine. - -## Slice 14 - Echo-Hosted State And Restart Posture - -User story: As a host, I can describe what survives restart and what remains -in-memory in the current release gate. - -Work: - -- Add restart posture to witness report. -- Report the current state owner. -- Report that process-local handler state is transitional when it is still - present. -- Report Echo-hosted package/evidence posture separately from jedit's text - state owner. -- If Echo exposes durable accepted-submission recovery, consume it. -- Otherwise report typed durability obstruction. - -Test plan: - -- Witness reports restart posture. -- No half-accepted submission is claimed. -- Missing persistence is explicit. - -Checklist: - -- [x] Restart posture exists. -- [x] Current state owner is reported. -- [x] Process-local handler state is called transitional. -- [x] Echo-hosted package/evidence posture is reported. -- [x] Durable support is consumed if available. -- [x] Missing durable support is typed. -- [x] Docs avoid overclaiming persistence. - -## Slice 15 - Local Replay Proof - -User story: As a developer, I can rerun the same local jedit/Echo scenario and -compare receipts/readings deterministically. - -Work: - -- Add replay/compare command path. -- Compare stable evidence identity, not wall-clock timing. -- Keep replay local; no Continuum transport claim. - -Test plan: - -- Same inputs reproduce same outcome/reading identity. -- Wall-clock cadence is ignored. -- Mismatch reports typed replay failure. - -Checklist: - -- [x] Replay command path exists. -- [x] Stable identity comparison exists. -- [x] Wall-clock is non-semantic. -- [x] Mismatch is typed. - -## Slice 16 - Interactive TUI Adapter Cutover - -User story: As a jedit user, I can run the interactive editor with the -Echo-backed text path enabled for a narrow scenario. - -Work: - -- Add opt-in interactive mode that uses the Echo-backed session. -- Keep fallback local mode available. -- Preserve UI responsiveness. - -Test plan: - -- Interactive smoke starts. -- Narrow edit/read path uses Echo-backed session. -- Fallback mode remains available. - -Checklist: - -- [x] Opt-in Echo-backed mode exists. -- [x] Narrow interactive edit path uses Echo. -- [x] Fallback mode remains available. -- [x] UI smoke test updated. - -## Slice 17 - Release Quickstart - -User story: As a new developer, I can follow one quickstart and see jedit use -Echo for a real edit/read flow. - -Work: - -- Add quickstart commands. -- Include expected JSON snippets. -- Include troubleshooting for missing Echo WASM, missing observer, and replay - unavailability. - -Test plan: - -- Quickstart commands execute on clean checkout. -- Docs snippets match current JSON. -- Missing dependency errors are actionable. - -Checklist: - -- [x] Quickstart exists. -- [x] Commands are executable. -- [x] Expected output is current. -- [x] Troubleshooting covers common failures. - -## Slice 18 - Release Gate Quality Ratchet - -User story: As a maintainer, I can run one release-gate check that proves the -jedit/Echo path remains intact. - -Work: - -- Add `npm` script for the release gate. -- Run build, quality, focused package/handler/observer/witness tests. -- Keep it faster than full exhaustive CI where possible. - -Test plan: - -- Script passes locally. -- Script fails on missing package descriptor. -- Script fails on missing observer witness. - -Checklist: - -- [x] Release-gate script exists. -- [x] Script includes relevant focused tests. -- [x] Script is documented. -- [x] Script catches missing contract package path. - -## Slice 19 - v0.1.0 Release Documentation - -User story: As a release reader, I can see exactly what "jedit powered by Echo" -means and what remains post-release. - -Work: - -- Update release docs. -- Name non-goals clearly. -- Link evidence commands. -- Keep Echo generic boundary front and center. - -Test plan: - -- Docs links resolve. -- Release checklist references release-gate script. -- Non-goals include no Continuum transport and no full observer-rights lattice. - -Checklist: - -- [x] Release docs updated. -- [x] Evidence commands linked. -- [x] Non-goals listed. -- [x] Echo generic boundary stated. - -## Slice 20 - Release Gate Closeout - -User story: As the project owner, I can decide whether v0.1.0 is honest based -on executable evidence, not vibes. - -Work: - -- Run the release-gate script. -- Run full `npm run check`. -- Record final witness report. -- Update this plan with final status. -- Prepare release/PR notes. - -Test plan: - -- Release-gate script passes. -- Full check passes. -- Final witness report is committed or linked as appropriate. - -Checklist: - -- [x] Release-gate script passes. -- [x] `npm run check` passes. -- [x] Final witness report recorded. -- [x] Plan final status updated. -- [x] Release notes prepared. - -## Continuation Budget - -The first twenty slices proved the local jedit/Echo witness path, but they also -made the next truth visible: jedit still has transitional process-local text -state and a synchronous installed-contract adapter. The next twenty slices move -that witness toward a stricter Echo-powered shape without moving text/editor -nouns into Echo. - -Continuation target: - -```text -jedit submits generic work envelopes --> Echo/trusted host owns handler invocation timing --> jedit handlers model text state through jedit-owned Echo graph facts --> outcomes, readings, retention, restart, and replay stay honest -``` - -The continuation does not authorize Echo to know about ropes, buffers, windows, -or editor commands. Those remain jedit-owned contract semantics. - -Publication posture: this historical plan records local slice checkpoints, not -current remote truth. Agents must check `git status --short --branch`, pushed -commits, and PR state directly before claiming any slice group is published. - -## Slice 21 - Continuation Plan And Remote Posture - -User story: As a contributor, I can see exactly how the second twenty-slice -budget extends the jedit/Echo release gate without mistaking local commits for -remote PR state. - -Work: - -- Extend this plan with slices 21 through 40. -- Document that branch publication is a separate operator-approved action. -- Update `docs/BEARING.md` to point at the continuation budget. -- Keep the release target focused on jedit being powered by Echo generically, - not on a full product release. - -Test plan: - -- `git diff --check` -- Text search for the continuation phrase from `docs/BEARING.md`. - -Checklist: - -- [x] Slices 21 through 40 are recorded. -- [x] Remote publication posture is explicit. -- [x] `docs/BEARING.md` references the continuation budget. -- [x] The continuation keeps Echo generic. - -## Slice 22 - Runtime Work Envelope Boundary - -User story: As the jedit/Echo adapter, I can represent submitted work as a -generic runtime work envelope before any handler executes. - -Work: - -- Add a jedit-owned runtime work envelope port. -- Bind package id, operation name, operation kind, canonical request bytes, and - deterministic submission identity. -- Keep the envelope free of text/editor runtime nouns. -- Make envelope identity content-addressed through the existing hash port. - -Test plan: - -- Same package, operation, kind, and bytes produce the same submission id. -- Different bytes produce a different submission id. -- Operation kind is typed. -- Envelope source contains no editor semantic nouns beyond jedit ownership. - -Checklist: - -- [x] Runtime work envelope type exists. -- [x] Submission id is deterministic. -- [x] Operation kind is typed. -- [x] Envelope is free of text/editor semantic fields. -- [x] Focused envelope tests pass. - -## Slice 23 - Installed Transport Work Envelope Staging - -User story: As the installed transport, I stage a runtime work envelope for a -submitted mutation before the jedit handler path executes. - -Work: - -- Add an optional runtime work sink to the installed transport. -- Record the runtime work envelope before mutation execution. -- Preserve existing response behavior while exposing the staging witness for - tests and diagnostics. -- Do not stage query observations as mutation work. - -Test plan: - -- Installed transport records a work envelope before mutation execution. -- The envelope uses the canonical request bytes passed to `submitIntentBytes`. -- Query observation does not record mutation work. -- Existing installed transport headless flow still passes. - -Checklist: - -- [x] Installed transport accepts a work sink. -- [x] Mutation submission records a work envelope. -- [x] Envelope is recorded before handler execution. -- [x] Query observation does not stage mutation work. -- [x] Focused installed transport tests pass. - -## Slice 24 - Handler Invocation Boundary - -User story: As jedit, I can distinguish raw mutation handler registration from -Echo scheduler-owned handler invocation. - -Work: - -- Add a jedit-owned handler invocation boundary. -- Require scheduler authority for mutation handler invocation. -- Return typed blocked posture for non-scheduler invocation attempts. -- Keep the boundary outside app-facing `TextBufferOptic`. - -Test plan: - -- Scheduler authority invokes a registered mutation handler. -- Application authority is blocked before handler execution. -- Blocked invocation has typed posture. -- No app-facing object exposes the invocation authority. - -Checklist: - -- [x] Handler invocation boundary exists. -- [x] Scheduler authority is required. -- [x] Non-scheduler authority is blocked. -- [x] Blocked invocation does not call handlers. -- [x] Focused invocation tests pass. - -## Slice 25 - Scheduler-Owned Installed Handler Guard - -User story: As the installed transport, I execute jedit mutation handlers only -through the scheduler-owned invocation boundary. - -Work: - -- Route installed transport mutation execution through the handler invocation - boundary. -- Record scheduler invocation source for focused tests. -- Preserve app-facing submit/read behavior. -- Keep lifecycle/tick authority behind trusted host ports. - -Test plan: - -- Installed transport invokes handlers with scheduler authority. -- App-facing session still exposes no tick, lifecycle, install, or invocation - authority. -- Existing headless installed flow still passes. -- Quality gate remains clean. - -Checklist: - -- [x] Installed transport uses the invocation boundary. -- [x] Scheduler source is observable in tests. -- [x] App-facing authority remains absent. -- [x] Headless flow still passes. -- [x] Quality gate passes. - -## Slice 26 - Ticketed Runtime Ingress Shape - -User story: As the adapter boundary, I can model the difference between a -submitted work envelope and ticketed runtime ingress. - -Work: - -- Add ticketed ingress posture types. -- Keep admission ticket identity distinct from submission identity. -- Do not claim real Echo tickets until the Echo port supplies them. -- Report missing ticketed ingress as typed posture. - -Test plan: - -- Submission identity is not ticket identity. -- Missing ticket posture is typed. -- Existing witness reports do not overclaim ticketed ingress. - -Checklist: - -- [x] Ticketed ingress type exists. -- [x] Submission and ticket identity are distinct. -- [x] Missing ticket posture is typed. -- [x] Witness report uses the posture. - -## Slice 27 - Real Echo Receipt Correlation Adapter - -User story: As jedit, I can correlate app-safe outcome handles to Echo receipt -identity when the transport provides receipt evidence. - -Work: - -- Add a receipt correlation port. -- Preserve current transitional correlation posture when real Echo receipts are - unavailable. -- Keep unsupported/missing correlation typed. - -Test plan: - -- Real receipt evidence maps to app outcome handle. -- Missing receipt evidence remains obstruction/posture, not success. -- Unsupported operations do not fabricate receipts. - -Checklist: - -- [x] Receipt correlation port exists. -- [x] Real receipt mapping path exists. -- [x] Missing receipt posture is typed. -- [x] Tests cover unsupported operations. - -## Slice 28 - Retained Evidence Adapter Against Echo Retention - -User story: As a diagnostic host, I can ask jedit for retained evidence through -an Echo retention-shaped adapter instead of process-local summaries only. - -Work: - -- Add Echo retention lookup port for receipt, reading envelope, and payload - refs. -- Keep semantic coordinate distinct from byte hash. -- Preserve typed missing-material posture. - -Test plan: - -- Retention lookup succeeds through fake Echo retention port. -- Missing material is typed. -- Query identity is not treated as payload retention identity. - -Checklist: - -- [x] Echo retention lookup port exists. -- [x] Receipt lookup path exists. -- [x] Reading lookup path exists. -- [x] Missing material is typed. - -## Slice 29 - Echo-Hosted Contract Entity Model - -User story: As jedit, I can describe text runtime entities as jedit-owned graph -facts suitable for Echo hosting without requiring Echo editor semantics. - -Work: - -- Add jedit-owned entity/fact model for worldline, head, root, tick, and - checkpoint. -- Keep fact names in jedit code. -- Provide conversion from current process-local session to facts. - -Test plan: - -- Session converts to stable fact set. -- Historical tick and checkpoint roots have corresponding root facts. -- Fact set contains no Echo-specific editor APIs. -- Same session produces same fact identities. - -Checklist: - -- [x] Entity/fact model exists. -- [x] Session conversion exists. -- [x] Historical root references have matching root facts. -- [x] Fact identities are stable. -- [x] Tests prove deterministic conversion. - -## Slice 30 - Echo-Backed State Port - -User story: As jedit, I can read and write jedit text contract facts through a -state port that can later be backed by Echo instead of process memory. - -Work: - -- Add state port for jedit contract facts. -- Provide in-memory adapter as the current implementation. -- Route contract runtime through the port without exposing it to app code. - -Test plan: - -- Runtime can create/read/write through the state port. -- Existing contract runtime tests still pass. -- App-facing API does not expose the state port. - -Checklist: - -- [x] State port exists. -- [x] In-memory adapter exists. -- [x] Runtime can use the port. -- [x] App-facing API remains clean. - -## Slice 31 - Text Runtime Port Cutover - -User story: As jedit, the installed handler path no longer owns text state as a -private process-local implementation detail. - -Work: - -- Route installed handlers through the Echo-backed state port abstraction. -- Keep the current in-memory adapter as a test/local implementation. -- Report state owner more precisely in witness output. - -Test plan: - -- Installed flow still edits and reads text. -- Witness reports state port owner. -- Restart posture remains honest. - -Checklist: - -- [ ] Installed handlers use the state port. -- [ ] Witness reports state owner. -- [ ] Existing installed flow passes. - -## Slice 32 - Worldline Snapshot From State Port - -User story: As an observer, `worldlineSnapshot` reads from the jedit state port -instead of directly trusting session-local state. - -Work: - -- Route snapshot observer through state port where feasible. -- Preserve observer read-only authority. -- Keep current session input as compatibility until Echo supplies basis lookup. - -Test plan: - -- Snapshot observer returns state-port-backed reading. -- Observer cannot mutate state. -- Missing state basis returns typed obstruction. - -Checklist: - -- [ ] Snapshot observer uses state port. -- [ ] Read-only authority holds. -- [ ] Missing state is typed. - -## Slice 33 - Text Window From State Port - -User story: As an observer, `textWindow` reads through the same jedit state port -used by mutation handlers. - -Work: - -- Route text-window reading through state port. -- Preserve bounded aperture and byte budget. -- Keep query identity distinct from retained payload identity. - -Test plan: - -- Text window returns state-port-backed text. -- Bounds are honored. -- Missing state returns typed obstruction. - -Checklist: - -- [ ] Text-window observer uses state port. -- [ ] Bounds are honored. -- [ ] Missing state is typed. - -## Slice 34 - Durable Accepted Submission Persistence - -User story: As a trusted local host, an accepted but not yet decided jedit -submission is recoverable after restart. - -Work: - -- Add durable submission ledger port. -- Persist accepted submission identity and envelope before execution. -- Recover pending submissions without executing them during recovery. - -Test plan: - -- Accepted pending submission survives restart. -- Recovery does not execute handlers. -- Half-accepted state is impossible or obstructed. - -Checklist: - -- [ ] Durable submission ledger port exists. -- [ ] Accepted pending submission is persisted. -- [ ] Recovery is non-executing. -- [ ] Half-accepted state is rejected. - -## Slice 35 - Crash Restart Witness - -User story: As a release reviewer, I can see crash/restart behavior for -accepted, pending, decided, and missing jedit submissions. - -Work: - -- Add crash/restart witness script or test fixture. -- Cover accepted-pending, accepted-applied, rejected, and unknown submission - postures. -- Keep evidence local and deterministic. - -Test plan: - -- Restart fixture passes. -- Unknown submission is typed. -- Decided receipt correlation survives. - -Checklist: - -- [ ] Restart witness exists. -- [ ] Pending posture covered. -- [ ] Decided posture covered. -- [ ] Unknown posture covered. - -## Slice 36 - Interactive Real Runtime Path - -User story: As a user, the opt-in interactive Echo mode uses the same runtime -work envelope and state-port path as the headless witness. - -Work: - -- Remove interactive-only shortcuts around submission or state. -- Keep local fallback mode. -- Add interactive smoke evidence. - -Test plan: - -- Interactive Echo mode uses installed transport path. -- Interactive fallback mode still works. -- Smoke test covers edit/read path. - -Checklist: - -- [ ] Interactive mode uses real envelope path. -- [ ] Interactive mode uses state-port path. -- [ ] Fallback remains available. - -## Slice 37 - Conflict Or Rejection With Echo Evidence - -User story: As app code, I can observe a real conflict/rejection outcome with -Echo-shaped evidence rather than a synthetic unsupported-operation placeholder. - -Work: - -- Add deterministic conflict/rejection witness when the Echo boundary exposes - enough evidence. -- Keep retry explicit. -- Preserve healthy later work. - -Test plan: - -- Conflict/rejection outcome is typed. -- No hidden retry occurs. -- Later unrelated work proceeds. - -Checklist: - -- [ ] Real conflict/rejection witness exists. -- [ ] Retry remains explicit. -- [ ] Healthy later work proceeds. - -## Slice 38 - Release Gate Upgrade - -User story: As a maintainer, the release-gate script proves the stricter -runtime-envelope, scheduler-invocation, state-port, persistence, and replay -truths. - -Work: - -- Add slices 21-37 focused tests to `release-gate:echo`. -- Keep the script reasonably fast. -- Report which phase failed. - -Test plan: - -- Release-gate script passes. -- Removing envelope staging fails the gate. -- Removing state-port path fails the gate. - -Checklist: - -- [ ] Release gate includes continuation tests. -- [ ] Script remains focused. -- [ ] Failure reporting is clear. - -## Slice 39 - v0.1.0 Release Docs Upgrade - -User story: As a release reader, I can distinguish the stricter powered-by-Echo -claim from the earlier transitional process-local witness. - -Work: - -- Update v0.1.0 release docs with continuation evidence. -- Name remaining post-v0.1 limits. -- Keep Echo generic boundary prominent. - -Test plan: - -- Release docs reference current evidence commands. -- Non-goals remain explicit. -- No docs claim Echo knows jedit semantics. - -Checklist: - -- [ ] Release docs updated. -- [ ] Evidence commands current. -- [ ] Non-goals current. -- [ ] Echo generic boundary stated. - -## Slice 40 - Continuation Closeout - -User story: As the project owner, I can decide whether the stricter local -jedit-powered-by-Echo gate is ready for PR or release-candidate inspection. - -Work: - -- Run release-gate script. -- Run full `npm run check`. -- Record continuation witness. -- Update this plan status. -- Prepare PR/release notes. - -Test plan: - -- Release-gate script passes. -- Full check passes. -- Continuation witness is committed or linked. - -Checklist: - -- [ ] Release-gate script passes. -- [ ] `npm run check` passes. -- [ ] Continuation witness recorded. -- [ ] Plan status updated. -- [ ] PR/release notes prepared. diff --git a/docs/design/0025-echo-application-hosting-pattern.md b/docs/design/0025-echo-application-hosting-pattern.md deleted file mode 100644 index 85e1a84f..00000000 --- a/docs/design/0025-echo-application-hosting-pattern.md +++ /dev/null @@ -1,469 +0,0 @@ -# Echo Application Hosting Pattern - -Status: active post-release-pressure direction - -This document records the reusable application-hosting pattern that `jedit` -must prove before the same model is trusted for Graft, Think, or other Echo -applications. - -The goal is no longer to force a release label. The goal is to make the -architecture correct. - -## Claim - -An Echo-hosted application is a domain-owned contract package installed into a -generic Echo runtime boundary. The application owns its nouns, state model, -mutation handlers, query observers, and app-safe capability API. Echo owns -generic admission, scheduling, tick authority, receipt posture, retained -evidence, query routing, and obstruction/fault posture. - -For `jedit`, that means: - -```text -jedit owns TextBufferOptic, text windows, roots, buffers, cursors, panes, -commands, and editor policy. - -Echo never owns those nouns. -``` - -The reusable pattern is: - -```text -App GraphQL contract --> Wesley generated helpers/codecs/metadata --> app-owned package descriptor --> app-owned mutation handlers --> app-owned query observers --> app-owned state and submission ports --> generic Echo transport/admission/scheduler/retention boundaries --> app-safe client capability -``` - -## Why This Exists - -The first thirty slices proved that `jedit` can expose an Echo-shaped witness -path without giving the app tick authority and without moving `jedit` nouns into -Echo. That is necessary, but not sufficient. - -The next work must prove the hosting pattern itself: - -- writes and reads converge on one app-owned state authority; -- submission is separate from execution; -- ticketed work is separate from accepted submission; -- receipt correlation is real when execution is decided; -- retained evidence is inspectable; -- local restart posture is honest; -- at least one second app-shaped contract can follow the same recipe. - -The test app is `jedit`, but the deliverable is a repeatable application-hosting -spine. - -## Ownership Boundaries - -| Boundary | Owned By | Examples | Forbidden Leakage | -|---|---|---|---| -| Domain vocabulary | App | `TextBufferOptic`, text window, cursor, workflow, note | Echo core imports app nouns | -| Contract schema | App | GraphQL SDL, operation names, query names | Echo edits product schemas | -| Code generation | Wesley | typed helpers, codecs, metadata | hand-written generated shadows | -| Package descriptor | App adapter | package id, schema hash, operation ids | app capability installs packages | -| Mutation handlers | App host code | jedit replace/checkpoint handlers | application dispatch invokes handlers | -| Query observers | App host code | jedit text-window observer | observer mutates state or ticks | -| State authority | App port/adapter | jedit contract facts, state port | caller-owned session object as truth | -| Submission ledger | Host/app adapter | accepted submission identity | hidden execution during acceptance | -| Scheduling and ticks | Echo trusted runtime | run-until-idle, receipts | app code controls ticks | -| Retention | Echo/app adapter seam | receipts, readings, payload refs | byte hash treated as semantic identity | - -## Authority Bar - -These constraints are release-independent. They are the shape of correctness. - -- Application code cannot tick Echo. -- Application code cannot access trusted runtime control. -- Application dispatch does not execute synchronously. -- App-safe capability APIs do not expose package install, handler invocation, - state-port write access, lifecycle control, or tick control. -- Mutation handlers run only behind scheduler-authority invocation. -- Query observers are read-only. -- Submission identity is not ticket identity. -- Admission or ticket posture is not execution. -- Receipt correlation happens only after a decided runtime outcome. -- Conflict or rejection is final for that attempt. -- Retry is a new explicit causal input. -- Wall-clock cadence is host/runtime policy, not semantic history. - -## Generic Hosting Flow - -```mermaid -sequenceDiagram - participant App as App Capability - participant Adapter as App Adapter - participant Wesley as Wesley Helpers - participant Echo as Generic Echo Boundary - participant Handler as App Handler - participant State as App State Port - participant Observer as App Query Observer - - App->>Adapter: submit app intent - Adapter->>Wesley: encode canonical request - Adapter->>Echo: submit package operation bytes - Echo-->>Adapter: accepted submission posture - Echo->>Echo: admission and scheduler-owned tick - Echo->>Handler: invoke with scheduler authority - Handler->>State: read/write app facts - Handler-->>Echo: app-owned result evidence - Echo-->>Adapter: receipt / obstruction posture - App->>Adapter: observe app query - Adapter->>Echo: QueryView / query request - Echo->>Observer: read-only observer context - Observer->>State: read app facts - Observer-->>Echo: bounded reading - Echo-->>App: payload + reading evidence -``` - -## Port/Adapter Rule - -Every crossing that could become a second app's integration point must be behind -a port or adapter. In particular: - -- app-facing UI and command code speaks to app capabilities; -- app capabilities speak to app client ports; -- app client ports encode/decode at adapters; -- installed packages speak through package host ports; -- handlers speak through state ports; -- observers speak through read-only state/query ports; -- submission and retention use explicit ledger/lookup ports; -- Echo-facing code sees generic package, operation, query, ticket, receipt, - reading, obstruction, and retained-evidence shapes. - -If a direct call would teach a future Graft or Think implementation a `jedit` -detail, it belongs behind a port. - -## jedit Instantiation - -For `jedit`, the pattern currently maps like this: - -| Generic Role | jedit Concrete Surface | -|---|---| -| app-safe capability | `TextBufferOptic` | -| app contract | `contracts/jedit/hot-text-runtime.graphql` | -| package descriptor | `jedit.hot-text-runtime` descriptor | -| mutation handlers | create buffer, replace range, checkpoint | -| query observers | worldline snapshot, text window | -| state model | jedit-owned roots, heads, ticks, checkpoints, fact sets | -| submission evidence | jedit submission ids and pending/app outcome posture | -| retained evidence | package, receipt, reading-envelope, and payload refs | -| local witness | `scripts/jedit-echo-powered-session.mjs` | - -The app-facing API may use `TextBufferOptic`. The Echo-facing transport must -not. Echo sees installed package operations and query observers. - -## Second-App Litmus Test - -This pattern is not proven until a second small contract can follow it without -copying `jedit` internals. - -The second-app proof can be intentionally small, such as a counter or todo -contract. It must still exercise the same shape: - -- Wesley schema and generated helpers; -- package descriptor; -- mutation handler; -- query observer; -- state port; -- submission ledger; -- receipt or obstruction posture; -- retained reading or payload evidence; -- no imports from `jedit` product modules except shared test harness utilities. - -If the second app needs to know `TextBufferOptic`, the architecture failed. - -## Next Ten Slices - -These slices supersede the release-pressure continuation shape after slice 30. -They keep `jedit` as the proof app, but the objective is reusable hosting -correctness rather than release ceremony. - -### Slice 31 - Application Hosting Contract Pattern - -User story: As a future Echo application author, I can read one document and -understand where app semantics, generated code, app adapters, and generic Echo -runtime boundaries belong. - -Work: - -- Define the reusable Echo application-hosting pattern. -- State the ownership and authority boundaries. -- Show how `jedit` instantiates the pattern. -- Name the second-app litmus test. -- Point the repo bearing at this direction. - -Test plan: - -- `git diff --check` -- `npm run --silent quality` -- Manual review that the document does not move `jedit` nouns into Echo. - -Checklist: - -- [x] Hosting pattern document exists. -- [x] Ownership boundaries are explicit. -- [x] Authority bar is explicit. -- [x] `jedit` instantiation is mapped. -- [x] Second-app litmus test is named. - -### Slice 32 - jedit State Authority Cutover - -User story: As `jedit`, installed mutation handlers use the jedit contract -state port as their state authority instead of private process-local state. - -Work: - -- Route installed handlers through the state port. -- Keep the in-memory adapter as the local implementation. -- Prevent app-facing code from writing or reading fact sets directly. - -Test plan: - -- Installed mutation flow writes through the state port. -- App-facing `TextBufferOptic` exposes no state-port methods. -- Existing installed headless flow still edits and reads text. - -Checklist: - -- [x] Installed handlers use the state port. -- [x] In-memory adapter remains behind the port. -- [x] App-facing API remains clean. -- [x] Existing installed flow passes. - -### Slice 33 - Read-Side State Authority Cutover - -User story: As an observer, jedit query observers read from the same state -authority used by mutation handlers. - -Work: - -- Route `worldlineSnapshot` through state-port-backed state. -- Route `textWindow` through state-port-backed state. -- Preserve read-only observer authority. -- Preserve bounded aperture and byte budget. - -Test plan: - -- Snapshot observer returns state-port-backed reading. -- Text-window observer returns state-port-backed reading. -- Missing basis/state returns typed obstruction. -- Query observer cannot mutate state or tick. - -Checklist: - -- [x] Snapshot observer uses state port. -- [x] Text-window observer uses state port. -- [x] Missing state is typed. -- [x] Read-only authority holds. - -### Slice 34 - Submission Ledger Port - -User story: As a host adapter, I can record accepted jedit submissions without -pretending they executed synchronously. - -Work: - -- Add submission ledger port. -- Record accepted submission identity and canonical envelope before runtime - work can decide it. -- Keep ledger write authority away from app-facing capability code. - -Test plan: - -- Accepted submission is recorded before handler execution. -- Duplicate canonical submission returns same identity or duplicate posture. -- Recording a submission does not tick, mutate text state, or dispatch handlers. -- App-facing code cannot write ledger entries directly. - -Checklist: - -- [x] Submission ledger port exists. -- [x] Accepted submission is recorded before execution. -- [x] Duplicate posture is deterministic. -- [x] App-facing API cannot write ledger entries. - -### Slice 35 - Ticketed Work Boundary - -User story: As an Echo-hosted app, accepted submission and runtime work are -separate; only ticketed work can reach handler invocation. - -Work: - -- Route jedit installed work through a ticketed work boundary. -- Preserve submission id, package id, operation id, and basis identity. -- Keep ticket identity distinct from submission identity. - -Test plan: - -- Unticketed work cannot invoke handlers. -- Ticketed work preserves submission and operation identity. -- Missing ticket posture is typed. -- Ticketed work does not imply execution until scheduler-authority invocation. - -Checklist: - -- [x] Ticketed work boundary exists. -- [x] Unticketed work is blocked. -- [x] Ticket and submission identities are distinct. -- [x] Handler invocation still requires scheduler authority. - -### Slice 36 - Real Receipt Correlation - -User story: As an app, I can correlate a decided jedit submission to the receipt -that decided it. - -Work: - -- Replace transitional missing correlation on the happy path. -- Correlate submission, ticket/work, and receipt identity. -- Keep unsupported and incomplete paths typed. - -Test plan: - -- Applied jedit intent maps to receipt correlation. -- Missing receipt remains typed outside decided paths. -- Unsupported operation does not fabricate receipt. -- Witness report carries real correlation where available. - -Checklist: - -- [x] Happy path has real receipt correlation. -- [x] Missing receipt remains typed. -- [x] Unsupported operation does not fabricate receipt. -- [x] Witness report exposes correlation. - -### Slice 37 - Real Local Retained Evidence Lookup - -User story: As a diagnostic host or agent, I can load retained jedit evidence -material through the retention lookup boundary. - -Work: - -- Store/load receipt material. -- Store/load reading envelope material. -- Store/load reading payload material. -- Preserve semantic coordinate versus byte identity distinction. - -Test plan: - -- Receipt material loads by byte hash. -- Reading envelope material loads by byte hash. -- Reading payload material loads by byte hash. -- Missing material returns obstruction. -- Semantic coordinate mismatch does not become a cache hit. - -Checklist: - -- [x] Receipt material lookup works. -- [x] Reading envelope lookup works. -- [x] Reading payload lookup works. -- [x] Semantic coordinate and byte identity remain distinct. - -### Slice 38 - Restart And Recovery Witness - -User story: As a local host operator, I can restart and observe honest posture -for pending, decided, rejected, and unknown submissions. - -Work: - -- Add deterministic restart witness fixture. -- Cover pending, decided, rejected, and unknown postures. -- Ensure recovery does not execute handlers. - -Test plan: - -- Pending submission recovers as pending. -- Decided submission recovers with receipt correlation. -- Unknown submission remains typed. -- Half-accepted state is impossible or obstructed. - -Checklist: - -- [x] Restart witness exists. -- [x] Pending posture covered. -- [x] Decided posture covered. -- [x] Unknown posture covered. -- [x] Recovery is non-executing. - -### Slice 39 - Second-App Template Proof - -User story: As a future Echo app author, I can see a tiny non-jedit contract -hosted through the same pattern. - -Work: - -- Add a minimal second contract fixture. -- Generate or provide its app-owned helper surface. -- Install package descriptor, mutation handler, query observer, and state port. -- Prove no `jedit` product module imports are required. - -Test plan: - -- Second app installs through same hosting shape. -- Second app mutation and query path pass. -- Echo-facing abstractions do not import jedit modules. -- App-specific nouns stay in the app fixture. - -Checklist: - -- [x] Second contract fixture exists. -- [x] Same hosting shape works. -- [x] No jedit product imports leak into the second app. -- [x] Generic helper docs cover both apps. - -### Slice 40 - Developer App Host Guide - -User story: As a developer building Graft, Think, or another app on Echo, I can -follow a concrete guide rather than reverse-engineering `jedit`. - -Work: - -- Write the app-host guide. -- Include mutation flow, query flow, submission/outcome lifecycle, and authority - diagrams. -- Link evidence commands and required tests. -- Update BEARING with the completed status. - -Test plan: - -- Documentation links are valid. -- Example commands run. -- The guide names required tests for a new app. - -Checklist: - -- [x] Developer guide exists. -- [x] Diagrams are included. -- [x] Evidence commands are current. -- [x] BEARING reflects completed status. - -## Non-Goals - -These are intentionally outside this ten-slice plan: - -- release tagging; -- package publishing; -- browser packaging; -- streaming subscriptions; -- distributed replica import; -- settlement shells; -- full observer-rights governance; -- social/speculative lane policy; -- moving `jedit` semantics into Echo. - -## Completion Bar - -This ten-slice plan is complete when the repository can honestly say: - -```text -jedit proves the reusable Echo application-hosting pattern. jedit owns its -domain semantics; Echo remains generic; Wesley supplies generated contract -surfaces; app-hosting uses explicit ports for package install, submission, -ticketed work, state, query observation, receipt correlation, retention, and -restart posture. -``` diff --git a/docs/design/0026-echo-hosting-hardening-first-twenty.md b/docs/design/0026-echo-hosting-hardening-first-twenty.md deleted file mode 100644 index 6b5d998b..00000000 --- a/docs/design/0026-echo-hosting-hardening-first-twenty.md +++ /dev/null @@ -1,388 +0,0 @@ -# Echo Hosting Hardening - Next Twenty Slices - -Status: active follow-on plan - -This plan extends the reusable Echo application-hosting pattern after -[`0025-echo-application-hosting-pattern.md`](0025-echo-application-hosting-pattern.md). -The goal is still not release ceremony. The goal is to make `jedit` a -credible proof app for Echo without teaching Echo any `jedit` semantics. - -## Claim - -`jedit` should be powered by Echo through ports, adapters, generated helpers, -installed contract packages, trusted runtime lifecycle control, bounded -readings, retained evidence, and replay witnesses. Echo must remain generic: -it owns admission, scheduling, ticks, receipts, query routing, retention, and -fault posture; `jedit` owns editor vocabulary, text law, handler behavior, -query observer behavior, and app-safe capability APIs. - -## Slice Budget - -### Slice 41 - Trusted Runtime Lifecycle Doctrine Closure - -User story: As a host operator, I can start, drain, and stop the trusted Echo -runtime without giving application code tick authority. - -Test plan: - -- Lifecycle port exposes start, run-until-idle, and stop. -- Lifecycle port exposes no discrete tick injection. -- Session witness records host lifecycle requests separately from app intent. - -Checklist: - -- [x] Trusted start cadence exists on the lifecycle port. -- [x] Start cadence remains trusted host control. -- [x] Application capability still exposes no tick control. -- [x] Witness summary records start, drain, and stop posture. - -### Slice 42 - Runtime Host Port Finalization - -User story: As a future Echo app author, I can depend on a lifecycle port shape -that describes host policy instead of raw Echo control bytes. - -Test plan: - -- Adapter encodes start/drain/stop through the trusted host control transport. -- Failed start does not mark the host loop as running. -- App-facing sessions do not expose the lifecycle port. - -Checklist: - -- [x] Lifecycle codec owns start/drain/stop bytes. -- [x] Trusted runtime loop calls lifecycle start before it can drain. -- [x] Rejected start leaves drain unavailable. -- [x] App-facing sessions expose no lifecycle methods. - -### Slice 43 - Echo Adapter Lifecycle Integration - -User story: As `jedit`, the real Echo-powered witness can report host lifecycle -posture next to app submission and reading evidence. - -Test plan: - -- CLI witness reports startup, drain, and shutdown. -- CLI witness keeps app-facing capability separate from trusted host lifecycle. -- CLI witness still reports bounded reading evidence. - -Checklist: - -- [x] CLI witness records startup. -- [x] CLI witness records drain. -- [x] CLI witness records shutdown. -- [x] CLI witness still returns reading evidence. - -### Slice 44 - Lifecycle Failure Posture - -User story: As a host operator, a rejected lifecycle start is not silently -converted into a running loop. - -Test plan: - -- Runtime loop rejected start returns stopped posture. -- Drain after rejected start returns not-running posture. -- No scheduler drain request is issued after rejected start. - -Checklist: - -- [x] Rejected start posture is tested. -- [x] Drain is blocked after rejected start. -- [x] No hidden run-until-idle happens after rejected start. - -### Slice 45 - Agent Lifecycle Surface - -User story: As an agent, I can run the `jedit` Echo witness through the CLI/MCP -surface without receiving lifecycle or tick authority. - -Test plan: - -- MCP adapter exposes only the witness call. -- CLI emits lifecycle posture as evidence. -- Neither surface exposes tick, start, stop, or raw trusted lifecycle methods. - -Checklist: - -- [x] MCP adapter remains witness-only. -- [x] CLI exposes lifecycle posture as data. -- [x] Agent-facing surface has no tick authority. - -### Slice 46 - Contract Package Identity Audit - -User story: As a trusted host, I can install a package through one descriptor -that binds schema, artifact, codec, mutation operations, query operations, and -observer plan identities. - -Test plan: - -- Installer forwards all descriptor identity fields to the generic package host. -- Recording host treats exact duplicate install as idempotent. -- Recording host rejects conflicting package identity for the same package id. - -Checklist: - -- [x] Package install request carries complete identity. -- [x] Duplicate identical install is idempotent. -- [x] Conflicting same-id package install is blocked. - -### Slice 47 - No App Nouns In Echo Gate - -User story: As an Echo maintainer, I can prove production Echo source does not -carry hardcoded `jedit` fixture shortcuts. - -Test plan: - -- Echo guard scans production crate source for forbidden app-specific fixture - tokens. -- Guard passes on current Echo main. -- Guard does not ban generic byte/text buffer implementation vocabulary. - -Checklist: - -- [x] Echo source noun guard exists. -- [x] Guard targets production crate source. -- [x] Guard passes after Stack Witness shortcut removal. - -### Slice 48 - jedit Contract Package Install Fixture - -User story: As `jedit`, I can inject a package host and prove package install -posture controls whether runtime work can reach handlers. - -Test plan: - -- Installed transport accepts injected package host. -- Non-installed package posture obstructs before handler invocation. -- Non-installed package posture obstructs before runtime work envelope staging. - -Checklist: - -- [x] Installed transport accepts package host injection. -- [x] Blocked install obstructs mutation response. -- [x] Blocked install does not invoke handlers. -- [x] Blocked install does not stage runtime work. - -### Slice 49 - Unsupported Operation Boundary - -User story: As `jedit`, unsupported mutation and query names fail before they -become runtime-visible work or accepted reads. - -Test plan: - -- Package operation classifier rejects unsupported mutation. -- Package operation classifier rejects unsupported query. -- Unsupported operation witness is final for that attempt. - -Checklist: - -- [x] Unsupported mutation classification exists. -- [x] Unsupported query classification exists. -- [x] Unsupported mutation CLI witness has no hidden retry. - -### Slice 50 - Package Reinstall And Duplicate Policy - -User story: As a trusted host, reinstalling the same package is safe, while a -same-id package with changed identity is blocked. - -Test plan: - -- First install succeeds. -- Identical reinstall succeeds. -- Same package id with different artifact identity is blocked. - -Checklist: - -- [x] First install succeeds. -- [x] Identical reinstall succeeds. -- [x] Conflicting reinstall is blocked. - -## Drift Closure Before Slice 51 - -The slice-50 reflection found four drift risks. They are closed or explicitly -bounded here before the next slice batch starts. - -Checklist: - -- [x] Local witness evidence is stamped as `LOCAL_PROCESS_WITNESS` and does not - claim durable receipt correlation, ticketed runtime ingress, or accepted - submission recovery. -- [x] Retained material lookup requires both byte identity and semantic - coordinate match; byte hash alone is not retained evidence. -- [x] Echo's app-noun guard is intentionally production-source-scoped. Tests and - docs may contain app-shaped fixtures only as external-consumer examples. -- [x] Durable restart persistence remains future work under slice 55; current - witness output must continue reporting partial restart posture. -- [x] PR/CI review state remains branch process, not architectural truth. -- [x] `TextBufferSessionPort` owns the jedit app-facing session boundary, while - `createEchoBackedTextBufferSession(...)` is only one adapter behind the port. - -### Slice 51 - Ticketed Mutation Execution Tightening - -User story: As `jedit`, mutation handlers run only after ticketed runtime work -is available and scheduler authority is present. - -Test plan: - -- Unticketed work cannot invoke handlers. -- Application capability cannot invoke handlers. -- Scheduler authority remains a runtime object, not an app string. - -Checklist: - -- [x] Unticketed work blocks handler invocation. -- [x] App authority cannot invoke handlers. -- [x] Scheduler authority object is explicit. - -### Slice 52 - Query Observer Read-Only Tightening - -User story: As `jedit`, query observers can read bounded state but cannot write -or tick. - -Test plan: - -- Query observer context has no write methods. -- Query observer context has no lifecycle or tick methods. -- Query observer failures map to query obstruction, not package install - failure. - -Checklist: - -- [x] Query observer context remains read-only. -- [x] Query observer has no lifecycle surface. -- [x] Query runtime failures remain typed. - -### Slice 53 - Receipt Correlation Happy Path Closure - -User story: As `jedit`, an applied mutation can be mapped to the receipt that -decided it without fabricating receipt evidence. - -Test plan: - -- Applied mutation reports real correlation. -- Unsupported mutation reports missing/unsupported correlation. -- Correlation identity survives witness summary serialization. - -Checklist: - -- [x] Applied mutation reports real correlation. -- [x] Unsupported mutation does not fabricate receipt. -- [x] CLI summary carries correlation identity. - -### Slice 54 - Retained Reading Lookup Closure - -User story: As an agent, I can inspect retained reading material by semantic -coordinate and byte identity. - -Test plan: - -- Reading envelope lookup works. -- Reading payload lookup works. -- Same bytes under different semantic coordinates do not alias. - -Checklist: - -- [x] Envelope lookup works. -- [x] Payload lookup works. -- [x] Semantic coordinate mismatch is not a cache hit. - -### Slice 55 - Restart Persistence Adapter Boundary - -User story: As a host operator, pending and decided submission posture can be -loaded through a restart adapter instead of process-local memory claims. - -Test plan: - -- Pending posture loads through adapter. -- Decided posture loads through adapter. -- Half-accepted posture remains obstructed. - -Checklist: - -- [x] Restart adapter exists. -- [x] Pending posture loads. -- [x] Decided posture loads. -- [x] Half-accepted posture is blocked. - -### Slice 56 - Local Replay Proof Hardening - -User story: As a maintainer, replay compares semantic receipt and reading -identity, not wall-clock timing or diagnostic strings. - -Test plan: - -- Replay witness compares package, receipt, reading, and payload identity. -- Wall-clock cadence is explicitly non-semantic. -- Diagnostic strings do not decide replay equality. - -Checklist: - -- [x] Replay identity excludes wall-clock timing. -- [x] Replay equality avoids diagnostic prose. -- [x] Replay witness is deterministic. - -### Slice 57 - Second-App Template Authority Audit - -User story: As a future app author, the counter template proves the pattern -without importing `jedit` product modules. - -Test plan: - -- Counter template install path passes. -- Counter template mutation/query path passes. -- Static import audit rejects `jedit` product imports. - -Checklist: - -- [x] Counter install path passes. -- [x] Counter mutation/query path passes. -- [x] Import audit passes. - -### Slice 58 - Developer Guide Drift Check - -User story: As a developer, the hosting guide matches the executable witness -commands and current port names. - -Test plan: - -- Guide command snippets run or are checked by tests. -- Guide names current lifecycle and package ports. -- Guide does not imply app-controlled ticking. - -Checklist: - -- [x] Guide commands are current. -- [x] Port names are current. -- [x] Tick authority doctrine is correct. - -### Slice 59 - PR Release Gate Consolidation - -User story: As a reviewer, one command proves the current `jedit` Echo hosting -surface. - -Test plan: - -- Release gate runs build, quality, hosting witness, replay witness, and core - static guards. -- Failure output names the failed witness. - -Checklist: - -- [x] Release gate includes hosting witness. -- [x] Release gate includes replay witness. -- [x] Release gate includes static guards. - -### Slice 60 - Drift Reflection And Next Plan - -User story: As maintainers, we can pause after the hardening batch and decide -whether the next work is receipt correlation, retention, replay, UI adoption, -or Echo core support. - -Test plan: - -- Reflection document names remaining gaps. -- BEARING points at the next active plan. -- No completed slice is left unchecked. - -Checklist: - -- [x] Reflection exists. -- [x] BEARING is current. -- [x] Next active slice is explicit. diff --git a/docs/design/0027-echo-hosted-production-cutover.md b/docs/design/0027-echo-hosted-production-cutover.md deleted file mode 100644 index 66070870..00000000 --- a/docs/design/0027-echo-hosted-production-cutover.md +++ /dev/null @@ -1,522 +0,0 @@ -# Echo-Hosted Production Cutover - Next Twenty Slices - -Status: active plan after slices 51-60 merge - -This plan follows -[`0026-echo-hosting-hardening-first-twenty.md`](0026-echo-hosting-hardening-first-twenty.md). -Slices 51-60 closed the app-hosting witness path: ticketed mutation authority, -read-only query observers, local receipt correlation, retained reading lookup, -restart recovery adapter shape, replay identity, second-app template identity, -guide drift checks, and the release gate are now explicit. - -The next goal is not to preserve an optional "Echo mode." That wording was -useful during transition, but the production target is sharper: - -```text -jedit's production text model is Echo-hosted. -The legacy in-memory text model is deleted, quarantined as a test fixture, or -kept only as an adapter-local implementation detail behind ports. -Echo remains generic and never learns jedit nouns. -``` - -## Doctrine - -- Identity follows the locked - [`echo-identity-doctrine.md`](echo-identity-doctrine.md): values are hashed, - things are declared IDs, names are bindings, and views are Basis. -- `EchoHosted` is jedit host terminology, not Echo terminology. -- Echo must not define `TextBufferOptic`, text buffers, ropes, panes, cursors, - text windows, filesystem save policy, or editor commands. -- jedit owns the contract semantics, handlers, observers, app-safe capability - APIs, and artifact export policy. -- Echo owns generic admission, scheduling, trusted ticks, receipts, retention, - QueryView routing, installed package boundaries, faults, and causal-history - serialization. -- The local in-memory text model is no longer a production authority target. It - may remain only while it is explicitly marked as a test/dev fixture or hidden - behind an adapter port. - -## Production Cutover Acceptance Bar - -Production cutover is complete only when all of these are true: - -- production text editing flows are Echo-hosted by default; -- no product path depends on the legacy in-memory text model as source of - truth; -- any retained legacy model is quarantined as a test fixture or adapter-local - implementation detail behind ports; -- jedit text materialization is derived from Echo causal state through jedit - ports and contract-owned observers; -- Echo contains no jedit nouns, text-buffer nouns, or editor-specific - semantics; -- export reads from an Echo causal basis and does not mutate Echo state; -- WSC durability work is explicitly deferred until after slice 80 unless a prior - slice exposes an unavoidable storage dependency; -- the release gate proves the production cutover instead of merely proving a - headless witness path. - -## Current Reflection - -The previous branch closed the hardening batch without changing Echo's -authority boundary: - -- handler invocation requires scheduler authority and cannot be forged by a - matching caller string; -- query observers expose no lifecycle, tick, mutation, state-write, or transport - submission methods; -- applied local witness runs report a real local receipt correlation; -- unsupported mutation witnesses do not fabricate receipt evidence; -- retained material lookup requires byte identity plus semantic coordinate; -- restart recovery has a named adapter boundary; -- replay equality ignores wall-clock cadence and diagnostic prose; -- the counter template now proves package identity and install shape without - importing jedit modules; -- the hosting guide and release gate include the current hardening witnesses. - -Remaining gaps before the phrase "jedit is powered by Echo" is fully honest: - -- the production text session/controller surface exists for open, edit, - obstruction, checkpoint, export, local replay, and bounded read posture; -- the release gate now proves the production text session witness and guard; -- interactive workspace open/edit/render wiring must still move onto that - production session/controller surface; -- editor save/export UI behavior must still distinguish filesystem persistence - from Echo causal/evidence posture; -- UI-level obstruction and retry affordances must be explicit; -- production imports must stop depending on legacy direct text-state mutation; -- durable accepted-submission recovery remains future work; -- durable/Continuum replay remains future work; -- the current witness still reports `TICKETED_RUNTIME_INGRESS_MISSING` until - Echo exposes that concrete runtime evidence to the app-facing report. - -## Slice 61-70 Checkpoint - -Slices 61-70 close the production session/controller boundary, not the final -interactive UI cutover. That distinction is intentional: - -```text -text runtime profile --> TextBufferSessionPort --> production text session controller --> open/edit/read/obstruction posture -``` - -The remaining interactive workspace imports are still visible in the authority -inventory and become the target for the next slices. Do not hide that drift by -calling the legacy `EditorState.lines` path production-complete. - -## Slice 71-80 Checkpoint - -Slices 71-80 close the production text session witness and release-gate layer: - -```text -production text session --> open/edit/checkpoint/read/export --> retained refs --> local replay --> static guard --> release gate -``` - -This is still not the final interactive TUI cutover. The remaining direct -`EditorState.lines` paths stay visible in the authority inventory. The next -batch must make the workspace event loop consume the production text session as -its only product text authority, then delete or fixture-scope the direct line -model. - -## Post-Slice-80 Requirement: WSC Causal History And Export - -After the production cutover, the next product bar is durable causal-history -recovery through Echo's WSC file format: - -```text -Echo natively serializes its generic causal history into WSC. -The entire causal history of editing a file in jedit is recoverable between -application lifecycles. -jedit can materialize file artifacts from any point in time through an export -flow. -``` - -Ownership remains strict: - -- Echo owns WSC serialization of generic causal history, receipts, witnesses, - frontiers, retained artifact coordinates, and replayable runtime evidence. -- jedit owns the interpretation of that history as editor buffers, text - materializations, file artifacts, and export formats. -- A WSC file is not a jedit file format. It is Echo causal-history storage. -- A jedit export is not Echo state mutation. It is a jedit-owned reading and - materialization over an Echo causal basis. - -This requirement is intentionally post-slice-80 unless a prior slice exposes an -unavoidable storage dependency. The production cutover should not fake durable -WSC recovery with process-local memory. - -## Slice Budget - -### Slice 61 - Runtime Terminology Cleanup - -User story: As a maintainer, I can read docs and public jedit names without -mistaking transitional "Echo mode" for an Echo-owned runtime concept. - -Test plan: - -- Docs use `Echo-hosted` for jedit host posture. -- App-facing names avoid implying Echo owns text semantics. -- Legacy "Echo mode" wording is either removed or marked transitional. - -Checklist: - -- [x] Docs use `Echo-hosted` terminology. -- [x] Public jedit names do not imply Echo-owned text semantics. -- [x] Transitional wording is bounded. - -### Slice 62 - Production Runtime Authority Inventory - -User story: As a maintainer, I can see every interactive editor path that reads -or writes text state and whether it already goes through `TextBufferSessionPort`. - -Test plan: - -- Static inventory lists direct editor-state text mutation/read paths. -- Inventory distinguishes app-owned session ports from direct in-memory helpers. -- No Echo or text semantics are added to Echo core. - -Checklist: - -- [x] Inventory document exists. -- [x] Direct read/write paths are listed. -- [x] Next cutover targets are explicit. - -### Slice 63 - Runtime Profile Port - -User story: As a host operator, I can construct the production -`TextBufferSessionPort` through a jedit-owned runtime profile port, while -legacy local state remains outside production runtime selection. - -Test plan: - -- Runtime profile accepts `echoHosted` as the only production profile. -- Unknown profile returns typed configuration obstruction. -- Selected app session exposes no tick, lifecycle, package install, handler, or - state-port authority. - -Checklist: - -- [x] Runtime profile port exists. -- [x] `echoHosted` creates a `TextBufferSessionPort`. -- [x] Non-Echo profile input is rejected. -- [x] Invalid profile is typed. -- [x] App session authority remains narrow. - -### Slice 64 - Echo-Hosted Default Behind Host Configuration - -User story: As a host operator, the configured production runtime profile is -Echo-hosted, while local in-memory helpers remain focused test scaffolding. - -Test plan: - -- Default production configuration selects Echo-hosted session creation. -- Development/test fixtures inject fake ports directly. -- Product UI does not expose runtime selection as a normal user feature. - -Checklist: - -- [x] Production default is Echo-hosted. -- [x] Non-Echo runtime profile selection is absent. -- [x] User-facing mode switch is absent. - -### Slice 65 - Buffer Open Cutover - -User story: As a user in the production Echo-hosted profile, opening a buffer -creates the editor buffer through `TextBufferSessionPort.createBuffer(...)`. - -Test plan: - -- Production open calls `TextBufferSessionPort.createBuffer`. -- Local fixture path still preserves existing test behavior. -- Open does not request lifecycle drain or direct tick. - -Checklist: - -- [x] Production open uses the session port. -- [x] Local fixture path remains available for tests. -- [x] Open has no tick authority. - -### Slice 66 - Edit Command Cutover I - -User story: As a user, insert and replace commands submit canonical app intents -through the session port. - -Test plan: - -- Insert command calls `applyIntent` on the app capability. -- Replace command calls `applyIntent` on the app capability. -- The command records obstruction instead of mutating UI state on failed apply. - -Checklist: - -- [x] Insert path uses `applyIntent`. -- [x] Replace path uses `applyIntent`. -- [x] Failure posture is typed. - -### Slice 67 - Edit Command Cutover II - -User story: As a user, delete, backspace, and multi-range edits use the same -Echo-hosted intent path as insert and replace. - -Test plan: - -- Delete/backspace commands submit app intents. -- Multi-range or grouped edit commands submit app intents or typed obstruction. -- No direct text mutation bypass remains in production edit commands. - -Checklist: - -- [x] Delete/backspace paths use `applyIntent`. -- [x] Multi-range path is app-intent-backed or obstructed. -- [x] Production bypasses are inventoried for removal. - -### Slice 68 - Read Model Cutover - -User story: As a user, rendered editor text comes from bounded `textWindow` -readings instead of direct mutable snapshots in the production profile. - -Test plan: - -- Render model requests `textWindow` through the app capability. -- Reading envelope identity is retained in the UI model. -- Query observer remains read-only. - -Checklist: - -- [x] Production session render path uses bounded reading. -- [x] Reading identity reaches production session outcome. -- [x] No query observer write/tick authority appears. - -### Slice 69 - Cursor And Viewport Reading Basis - -User story: As a user, cursor and viewport state select the bounded reading -aperture without becoming Echo semantics. - -Test plan: - -- Cursor/viewport state feeds the jedit query input. -- Echo basis and reading identity remain separate from UI cursor policy. -- Scroll/cursor changes do not mutate Echo causal history by themselves. - -Checklist: - -- [x] Cursor state feeds query input. -- [x] Viewport state feeds query input. -- [x] Cursor/scroll-only moves do not submit edit intents. - -### Slice 70 - UI Runtime Issue Posture - -User story: As a user, an Echo obstruction appears as explicit UI/runtime -posture instead of silent retry or direct state mutation. - -Test plan: - -- Unsupported operation, query obstruction, and lifecycle obstruction map to - typed UI runtime issues. -- Retry requires a new explicit user/agent action. -- UI state is not mutated by obstructed work. - -Checklist: - -- [x] Obstructions map to runtime issues. -- [x] Hidden retry remains absent. -- [x] Obstructed work does not mutate editor state. - -### Slice 71 - Filesystem Save Boundary - -User story: As a user, saving a file is separated from Echo's causal -checkpoint/evidence posture. - -Test plan: - -- Save-to-filesystem remains a jedit adapter action. -- Echo checkpoint mutation remains a contract operation. -- Documentation distinguishes filesystem save from Echo causal history. - -Checklist: - -- [x] Filesystem save/export stays behind a jedit materialization boundary. -- [x] Checkpoint intent path is explicit. -- [x] Docs distinguish the two. - -### Slice 72 - Checkpoint Command Cutover - -User story: As a user, checkpoint/save-intent semantics route through the jedit -contract operation path, not direct runtime mutation. - -Test plan: - -- Checkpoint command submits a contract operation. -- Checkpoint result carries receipt/evidence posture. -- Failed checkpoint does not mutate UI state as if committed. - -Checklist: - -- [x] Checkpoint command uses contract operation. -- [x] Checkpoint result carries evidence. -- [x] Failure posture is typed. - -### Slice 73 - Agent Editing Surface - -User story: As an agent, I can perform a small edit through the same production -`TextBufferSessionPort` used by the interactive editor. - -Test plan: - -- CLI/MCP witness opens a buffer, applies an edit, observes a text window, and - reports receipt/reading identity. -- The agent surface exposes no trusted lifecycle or tick method. -- The same command works after an unsupported mutation witness. - -Checklist: - -- [x] Agent Echo-hosted edit command exists. -- [x] Agent authority remains app-safe. -- [x] Healthy work proceeds through a fresh explicit command. - -### Slice 74 - UI Retention Evidence - -User story: As a maintainer, the interactive Echo-hosted path can emit the same -retention evidence refs as the headless witness. - -Test plan: - -- UI-path command reports retained evidence refs. -- Retained evidence includes receipt, reading envelope, and payload roles. -- Durable retention remains honestly scoped to what Echo exposes. - -Checklist: - -- [x] Production-session retention report exists. -- [x] Receipt/checkpoint/reading/export refs are present. -- [x] Durable claims are not overclaimed. - -### Slice 75 - UI Local Replay Witness - -User story: As a maintainer, the interactive Echo-hosted path can be locally -replayed by semantic identity. - -Test plan: - -- Same inputs produce same package identity, receipt identity, reading identity, - and text result. -- Replay equality ignores wall-clock cadence. -- Durable/Continuum replay remains honestly unavailable. - -Checklist: - -- [x] Production-session local replay report exists. -- [x] Semantic identity matches. -- [x] Durable replay is not overclaimed. - -### Slice 76 - Legacy Model Quarantine - -User story: As a maintainer, the old in-memory text model is no longer a -production authority path. - -Test plan: - -- Legacy local model lives under a focused test fixture or adapter-internal name. -- Production app code cannot import legacy direct mutation modules. -- Existing tests either use production ports or explicitly opt into fixtures. - -Checklist: - -- [x] Legacy runtime-choice files are removed. -- [ ] Full direct `EditorState.lines` model quarantine remains open. -- [x] Non-Echo runtime profile selection is removed. - -### Slice 77 - Legacy Bypass Static Guard - -User story: As a reviewer, a static guard fails if production UI/editor code -imports legacy direct text-state mutation modules instead of ports. - -Test plan: - -- Guard scans production source. -- Guard allows explicit test/dev fixtures. -- Guard catches a sample forbidden import. - -Checklist: - -- [x] Production source guard exists. -- [x] Test/dev fixture allowlist exists. -- [x] Sample forbidden import is covered. - -### Slice 78 - Remove Runtime Choice From Product UX - -User story: As a user, jedit no longer presents Echo hosting as an optional -mode; it is the production runtime posture. - -Test plan: - -- User-facing labels do not expose local-vs-Echo mode selection. -- Host/test configuration still allows explicit fixture override. -- Documentation describes Echo-hosted production posture. - -Checklist: - -- [x] Product mode wording is removed. -- [x] Host/test override remains. -- [x] Docs describe production posture. - -### Slice 79 - Delete Or Demote Legacy Code - -User story: As a maintainer, dead in-memory production paths are deleted where -possible and demoted where deletion is not yet safe. - -Test plan: - -- Dead paths are removed. -- Remaining paths are fixture/adapter-internal only. -- Release gate still passes. - -Checklist: - -- [x] Dead transitional runtime-mode paths are removed. -- [ ] Remaining local line-model paths are still scheduled for fixture-scoping. -- [x] Release gate passes. - -### Slice 80 - Echo-Hosted jedit Release Gate - -User story: As a reviewer, one focused command proves the interactive -Echo-hosted production path. - -Test plan: - -- Release gate proves interactive open, edit, read, save/checkpoint posture, - retention refs, local replay, no tick authority, and no legacy bypass. -- Failure output names the failed witness. -- BEARING points at the WSC persistence/export plan. - -Checklist: - -- [x] Release gate includes production Echo-hosted smoke. -- [x] Release gate includes no-legacy-bypass guard. -- [x] Failure output is actionable. -- [x] BEARING points at the WSC persistence/export plan. - -## Post-80 Candidate Plan: WSC Persistence And Export - -The post-80 plan should start only after the production cutover is credible. -Likely slices: - -1. Echo WSC capability map and jedit adapter requirements. -2. WSC-backed accepted submission recovery witness. -3. WSC-backed causal history reload between jedit lifecycles. -4. Point-in-time materialization query for jedit file artifacts. -5. Export adapter that writes materialized artifacts to the filesystem. -6. Export obstruction taxonomy for missing basis, missing retained material, and - unsupported historical coordinate. -7. CLI/MCP export flow for agents. -8. Release gate that proves edit, restart, recover, materialize, and export. - -The WSC plan belongs partly in Echo and partly in jedit. Echo must implement -generic WSC causal-history serialization. jedit must consume it through ports -and materialize editor/file artifacts without adding app nouns to Echo. diff --git a/docs/design/0028-production-text-authority-inventory.md b/docs/design/0028-production-text-authority-inventory.md deleted file mode 100644 index 02a5dfb2..00000000 --- a/docs/design/0028-production-text-authority-inventory.md +++ /dev/null @@ -1,60 +0,0 @@ -# Production Text Authority Inventory - -Status: active inventory for -[`0027-echo-hosted-production-cutover.md`](0027-echo-hosted-production-cutover.md) -slices 61-80. - -This document names the current interactive editor paths that read or write text -state. Its purpose is to prevent the Echo-hosted production cutover from leaving -a hidden second source of truth. - -## Authority Rule - -Production text authority must converge on this shape: - -```text -workspace command --> jedit-owned text session/controller port --> TextBufferSessionPort --> TextBufferOptic --> jedit contract adapter --> Echo generic runtime -``` - -The local editor model may continue to hold cursor, scroll, visual mode, -selection/register, and rendering cache state. It must not remain the -production source of truth for buffer text once the cutover is complete. - -Echo remains generic. Echo must not learn text buffers, ropes, cursors, panes, -documents, selections, or file export semantics. - -## Direct Text Read/Write Paths - -| Path | Current authority | Cutover target | -| --- | --- | --- | -| `src/app/workspace/file-tree.ts` | Opening a file calls `loadEditor(...)`, which reads file content into `EditorState.lines`. | Open through a production text controller that calls `TextBufferSessionPort.createBuffer(...)`. | -| `src/app/workspace/editor-session.ts` | `loadEditor(...)` and `saveEditor(...)` read/write filesystem text directly. | Keep filesystem import/export behind adapters; separate file export from Echo causal mutation. | -| `src/app/workspace/viewer-key.ts` | Insert and normal-mode commands call local mutation helpers over `EditorState.lines`. | Convert editing commands to jedit app intents through `TextBufferOptic.applyIntent(...)`. | -| `src/app/workspace/editor-editing.ts` | Command routing returns locally mutated `EditorState`. | Keep cursor/visual command calculation local, but route text-changing commands through the app intent path. | -| `src/app/workspace/editor-editing-core.ts` | Low-level helpers mutate local line arrays. | Demote to fixture/adapter-local support or pure command-planning helpers once production text authority is Echo-hosted. | -| `src/app/workspace/viewer-content.ts` | Rendering reads `editor.lines` directly. | Render from bounded `TextBufferOptic.textWindow(...)` readings with retained reading identity in UI state. | -| `src/app/workspace/global-key-bindings.ts` | Save calls `saveEditor(...)` over local lines. | Save/export reads a bounded Echo-backed basis and writes a jedit-owned file artifact; checkpoint remains a contract intent. | - -## Current Slice Boundary - -Slices 61-70 establish the production runtime profile and a production text -session/controller surface. They do not delete every legacy helper in one pass. -The remaining direct imports are tracked here so later slices can quarantine or -remove them without guessing. - -## Cutover Invariants - -- `echoHosted` is the only production runtime profile. -- Focused tests use fake-port injection instead of a non-Echo runtime profile. -- Opening a production buffer uses `TextBufferSessionPort.createBuffer(...)`. -- Editing a production buffer uses `TextBufferOptic.applyIntent(...)`. -- Rendering a production buffer uses `TextBufferOptic.textWindow(...)`. -- Cursor and viewport state select the jedit query aperture; they are not Echo - semantics. -- Obstructed work produces explicit runtime issue posture and no hidden retry. -- Export reads from a causal basis and does not mutate Echo state. diff --git a/docs/design/0029-production-text-session-release-witness.md b/docs/design/0029-production-text-session-release-witness.md deleted file mode 100644 index 90820be7..00000000 --- a/docs/design/0029-production-text-session-release-witness.md +++ /dev/null @@ -1,67 +0,0 @@ -# Production Text Session Release Witness - -Status: active checkpoint for -[`0027-echo-hosted-production-cutover.md`](0027-echo-hosted-production-cutover.md) -slices 71-80. - -This slice batch upgrades the Echo-hosted production text path from a narrow -controller to an agent/release witness: - -```text -TextRuntimeProfile echoHosted --> TextBufferSessionPort --> ProductionTextSession --> open/edit/checkpoint/read/export --> retained evidence refs --> local replay comparison -``` - -## What This Proves - -- Filesystem save/export is a jedit-owned materialization concern, not Echo - state mutation. -- Manual checkpoint posture goes through the jedit contract operation path. -- Agent tooling can run the production text session without lifecycle or tick - authority. -- The witness reports receipt, checkpoint, reading, and export refs. -- Local replay compares deterministic semantic identity while explicitly - declining durable replay claims. -- The release gate runs the production text witness and the production cutover - static guard. - -## What This Does Not Yet Prove - -This checkpoint still does not claim the full interactive TUI event loop has no -legacy direct `EditorState.lines` path. Those paths are inventoried in -[`0028-production-text-authority-inventory.md`](0028-production-text-authority-inventory.md) -and remain the next cutover pressure: - -- file-tree open; -- viewer key edit routing; -- source rendering; -- filesystem save/export key handling. - -The distinction is deliberate. The production session path is now executable -and guarded; the next work is to make the interactive workspace consume it as -the only product authority path. - -## Release Commands - -```bash -npm run build -node scripts/jedit-production-text-session.mjs --json --allow-full-snapshot-fixture --text "hello Echo" -node scripts/jedit-production-text-session.mjs --json --allow-full-snapshot-fixture --replay-local -node scripts/jedit-production-cutover-guard.mjs -npm run release-gate:jedit-echo -``` - -## Non-Negotiables - -- Echo still does not know text buffers, files, panes, cursors, selections, or - exports. -- `TextBufferOptic` remains a jedit capability. -- The production TUI has no non-Echo text runtime profile; focused tests use - direct fake-port injection when they need fixture behavior. -- Export is a reading/materialization over a jedit-owned basis. -- Hidden retry remains absent. -- Durable WSC replay remains post-slice-80. diff --git a/docs/design/0031-jedit-echo-real-app-proof-pr-notes.md b/docs/design/0031-jedit-echo-real-app-proof-pr-notes.md deleted file mode 100644 index 357f579f..00000000 --- a/docs/design/0031-jedit-echo-real-app-proof-pr-notes.md +++ /dev/null @@ -1,61 +0,0 @@ - - - -# jedit Echo Real App Proof PR Notes - -Status: completed local PR package for slices 91-100. Slices 101-110 are -tracked in -[`0032-jedit-echo-reading-cache-and-fallback-boundaries.md`](0032-jedit-echo-reading-cache-and-fallback-boundaries.md). - -## Scope - -This package proves the jedit interactive workspace calls the jedit-owned -production text session through the real workspace runtime path. It does not -implement WSC durability, historical export, or full multi-buffer recovery. - -## Closed Slices - -- Slice 91: canonical gate name is `release-gate:jedit-echo`; the older - `release-gate:echo` script is a compatibility alias. -- Slice 92: the real app harness drives the same workspace runtime update path - used by the app. -- Slice 93: file open imports host bytes into the production text session and - renders the returned bounded reading. -- Slice 94: insert/delete/backspace proof goes through production session edit - commands. -- Slice 95: save exports materialized production text and checkpoints through - the session. -- Slice 96: open/edit/read/export/checkpoint obstruction posture is explicit - and does not retry automatically. -- Slice 97: agent-facing workspace witness reports open, edit, read, export, - and checkpoint evidence without lifecycle authority. -- Slice 98: UI lifecycle authority is statically guarded. -- Slice 99: direct text authority is inventoried and scoped below. - -## Legacy Text Authority Inventory - -| Path | Current disposition | -| --- | --- | -| `src/app/workspace/editor-session.ts` | Legacy editor import/export helpers remain adapter-private and test-local support. | -| `src/app/workspace/editor-editing.ts` | Local editing helpers remain render/navigation mechanics and fixture support. | -| `src/app/workspace/editor-editing-helpers.ts` | Local editing implementation remains non-production authority. | -| `src/app/workspace/viewer-key.ts` | Production mutation keys submit session commands; remaining editor helpers are navigation/cache mechanics. | -| `src/app/workspace/viewer-content.ts` | Production rendering reads from the reading cache. | -| `src/app/workspace/workspace-save-key.ts` | Production save exports/checkpoints through the session; legacy save is only for non-opened/test-local authority. | - -No listed path may become production text authority without a new slice and an -executable witness. - -## Required Local Witnesses - -```bash -npm run build -node --test --test-concurrency=1 \ - spec/release-gate-script.spec.mjs \ - spec/workspace-app-echo-cutover.spec.mjs \ - spec/workspace-echo-witness-cli.spec.mjs \ - spec/production-cutover-guard.spec.mjs -npm run release-gate:jedit-echo -npm run quality -git diff --check -``` diff --git a/docs/design/0032-jedit-echo-reading-cache-and-fallback-boundaries.md b/docs/design/0032-jedit-echo-reading-cache-and-fallback-boundaries.md deleted file mode 100644 index 1c8c2252..00000000 --- a/docs/design/0032-jedit-echo-reading-cache-and-fallback-boundaries.md +++ /dev/null @@ -1,168 +0,0 @@ - - - -# jedit Echo Reading Cache And Fallback Boundaries - -Status: local slice package for slices 101-110. - -## Scope - -This package closes the ambiguity between production text authority and -workspace display material before WSC durability work begins. It does not add a -new Echo feature. It keeps the editor, text, buffer, cursor, selection, preview, -highlight, and save semantics inside jedit-owned modules and ports. - -## Closed Slices - -- Slice 101: display-line terminology now flows through a reading-cache - boundary instead of implying that local lines are production authority. -- Slice 102: reading-cache posture and materialization live in - `workspace-text-reading-cache.ts`. -- Slice 103: cursor and selection-to-byte range conversion lives in - `workspace-text-edit-planner.ts`. -- Slice 104: replace command execution goes through `replaceRange` on the - production text session and refreshes bounded reading material. -- Slice 105: production undo and redo return explicit unsupported posture until - they are modeled as causal input. -- Slice 106: workspace footer state can render concise text posture without - exposing Echo lifecycle authority. -- Slice 107: source highlighting consumes refreshed reading material. -- Slice 108: preview rendering consumes reading material instead of stale local - lines. -- Slice 109: the current policy is explicit single-active-buffer authority; - save targets the active production buffer only. -- Slice 110: non-Echo profile input is rejected; focused fake-port tests remain - fixture scaffolding without becoming a production runtime mode. - -## Doctrine - -In production, Echo/session authority owns causal text. `EditorState.lines` is -the full local visible projection cache used for rendering, cursoring, and -transitional edit planning. It must not be reconstructed from bounded readings. -It is not saved or recovered as authority. The production authority path is: - -```text -jedit UI command --> jedit planner or workspace command --> TextBufferSessionPort --> Echo-hosted jedit contract state --> bounded reading cache --> render, preview, highlight --> full export snapshot --> save/export materialization -``` - -Echo remains generic. It does not own text, editor, buffer, cursor, file, -selection, preview, highlight, or save semantics. - -The campaign acceptance criterion is stronger than using Echo-shaped names or -an in-process transport: every durable or recoverable user-state transition and -every authoritative reading must be backed by Echo-owned admission, witnessed -history, receipts, and recovery. Jim-owned caches and indexes are permitted -only when they are disposable, basis-pinned projections whose loss cannot -change semantic history. The current handwritten invocation corridor remains -transitional until generated Edict operations are installed and invoked by -Echo. - -## Projection Coverage - -The production path names coverage explicitly because these terms are not -interchangeable: - -- **Full projection**: a complete selected text frontier that covers the whole - document. It may replace `editor.lines` when the coverage predicate proves - the reading is full. -- **Window projection**: an Echo text-window observation with `startLine`, - returned line count, total line count, before/after flags, and truncation - posture. It may update cache, history, diagnostics, and status. It may not - replace the whole editor. -- **Viewport rendering slice**: the bounded source or preview rows painted into - the current terminal rectangle. It is paint material only. -- **Export snapshot**: a full selected frontier materialization payload used by - save/export. It is not a viewport window and not `WorkspaceTextReadingCache` - lines by convention. -- **Recovery evidence**: retained operation, observation, replay, or snapshot - evidence. It is materializable only when it proves full coverage or a - replayable chain from a known full basis. - -## Forbidden Patterns - -These patterns are architecture bugs: - -- `editor.lines = cache.lines` when cache coverage is `window`; -- `saveEditorFile(cache.lines)`; -- WSC recovery or materialization from a truncated/window reading; -- default top-of-file aperture for current cursor or edit follow-up refresh; -- Graft drawer rows that use stale or saved-only data without visible posture. - -## Materialization Cache Provenance - -The text-window observer may retain exact-repeat materializations to avoid -reading unchanged rope bytes repeatedly. Each entry is keyed by Jim worldline -and head, exact branded UTF-8 coverage, schema and materializer versions, -observer plan, policy digest, and a request namespace. Entries declare exact -range completeness and separately count their UTF-8 projection bytes. - -This metadata is cache provenance, not causal provenance. The transitional -`requestFrontierRef` is not an Echo frontier witness, and cache digests are not -Echo identities. Cache lookup must fail closed when any coordinate or -projection metadata is stale. Invalidating, evicting, or losing the cache may -increase read cost only; it must never rewrite graph-rope authority or alter -retained evidence. - -## WSC Reading Evidence - -WSC retained readings are evidence. They are not automatically recovery -material and they are not automatically host materialization payloads. - -A retained text edit envelope may carry: - -- operation evidence, such as the edit range, receipt, file path, and submitted - time; -- observation evidence, such as a bounded reading window and its coverage - metadata; -- replay or export evidence, if a later cycle proves a full projection or a - replayable operation chain from a known full basis. - -A bounded reading is not a document. A current-history export, recovered -materialization, or restart recovery path must fail closed unless it has either -a full-document projection or a replayable causal operation chain from a known -full basis. Window-only evidence remains useful for history and debugging, but -it must not be presented as recovered full text and must not be written to disk. - -## Text Windows And Export Snapshots - -`textWindow` is a bounded observation operation. It is for rendering, -navigation, projection evidence, and diagnostics. The app may request different -apertures as the cursor or viewport moves, but the returned lines remain window -evidence unless the reading explicitly covers the whole document. - -Save and host export use a separate app-level operation: `exportSnapshot`. -Today that operation is a transitional wrapper over the existing text-window -read path. The wrapper must prove full coverage before it returns text: - -- `startLine` is zero; -- no earlier or later lines exist; -- the reading is not truncated; -- returned line count equals total line count; -- returned line entries cover the total line count. - -If those facts are not present, export is obstructed before host preflight, -`saveEditorFile`, checkpointing, or clean/materialized authority updates. A -future Echo API can replace the transitional wrapper with a native full -frontier snapshot or replay-backed materialization operation, but the product -boundary remains the same: a text window is not an export. - -## Local Witnesses - -```bash -npm run build && npm run quality -node --test \ - spec/workspace-text-boundaries.spec.mjs \ - spec/workspace-app-echo-cutover.spec.mjs \ - spec/workspace-echo-witness-cli.spec.mjs \ - spec/production-cutover-guard.spec.mjs \ - spec/release-gate-script.spec.mjs -npm run release-gate:jedit-echo -git diff --check -``` diff --git a/docs/design/0033-echo-authoritative-recovery-gate-b.md b/docs/design/0033-echo-authoritative-recovery-gate-b.md deleted file mode 100644 index 46f7e0e9..00000000 --- a/docs/design/0033-echo-authoritative-recovery-gate-b.md +++ /dev/null @@ -1,36 +0,0 @@ -# Echo Authoritative Recovery Gate B - -This is the jedit-local companion to Echo's -`docs/design/echo-authoritative-jedit-recovery-40-slice-plan.md`. - -Gate B asks one question: - -```text -Can jedit consume Echo truth through ports without local memory fallback? -``` - -The required artifact is a jedit recovery report that proves: - -- jedit asks Echo for generic recovery posture through an app-owned port; -- process, path, CLI, and WAL details stay adapter-private; -- generic Echo posture is mapped into jedit-owned editor status; -- stable edit submission identity makes retry safe; -- legacy local text memory is blocked by static and runtime tripwires; -- bounded readings and materialized artifacts come from Echo recovery evidence. - -## Slice Checklist - -- [x] Slice 18: Echo recovery port interface. -- [x] Slice 19: Echo recovery adapter implementation. -- [x] Slice 20: Generic-to-editor posture mapping. -- [x] Slice 21: Stable edit submission identity. -- [x] Slice 22: Recovery evidence report fields. -- [x] Slice 32: Production legacy memory static guard. -- [x] Slice 33: Release-gate runtime tripwire mode. -- [x] Slice 23: Recovered bounded reading path. -- [x] Slice 24: Happy-path recovery gate scenario. -- [x] Slice 25: Retry after local amnesia scenario. -- [x] Slice 34: Materialize artifact from recovered causal basis. - -Check off each slice here and in `docs/BEARING.md` immediately before the -commit that lands the slice. diff --git a/docs/design/0034-ci-shard-and-impact-planning.md b/docs/design/0034-ci-shard-and-impact-planning.md deleted file mode 100644 index eb0a373f..00000000 --- a/docs/design/0034-ci-shard-and-impact-planning.md +++ /dev/null @@ -1,116 +0,0 @@ -# CI Shard And Impact Planning - -Status: active - -## Claim - -Jedit CI should stop treating every pull request as the same monolithic -`npm run check` event. The repository needs a planner that can explain which -checks are necessary for a diff, a shard manifest that accounts for every spec, -and a final aggregate `check` gate that stays conservative when the planner is -unsure. - -The goal is shorter iteration time without lowering the release bar. - -## Current Baseline - -The current GitHub workflow has one job named `check`. - -```text -npm run check --> npm run test:all - -> npm run build - -> JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/**/*.spec.mjs tests/**/*.spec.mjs --> npm run quality -``` - -Recent CI evidence showed checkout, Node setup, and dependency installation -finishing in seconds. The long pole was the single `Run checks` step. Local -full-suite execution also must build `dist` once and then run specs with -`JEDIT_DIST_PREBUILT=1`; otherwise each spec process can rebuild TypeScript -even after an explicit build. - -## Design Rules - -- The final required GitHub check remains named `check`. -- Each spec belongs to exactly one test shard. -- Unknown paths force the full shard set. -- Workflow, package, TypeScript config, shard-planner, and quality-gate changes - force the full shard set. -- Package changes that parse as Bijou-only dependency bumps use a narrower - package-compatibility plan instead of full CI. -- Mainline pushes and explicit full runs execute the full shard set. -- Echo authority and release-gate paths run the release gate. -- Skipped shards must be explainable from the changed path set. -- Local `npm run check` remains the full local truth. - -## Shards - -| Shard | Scope | -| --- | --- | -| `contract-api` | Contract, codec, observer, operation, and generated API specs. | -| `cycle-proofs` | Cycle design proof specs under `tests/`. | -| `docs-release` | Documentation, guide, quickstart, and release-script specs. | -| `echo-authority` | Echo hosting, recovery, production text, WSC, restart, retained evidence, and release authority specs. | -| `misc-fast` | Small specs that are not owned by a narrower domain shard. | -| `title-rendering` | Title scene, title screen, mesh, camera, and theme-rendering specs. | -| `workspace-ui` | Workspace, drawer, key binding, footer, editor, panel, source, markdown, and UI interaction specs. | - -Static build and quality are separate non-test jobs. The release gate is a -separate conditional job. - -Shard jobs receive the `dist` artifact from the build job and set -`JEDIT_DIST_PREBUILT=1`. Specs that import compiled modules must use the shared -`spec/dist-helpers.mjs` loader path so shard jobs do not rebuild TypeScript or -depend on ignored generated source files in a fresh checkout. - -## Path Impact Rules - -| Changed path | Required checks | -| --- | --- | -| `.github/**`, non-Bijou package changes, `tsconfig*.json`, `scripts/ci/**`, `scripts/quality*` | Full shard set and release gate. | -| `package*.json` with only Bijou dependency version/resolution changes | `contract-api`, `echo-authority`, `title-rendering`, `workspace-ui`, release gate. | -| `contracts/**`, generated contract code, Wesley tooling | `contract-api`, `echo-authority`, release gate. | -| Echo authority surfaces | `echo-authority`, `workspace-ui`, release gate. | -| Workspace surfaces | `workspace-ui`, `echo-authority`. | -| Title scene and theme surfaces | `title-rendering`, `workspace-ui`. | -| UI surfaces outside title/workspace | `workspace-ui`. | -| Docs and README | `docs-release`. | -| Tests | The owning shard for the changed test. | -| Unknown paths | Full shard set and release gate. | - -Every plan also runs static build and quality. - -## Ten Slices - -- [x] Slice 1: record baseline and define the CI split design. -- [x] Slice 2: add the shard manifest and every-spec coverage check. -- [x] Slice 3: add the changed-path impact planner. -- [x] Slice 4: add shard runner scripts and package commands. -- [x] Slice 5: add shared prebuilt-dist support for specs that used to rebuild - dist. -- [x] Slice 6: add planner/shard tests. -- [x] Slice 7: split GitHub Actions into plan, build, shard, release-gate, - quality, and aggregate `check` jobs. -- [x] Slice 8: add job summaries and timing/profiling support. -- [x] Slice 9: keep local full `npm run check` semantics intact. -- [x] Slice 10: validate the new planner, shards, quality, and full check. - -## Non-Goals - -- No branch-protection changes in this repository change. -- No weakening of the Echo release gate. -- No attempt to make dependency installation the primary optimization target. -- No test deletion. - -## Merge Gate - -This campaign is ready when: - -- The shard coverage check proves every spec is assigned to exactly one shard. -- The changed-path planner proves docs-only, workspace, Echo authority, and - unknown-path cases. -- `npm run check` remains green locally. -- GitHub CI reports a final aggregate `check` job and exposes shard-level jobs. -- Shard jobs import compiled modules from the downloaded build artifact instead - of running per-spec TypeScript rebuilds. diff --git a/docs/design/0034-design-cycle-template-and-lifecycle.md b/docs/design/0034-design-cycle-template-and-lifecycle.md deleted file mode 100644 index dec81e9d..00000000 --- a/docs/design/0034-design-cycle-template-and-lifecycle.md +++ /dev/null @@ -1,372 +0,0 @@ ---- -title: "WF-0034 - Executable Design Cycle Template" -legend: "WF" -lane: "design" -issue: "https://github.com/flyingrobots/jedit/issues/51" -status: "active" -owners: - - "@flyingrobots" -created: "2026-06-03" -updated: "2026-06-03" ---- - -# WF-0034 - Executable Design Cycle Template - -## Linked Issue - -- https://github.com/flyingrobots/jedit/issues/51 - -## Decision Summary - -jedit will make full-cycle design docs a first-class workflow artifact, backed -by `docs/design/TEMPLATE.md`, `docs/method/process.md`, `AGENTS.md`, and a -process spec. The template requires concrete contracts, current-truth evidence, -test-first slices, lower-mode posture, accessibility, localization when strings -change, and a retrospective, while explicitly forbidding design-doc assertions -as the sole proof for implementation work. - -## Sponsored Human - -A jedit maintainer wants cycle work to start from a precise, reviewable design -so that implementation can move quickly without repeatedly renegotiating scope, -without having to mine chat transcripts for the intended behavior. - -## Sponsored Agent - -An agent needs a stable cycle template and process contract so it can create -branches, issues, docs, RED tests, PRs, and retrospectives, without inferring -private workflow expectations from previous conversations. - -## Hill - -By the end of this cycle, a maintainer or agent can start a full jedit cycle -through `docs/design/TEMPLATE.md` and `docs/method/process.md`, and the repo -proves the policy with a focused process spec plus the quality gate. - -## Current Truth - -At the merge target SHA `df35e90cd77823d295240116cbc7ff07b66c3c76`, -`AGENTS.md` states git safety and delivery workflow rules, but does not define a -design-cycle startup path, GitHub issue linkage, WIP labeling, or template -contract: -[AGENTS.md#L3:df35e90cd77823d295240116cbc7ff07b66c3c76](https://github.com/flyingrobots/jedit/blob/df35e90cd77823d295240116cbc7ff07b66c3c76/AGENTS.md#L3) -and -[AGENTS.md#L72:df35e90cd77823d295240116cbc7ff07b66c3c76](https://github.com/flyingrobots/jedit/blob/df35e90cd77823d295240116cbc7ff07b66c3c76/AGENTS.md#L72). - -`docs/method/process.md` is a placeholder with no executable cycle workflow: -[docs/method/process.md#L1:df35e90cd77823d295240116cbc7ff07b66c3c76](https://github.com/flyingrobots/jedit/blob/df35e90cd77823d295240116cbc7ff07b66c3c76/docs/method/process.md#L1). - -`docs/design/project-invariants.md` already says tests are executable spec and -design should become repo truth, but it does not say that design docs cannot be -the sole implementation proof: -[docs/design/project-invariants.md#L191:df35e90cd77823d295240116cbc7ff07b66c3c76](https://github.com/flyingrobots/jedit/blob/df35e90cd77823d295240116cbc7ff07b66c3c76/docs/design/project-invariants.md#L191). - -Several historical design packets include retrospectives and playback notes, but -there is no current reusable jedit template that requires lower modes, agent -inspectability, UI geometry, Echo authority, Graft boundary, and executable -witnesses together. - -## Problem - -jedit design cycles are inspectable only when individual contributors remember -the full method. The repo has strong design precedent, but the process is not -encoded as a reusable template or tested contract, so a new cycle can still land -with vague intent, missing current-truth evidence, missing lower-mode posture, -or documentation assertions masquerading as proof. - -## Scope - -This cycle includes: - -- Add a jedit-specific full-cycle design template. -- Replace the placeholder process doc with the official cycle workflow. -- Update `AGENTS.md` so agents follow the same workflow. -- Record this policy decision as a design doc. -- Add a focused spec that protects the template and process contract. -- Create and link the GitHub issue for the policy cycle. - -## Non-Goals - -This cycle does not include: - -- Rewriting existing historical design docs into the new template. -- Enforcing the template against every old design document. -- Changing branch protection. -- Changing release-gate behavior. -- Adding a new docs inventory system. -- Porting the template to Echo, Bijou, or other repositories in this jedit PR. - -## User Experience / Product Shape - -This is a repository workflow change, not a rendered jedit TUI surface. The user -experience is the maintainer or agent flow for starting and reviewing a cycle. - -### User Journey - -```mermaid -flowchart TD - Fetch[Fetch origin] --> Branch[Branch from origin/main] - Branch --> Issue[Create or link GitHub issue] - Issue --> Design[Write docs/design template packet] - Design --> Commit[Commit and push design setup] - Commit --> PR[Open early PR] - PR --> WIP[Apply work-in-progress] - WIP --> Slices[Run RED/GREEN slices] - Slices --> Retro[Fill retrospective] - Retro --> Ready[Remove WIP and mark ready] -``` - -### Wide UI Mockup - -Not applicable. This cycle changes repository workflow docs and process tests, -not rendered UI. - -### Narrow UI Mockup - -Not applicable. This cycle changes repository workflow docs and process tests, -not rendered UI. - -### Accessibility Considerations - -The workflow is text-first Markdown. Headings, tables, checklists, and code -blocks are screen-reader and agent-readable without requiring visual layout. - -## Runtime / API Contract - -The software contract is a repository process contract: - -- `docs/design/TEMPLATE.md` defines required full-cycle design sections. -- `docs/method/process.md` defines cycle classes, startup, active work, - ready-for-review, and landing rules. -- `AGENTS.md` points agents to the canonical process and proof standard. -- `spec/design-cycle-policy.spec.mjs` verifies the required headings and policy - anchors. - -This contract does not add runtime APIs, command intents, Echo schema, Graft -schema, or editor state transitions. - -## Lower Modes - -Not applicable to rendered output. The lower-mode equivalent is that an agent -can inspect the policy with plain filesystem reads and `node --test`, without a -browser, TUI, or GitHub UI. - -## Data / State Model - -| Category | Description | -| --- | --- | -| Source of truth | `docs/method/process.md`, `docs/design/TEMPLATE.md`, and `AGENTS.md`. | -| Derived state | GitHub issues, PR labels, checklists, retrospectives, and process tests. | -| Invalid states | Full-cycle implementation with no executable witness, no linked issue, or design-only proof for runtime work. | -| Reset behavior | Superseded process docs must be replaced by a new design decision and issue. | -| Serialization | Markdown frontmatter, headings, checklists, and GitHub issue/PR metadata. | -| Deterministic assumptions | Process tests inspect stable headings and phrases; no clock-sensitive behavior. | - -```mermaid -stateDiagram-v2 - [*] --> DraftDesign - DraftDesign --> WipCycle - WipCycle --> ReadyForReview - ReadyForReview --> Landed - WipCycle --> Superseded -``` - -## Accessibility Posture - -| Concern | Posture | -| --- | --- | -| Semantic labels or facts | Markdown headings and frontmatter expose stable sections and status. | -| Focus order or ownership | Not applicable; no interactive UI changes. | -| Hidden or visual-only information | None. Required proof must be inspectable in text or command output. | -| Keyboard behavior | Not applicable; no TUI input changes. | -| Secret or redaction behavior | GitHub issue/PR links are public repo metadata; no secrets are introduced. | - -## Localization / Directionality Posture - -No product strings change. The new visible text is maintainer documentation in -English and does not touch `translations.json` or runtime i18n catalogs. - -| Concern | Posture | -| --- | --- | -| User-visible strings | Documentation-only process text. | -| Catalog keys | None. | -| Supported locales updated | None required. | -| Directionality assumptions | Markdown remains readable in source order. | -| Validation command | `npm run quality`; no i18n command applies. | - -## Agent Inspectability / Explainability Posture - -Agents can inspect the result through: - -- stable headings in `docs/design/TEMPLATE.md` -- explicit cycle workflow in `docs/method/process.md` -- agent-facing rules in `AGENTS.md` -- issue link `https://github.com/flyingrobots/jedit/issues/51` -- `spec/design-cycle-policy.spec.mjs` -- deterministic `node --test` output - -No agent needs to scrape pixels or infer workflow from chat. - -## Linked Invariants - -- Tests are executable spec. -- Design should become repo truth. -- Runtime truth beats type theater. -- Agent-first. -- Honest causal strata. - -## Design Alternatives Considered - -### Option A: Template Only - -Pros: - -- Small change. -- Gives humans a starting point. - -Cons: - -- Agents may miss the workflow if `AGENTS.md` and process docs do not point to - it. -- Nothing protects the template from drifting into fake proof. - -### Option B: Process Doc Only - -Pros: - -- Centralizes workflow. -- Avoids a large template. - -Cons: - -- Does not give cycle authors a concrete packet structure. -- Leaves lower modes, accessibility, localization, and agent inspectability as - easy omissions. - -### Option C: Template, Process, Agent Contract, And Spec - -Pros: - -- Makes the policy visible to humans and agents. -- Gives cycle authors a concrete shape. -- Adds an executable guard against missing proof language. - -Cons: - -- Adds more documentation surface. -- Requires future cycles to spend design effort before implementation. - -## Decision - -Choose Option C. jedit will use a full-cycle template plus canonical process -doc, agent contract, and process spec. The extra documentation cost is accepted -because it reduces ambiguous implementation cycles and blocks design-only proof. - -## Implementation Slices - -- [x] Slice 1: Create issue #51 and mark the policy cycle work in progress. -- [x] Slice 2: Add `docs/design/TEMPLATE.md`. -- [x] Slice 3: Replace `docs/method/process.md` with the official cycle - workflow. -- [x] Slice 4: Update `AGENTS.md` to point agents at the workflow and proof - standard. -- [x] Slice 5: Add a process spec for required headings and policy anchors. -- [x] Slice 6: Validate, commit, push, and open a PR. - -## Tests To Write First - -Behavior tests required: - -- [ ] Not applicable; this is a repository workflow contract. - -Documentation and process tests: - -- [x] `spec/design-cycle-policy.spec.mjs` proves the template has required - sections. -- [x] `spec/design-cycle-policy.spec.mjs` proves the process doc forbids - design-only proof for implementation work. -- [x] `spec/design-cycle-policy.spec.mjs` proves `AGENTS.md` points to the - template and process. - -Rule: documentation tests cannot be the only proof for implementation work. -This cycle is process-only, so a process spec is the relevant witness. - -## Acceptance Criteria - -The work is done when: - -- [x] Template exists at `docs/design/TEMPLATE.md`. -- [x] Process doc defines cycle classes, startup, active work, ready, and - landing. -- [x] AGENTS points to the template and process. -- [x] Process spec covers required headings and proof doctrine. -- [x] Issue and PR are linked correctly. -- [x] CI and local validation are green. - -## Validation Plan - -Commands expected before PR: - -```bash -node --test --test-concurrency=1 spec/design-cycle-policy.spec.mjs -npm run quality -``` - -Run `npm run check` if the process spec or docs changes interact with broader -repo validation. - -## Playback / Witness - -Reviewers can inspect: - -```bash -sed -n '1,220p' docs/design/TEMPLATE.md -sed -n '1,180p' docs/method/process.md -sed -n '1,120p' AGENTS.md -node --test --test-concurrency=1 spec/design-cycle-policy.spec.mjs -``` - -## Risks - -Known risks: - -- The full template may feel heavy for small fixes. -- Future agents may still try to treat design text as proof. -- Draft PR behavior may differ across repositories. - -Mitigations: - -- `docs/method/process.md` defines full, mini, and no-design classes. -- The template and process doc explicitly require executable witnesses. -- The process permits a normal PR with `work-in-progress` when draft PRs are - unavailable. - -## Follow-On Debt - -No jedit follow-on debt is deferred in this cycle. - -Adapting equivalent templates in Echo, Bijou, or other repositories should be -tracked in those repositories so their local invariants own the final shape. - -## Retrospective - -What changed from the design: - -- The implemented policy keeps the template broad but makes UI mockups - conditional for rendered surfaces. -- The process allows draft PRs only for cycle work, with a labeled normal PR as - the fallback. - -What the tests proved: - -- The template contains the required sections. -- The process doc names the cycle lifecycle and executable-proof rule. -- AGENTS points future agents at the canonical workflow. - -What remains open: - -- Other repositories still need their own adapted templates. - -PR: - -- https://github.com/flyingrobots/jedit/pull/52 diff --git a/docs/design/0034-echo-history-drawer.md b/docs/design/0034-echo-history-drawer.md deleted file mode 100644 index ac2277ca..00000000 --- a/docs/design/0034-echo-history-drawer.md +++ /dev/null @@ -1,88 +0,0 @@ -# Echo History Drawer - -## Status - -Implemented as a first interactive drawer slice. Worldline jump is intentionally -designed but not implemented until jedit has a port that can ask Echo for a -bounded historical basis and reproject the editor from that basis. - -## User Experience Claim - -`ctrl+h` opens a right-side Echo History drawer. The drawer is for a person -editing in jedit, not for raw Echo runtime debugging. It lists the Echo activity -that jedit can explain in workspace terms: - -- file opens that returned a bounded reading; -- edit submissions that returned receipts; -- bounded reads that refreshed the editor cache; -- exports and checkpoints from save; -- obstructions from the same flows. - -Rows are sorted by tick id when evidence carries one, otherwise by local -admission sequence. The selected row is visible with the same marker language as -other jedit drawers, and `j`/`k` plus page keys move selection while the drawer -owns focus. - -## Controls - -- `ctrl+h`: open or close Echo History. -- `esc`: close Echo History when it owns focus. -- `tab`: cycle through visible workspace panes. -- `j`/`k`, arrows, page up, page down: move the selected history row. - -`ctrl+h` is a workspace command. If a Vim-like normal-mode command is pending, -opening History moves focus out of the editor and clears the pending motion. -That avoids leaving an armed edit command behind while the user is inspecting -evidence. - -## Evidence Model - -The drawer stores `EchoHistoryEntry` values in `WorkspaceModel`. Each entry has: - -- `sequence`: local admission order; -- `tickId`: parsed from `tick:*` or receipt-shaped evidence when available; -- `kind`: open, edit, read, export, or checkpoint; -- `status`: opened, applied, observed, exported, checkpointed, or obstructed; -- `evidenceId`: receipt, reading, checkpoint, or other citable id; -- `summary`: path or obstruction message. - -This is deliberately a jedit optic over Echo evidence, not a complete Echo -activity log. A future lower-level Echo activity inspector can exist, but this -drawer should remain the editor-facing receipt trail. - -## Bijou Breakpoints - -The drawer participates in the same surface composition path as Files and -Graft. Files stay left aligned. Graft and History stack on the right, with -History at the outer edge and Graft immediately to its left. - -When all drawers are open, layout preserves a minimum editor region instead of -allowing drawers to consume the whole terminal. At narrow supported widths, -drawer widths scale down together. Below the workspace minimum terminal size, -jedit continues to show the existing small-terminal notice. - -## Worldline Jump Design - -The intended next experience is: - -1. Select a history row. -2. Press Enter. -3. jedit asks a port for a bounded historical reading at that evidence basis. -4. The editor reprojects that reading without mutating current Echo history. -5. The footer clearly marks that the editor is viewing a historical basis. - -That needs a real basis-navigation port and footer/view posture before it should -ship. A no-op Enter binding would make the drawer feel more complete than it is, -so the first slice exposes selection only. - -## Verification - -The implementation is covered by focused specs for: - -- `ctrl+h` opening History and clearing pending normal-mode motion; -- history rows populated from production text-session open/edit/export/checkpoint - results; -- drawer rendering of evidence ids and summaries; -- focus cycling and active-edge painting for History; -- layout behavior with Files, Graft, and History at narrow Bijou breakpoints; -- footer mode, hints, and context for the History drawer. diff --git a/docs/design/0035-jedit-wsc-durability-scope.md b/docs/design/0035-jedit-wsc-durability-scope.md deleted file mode 100644 index f4605414..00000000 --- a/docs/design/0035-jedit-wsc-durability-scope.md +++ /dev/null @@ -1,107 +0,0 @@ - - - -# jedit WSC Durability Scope - -Status: slice 111 scope document. - -## Claim - -jedit becomes durably powered by Echo only when its production text authority -can survive process death through Echo causal-history evidence. The host -filesystem is an import/export boundary. It is not the durable authority for an -opened production buffer after Echo has admitted that buffer into a worldline. - -This slice does not define a jedit-specific storage feature in Echo. It defines -the boundary that later slices must implement: - -```text -jedit-owned import/export/path policy --> generic Echo WSC causal-history persistence --> jedit-owned recovery/materialization/export adapters -``` - -Echo persists generic causal history and retained evidence. jedit owns file -paths, text semantics, buffer policy, UI posture, and export artifacts. - -## Durable Material - -The WSC-backed history for a jedit production edit must retain enough generic -Echo evidence to recover: - -- the worldline or site coordinate that hosted the edit; -- the accepted submission identity, if admission reached accepted posture; -- ticket or ingress correlation for accepted work; -- tick receipt or decided outcome correlation when work is decided; -- rejected or obstructed outcome posture when no edit was applied; -- reading envelope references for material shown to jedit; -- retained payload references required to materialize that reading; -- checkpoint or export evidence refs when jedit records them as app posture. - -jedit may persist additional adapter-private placement metadata next to WSC -history, such as workspace-relative file paths. That metadata is not Echo -semantics and must not enter Echo core APIs as file, text, buffer, or editor -nouns. - -## Restart States - -Every restart must classify recovered history into one of these postures: - -| State | Meaning | jedit behavior | -| --- | --- | --- | -| `not_accepted` | The edit never reached accepted Echo submission posture. | Keep host import explicit; do not invent pending work. | -| `pending` | Submission was accepted but no decided outcome was recovered. | Show pending posture; do not retry automatically. | -| `decided_applied` | Receipt says the edit applied under named law. | Restore materialized reading and receipt evidence. | -| `decided_rejected` | Receipt says the edit was rejected or conflicted. | Show final rejection; retry requires new user input. | -| `obstructed` | Required persisted evidence is missing or corrupt. | Fail closed with visible obstruction and no local authority fallback. | - -Missing ticket, receipt, reading, payload, or commit-marker evidence is -`obstructed`, not "best effort." Host file bytes may be offered as a fresh -import only through an explicit import path. - -## Export Boundary - -Saving or exporting a file is a jedit materialization operation: - -```text -selected Echo causal basis --> bounded reading/materialization --> jedit export adapter writes host bytes -``` - -Export does not mutate Echo causal history. If jedit wants to record the fact -that an export happened, that is app-owned posture over a reading/export -evidence ref. A failed export must not change the recovered Echo authority or -clear dirty, pending, stale, or obstructed posture. - -## Out Of Scope - -- Cross-device or adversarial replication. -- Blockchain-style consensus. -- jedit nouns in Echo persistence APIs. -- Treating WSC as a host-file backup format. -- Local undo stacks as production authority. -- Silent retry after restart. -- Historical export UI polish beyond the app-safe basis and materialization - boundary. - -## Slice Handoff - -Slices 112-119 are Echo-side or cross-boundary durability primitives: - -- generic WSC store port; -- accepted submission persistence; -- ticket and receipt correlation; -- reading and retention reference persistence; -- atomic commit markers; -- pending and decided recovery; -- half-accepted corruption rejection. - -Slices 120-125 consume those primitives in jedit: - -- workspace store adapter; -- startup recovery; -- edit-settlement persistence; -- restart round-trip proof; -- historical basis selection; -- current history export. diff --git a/docs/design/0036-title-intro-startup-file-modal.md b/docs/design/0036-title-intro-startup-file-modal.md deleted file mode 100644 index ed1ea1dd..00000000 --- a/docs/design/0036-title-intro-startup-file-modal.md +++ /dev/null @@ -1,196 +0,0 @@ - - - -# Title Intro And Startup File Drawer - -Status: design-first slice for the title screen startup flow. - -## Claim - -jedit's no-editor startup screen should feel like a product entry flow, not only -an ambient title render. The title sequence introduces FLYINGROBOTS and jedit on -a deterministic timeline, allows immediate skip with Enter or Tab, and then -opens a focused startup file drawer where the user can type a target and inspect -files from the current working directory. - -This is UI state in jedit. It does not create Echo work, mutate text authority, -or introduce new runtime modes. The file list is a jedit-facing projection of -the existing startup directory entries, not a recent-workspace database or a -raw Echo activity log. - -## Intro Timeline - -The sequence starts when no editor is open: - -| Time | State | -| ------- | ------------------------------------------------------------ | -| `0s` | FLYINGROBOTS logo and `PRESENTS` are visible immediately. | -| `2s` | jedit logo appears. | -| `2s-7s` | FLYINGROBOTS, `PRESENTS`, and jedit remain visible together. | -| `7s` | Intro is complete and the startup file drawer opens. | - -The title renderer may keep the existing jedit logo sheen while the jedit logo -is visible. The old delayed 5s FLYINGROBOTS entrance and long 15s fade are -removed from the product startup path. - -## Skip Semantics - -Enter and Tab skip the intro only while the title startup flow is active and -no editor is open. Skipping marks the intro complete and opens the startup file -drawer immediately. - -Skip must not: - -- submit an edit intent; -- open a file; -- quit the process; -- activate scene-picker or settings behavior; -- leave an armed normal-mode motion behind. - -Escape is not a startup skip key. When the drawer is closed, Escape opens the -standard quit confirmation. After the startup file drawer is open, Enter and -Escape are drawer keys, not title intro skip keys. - -## Startup File Drawer - -The post-intro selector is a Bijou-backed left drawer over the title scene. It -opens with a critically damped spring progress value and contains: - -- a single-line input area; -- a current-directory file list; -- stable keyboard focus on the input by default. - -Initial file rows should be useful with current state and cheap to compute: - -- the active workspace root as context, not as a selectable recent workspace; -- file and directory entries from `WorkspaceModel.entries`; -- deterministic ordering that matches the file drawer unless filtering is - active; -- row labels that distinguish directories from files without exposing host - adapter internals. - -The first implementation renders the input as local UI state, filters visible -current-directory rows, and opens selected file rows through the existing -production file-open command path. Directory rows reuse the existing file-tree -directory transition path and keep the drawer open in the new directory. - -## Live Title Backdrop - -While the startup file drawer is open, the title scene keeps ray tracing and -camera motion live until the app has a file open. The drawer is an overlay over -the current title scene, not a modal that disables the renderer. - -This is a render-performance posture only: - -- time ticks may continue updating runtime timing fields; -- drawer input must stay responsive through normal Bijou message handling; -- opening a file stops the title scene because the editor becomes the active - rendered surface; -- slow idle title-screen caching remains a separate non-browser posture. - -## Small Screens - -The startup drawer participates in the same Bijou breakpoint posture as drawers and -overlays: - -- it must fit inside the supported workspace minimum; -- it should clamp width to the viewport and leave at least one column of title - scene visible when possible; -- on short terminals it should reduce the visible file row count before - shrinking the input; -- below the existing minimum terminal size, the small-terminal notice remains - authoritative and the drawer is not rendered. - -## State Model - -Workspace state needs a startup-flow structure with: - -- intro completion flag; -- drawer open flag; -- drawer progress; -- input text; -- selected file row index. - -The intro completion flag is derived from either elapsed title time or explicit -skip. After the user closes the drawer, Enter or `o` should reopen it while no -editor or higher-priority overlay owns focus. - -File rows should be value objects, not pre-rendered strings, so the renderer can -adapt to width and theme tokens. - -## Controls - -While intro is active: - -- `enter`: skip intro and open startup file drawer. -- `tab`: skip intro and open startup file drawer. -- `esc`: open the standard quit confirmation. -- `m`, `M`: cycle the title mesh material preset and show a toast with its name. - -While the startup file drawer is open: - -- printable keys append to the input. -- `backspace` deletes from the input. -- `j`, `down`: move file selection down when the input is empty or the drawer is - in list navigation posture. -- `k`, `up`: move file selection up when the input is empty or the drawer is in - list navigation posture. -- `esc`: dismiss the drawer with the close spring animation. -- `enter`: opens the selected file through the existing production open path, - or enters the selected directory while keeping the drawer open. - -After the intro is complete and the drawer is closed: - -- `tab`, `enter`, `o`: reopen the startup file drawer. -- `esc`: open the standard quit confirmation. -- `m`, `M`: cycle the title mesh material preset and show a toast with its name. - -## Evidence - -The first executable claim is: - -```text -At title time 0 FLYINGROBOTS is visible, at title time 2 jedit is visible, at -title time 7 the workspace considers the intro complete, and Enter/Tab -complete it immediately by opening a startup drawer whose input filters current -directory file rows. -``` - -Focused witnesses: - -- title presentation sequence spec for the new timing; -- workspace key spec for Enter/Tab skip before drawer; -- workspace render spec for drawer input and current-directory files; -- workspace key spec for input editing and animated Escape close; -- workspace key spec for selected file open and selected directory traversal; -- workspace render spec proving drawer input keeps the title renderer live; -- workspace key spec proving `m` and `M` cycle title mesh material presets; -- small-screen spec proving the drawer does not override the minimum-terminal - notice. - -## Fifteen-Slice Ledger - -- [x] Slice 1: retime the pure title presentation sequence. -- [x] Slice 2: pin the new logo/sheens timeline with focused title specs. -- [x] Slice 3: add startup-flow state to the workspace model. -- [x] Slice 4: derive current-directory drawer rows from `WorkspaceModel.entries`. -- [x] Slice 5: render the startup drawer shell with input and file rows. -- [x] Slice 6: integrate the drawer as a workspace overlay above the title scene. -- [x] Slice 7: preserve the small-terminal notice as the highest-priority view. -- [x] Slice 8: skip the intro with Enter or Tab before other title keys. -- [x] Slice 9: auto-complete the intro and open the drawer at the timeline end. -- [x] Slice 10: edit drawer input with printable keys and Backspace. -- [x] Slice 11: filter file rows from the drawer input. -- [x] Slice 12: navigate drawer file rows with arrows and Vim-shaped keys. -- [x] Slice 13: open the selected file through the existing production open path. -- [x] Slice 14: handle directories, empty directories, and no-match states. -- [x] Slice 15: close quality gaps, document follow-on ideas/debt, and refresh the PR. - -## Non-Goals - -- No command palette implementation. -- No fuzzy project search. -- No Zed-compatible project switcher semantics. -- No recent workspace database. -- No Echo core changes. -- No app-controlled Echo lifecycle or tick authority. diff --git a/docs/design/0037-title-intro-fade-before-modal.md b/docs/design/0037-title-intro-fade-before-modal.md deleted file mode 100644 index f9cb5527..00000000 --- a/docs/design/0037-title-intro-fade-before-modal.md +++ /dev/null @@ -1,383 +0,0 @@ ---- -title: "WF-0037 - Title Intro Fade Before Drawer" -legend: "WF" -lane: "design" -issue: "https://github.com/flyingrobots/jedit/issues/63" -status: "active" -owners: - - "@flyingrobots" -created: "2026-06-04" -updated: "2026-06-05" ---- - -# WF-0037 - Title Intro Fade Before Drawer - -## Linked Issue - -- https://github.com/flyingrobots/jedit/issues/63 - -## Decision Summary - -The title presentation sequence will fade `FLYINGROBOTS PRESENTS` out before -the startup file browser opens, then fade the `jedit` logo out before the -startup file drawer appears. The startup selector remains responsible only for -opening at the completed intro boundary; the title presentation owns logo -opacity, sheen timing, and direction-aware highlight motion. - -## Sponsored Human - -A person starting jedit without a file wants the title sequence to finish cleanly -before the file browser appears so that startup feels deliberate, without having -title logos visually collide with the first actionable drawer. - -## Sponsored Agent - -An agent needs a deterministic title-presentation contract so it can assert the -logo opacity and drawer-open boundary from rendered output, without inferring -animation state from visual overlap in terminal screenshots. - -## Hill - -By the end of this cycle, the user sees `FLYINGROBOTS PRESENTS` immediately, -the `jedit` logo at 2 seconds, the `FLYINGROBOTS PRESENTS` layer fading after 3 -seconds, the `jedit` layer fading after 5 seconds, and the file browser opening -at 7 seconds, and the repo proves it with focused title-render and workspace -startup tests. - -## Current Truth - -The merge target for this cycle is `origin/main` at -`2fd89d253046b1dd2b4122426dc0a3dd2f8ed7f6`. - -Current anchors: - -- `src/ui/title-presentation-sequence.ts` sets the title appear time to 2 - seconds, the complete time to 7 seconds, and the fade duration to 0 seconds: - [src/ui/title-presentation-sequence.ts#L17:2fd89d253046b1dd2b4122426dc0a3dd2f8ed7f6](https://github.com/flyingrobots/jedit/blob/2fd89d253046b1dd2b4122426dc0a3dd2f8ed7f6/src/ui/title-presentation-sequence.ts#L17). -- The same sequence keeps any visible layer fully opaque until its fade boundary - when fade duration is 0: - [src/ui/title-presentation-sequence.ts#L65:2fd89d253046b1dd2b4122426dc0a3dd2f8ed7f6](https://github.com/flyingrobots/jedit/blob/2fd89d253046b1dd2b4122426dc0a3dd2f8ed7f6/src/ui/title-presentation-sequence.ts#L65). -- `src/app/workspace/startup-file-modal.ts` opens the startup browser at 7 - seconds: - [src/app/workspace/startup-file-modal.ts#L17:2fd89d253046b1dd2b4122426dc0a3dd2f8ed7f6](https://github.com/flyingrobots/jedit/blob/2fd89d253046b1dd2b4122426dc0a3dd2f8ed7f6/src/app/workspace/startup-file-modal.ts#L17). -- The existing title spec asserts both logos are still visible at 6.5 seconds - and gone only after 7 seconds: - [spec/title-screen.spec.mjs#L247:2fd89d253046b1dd2b4122426dc0a3dd2f8ed7f6](https://github.com/flyingrobots/jedit/blob/2fd89d253046b1dd2b4122426dc0a3dd2f8ed7f6/spec/title-screen.spec.mjs#L247). -- The linked bug report records the desired timing and observed regression: - https://github.com/flyingrobots/jedit/issues/63. - -## Problem - -The title sequence currently treats the file browser open time as the same -moment as logo disappearance. Because fade duration is 0, the logos stay fully -visible through the intro and then disappear abruptly at the drawer boundary, -which regresses the requested product startup rhythm. - -## Scope - -This cycle includes: - -- Retiming the pure title presentation sequence. -- Preserving the 7 second startup selector open boundary. -- Preserving Enter and Escape as intentional intro skips. -- Adding regression coverage that fails when the logos are still visible near - the drawer-open boundary. -- Filling in this design doc retrospective before the PR is marked ready. - -## Non-Goals - -This cycle does not include: - -- Replacing the startup file drawer with a full app-frame picker. -- Changing the file browser drawer layout. -- Adding a new title-scene director timeline authoring tool. -- Adding screenshot or pixel-baseline infrastructure beyond focused rendered - surface assertions. -- Changing localization strings. - -## User Experience / Product Shape - -The user starts jedit without a file. The title scene appears immediately with -`FLYINGROBOTS PRESENTS`. At 2 seconds, `jedit` appears and the highlight sheen -can sweep across the logo in the local text direction. At 3 seconds, the -`FLYINGROBOTS PRESENTS` layer begins fading away. At 5 seconds, the `jedit` -layer begins fading away. At 7 seconds, neither logo is visible and the startup -file browser can appear over the live title scene. - -Success is communicated by the drawer appearing only after the title layers have -cleared. Failure is the old behavior: any title logo still visible at the drawer -open boundary. The user can skip the sequence with Enter or Tab before the -drawer opens; a skip intentionally jumps to the drawer without playing the fade. -Escape opens the standard quit confirmation when the browser is closed. - -### User Journey - -```mermaid -flowchart TD - Start[Launch jedit without a file] --> Present[Frame 0 shows FLYINGROBOTS PRESENTS] - Present --> Logo[2s shows jedit and starts sheen window] - Logo --> SponsorFade[3s fades FLYINGROBOTS PRESENTS] - SponsorFade --> TitleFade[5s fades jedit] - TitleFade --> Drawer[7s opens file browser] - Present --> Skip[Enter or Tab skips intro] - Skip --> Drawer -``` - -### Wide UI Mockup - -Static layout does not change in this cycle. The wide product shape is the -existing full-width title scene with the following timeline: - -| Time | Wide terminal state | -| ---- | ------------------------------------------------------- | -| 0s | `FLYINGROBOTS PRESENTS` visible above the scene. | -| 2s | `jedit` logo visible below the sponsor layer. | -| 3s | Sponsor layer fades. | -| 5s | `jedit` layer fades. | -| 7s | Startup file drawer appears with no title logo overlap. | - -### Narrow UI Mockup - -Static layout does not change in this cycle. Narrow terminals use the same -timeline and the same existing drawer breakpoint behavior; this cycle only -changes layer opacity before the drawer appears. - -### Accessibility Considerations - -The intro remains keyboard-skippable with Enter and Escape. The sequence does -not add hidden state that must be narrated. The drawer retains existing focus -ownership once it opens. - -## Runtime / API Contract - -Contract: `titlePresentationSequence(time, textDirection)`. - -Relevant behavior: - -- `flyingRobotsOpacity` is 1 at 0 seconds. -- `titleOpacity` is 0 before 2 seconds and greater than 0 at 2 seconds. -- `titleSheen` is present only while the title logo is visible and inside the - sheen window. -- `flyingRobotsOpacity` fades after 3 seconds and reaches 0 before the 7 second - drawer boundary. -- `titleOpacity` fades after 5 seconds and reaches 0 before the 7 second drawer - boundary. -- Right-to-left text direction keeps the sheen direction right-to-left. -- Startup selector auto-open remains keyed to 7 seconds in - `applyStartupIntroTime`. - -## Lower Modes - -No separate lower-mode output changes. The proof surface is the same rendered -terminal surface used by the existing title-screen spec, and the existing -keyboard-only skip behavior remains covered by workspace specs. - -## Data / State Model - -| Category | Description | -| ------------------------- | ---------------------------------------------------------------------------- | -| Source of truth | `titlePresentationSequence` owns logo opacity and sheen timing. | -| Derived state | Rendered title cells derive from opacity values. | -| Invalid states | The startup drawer opens at 7 seconds while any title logo layer is visible. | -| Reset behavior | A new process starts from title time 0. | -| Serialization | No serialized state changes. | -| Deterministic assumptions | Tests pass fixed times into deterministic render functions. | - -```mermaid -stateDiagram-v2 - [*] --> SponsorVisible - SponsorVisible --> TitleVisible: 2s - TitleVisible --> SponsorFading: 3s - SponsorFading --> TitleFading: 5s - TitleFading --> DrawerReady: 7s -``` - -## Accessibility Posture - -| Concern | Posture | -| --------------------------------- | ------------------------------------------------------------------------------------------------- | -| Semantic labels or facts | No new copy or semantic labels. | -| Focus order or ownership | Focus remains in title startup flow until drawer open; drawer owns focus after 7 seconds or skip. | -| Hidden or visual-only information | No required action depends on observing the fade. | -| Keyboard behavior | Enter and Escape still skip the intro before the drawer opens. | -| Secret or redaction behavior | Not applicable. | - -## Localization / Directionality Posture - -No visible strings change. Directionality remains relevant only to the existing -logo sheen direction, which must keep sweeping right-to-left for right-to-left -locales. - -## Agent Inspectability / Explainability Posture - -Agents can inspect: - -- deterministic `titlePresentationSequence` return values; -- rendered surface cells at fixed timestamps; -- workspace startup state after `applyStartupIntroTime`; -- GitHub issue and PR links attached to this cycle. - -## Linked Invariants - -- Tests are executable spec. -- Runtime truth beats type theater. -- Design should become repo truth. -- Files and previews are projections. -- Echo authority remains outside jedit product nouns. - -## Design Alternatives Considered - -### Option A: Independent Fade Windows - -Pros: - -- Matches the reported timing exactly. -- Keeps drawer open time stable at 7 seconds. -- Keeps animation state local to the title presentation sequence. - -Cons: - -- Adds two fade constants instead of one shared complete boundary. - -### Option B: Delay Drawer Until Existing Logos Disappear - -Pros: - -- Smaller code change if current sequence stayed mostly intact. - -Cons: - -- Changes startup interaction latency. -- Does not match the issue's requested timing. -- Keeps the title sequence coupled to drawer timing. - -## Decision - -Choose Option A. The title presentation will own separate fade start times for -the sponsor layer and title layer while the startup flow keeps the drawer open -boundary at 7 seconds. - -## Implementation Slices - -- [x] Slice 1: Commit this design packet. Commit message: - `docs: design title intro fade before drawer`. -- [x] Slice 2: Add a failing rendered title regression test for the 3s, 5s, - and 7s fade contract. -- [x] Slice 3: Retiming `titlePresentationSequence` with independent fade - windows while preserving sheen direction. -- [x] Slice 4: Verify focused title and workspace startup tests. -- [x] Slice 5: Fill in the retrospective, push, and mark the PR ready. - -## Tests To Write First - -Behavior tests required: - -- [x] `spec/title-screen.spec.mjs` proves sponsor fade after 3 seconds, title - fade after 5 seconds, and no logo cells before the drawer opens at 7 seconds. -- [x] `spec/workspace-title-screen.spec.mjs` continues proving Enter and Escape - skip directly to the startup drawer. - -Documentation and process tests: - -- [x] Prettier validates this design doc. - -Rule: documentation tests cannot be the only proof for implementation work. - -## Acceptance Criteria - -The work is done when: - -- [x] Rendered title output proves `FLYINGROBOTS PRESENTS` is absent before the - drawer opens. -- [x] Rendered title output proves `jedit` is absent before the drawer opens. -- [x] Direction-aware sheen behavior still passes. -- [x] Startup drawer still opens at 7 seconds and still supports Enter/Tab - skip. -- [x] Issue and PR are linked correctly. -- [ ] CI and local validation are green. - -## Validation Plan - -Commands expected before PR: - -```bash -npm run build -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-screen.spec.mjs spec/workspace-title-screen.spec.mjs -npm run quality -npx --no-install prettier --check docs/design/0037-title-intro-fade-before-modal.md -``` - -## Playback / Witness - -Reviewers can run: - -```bash -npm run build -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-screen.spec.mjs spec/workspace-title-screen.spec.mjs -``` - -Visual reproduction: - -- Launch jedit without a file. -- Do not press keys. -- Watch `FLYINGROBOTS PRESENTS` immediately, `jedit` at 2 seconds, sponsor - fade after 3 seconds, title fade after 5 seconds, and file browser at 7 - seconds. -- Repeat with Enter or Tab before 7 seconds to confirm skip still opens the - drawer immediately. - -## Risks - -Known risks: - -- Rendered-cell assertions can accidentally count scene cells as logo cells if - the test predicates are too broad. -- Very short fade windows could become visually abrupt. - -Mitigations: - -- Reuse existing logo cell predicates that already distinguish bold logo - overlays from scene cells. -- Keep fade windows long enough to be visible while still complete before the - drawer opens. - -## Follow-On Debt - -No follow-on debt is introduced by this cycle. Existing title-screen issues -remain tracked separately: - -- https://github.com/flyingrobots/jedit/issues/39 -- https://github.com/flyingrobots/jedit/issues/40 -- https://github.com/flyingrobots/jedit/issues/41 -- https://github.com/flyingrobots/jedit/issues/42 -- https://github.com/flyingrobots/jedit/issues/43 -- https://github.com/flyingrobots/jedit/issues/44 -- https://github.com/flyingrobots/jedit/issues/46 -- https://github.com/flyingrobots/jedit/issues/56 -- https://github.com/flyingrobots/jedit/issues/78 - -## Retrospective - -What changed from the design: - -- Implemented the independent fade-window option from the decision section. -- Started the title logo sheen at the title logo appearance time so the - highlight is active when `jedit` appears. -- Preserved the startup drawer open boundary at 7 seconds. - -What the tests proved: - -- RED: the updated rendered title spec failed because 289 sponsor logo cells - were still visible at the new sponsor fade-complete point. -- GREEN: - `JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-screen.spec.mjs spec/workspace-title-screen.spec.mjs` - passed after the sequence retiming. - -What remains open: - -- GitHub CI has not run yet at the time of this implementation commit. -- Other title-screen issues remain tracked as separate cycles. - -PR: - -- https://github.com/flyingrobots/jedit/pull/88 diff --git a/docs/design/0038-startup-file-modal-bijou-recovery.md b/docs/design/0038-startup-file-modal-bijou-recovery.md deleted file mode 100644 index 63583e1f..00000000 --- a/docs/design/0038-startup-file-modal-bijou-recovery.md +++ /dev/null @@ -1,450 +0,0 @@ ---- -title: "WF-0038 - Startup File Drawer Bijou Recovery" -legend: "WF" -lane: "design" -issue: "https://github.com/flyingrobots/jedit/issues/56" -status: "active" -owners: - - "@flyingrobots" -created: "2026-06-04" -updated: "2026-06-05" ---- - -# WF-0038 - Startup File Drawer Bijou Recovery - -## Linked Issue - -- https://github.com/flyingrobots/jedit/issues/56 - -## Decision Summary - -The startup file selector will keep Jedit-owned file identity, filtering, and -open effects, but it will render as a Bijou-backed left drawer whose selectable -file list uses Bijou's browsable list and viewport surface. The drawer opens -with a critically damped spring progress value, exposes real scrollbar -affordance on overflow, dismisses with the same spring toward zero progress, -and remains recoverable with Tab, Enter, or `o` after Escape dismissal. - -## Sponsored Human - -A person launching jedit without a file wants the startup file selector to look -and behave like the rest of the app so that opening a file is obvious and -recoverable, without getting stranded on an inert title screen after pressing -Escape. - -## Sponsored Agent - -An agent needs a deterministic drawer rendering contract so it can inspect theme -tokens, spring progress, overflow affordances, and key recovery from surfaces and -model state, without comparing screenshots or assuming private title-screen -state. - -## Hill - -By the end of this cycle, the title startup selector slides in as a Bijou left -drawer, renders overflowing file rows with a Bijou scrollbar using jedit theme -tokens, Escape can dismiss the selector without trapping the user, Tab, Enter, -or `o` reopens it from the title screen, and focused workspace specs prove the -behavior. - -## Current Truth - -The merge target for this cycle is `origin/main` at -`62b8ae43e729bec7602311477646c00c5fb817b6`. - -Current anchors: - -- `src/ui/startup-file-modal.ts` imports Bijou's `modal` shell: - [src/ui/startup-file-modal.ts#L2:62b8ae43e729bec7602311477646c00c5fb817b6](https://github.com/flyingrobots/jedit/blob/62b8ae43e729bec7602311477646c00c5fb817b6/src/ui/startup-file-modal.ts#L2). -- The same file still hand-paints the modal body and rows: - [src/ui/startup-file-modal.ts#L68:62b8ae43e729bec7602311477646c00c5fb817b6](https://github.com/flyingrobots/jedit/blob/62b8ae43e729bec7602311477646c00c5fb817b6/src/ui/startup-file-modal.ts#L68). -- The current scroll window is bespoke row slicing with no rendered scrollbar: - [src/ui/startup-file-modal.ts#L98:62b8ae43e729bec7602311477646c00c5fb817b6](https://github.com/flyingrobots/jedit/blob/62b8ae43e729bec7602311477646c00c5fb817b6/src/ui/startup-file-modal.ts#L98). -- Escape closes the open startup browser: - [src/app/workspace/startup-file-modal-key-bindings.ts#L44:62b8ae43e729bec7602311477646c00c5fb817b6](https://github.com/flyingrobots/jedit/blob/62b8ae43e729bec7602311477646c00c5fb817b6/src/app/workspace/startup-file-modal-key-bindings.ts#L44). -- Existing workspace specs cover rendering, filtering, opening files, bounded - navigation, directory entry, empty states, and small-terminal behavior: - [spec/workspace-title-screen.spec.mjs#L258:62b8ae43e729bec7602311477646c00c5fb817b6](https://github.com/flyingrobots/jedit/blob/62b8ae43e729bec7602311477646c00c5fb817b6/spec/workspace-title-screen.spec.mjs#L258). -- Bijou TUI exposes `browsableListSurface` and `viewportSurface` with a - `showScrollbar` option through `@flyingrobots/bijou-tui` 7.0.0. -- The linked issue records the user-facing failure report: - https://github.com/flyingrobots/jedit/issues/56. - -## Problem - -The startup file selector is only partially Bijou-backed. It uses Bijou for the -modal frame but owns row clipping and list rendering itself, so long current -directories do not expose a scrollbar affordance. Escape dismisses the modal -and leaves no tested key path to reopen it from the title screen. - -## Scope - -This cycle includes: - -- Rendering the selectable file row viewport with Bijou's browsable list - surface. -- Painting list, selected row, and scrollbar cells with existing jedit theme - tokens. -- Preserving current filtering, directory navigation, selected index, and file - open behavior. -- Replacing the centered startup selector shell with a Bijou left drawer. -- Animating the drawer width through a runtime-owned, critically damped spring - progress value. -- Adding a recoverable closed-drawer title path: Tab, Enter, or `o` reopens the - startup selector when no editor is open and the intro is complete. -- Adding regression specs for overflow scrollbar rendering, theme-token use, - and Esc recovery. - -## Non-Goals - -This cycle does not include: - -- Moving Jedit file identity or open effects into Bijou's `filePicker` state. -- Adding mouse support to the startup selector. -- Replacing the startup drawer with a full app-frame project picker. -- Changing localization copy. -- Changing the title intro timing. - -## User Experience / Product Shape - -The user starts jedit without a file. After the intro, the file selector slides -in from the left over the live title scene. The selector shows the current -directory, an input line, a current-directory label, and a scrollable list of -matching files. When the matching file list overflows, a scrollbar appears at -the list edge. Escape dismisses the selector with the drawer-close spring. From -the title screen, Tab, Enter, or `o` opens the selector again. - -Success is communicated by the visible scrollbar on overflow, selected row -highlighting, and the drawer returning when the user presses Tab, Enter, or `o` -after Escape. Failure is a long file list with no scroll affordance or a -drawer-close state where common open keys do nothing. - -### User Journey - -```mermaid -flowchart TD - Start[Intro completes] --> Drawer[Startup selector drawer opens] - Drawer --> Filter[User types filter] - Drawer --> Scroll[Long list shows scrollbar] - Drawer --> Escape[User presses Escape] - Escape --> Title[Title screen remains active] - Title --> Reopen[User presses Tab, Enter, or o] - Reopen --> Drawer - Drawer --> Open[Enter opens selected file] -``` - -### Wide UI Mockup - -```text -+----------------------------------------------+ title scene backdrop -| Open file | remains visible -| /repo | -| Filter: read | -| | -| Current directory | -| > src/ █ | -| README.md │ | -| package.json │ | -| docs/ │ | -+----------------------------------------------+ -``` - -The wide view anchors the selector to the left edge. The drawer width is bounded -by the existing maximum selector width and the spring progress; the title scene -remains visible to the right while the drawer is open. - -### Narrow UI Mockup - -```text -+------------------------------------+ -| Open file | -| /repo | -| Filter: r | -| Current directory | -| > README.md █ | -| ROADMAP.md │ | -+------------------------------------+ -``` - -The narrow view keeps the existing small-terminal guard. When the terminal is -below the existing minimum geometry, the selector remains hidden and the -minimum-terminal notice wins. - -### Accessibility Considerations - -The startup selector is keyboard-only and remains keyboard-recoverable after -Escape. The scrollbar is an additional visual affordance; it is not the only -way to move through the list. Agents can inspect model state and rendered -surface cells to determine focus and overflow. - -## Runtime / API Contract - -Contract: startup file drawer rendering and key bindings. - -Relevant behavior: - -- `renderStartupFileDrawer` returns a `Surface` rendered by Bijou's `drawer` - primitive. -- `WorkspaceModel.startupFileDrawerProgress` clamps to `[0, 1]` and controls the - drawer width. -- Runtime time-tick completion and startup selector reopen keys emit a Bijou - spring animation command from the current progress to `1`. -- File rows are rendered through Bijou's browsable list surface. -- Overflowing rows render a scrollbar in the list viewport. -- The scrollbar track and thumb are painted from jedit theme tokens. -- Selected rows continue to use the current selected-index model. -- Escape marks an open startup drawer closed and emits a spring animation from - current progress to `0`. -- A closing drawer remains rendered while `startupFileDrawerProgress > 0`. -- Tab, Enter, and `o` reopen the startup drawer when no editor is open, the - intro is complete, and no higher-priority overlay owns focus. - -## Lower Modes - -The rendered surface remains deterministic for tests and non-interactive -inspection. The small-terminal lower mode is unchanged: the minimum-terminal -notice suppresses the startup selector below the existing geometry threshold. - -## Data / State Model - -| Category | Description | -| ------------------------- | ---------------------------------------------------------------------------------------------------------------------- | -| Source of truth | `WorkspaceModel.entries`, `startupFileModalInput`, `startupFileModalSelectedIndex`, and drawer progress. | -| Derived state | Filtered rows, Bijou list state, first visible row, scrollbar position, and rendered drawer width. | -| Invalid states | Drawer closed after Escape with no key path to reopen while no editor is open. | -| Reset behavior | Reopened drawer resets selection to the first row; Escape animates progress to `0`; file open resets progress to `0`. | -| Serialization | No serialized state changes. | -| Deterministic assumptions | Render tests use fixed model entries, theme tokens, and explicit drawer progress values. | - -```mermaid -stateDiagram-v2 - [*] --> Open - Open --> Closing: Escape / spring to 0 - Closing --> ClosedRecoverable: progress 0 - ClosedRecoverable --> Open: Tab, Enter, or o - Open --> FilePending: Enter on file - Open --> Open: Enter on directory -``` - -## Accessibility Posture - -| Concern | Posture | -| --------------------------------- | ---------------------------------------------------------------------------------- | -| Semantic labels or facts | Existing title, hint, input label, and current-directory copy remain. | -| Focus order or ownership | Drawer owns focus while open; title screen owns focus after Escape. | -| Hidden or visual-only information | Scrollbar is redundant to keyboard navigation and model-selected index. | -| Keyboard behavior | Escape closes; Tab, Enter, and `o` reopen; arrows and Vim keys keep existing navigation. | -| Secret or redaction behavior | Not applicable. | - -## Localization / Directionality Posture - -No user-visible strings change. The existing localized selector copy remains -authoritative. Directionality does not change in this cycle. - -## Agent Inspectability / Explainability Posture - -Agents can inspect: - -- `WorkspaceModel.startupFileModalOpen` and `startupFileDrawerProgress` after - Escape and reopen keys; -- rendered drawer `Surface` cells for scrollbar characters; -- rendered cells for theme-token foreground/background values; -- focused row text and model-selected index; -- PR and issue links for this cycle. - -## Linked Invariants - -- Tests are executable spec. -- Runtime truth beats type theater. -- Design should become repo truth. -- Buffers, panes, panels, and lenses are different things. -- Files and previews are projections. -- Echo authority remains outside jedit product nouns. - -## Design Alternatives Considered - -### Option A: Adopt Bijou Browsable List Surface - -Pros: - -- Reuses Bijou's viewport and scrollbar behavior. -- Keeps Jedit's file identity, filtering, and open effects unchanged. -- Gives this cycle a focused, testable surface contract. - -Cons: - -- Jedit still maps its theme tokens onto the resulting surface. - -### Option B: Adopt Bijou File Picker State - -Pros: - -- Would reuse more of Bijou's file picker surface and state transforms. - -Cons: - -- Duplicates or bypasses Jedit's existing file entry port and directory-open - behavior. -- Risks changing file identity while fixing a UI affordance bug. - -### Option C: Keep Bespoke Rows and Paint a Custom Scrollbar - -Pros: - -- Smallest code change. - -Cons: - -- Continues the exact bespoke-list drift the issue calls out. -- Makes future list behavior diverge from Bijou primitives. - -## Decision - -Choose Option A plus a Bijou drawer shell. Jedit remains responsible for product -file semantics and startup flow state, while Bijou owns the drawer, list -viewport, scrollbar primitive, and spring animation primitive used by the -selector. - -## Implementation Slices - -- [x] Slice 1: Commit this design packet. Commit message: - `docs: design startup file modal Bijou recovery`. -- [x] Slice 2: Add failing specs for overflow scrollbar, scrollbar token use, - and Escape-to-reopen recovery. -- [x] Slice 3: Render file rows through Bijou `browsableListSurface` with - jedit theme-token styling. -- [x] Slice 4: Add title-screen reopen key handling after Escape. -- [x] Slice 5: Verify focused tests, quality, and docs formatting. -- [x] Slice 6: Fill retrospective, push, mark PR ready, and merge when eligible. -- [x] Slice 7: Convert the startup selector shell to a Bijou left drawer with - critical spring progress. Commit message: - `UX: animate startup file drawer`. - -## Tests To Write First - -Behavior tests required: - -- [x] `spec/workspace-title-screen.spec.mjs` proves overflowing startup drawer - rows render a scrollbar. -- [x] `spec/workspace-title-screen.spec.mjs` proves scrollbar cells use jedit - theme token colors. -- [x] `spec/workspace-title-screen.spec.mjs` proves Escape followed by Tab, - Enter, or `o` reopens the startup selector from the title screen. -- [x] `spec/workspace-title-screen.spec.mjs` proves drawer width follows spring - progress. -- [x] `spec/workspace-runtime.spec.mjs` proves intro completion emits the startup - drawer animation command and that the spring is critically damped. -- [x] Existing workspace startup specs continue to prove filtering, opening, - directory navigation, and small-terminal behavior. - -Documentation and process tests: - -- [x] Prettier validates this design doc. - -Rule: documentation tests cannot be the only proof for implementation work. - -## Acceptance Criteria - -The work is done when: - -- [x] Overflowing startup selector rows visibly expose a scrollbar. -- [x] The startup selector is painted as a left drawer instead of a centered - modal. -- [x] Drawer open is driven by a critically damped spring progress command. -- [x] The scrollbar and selected row use theme-token-derived cell styles. -- [x] Escape dismissal is recoverable with Tab, Enter, or `o`. -- [x] Existing startup selector filtering and open behavior still pass. -- [x] New strings have supported translations, if relevant. -- [x] Issue and PR are linked correctly. -- [ ] CI and local validation are green. - -## Validation Plan - -Commands expected before PR: - -```bash -npm run build -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/workspace-title-screen.spec.mjs -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/workspace-runtime.spec.mjs -npm run quality -npx --no-install prettier --check docs/design/0038-startup-file-modal-bijou-recovery.md -``` - -## Playback / Witness - -Reviewers can run: - -```bash -npm run build -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/workspace-title-screen.spec.mjs -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/workspace-runtime.spec.mjs -``` - -Manual playback: - -- Launch jedit without a file from a directory with more files than the selector - can show. -- Wait for the startup selector. -- Confirm it opens from the left as a drawer and the list shows a scrollbar. -- Press Escape, then Tab, Enter, or `o`, and confirm the selector returns. - -## Risks - -Known risks: - -- Bijou list rows may not preserve jedit's selected-row colors unless Jedit - explicitly maps theme tokens after rendering. -- Reopen keys could steal input from another overlay if the candidate predicate - is too broad. -- The drawer could visually pop in if the runtime forgets to emit the spring - animation command at intro completion or reopen. - -Mitigations: - -- Add token-level surface assertions for the scrollbar and selected row. -- Reuse the existing startup intro candidate constraints and require no editor, - no drawer, and editor focus before reopening. -- Add runtime coverage for intro completion animation and key-binding coverage for - reopen animation. - -## Follow-On Debt - -No follow-on debt is introduced by this cycle. Broader title-screen component -tooling remains tracked by separate issues. - -## Retrospective - -What changed from the design: - -- Implemented the planned Bijou `browsableListSurface` row viewport while - preserving Jedit-owned file rows and open behavior. -- Painted selected row and scrollbar cells with jedit theme tokens after Bijou - renders the viewport. -- Added title-screen reopen handling for Tab, Enter, and `o` after Escape - dismissal. -- Converted the centered selector shell to a Bijou left drawer painted above the - live title scene. -- Added `startupFileDrawerProgress` and Bijou spring animation commands for intro - completion and reopen. - -What the tests proved: - -- RED: the new overflow test failed because no startup selector scrollbar thumb - existed, and the new recovery test failed because Enter after Escape left the - selector closed. -- GREEN: - `JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/workspace-title-screen.spec.mjs` - passed after the renderer and key-binding changes. -- GREEN: - `JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/workspace-runtime.spec.mjs` - passed after the runtime animation contract was added. -- `npm run quality` and Prettier checks passed locally. - -What remains open: - -- GitHub CI has not run yet at the time of this implementation commit. -- Other title-screen issues remain tracked as separate cycles. - -PR: - -- https://github.com/flyingrobots/jedit/pull/89 diff --git a/docs/design/0039-title-screen-spec-harness.md b/docs/design/0039-title-screen-spec-harness.md deleted file mode 100644 index 97126142..00000000 --- a/docs/design/0039-title-screen-spec-harness.md +++ /dev/null @@ -1,312 +0,0 @@ ---- -title: "DX-0039 - Title Screen Spec Harness" -legend: "DX" -lane: "design" -issue: "https://github.com/flyingrobots/jedit/issues/39" -status: "active" -owners: - - "@flyingrobots" -created: "2026-06-04" -updated: "2026-06-04" ---- - -# DX-0039 - Title Screen Spec Harness - -## Linked Issue - -- https://github.com/flyingrobots/jedit/issues/39 - -## Decision Summary - -Title-related specs will share a small test-only harness for build-once module -imports and genuinely reused surface helpers. The harness will not own one-off -assertions, production constants, or title-scene behavior; it only removes -duplicated setup that makes title specs slower to maintain. - -## Sponsored Human - -A contributor adding title-screen coverage wants one obvious import/setup helper -so that title specs stay focused on behavior, without copying local -`loadTitleModules` functions and path constants between files. - -## Sponsored Agent - -An agent needs a shared title spec harness so it can add focused title tests -without inferring dist paths, build timing, or duplicated helper conventions -from neighboring specs. - -## Hill - -By the end of this cycle, title-screen and title-screen-optics specs share a -test-only harness for dist imports and common surface helpers, each focused spec -remains below the 500-line doctrine, and the repo proves it with focused title -specs plus `npm run quality`. - -## Current Truth - -The merge target for this cycle is `origin/main` at -`e3f064eb5458b6131f9a996bf7cd5f8bfe63fdaf`. - -Current anchors: - -- `spec/title-screen.spec.mjs` defines its own dist module paths and - `loadTitleModules` helper: - [spec/title-screen.spec.mjs#L8:e3f064eb5458b6131f9a996bf7cd5f8bfe63fdaf](https://github.com/flyingrobots/jedit/blob/e3f064eb5458b6131f9a996bf7cd5f8bfe63fdaf/spec/title-screen.spec.mjs#L8). -- `spec/title-screen.spec.mjs` also owns common surface helpers such as `cells`, - `positionedCells`, and `isBraille`: - [spec/title-screen.spec.mjs#L79:e3f064eb5458b6131f9a996bf7cd5f8bfe63fdaf](https://github.com/flyingrobots/jedit/blob/e3f064eb5458b6131f9a996bf7cd5f8bfe63fdaf/spec/title-screen.spec.mjs#L79). -- `spec/title-screen-optics.spec.mjs` defines a second local title module - loader: - [spec/title-screen-optics.spec.mjs#L7:e3f064eb5458b6131f9a996bf7cd5f8bfe63fdaf](https://github.com/flyingrobots/jedit/blob/e3f064eb5458b6131f9a996bf7cd5f8bfe63fdaf/spec/title-screen-optics.spec.mjs#L7). -- The issue requests a shared helper while warning against creating a dumping - ground for one-off assertions: https://github.com/flyingrobots/jedit/issues/39. - -## Problem - -Title specs repeat build/import setup and basic surface traversal helpers. That -duplication is small today, but every new title-scene spec can copy the same -loader and drift from the other files when dist paths or setup behavior change. - -## Scope - -This cycle includes: - -- Adding `spec/title-screen-helpers.mjs`. -- Moving shared title dist import setup into the helper. -- Moving genuinely reused surface helpers into the helper. -- Updating title-screen and title-screen-optics specs to consume the harness. -- Splitting title scene render assertions into a focused spec if formatting - would push an existing spec above the 500-line doctrine. -- Keeping focused specs below 500 lines. - -## Non-Goals - -This cycle does not include: - -- Changing title rendering behavior. -- Changing title-scene optics behavior. -- Adding new visual regression baselines. -- Extracting every helper from every spec. -- Changing CI shard selection. - -## User Experience / Product Shape - -Not applicable. This cycle changes test authoring infrastructure only; rendered -Jedit behavior does not change. - -### User Journey - -```mermaid -flowchart TD - Author[Contributor adds title spec] --> Import[Import title-screen harness] - Import --> Build[Harness ensures dist is built once] - Build --> Test[Spec asserts title behavior] -``` - -### Wide UI Mockup - -Not applicable. No rendered UI changes. - -### Narrow UI Mockup - -Not applicable. No rendered UI changes. - -### Accessibility Considerations - -Not applicable. No rendered surface or input behavior changes. - -## Runtime / API Contract - -Contract: test-only `spec/title-screen-helpers.mjs`. - -The harness may export: - -- fixed title render options used by multiple specs; -- `loadTitleModules` for dist imports; -- `cells`, `positionedCells`, and `isBraille` for surface inspection. - -The harness must not export: - -- product runtime APIs; -- one-off assertion helpers used by only one spec; -- mutable shared test state beyond the build/import promise. - -## Lower Modes - -Not applicable. This is test infrastructure only. The executable lower mode is -the focused Node test command. - -## Data / State Model - -| Category | Description | -| ------------------------- | ---------------------------------------------------------------- | -| Source of truth | Dist modules built by `ensureDistBuilt`. | -| Derived state | Cached title module import promise in the helper. | -| Invalid states | Multiple title specs carry divergent local loaders. | -| Reset behavior | Each Node test process starts with an empty helper module cache. | -| Serialization | No serialization changes. | -| Deterministic assumptions | Fixed render options remain explicit in specs or helper exports. | - -## Accessibility Posture - -Not applicable. No user-visible surface changes. - -## Localization / Directionality Posture - -No visible strings change. - -## Agent Inspectability / Explainability Posture - -Agents can inspect: - -- the shared helper exports; -- title spec imports; -- line counts for title specs; -- focused spec output and quality gate output. - -## Linked Invariants - -- Tests are executable spec. -- Runtime truth beats type theater. -- Design should become repo truth. -- No file over 500 lines of code. - -## Design Alternatives Considered - -### Option A: Shared Minimal Harness - -Pros: - -- Removes duplicated setup. -- Keeps one-off assertions close to the tests that use them. -- Reduces future title spec drift. - -Cons: - -- Adds one more test helper module. - -### Option B: Leave Local Helpers Alone - -Pros: - -- No immediate refactor. - -Cons: - -- Lets setup drift continue. -- Makes future title specs more likely to copy stale paths. - -### Option C: Large Title Assertion Library - -Pros: - -- Could centralize more title-specific checks. - -Cons: - -- Creates the dumping ground the issue warns against. -- Makes tests less explicit. - -## Decision - -Choose Option A. Extract only repeated setup and surface traversal helpers. - -## Implementation Slices - -- [x] Slice 1: Commit this design packet. Commit message: - `docs: design title screen spec harness`. -- [x] Slice 2: Add the shared title spec harness. -- [x] Slice 3: Move title-screen spec to the harness. -- [x] Slice 4: Move title-screen-optics spec to the harness. -- [x] Slice 5: Keep focused title specs under 500 lines. -- [x] Slice 6: Verify focused title specs and quality. -- [x] Slice 7: Fill retrospective, push, mark PR ready, and merge when eligible. - -## Tests To Write First - -Behavior tests required: - -- [x] `spec/title-screen.spec.mjs` still passes. -- [x] `spec/title-screen-optics.spec.mjs` still passes. -- [x] `spec/title-scene-render.spec.mjs` still passes. -- [x] `npm run quality` proves the line-count doctrine remains green. - -Documentation and process tests: - -- [x] Prettier validates this design doc. - -Rule: documentation tests cannot be the only proof for implementation work. - -## Acceptance Criteria - -The work is done when: - -- [x] A shared title spec harness exists. -- [x] Title-screen and title-screen-optics specs use the shared loader. -- [x] No one-off assertion helpers are moved into the harness. -- [x] Title specs remain below 500 lines. -- [x] Issue and PR are linked correctly. -- [ ] Local validation is green; CI is green before merge. - -## Validation Plan - -Commands expected before PR: - -```bash -npm run build -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-screen.spec.mjs spec/title-screen-optics.spec.mjs spec/title-scene-render.spec.mjs -npm run quality -npx --no-install prettier --check docs/design/0039-title-screen-spec-harness.md spec/title-screen-helpers.mjs spec/title-screen.spec.mjs spec/title-screen-optics.spec.mjs spec/title-scene-render.spec.mjs -``` - -## Playback / Witness - -Reviewers can run: - -```bash -npm run build -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-screen.spec.mjs spec/title-screen-optics.spec.mjs spec/title-scene-render.spec.mjs -``` - -## Risks - -Known risks: - -- Moving too many helpers would make the harness vague. -- Import caching could accidentally hide test isolation bugs. - -Mitigations: - -- Export only loader and surface traversal helpers. -- Keep assertion helpers in the spec files where their test intent is visible. - -## Follow-On Debt - -No follow-on debt is introduced by this cycle. - -## Retrospective - -What changed from the design: - -- The shared harness landed as designed. -- Formatting the touched specs made the original `title-screen.spec.mjs` exceed - 500 lines, so scene render assertions moved into - `spec/title-scene-render.spec.mjs` to keep each focused spec below the - doctrine limit. - -What the tests proved: - -- `npm run build` proved the dist import surface still builds. -- `JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-screen.spec.mjs spec/title-screen-optics.spec.mjs spec/title-scene-render.spec.mjs` - proved the extracted harness preserves the existing title, optics, and scene - render assertions. -- `npm run quality` stayed green. -- Prettier and `git diff --check` stayed green for touched files. - -What remains open: - -- CI must pass on the PR branch before merge. - -PR: - -- https://github.com/flyingrobots/jedit/pull/90 diff --git a/docs/design/0040-title-scene-optics-hook.md b/docs/design/0040-title-scene-optics-hook.md deleted file mode 100644 index 04feb75a..00000000 --- a/docs/design/0040-title-scene-optics-hook.md +++ /dev/null @@ -1,336 +0,0 @@ ---- -title: "DX-0040 - Title Scene Optics Hook" -legend: "DX" -lane: "design" -issue: "https://github.com/flyingrobots/jedit/issues/40" -status: "active" -owners: - - "@flyingrobots" -created: "2026-06-04" -updated: "2026-06-04" ---- - -# DX-0040 - Title Scene Optics Hook - -## Linked Issue - -- https://github.com/flyingrobots/jedit/issues/40 - -## Decision Summary - -The title-scene spotlight anchoring seam will move into -`src/ui/title-screen-optics.ts` as a spotlight-specific helper, and -`titleSceneRayContext` will become private to `src/ui/title-screen.ts` again. -Tests will assert spotlight anchoring through the optics helper instead of -calling the full renderer ray-context constructor. - -## Sponsored Human - -A contributor maintaining title-scene rendering wants tests to expose only the -behavior under review so that renderer internals do not become accidental API, -without losing regression coverage for the startup scene spotlight. - -## Sponsored Agent - -An agent needs a named optics helper for spotlight anchoring so it can verify -camera/spotlight geometry directly, without inferring private ray-rendering -state from an exported broad test seam. - -## Hill - -By the end of this cycle, the spotlight anchoring regression passes through a -spotlight-named optics helper, `titleSceneRayContext` is no longer exported from -the title-screen module, and the repo proves the boundary with focused title -optics specs plus `npm run quality`. - -## Current Truth - -The merge target for this cycle is `origin/main` at -`de5e4dc5e0c9f05f69345b80c2ddf23d16d9b1f8`. - -Current anchors: - -- `src/ui/title-screen.ts` exports `titleSceneRayContext`, which constructs the - full renderer ray context: - [src/ui/title-screen.ts#L186:de5e4dc5e0c9f05f69345b80c2ddf23d16d9b1f8](https://github.com/flyingrobots/jedit/blob/de5e4dc5e0c9f05f69345b80c2ddf23d16d9b1f8/src/ui/title-screen.ts#L186). -- The exported ray context creates its spotlight from `options.spotlightCamera` - rather than render camera angle/radius: - [src/ui/title-screen.ts#L191:de5e4dc5e0c9f05f69345b80c2ddf23d16d9b1f8](https://github.com/flyingrobots/jedit/blob/de5e4dc5e0c9f05f69345b80c2ddf23d16d9b1f8/src/ui/title-screen.ts#L191). -- `src/ui/title-screen-optics.ts` already owns the low-level spotlight object - constructor: - [src/ui/title-screen-optics.ts#L76:de5e4dc5e0c9f05f69345b80c2ddf23d16d9b1f8](https://github.com/flyingrobots/jedit/blob/de5e4dc5e0c9f05f69345b80c2ddf23d16d9b1f8/src/ui/title-screen-optics.ts#L76). -- `spec/title-screen-optics.spec.mjs` currently calls - `title.titleSceneRayContext` solely to prove spotlight anchoring: - [spec/title-screen-optics.spec.mjs#L70:de5e4dc5e0c9f05f69345b80c2ddf23d16d9b1f8](https://github.com/flyingrobots/jedit/blob/de5e4dc5e0c9f05f69345b80c2ddf23d16d9b1f8/spec/title-screen-optics.spec.mjs#L70). -- The GitHub issue asks for a narrower seam named around spotlight anchoring: - https://github.com/flyingrobots/jedit/issues/40. - -## Problem - -The optics regression exports and calls `titleSceneRayContext`, which exposes -renderer internals beyond the behavior under test. The exported surface invites -future tests or callers to depend on full ray-context construction when they -only need to verify spotlight anchoring. - -## Scope - -This cycle includes: - -- Adding a title-screen optics helper named around spotlight camera anchoring. -- Moving spotlight camera placement math out of the broad renderer test seam. -- Updating `titleSceneRayContext` to use the new optics helper internally. -- Removing the public export from `titleSceneRayContext`. -- Updating focused optics specs to assert through the new helper. -- Extracting directly related helper code if the quality ratchet requires the - touched files to stay under size and function limits. - -## Non-Goals - -This cycle does not include: - -- Changing title-scene visuals. -- Reworking all title-scene geometry. -- Adding visual regression snapshots. -- Changing the Echo-backed editor path. -- Changing title startup timing. - -## User Experience / Product Shape - -Not applicable. This cycle changes test and module boundaries only; rendered -Jedit behavior does not change. - -### User Journey - -```mermaid -flowchart TD - Maintainer[Maintainer reviews spotlight regression] --> Helper[Spec calls spotlight optics helper] - Helper --> Boundary[Ray context stays private to renderer] - Boundary --> Confidence[Regression remains focused on anchoring behavior] -``` - -### Wide UI Mockup - -Not applicable. No rendered UI changes. - -### Narrow UI Mockup - -Not applicable. No rendered UI changes. - -### Accessibility Considerations - -Not applicable. No rendered surface or input behavior changes. - -## Runtime / API Contract - -Contract: title-scene optics module boundary. - -`src/ui/title-screen-optics.ts` will export a helper shaped like: - -```ts -titleSceneSpotlightForCameraPlacement( - camera: TitleSceneCameraPlacement, - sphereCenter: TitleSceneVector3, - color: readonly [number, number, number], -): TitleSceneSpotlight -``` - -`src/ui/title-screen.ts` will keep `titleSceneRayContext` as an internal -function. Tests and external modules must not import it as a public seam. - -Error behavior does not change. Rendering state transitions do not change. - -## Lower Modes - -Not applicable. This is a TypeScript module boundary and focused Node spec -cycle. The lower-mode witness is the focused test command. - -## Data / State Model - -| Category | Description | -| ------------------------- | ------------------------------------------------------------------ | -| Source of truth | Title-scene camera placement and material colors passed to render. | -| Derived state | Spotlight source, target, direction, and cone metadata. | -| Invalid states | Tests depending on full ray context to inspect spotlight behavior. | -| Reset behavior | No persistent state. | -| Serialization | No serialization changes. | -| Deterministic assumptions | Same camera placement and color produce the same spotlight. | - -```mermaid -flowchart LR - Camera[TitleSceneCameraPlacement] --> Optics[Spotlight helper] - Center[Sphere center] --> Optics - Color[Spotlight color] --> Optics - Optics --> Spotlight[TitleSceneSpotlight] - Spotlight --> RayContext[Private ray context] -``` - -## Accessibility Posture - -Not applicable. No user-visible surface changes. - -## Localization / Directionality Posture - -No visible strings change. - -## Agent Inspectability / Explainability Posture - -Agents can inspect: - -- exported optics helper names; -- the absence of `export` on `titleSceneRayContext`; -- focused optics spec assertions; -- local and CI check output. - -## Linked Invariants - -- Tests are executable spec. -- Runtime truth beats type theater. -- Design should become repo truth. -- No accidental API surface for private renderer internals. - -## Design Alternatives Considered - -### Option A: Spotlight-Specific Optics Helper - -Pros: - -- Names the seam after the behavior under test. -- Keeps full ray-context construction private. -- Reuses the optics module that already owns spotlight math. - -Cons: - -- Adds one exported helper to optics. - -### Option B: Keep Exported Ray Context - -Pros: - -- No implementation work. - -Cons: - -- Keeps broad internals exposed. -- Encourages future tests to depend on ray-context construction. - -### Option C: Render Pixels Only - -Pros: - -- Tests the visible surface. - -Cons: - -- Makes the anchoring regression indirect and brittle. -- Belongs more naturally to the visual-regression follow-up issue. - -## Decision - -Choose Option A. Add the spotlight-specific optics helper and make the ray -context private again. - -## Implementation Slices - -- [x] Slice 1: Commit this design packet. Commit message: - `docs: design title scene optics hook`. -- [x] Slice 2: Add the spotlight camera placement helper in title optics. -- [x] Slice 3: Update title-screen renderer internals to use the helper. -- [x] Slice 4: Update optics specs to remove `titleSceneRayContext` usage. -- [x] Slice 5: Keep touched optics/rendering files within quality limits. -- [x] Slice 6: Verify focused specs, build, quality, and formatting. -- [x] Slice 7: Fill retrospective, push, mark PR ready, and merge when eligible. - -## Tests To Write First - -Behavior tests required: - -- [x] `spec/title-screen-optics.spec.mjs` fails while it still depends on - `titleSceneRayContext`, then passes through the narrower helper. -- [x] `npm run build` proves the removed export does not leak through public - consumers. -- [x] `npm run quality` stays green. - -Documentation and process tests: - -- [x] Prettier validates this design doc. - -Rule: documentation tests cannot be the only proof for implementation work. - -## Acceptance Criteria - -The work is done when: - -- [x] The spotlight anchoring regression asserts through a spotlight-named - optics helper. -- [x] `titleSceneRayContext` is no longer exported from `title-screen.ts`. -- [x] The new seam is narrower than full ray-context construction. -- [x] No title-scene visual behavior changes. -- [x] Issue and PR are linked correctly. -- [ ] Local validation is green; CI is green before merge. - -## Validation Plan - -Commands expected before PR: - -```bash -npm run build -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-screen-optics.spec.mjs -npm run quality -npx --no-install prettier --check docs/design/0040-title-scene-optics-hook.md src/ui/title-screen.ts src/ui/title-screen-optics.ts src/ui/title-floor-light-effects.ts src/ui/title-scene-math.ts spec/title-screen-optics.spec.mjs -``` - -## Playback / Witness - -Reviewers can run: - -```bash -npm run build -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-screen-optics.spec.mjs -``` - -## Risks - -Known risks: - -- Moving geometry can accidentally duplicate or drift camera height constants. -- A too-broad helper would repeat the same API-surface mistake under a new name. - -Mitigations: - -- Keep the exported helper named around spotlight placement. -- Leave ray origin/ray direction construction private to the renderer. -- Verify the focused optics regression and build. - -## Follow-On Debt - -No follow-on debt is introduced by this cycle. - -## Retrospective - -What changed from the design: - -- The spotlight-specific helper landed as - `titleSceneSpotlightForCameraPlacement`. -- `titleSceneRayContext` became private to `src/ui/title-screen.ts`. -- The quality ratchet required two directly related extractions: - `src/ui/title-floor-light-effects.ts` for floor light effects and - `src/ui/title-scene-math.ts` for shared title-scene vector/color math. - -What the tests proved: - -- RED: `JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-screen-optics.spec.mjs` - failed before implementation because the new helper was missing and - `titleSceneRayContext` was still exported. -- GREEN: `npm run build` proved the TypeScript public surface no longer leaks - the ray-context export. -- GREEN: `JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-screen-optics.spec.mjs` - proved spotlight anchoring through the narrower optics helper. -- GREEN: `npm run quality`, Prettier, and `git diff --check` passed. - -What remains open: - -- CI must pass on the PR branch before merge. - -PR: - -- https://github.com/flyingrobots/jedit/pull/91 diff --git a/docs/design/0041-title-scene-visual-regression.md b/docs/design/0041-title-scene-visual-regression.md deleted file mode 100644 index 1fd65663..00000000 --- a/docs/design/0041-title-scene-visual-regression.md +++ /dev/null @@ -1,340 +0,0 @@ ---- -title: "DX-0041 - Title Scene Visual Regression" -legend: "DX" -lane: "design" -issue: "https://github.com/flyingrobots/jedit/issues/41" -status: "active" -owners: - - "@flyingrobots" -created: "2026-06-04" -updated: "2026-06-04" ---- - -# DX-0041 - Title Scene Visual Regression - -## Linked Issue - -- https://github.com/flyingrobots/jedit/issues/41 - -## Decision Summary - -Title-scene visual regression coverage will use a small golden JSON witness with -human-readable glyph rows and separate color digests for representative -deterministic render cases. The witness will live under `spec/fixtures/`, and a -focused Node spec will compare glyph shape separately from color evidence so -failures identify the kind of visual drift. - -## Sponsored Human - -A maintainer changing the title scene wants a compact visual witness so that -intentional rendering changes are reviewable, without scanning a full terminal -frame or reverse-engineering low-level optics assertions. - -## Sponsored Agent - -An agent needs deterministic render witness data so it can identify glyph drift -and color drift independently, without scraping screenshots or inferring visual -state from prose. - -## Hill - -By the end of this cycle, title-scene renders have a committed compact visual -witness for deterministic Braille, ASCII, logo-visible, and logo-faded cases, -and the repo proves it with a focused witness spec plus `npm run quality`. - -## Current Truth - -The merge target for this cycle is `origin/main` at -`4a1cb499a46895dd3efdc6fd8fdf2b5d89fe5004`. - -Current anchors: - -- `spec/title-scene-render.spec.mjs` asserts deterministic title-scene - behavior through targeted optics and glyph checks: - [spec/title-scene-render.spec.mjs#L1:4a1cb499a46895dd3efdc6fd8fdf2b5d89fe5004](https://github.com/flyingrobots/jedit/blob/4a1cb499a46895dd3efdc6fd8fdf2b5d89fe5004/spec/title-scene-render.spec.mjs#L1). -- `spec/title-screen-helpers.mjs` provides shared title module loading and - surface traversal helpers: - [spec/title-screen-helpers.mjs#L1:4a1cb499a46895dd3efdc6fd8fdf2b5d89fe5004](https://github.com/flyingrobots/jedit/blob/4a1cb499a46895dd3efdc6fd8fdf2b5d89fe5004/spec/title-screen-helpers.mjs#L1). -- `src/ui/title-screen.ts` owns the rendered title surface entrypoint: - [src/ui/title-screen.ts#L124:4a1cb499a46895dd3efdc6fd8fdf2b5d89fe5004](https://github.com/flyingrobots/jedit/blob/4a1cb499a46895dd3efdc6fd8fdf2b5d89fe5004/src/ui/title-screen.ts#L124). -- There is no committed golden fixture for title-scene render shape or color - posture. -- The GitHub issue asks for deterministic visual regression coverage that is - small enough for review and separates glyph from color failures: - https://github.com/flyingrobots/jedit/issues/41. - -## Problem - -Existing title tests prove individual geometry, optics, material, and timeline -claims, but there is no compact artifact that lets a reviewer see and detect -whole-render drift across representative title-scene cases. - -## Scope - -This cycle includes: - -- Adding a focused title-scene visual witness spec. -- Adding a committed compact JSON fixture under `spec/fixtures/`. -- Capturing deterministic glyph rows separately from foreground/background - color digests. -- Covering at least one Braille render, one ASCII render, one logo-visible - timestamp, and one logo-faded timestamp. -- Keeping fixtures small and reviewable. - -## Non-Goals - -This cycle does not include: - -- Pixel screenshots or terminal screenshot comparison. -- Full-size terminal frame fixtures. -- A fixture update command. -- New title-scene visuals. -- New theme authoring or lighting behavior. - -## User Experience / Product Shape - -Not applicable. This cycle adds test witness coverage only; rendered Jedit -behavior does not change. - -### User Journey - -```mermaid -flowchart TD - Change[Contributor changes title rendering] --> Test[Run visual witness spec] - Test --> Glyph[Glyph rows compare] - Test --> Color[Color digests compare] - Glyph --> Review[Reviewer sees shape drift if intentional] - Color --> Review -``` - -### Wide UI Mockup - -Not applicable. No rendered UI changes. - -### Narrow UI Mockup - -Not applicable. No rendered UI changes. - -### Accessibility Considerations - -Not applicable. No rendered surface or input behavior changes. - -## Runtime / API Contract - -Contract: test-only title visual witness. - -The fixture will store entries shaped like: - -```ts -interface TitleVisualWitnessCase { - readonly name: string; - readonly cols: number; - readonly rows: number; - readonly glyphRows: readonly string[]; - readonly foregroundDigest: string; - readonly backgroundDigest: string; -} -``` - -The spec will produce the same shape from deterministic calls to -`renderTitleScreen` and compare `glyphRows`, `foregroundDigest`, and -`backgroundDigest` independently. - -No production API changes. - -## Lower Modes - -The witness is plain JSON and can be inspected without color-capable terminals -or screenshots. No-color rendering behavior is not changed. - -## Data / State Model - -| Category | Description | -| ------------------------- | ------------------------------------------------------------- | -| Source of truth | Deterministic title render surfaces from built dist modules. | -| Derived state | Compact glyph rows and color digests. | -| Invalid states | Fixture rows generated with non-fixed time, seed, or camera. | -| Reset behavior | Each Node test process regenerates actual witness data. | -| Serialization | Stable JSON fixture committed under `spec/fixtures/`. | -| Deterministic assumptions | Fixed dimensions, theme, time, camera, seed, and render mode. | - -```mermaid -flowchart LR - Render[renderTitleScreen] --> Surface[Surface cells] - Surface --> GlyphRows[Glyph rows] - Surface --> ColorDigests[FG/BG digests] - GlyphRows --> Fixture[Golden JSON] - ColorDigests --> Fixture -``` - -## Accessibility Posture - -Not applicable. The witness is test data, not a user-facing surface. - -## Localization / Directionality Posture - -No visible strings change. - -## Agent Inspectability / Explainability Posture - -Agents can inspect: - -- stable fixture case names; -- glyph rows as text; -- separate foreground and background digests; -- focused spec assertion failure messages. - -## Linked Invariants - -- Tests are executable spec. -- Runtime truth beats type theater. -- Design should become repo truth. -- Docs and witnesses should be compact enough to review. - -## Design Alternatives Considered - -### Option A: Compact JSON Witness - -Pros: - -- Reviewable in normal diffs. -- Separates glyph and color drift. -- Runs quickly in existing Node test flow. - -Cons: - -- Does not show true pixel output. - -### Option B: Screenshot Regression - -Pros: - -- Closest to visual inspection. - -Cons: - -- Requires heavier tooling and terminal/font control. -- More brittle across environments. - -### Option C: More Low-Level Assertions - -Pros: - -- Precise and cheap. - -Cons: - -- Does not create a whole-render visual artifact. - -## Decision - -Choose Option A. Add a compact JSON visual witness and focused spec. - -## Implementation Slices - -- [x] Slice 1: Commit this design packet. Commit message: - `docs: design title scene visual regression`. -- [x] Slice 2: Add the title visual witness spec and make it fail because the - fixture is missing. -- [x] Slice 3: Add the committed fixture generated from deterministic renders. -- [x] Slice 4: Verify focused witness spec, existing title render spec, build, - quality, and formatting. -- [x] Slice 5: Fill retrospective, push, mark PR ready, and merge when eligible. - -## Tests To Write First - -Behavior tests required: - -- [x] `spec/title-scene-visual-witness.spec.mjs` fails before the fixture - exists and passes after the fixture is committed. -- [x] `spec/title-scene-render.spec.mjs` still passes. -- [x] `npm run quality` stays green. - -Documentation and process tests: - -- [x] Prettier validates this design doc and fixture formatting. - -Rule: documentation tests cannot be the only proof for implementation work. - -## Acceptance Criteria - -The work is done when: - -- [x] A compact title-scene visual witness fixture is committed. -- [x] The witness covers Braille, ASCII, logo-visible, and logo-faded cases. -- [x] The spec compares glyph rows separately from foreground/background color - digests. -- [x] The fixture is deterministic under fixed render inputs. -- [x] Issue and PR are linked correctly. -- [ ] Local validation is green; CI is green before merge. - -## Validation Plan - -Commands expected before PR: - -```bash -npm run build -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-visual-witness.spec.mjs spec/title-scene-render.spec.mjs -npm run quality -npx --no-install prettier --check docs/design/0041-title-scene-visual-regression.md spec/title-scene-visual-witness.spec.mjs spec/fixtures/title-scene-visual-witness.json -``` - -## Playback / Witness - -Reviewers can inspect: - -```bash -spec/fixtures/title-scene-visual-witness.json -``` - -Reviewers can run: - -```bash -npm run build -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-visual-witness.spec.mjs -``` - -## Risks - -Known risks: - -- Fixture drift can become noisy if the render dimensions are too large. -- Color digests can hide the exact color cell that changed. - -Mitigations: - -- Keep dimensions deliberately small. -- Commit glyph rows for shape review and separate foreground/background digests - for color posture. - -## Follow-On Debt - -No follow-on debt is introduced by this cycle. - -## Retrospective - -What changed from the design: - -- The compact JSON witness landed as - `spec/fixtures/title-scene-visual-witness.json`. -- The focused spec landed as `spec/title-scene-visual-witness.spec.mjs`. -- The witness uses four 42x14 cases covering Braille logo-visible, Braille - logo-faded, ASCII logo-faded, and a later Braille orbit frame. - -What the tests proved: - -- RED: `JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-visual-witness.spec.mjs` - failed before the fixture existed. -- GREEN: `JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-visual-witness.spec.mjs spec/title-scene-render.spec.mjs` - proved the fixture matches deterministic renders and existing render coverage - still passes. -- GREEN: `npm run build`, `npm run quality`, Prettier, and `git diff --check` - passed. - -What remains open: - -- CI must pass on the PR branch before merge. - -PR: - -- https://github.com/flyingrobots/jedit/pull/92 diff --git a/docs/design/0042-title-scene-director-timeline.md b/docs/design/0042-title-scene-director-timeline.md deleted file mode 100644 index f1f5e9ed..00000000 --- a/docs/design/0042-title-scene-director-timeline.md +++ /dev/null @@ -1,331 +0,0 @@ ---- -title: "DX-0042 - Title Scene Director Timeline" -legend: "DX" -lane: "design" -issue: "https://github.com/flyingrobots/jedit/issues/42" -status: "active" -owners: - - "@flyingrobots" -created: "2026-06-04" -updated: "2026-06-04" ---- - -# DX-0042 - Title Scene Director Timeline - -## Linked Issue - -- https://github.com/flyingrobots/jedit/issues/42 - -## Decision Summary - -The title scene will gain a small validated director timeline object that owns -the default logo opacity cues, sheen cue, and camera drift cue. Existing render -behavior stays unchanged, but `titlePresentationSequence` and title camera drift -will read from the default timeline instead of isolated constants. - -## Sponsored Human - -A maintainer tuning the startup scene wants camera and logo timing expressed as -named cue data so that the scene feels intentionally directed, without changing -the existing title-screen timing by accident. - -## Sponsored Agent - -An agent needs an inspectable timeline object and pure interpolation helpers so -it can verify camera and logo cues, without scraping rendered cells or inferring -timing from private constants. - -## Hill - -By the end of this cycle, the default title-screen logo and camera behavior is -represented by a validated director timeline, existing timing specs still pass, -and new focused timeline specs prove validation, opacity, sheen, and camera -drift behavior. - -## Current Truth - -The merge target for this cycle is `origin/main` at -`4657d50f45f5179165e1a51d46f7aa6a414dab7a`. - -Current anchors: - -- `src/ui/title-presentation-sequence.ts` owns logo timing as private constants: - [src/ui/title-presentation-sequence.ts#L16:4657d50f45f5179165e1a51d46f7aa6a414dab7a](https://github.com/flyingrobots/jedit/blob/4657d50f45f5179165e1a51d46f7aa6a414dab7a/src/ui/title-presentation-sequence.ts#L16). -- `src/ui/title-screen.ts` owns camera drift as `TITLE_CAMERA_DRIFT_RATE`: - [src/ui/title-screen.ts#L120:4657d50f45f5179165e1a51d46f7aa6a414dab7a](https://github.com/flyingrobots/jedit/blob/4657d50f45f5179165e1a51d46f7aa6a414dab7a/src/ui/title-screen.ts#L120). -- `spec/title-screen.spec.mjs` already proves the existing title presentation - timing: - [spec/title-screen.spec.mjs#L282:4657d50f45f5179165e1a51d46f7aa6a414dab7a](https://github.com/flyingrobots/jedit/blob/4657d50f45f5179165e1a51d46f7aa6a414dab7a/spec/title-screen.spec.mjs#L282). -- `spec/title-scene-render.spec.mjs` proves camera drift is readable: - [spec/title-scene-render.spec.mjs#L17:4657d50f45f5179165e1a51d46f7aa6a414dab7a](https://github.com/flyingrobots/jedit/blob/4657d50f45f5179165e1a51d46f7aa6a414dab7a/spec/title-scene-render.spec.mjs#L17). -- The GitHub issue requests a data-authored director timeline with validation - and deterministic interpolation: https://github.com/flyingrobots/jedit/issues/42. - -## Problem - -The title scene has directed timing, but that timing is scattered across private -constants in the presentation sequence and renderer. This makes future cue work -harder to inspect and encourages procedural additions instead of authored data. - -## Scope - -This cycle includes: - -- Adding a `src/ui/title-scene-director.ts` module. -- Defining and validating the default director timeline data. -- Moving default logo opacity, sheen, and camera drift cues into that timeline. -- Updating presentation sequence and camera angle computation to use the - timeline. -- Adding focused director timeline specs. - -## Non-Goals - -This cycle does not include: - -- Changing default startup visuals or timing. -- Adding an authoring UI. -- Adding theme-authored lighting rigs. -- Adding object keyframes beyond existing camera drift. -- Replacing the existing title camera spring controls. - -## User Experience / Product Shape - -Rendered behavior should not visibly change in this cycle. The user still sees -the same FLYINGROBOTS and jedit timing, fades, sheen, and ambient camera drift. - -### User Journey - -```mermaid -flowchart TD - Maintainer[Maintainer changes title cue data] --> Spec[Run director timeline specs] - Spec --> Timing[Opacity and sheen timing verified] - Spec --> Camera[Camera drift verified] - Timing --> Render[Existing title specs still pass] - Camera --> Render -``` - -### Wide UI Mockup - -Not applicable. No visible UI changes. - -### Narrow UI Mockup - -Not applicable. No visible UI changes. - -### Accessibility Considerations - -Not applicable. No rendered surface or input behavior changes. - -## Runtime / API Contract - -Contract: `src/ui/title-scene-director.ts`. - -The module will export: - -- `TITLE_SCENE_DEFAULT_DIRECTOR_TIMELINE`; -- `validateTitleSceneDirectorTimeline`; -- `titleSceneCueOpacity`; -- `titleSceneCueProgress`; -- `titleSceneCameraAngleAt`. - -The timeline contains: - -- camera drift rate; -- FLYINGROBOTS opacity cue; -- jedit title opacity cue; -- title sheen cue. - -`titlePresentationSequence(time, textDirection)` remains the public presentation -helper and keeps its current return shape. `TITLE_CAMERA_DRIFT_RATE` remains -exported from `title-screen.ts` as a compatibility alias for the default -timeline drift rate. - -## Lower Modes - -Not applicable. This is deterministic runtime data and focused Node tests. - -## Data / State Model - -| Category | Description | -| ------------------------- | -------------------------------------------------------------- | -| Source of truth | `TITLE_SCENE_DEFAULT_DIRECTOR_TIMELINE`. | -| Derived state | Presentation sequence and camera angle at a given time. | -| Invalid states | Negative/non-finite times, fade before appear, negative drift. | -| Reset behavior | No mutable state. | -| Serialization | No serialization changes. | -| Deterministic assumptions | Same timeline and time produce same cues and camera angle. | - -```mermaid -flowchart LR - Timeline[Director timeline] --> Presentation[Presentation sequence] - Timeline --> Camera[Camera angle helper] - Presentation --> Logos[Logo opacity and sheen] - Camera --> Renderer[Ray context] -``` - -## Accessibility Posture - -Not applicable. No user-visible surface changes. - -## Localization / Directionality Posture - -No visible strings change. Directionality remains represented by -`TitleScreenTextDirection` and controls sheen direction. - -## Agent Inspectability / Explainability Posture - -Agents can inspect: - -- timeline cue names; -- pure helper outputs for fixed times; -- validation failures for invalid cue data; -- existing title render specs. - -## Linked Invariants - -- Tests are executable spec. -- Runtime truth beats type theater. -- Design should become repo truth. -- No file over 500 lines of code. - -## Design Alternatives Considered - -### Option A: Validated Default Timeline - -Pros: - -- Makes existing timing inspectable as data. -- Keeps behavior stable. -- Creates a foundation for future authoring work. - -Cons: - -- Adds one runtime module. - -### Option B: Leave Constants In Place - -Pros: - -- No implementation work. - -Cons: - -- Timing remains scattered and procedural. - -### Option C: Full Keyframe System Now - -Pros: - -- More expressive immediately. - -Cons: - -- Too much scope for this title-issue cleanup pass. -- Risks changing visuals before the data boundary is proven. - -## Decision - -Choose Option A. Land the validated default timeline first and keep default -rendering stable. - -## Implementation Slices - -- [x] Slice 1: Commit this design packet. Commit message: - `docs: design title scene director timeline`. -- [x] Slice 2: Add focused director timeline specs and prove the module is - missing. -- [x] Slice 3: Add the director timeline module and validation helpers. -- [x] Slice 4: Move presentation sequence and camera drift to the timeline. -- [x] Slice 5: Verify focused director specs plus existing title specs, build, - quality, and formatting. -- [ ] Slice 6: Fill retrospective, push, mark PR ready, and merge when eligible. - -## Tests To Write First - -Behavior tests required: - -- [x] `spec/title-scene-director.spec.mjs` fails before the module exists and - passes after implementation. -- [x] `spec/title-screen.spec.mjs` still proves current logo timing. -- [x] `spec/title-scene-render.spec.mjs` still proves camera drift. -- [x] `npm run quality` stays green. - -Documentation and process tests: - -- [x] Prettier validates this design doc. - -Rule: documentation tests cannot be the only proof for implementation work. - -## Acceptance Criteria - -The work is done when: - -- [x] Default logo and camera cues are represented by timeline data. -- [x] Timeline data is runtime-validated. -- [x] Default title render behavior remains stable under existing specs. -- [x] Camera and logo behavior are inspectable by focused specs. -- [x] Issue and PR are linked correctly. -- [x] Local validation is green. -- [ ] CI is green before merge. - -## Validation Plan - -Commands expected before PR: - -```bash -npm run build -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-director.spec.mjs spec/title-screen.spec.mjs spec/title-scene-render.spec.mjs -npm run quality -npx --no-install prettier --check docs/design/0042-title-scene-director-timeline.md src/ui/title-scene-director.ts src/ui/title-presentation-sequence.ts src/ui/title-screen.ts spec/title-scene-director.spec.mjs -``` - -## Playback / Witness - -Reviewers can run: - -```bash -npm run build -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-director.spec.mjs -``` - -## Risks - -Known risks: - -- Moving constants into data can silently retime the title if tests are too - coarse. -- Validation helpers can become broader than this cycle needs. - -Mitigations: - -- Keep existing title-screen timing specs in the validation set. -- Validate only the fields introduced in this cycle. - -## Follow-On Debt - -No follow-on debt is introduced by this cycle. - -## Retrospective - -What changed from the design: - -- Implementation matched the design. The default title timing and camera drift - now flow through `TITLE_SCENE_DEFAULT_DIRECTOR_TIMELINE`, which is validated - before export. - -What the tests proved: - -- `spec/title-scene-director.spec.mjs` proved the RED missing-module failure, - default cue values, validation failures, deterministic sheen progress, and - deterministic camera angle interpolation. -- `spec/title-screen.spec.mjs` and `spec/title-scene-render.spec.mjs` proved - the visible logo timing and render-facing drift behavior stayed stable. -- `npm run build` and `npm run quality` stayed green. - -What remains open: - -- CI must pass before merge. - -PR: - -- https://github.com/flyingrobots/jedit/pull/93 diff --git a/docs/design/0043-title-scene-authoring-preview.md b/docs/design/0043-title-scene-authoring-preview.md deleted file mode 100644 index 44add893..00000000 --- a/docs/design/0043-title-scene-authoring-preview.md +++ /dev/null @@ -1,407 +0,0 @@ ---- -title: "DX-0043 - Title Scene Authoring Preview" -legend: "DX" -lane: "design" -issue: "https://github.com/flyingrobots/jedit/issues/43" -status: "active" -owners: - - "@flyingrobots" -created: "2026-06-04" -updated: "2026-06-04" ---- - -# DX-0043 - Title Scene Authoring Preview - -## Linked Issue - -- https://github.com/flyingrobots/jedit/issues/43 - -## Decision Summary - -Jedit will add an opt-in title-scene authoring preview surface made of a pure -preview session contract and a developer CLI witness. The preview can scrub -time, adjust camera posture, cycle themes/render modes/scenes/objects, render a -plain terminal frame, and emit machine-readable inspection facts without adding -new authority to title-scene runtime logic or changing normal startup behavior. - -## Sponsored Human - -A maintainer tuning the title scene wants to preview scene timing, camera -posture, themes, render modes, and selected object facts from the terminal so -that scene authoring is faster, without editing constants and repeatedly -starting the full editor. - -## Sponsored Agent - -An agent needs deterministic preview state, control intents, and JSON -inspection output so it can verify scene authoring behavior, without scraping -pixels or inferring private renderer state. - -## Hill - -By the end of this cycle, a developer can run `npm run title:preview -- --json` -or apply preview controls through `titleScenePreviewInput`, and the repo proves -the state/control/inspection contract with focused session and CLI tests. - -## Current Truth - -The merge target for this cycle is `origin/main` at -`c05587481df6cb2c97899798c0b713c700446ee0`. - -Current anchors: - -- `renderTitleScreen` can already render a scene override, render mode, theme, - time, and camera options: - [src/ui/title-screen.ts#L138:c05587481df6cb2c97899798c0b713c700446ee0](https://github.com/flyingrobots/jedit/blob/c05587481df6cb2c97899798c0b713c700446ee0/src/ui/title-screen.ts#L138). -- `createTitleSceneLoaderPort` already decodes external scene JSON at the - adapter boundary: - [src/adapters/title-scene-loader.ts#L73:c05587481df6cb2c97899798c0b713c700446ee0](https://github.com/flyingrobots/jedit/blob/c05587481df6cb2c97899798c0b713c700446ee0/src/adapters/title-scene-loader.ts#L73). -- Built-in title scenes are already registered through - `BUILT_IN_TITLE_SCENE_NAMES`: - [src/ports/title-scene-loader.ts#L10:c05587481df6cb2c97899798c0b713c700446ee0](https://github.com/flyingrobots/jedit/blob/c05587481df6cb2c97899798c0b713c700446ee0/src/ports/title-scene-loader.ts#L10). -- `package.json` has no title-scene preview command: - [package.json#L5:c05587481df6cb2c97899798c0b713c700446ee0](https://github.com/flyingrobots/jedit/blob/c05587481df6cb2c97899798c0b713c700446ee0/package.json#L5). -- Issue #43 requests an opt-in preview mode with controls and focused tests: - https://github.com/flyingrobots/jedit/issues/43. - -## Problem - -Title-scene tuning currently requires changing runtime constants or scene JSON -and then running the normal editor or pixel-oriented specs. There is no small -authoring surface that exposes the title scene's time, camera, theme, render -mode, selected object, and scene facts as stable data. - -## Scope - -This cycle includes: - -- Adding a pure `src/app/title-scene-preview-session.ts` session contract. -- Adding a small `src/app/title-scene-preview-input.ts` input vocabulary - re-exported by the session contract. -- Adding preview inputs for time scrub, camera angle/radius adjustment, theme - cycling, render-mode cycling, scene cycling, and selected-object cycling. -- Adding an inspector snapshot that reports scene/theme/render/camera/object - facts. -- Adding an opt-in `scripts/title-scene-preview.mjs` CLI and - `npm run title:preview` script. -- Covering the session and CLI witness with focused Node tests. - -## Non-Goals - -This cycle does not include: - -- Changing the normal jedit startup title screen. -- Adding an interactive full-screen TUI editor for scenes. -- Writing scene JSON back to disk. -- Adding new scene semantics or lighting rigs. -- Moving scene JSON decoding out of the existing adapter boundary. -- Adding Echo authority to preview-only state. - -## User Experience / Product Shape - -The user runs an explicit command from the repo root: - -```bash -npm run title:preview -- --json -npm run title:preview -- --scene neon-orbit.jedit-scene --key time+ --key theme+ -``` - -Plain mode prints a terminal frame followed by compact inspector lines. JSON -mode emits a deterministic object with `preview`, `inspector`, and optional -`frame` fields. The command is keyboard-compatible through `--key`, which lets -developers and agents replay the same controls that a future full-screen TUI -can use. - -### User Journey - -```mermaid -flowchart TD - Start[Developer runs title preview] --> Load[CLI loads built-in or file scene] - Load --> Controls[Optional keys update preview session] - Controls --> Render[Renderer emits terminal frame] - Controls --> Inspect[Inspector emits scene facts] - Load --> Failure[Decode/load failure is printed and exits non-zero] - Failure --> Retry[Developer fixes scene JSON or chooses another scene] -``` - -### Wide UI Mockup - -Plain terminal output at 96 columns: - -```text - - -jedit title preview -scene neon-orbit.jedit-scene theme graphite render braille -time 2.50s camera angle -0.58 radius 6.10 object 2/6 sphere -object radius 0.72 reflectivity 1.00 color 78,195,224 -``` - -### Narrow UI Mockup - -Plain terminal output at 48 columns keeps inspector rows separate: - -```text - - -jedit title preview -scene neon-orbit.jedit-scene -theme graphite render ascii -time 2.50s camera -0.58 / 6.10 -object 2/6 sphere -``` - -### Accessibility Considerations - -The CLI is keyboard-only and text-first. JSON output provides the same state as -the visible inspector without requiring visual inspection of the rendered frame. - -## Runtime / API Contract - -Contract: `src/app/title-scene-preview-session.ts`. - -The session module will export: - -- `TITLE_SCENE_PREVIEW_INPUT`; -- `TITLE_SCENE_PREVIEW_RENDER_MODE`; -- `createTitleScenePreviewModel`; -- `updateTitleScenePreviewModel`; -- `titleScenePreviewInspector`; -- `titleScenePreviewRenderOptions`. - -Preview inputs: - -- time forward/back; -- camera angle left/right; -- camera radius in/out; -- next/previous theme; -- next/previous render mode; -- next/previous scene; -- next/previous object. - -`scripts/title-scene-preview.mjs` will load built-in scenes through -`createTitleSceneLoaderPort`, load meshes through `loadStartupTitleMeshes`, use -`renderTitleScreen`, and print either plain text or JSON. Scene JSON remains -decoded at the adapter boundary. The preview session receives already-decoded -scene facts and does not own file IO. - -## Lower Modes - -| Concern | Posture | -| ----------------- | ----------------------------------------------------------------------- | -| Terminal size | CLI accepts `--width` and `--height`; defaults are deterministic. | -| No color | Plain output uses glyphs and inspector text; JSON is color-independent. | -| JSON/pipe | `--json` emits deterministic structured data. | -| Keyboard-only | `--key` accepts replayable preview inputs. | -| Optional adapters | Mesh load failures remain reported by existing mesh loader behavior. | -| Partial evidence | Invalid scene paths or scene names fail before rendering. | - -## Data / State Model - -| Category | Description | -| ------------------------- | ---------------------------------------------------------------------- | -| Source of truth | Decoded `TitleScene`, built-in scene names, theme list, preview model. | -| Derived state | Render options, inspector facts, plain frame text. | -| Invalid states | Negative time, radius below minimum, empty theme/scene/render lists. | -| Reset behavior | Each CLI invocation starts from a fresh preview model. | -| Serialization | JSON output only; no persisted preview state. | -| Deterministic assumptions | Same model, scene, theme, and dimensions produce same output. | - -```mermaid -flowchart LR - Args[CLI args] --> Model[Preview model] - Key[Preview input] --> Model - Scene[Scene loader adapter] --> Inspector - Model --> RenderOptions[Render options] - RenderOptions --> Renderer[renderTitleScreen] - Model --> Inspector[Inspector facts] - Renderer --> Plain[Plain frame] - Inspector --> Json[JSON witness] -``` - -## Accessibility Posture - -| Concern | Posture | -| --------------------------------- | ---------------------------------------------------------------------- | -| Semantic labels or facts | JSON keys name scene, theme, render mode, camera, and selected object. | -| Focus order or ownership | Not applicable; no interactive focus in this slice. | -| Hidden or visual-only information | Inspector mirrors selected object facts outside the frame. | -| Keyboard behavior | `--key` replays named controls without pointer input. | -| Secret or redaction behavior | No secrets are read or emitted. | - -## Localization / Directionality Posture - -New visible strings are developer CLI strings and are not part of the localized -product TUI catalog in this cycle. The rendered title scene keeps the existing -left-to-right default; JSON facts are locale-independent. - -## Agent Inspectability / Explainability Posture - -Agents can inspect: - -- stable preview input ids; -- deterministic model fields; -- JSON output with scene/theme/render/camera/object facts; -- focused session tests for state transitions; -- CLI tests for pipe output. - -## Linked Invariants - -- Tests are executable spec. -- Runtime truth beats type theater. -- Design should become repo truth. -- Files and previews are projections. -- Echo authority remains outside jedit product nouns. - -## Design Alternatives Considered - -### Option A: Pure Session Plus CLI Witness - -Pros: - -- Small and testable. -- Keeps decoding at the adapter boundary. -- Gives agents JSON without pixel scraping. -- Does not disturb normal startup behavior. - -Cons: - -- Not a full-screen interactive editor yet. - -### Option B: Full-Screen TUI Preview - -Pros: - -- Best developer ergonomics eventually. - -Cons: - -- Larger scope and more focus/layout risk for a cleanup pass. - -### Option C: Pixel Fixtures Only - -Pros: - -- Easy to add more render snapshots. - -Cons: - -- Does not create an authoring surface or inspectable controls. - -## Decision - -Choose Option A. Land the session and CLI witness first so future full-screen -preview work can reuse the same controls and inspector contract. - -## Implementation Slices - -- [x] Slice 1: Commit this design packet. Commit message: - `docs: design title scene authoring preview`. -- [x] Slice 2: Add RED session and CLI tests for missing preview contract. -- [x] Slice 3: Add the pure preview session, reducer, render options, and - inspector. -- [x] Slice 4: Add `scripts/title-scene-preview.mjs` and - `npm run title:preview`. -- [x] Slice 5: Verify focused tests, build, quality, formatting, and - retrospective. -- [ ] Slice 6: Push, mark PR ready, and merge when eligible. - -## Tests To Write First - -Behavior tests required: - -- [x] `spec/title-scene-preview-session.spec.mjs` fails before the preview - session exists and passes after implementation. -- [x] `spec/title-scene-preview-cli.spec.mjs` fails before the CLI exists and - passes after implementation. -- [x] Existing title-screen render specs stay green. -- [x] `npm run quality` stays green. - -Documentation and process tests: - -- [x] Prettier validates this design doc. - -Rule: documentation tests cannot be the only proof for implementation work. - -## Acceptance Criteria - -The work is done when: - -- [x] Preview state/control contract is covered by behavior tests. -- [x] CLI JSON output proves scene/theme/render/camera/object inspection. -- [x] Plain CLI output renders a deterministic terminal frame and inspector. -- [x] Normal startup behavior is unchanged. -- [x] Issue and PR are linked correctly. -- [x] Local validation is green. -- [ ] CI is green before merge. - -## Validation Plan - -Commands expected before PR: - -```bash -npm run build -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-preview-session.spec.mjs spec/title-scene-preview-cli.spec.mjs spec/title-screen.spec.mjs -npm run quality -npx --no-install prettier --check docs/design/0043-title-scene-authoring-preview.md src/app/title-scene-preview-input.ts src/app/title-scene-preview-session.ts scripts/title-scene-preview.mjs spec/title-scene-preview-session.spec.mjs spec/title-scene-preview-cli.spec.mjs package.json -``` - -## Playback / Witness - -Reviewers can run: - -```bash -npm run title:preview -- --json --scene neon-orbit.jedit-scene --key time+ --key theme+ -npm run title:preview -- --width 72 --height 20 --render-mode ascii -``` - -## Risks - -Known risks: - -- CLI argument parsing can grow into an ad hoc framework. -- Rendering full frames in tests can become brittle. -- Mesh-heavy scenes can make the preview slower than expected. - -Mitigations: - -- Keep parser support to the flags needed in this cycle. -- Assert structural output and a non-empty frame instead of a full golden. -- Use small default dimensions in tests. - -## Follow-On Debt - -No follow-on debt is introduced by this cycle. A full-screen interactive preview -can be filed separately after the session contract proves useful. - -## Retrospective - -What changed from the design: - -- The preview input vocabulary moved into - `src/app/title-scene-preview-input.ts` and is re-exported by - `title-scene-preview-session.ts` so the session module stays below the - 500-line quality cap. -- The CLI loads only the final selected scene instead of eagerly decoding every - built-in scene. This keeps valid requested scenes usable even when unrelated - authoring fixtures need follow-up. - -What the tests proved: - -- `spec/title-scene-preview-session.spec.mjs` proved deterministic preview - controls, scene/object cycling, render-mode cycling, and object inspection - facts without pixel scraping. -- `spec/title-scene-preview-cli.spec.mjs` proved JSON output, plain terminal - frame output, and custom scene path loading. -- `spec/title-screen.spec.mjs` proved normal title-screen behavior stayed - stable. -- `npm run build`, `npm run quality`, Prettier, and `git diff --check` stayed - green locally. - -What remains open: - -- CI must pass before merge. - -PR: - -- https://github.com/flyingrobots/jedit/pull/94 diff --git a/docs/design/0044-theme-authored-title-lighting-rigs.md b/docs/design/0044-theme-authored-title-lighting-rigs.md deleted file mode 100644 index 3477c92c..00000000 --- a/docs/design/0044-theme-authored-title-lighting-rigs.md +++ /dev/null @@ -1,353 +0,0 @@ ---- -title: "DX-0044 - Theme-Authored Title Lighting Rigs" -legend: "DX" -lane: "design" -issue: "https://github.com/flyingrobots/jedit/issues/44" -status: "active" -owners: - - "@flyingrobots" -created: "2026-06-04" -updated: "2026-06-04" ---- - -# DX-0044 - Theme-Authored Title Lighting Rigs - -## Linked Issue - -- https://github.com/flyingrobots/jedit/issues/44 - -## Decision Summary - -Jedit will let themes author a constrained title-scene lighting rig through -named theme variables: `title.scene.spotlight`, `title.scene.floor.dark`, and -`title.scene.floor.light`. `titleSceneMaterialColors` will read those variables -with the current accent/floor fallback behavior, and one built-in theme will -ship an authored rig to prove the boundary. - -## Sponsored Human - -A maintainer tuning built-in themes wants the startup scene's spotlight and -floor lighting to be authored as theme data so that themes feel distinct, -without adding renderer branches for named themes. - -## Sponsored Agent - -An agent needs stable lighting variable names and material-color derivation -tests so it can verify title-scene lighting behavior, without comparing pixels -or inferring private renderer constants. - -## Hill - -By the end of this cycle, `titleSceneMaterialColors(theme)` derives spotlight -and floor colors from optional `title.scene.*` variables, and focused specs -prove both fallback behavior and one authored rig. - -## Current Truth - -The merge target for this cycle is `origin/main` at -`407d1f95aff5521a7c6079b34b7e812ace786800`. - -Current anchors: - -- `titleSceneMaterialColors` currently derives spotlight from the theme accent - and floor colors from ordered ink/muted values: - [src/ui/title-scene-material-colors.ts#L34:407d1f95aff5521a7c6079b34b7e812ace786800](https://github.com/flyingrobots/jedit/blob/407d1f95aff5521a7c6079b34b7e812ace786800/src/ui/title-scene-material-colors.ts#L34). -- `jedit-themes.ts` currently defines base theme variables but no title-scene - lighting variables: - [src/ui/jedit-themes.ts#L17:407d1f95aff5521a7c6079b34b7e812ace786800](https://github.com/flyingrobots/jedit/blob/407d1f95aff5521a7c6079b34b7e812ace786800/src/ui/jedit-themes.ts#L17). -- `title-screen-optics.spec.mjs` currently assumes every theme spotlight equals - the accent token: - [spec/title-screen-optics.spec.mjs#L14:407d1f95aff5521a7c6079b34b7e812ace786800](https://github.com/flyingrobots/jedit/blob/407d1f95aff5521a7c6079b34b7e812ace786800/spec/title-screen-optics.spec.mjs#L14). -- Issue #44 requests optional theme-authored title-scene light tokens with - fallback behavior and no ad hoc renderer branches: - https://github.com/flyingrobots/jedit/issues/44. - -## Problem - -The title scene is visually rich, but the lighting rig is only partially -theme-authored: spotlight color is tied to `accent`, and floor tint is derived -from `ink`/`muted`. This prevents a theme from deliberately authoring the title -scene's lighting posture without changing renderer code. - -## Scope - -This cycle includes: - -- Adding exported title-scene lighting variable names. -- Teaching `titleSceneMaterialColors` to read optional lighting variables. -- Authoring one built-in theme lighting rig. -- Updating material/optics specs to prove fallback and authored-rig behavior. - -## Non-Goals - -This cycle does not include: - -- Adding intensity, ambient, rim, or sky scalar controls. -- Changing raytracing algorithms. -- Adding per-theme conditionals to renderer or optics code. -- Requiring every built-in theme to author a lighting rig immediately. -- Changing title-scene layout, camera, object placement, or startup timing. - -## User Experience / Product Shape - -Normal users do not see a new control. The startup scene may render one theme -with more intentionally authored spotlight/floor colors, while all other themes -continue using the current fallback. - -### User Journey - -```mermaid -flowchart TD - Theme[Theme author defines title.scene variables] --> Build[Theme builder validates RGB variables] - Build --> Material[Material colors derive spotlight/floor rig] - Material --> Render[Title scene renders with authored rig] - Themeless[Theme without title.scene variables] --> Fallback[Accent plus ordered floor fallback] - Fallback --> Render -``` - -### Wide UI Mockup - -Not applicable. This is a theme data boundary with no new rendered UI controls. - -### Narrow UI Mockup - -Not applicable. This is a theme data boundary with no new rendered UI controls. - -### Accessibility Considerations - -No user input changes. Existing contrast specs continue to verify floor dark -and floor light ordering across built-in themes. - -## Runtime / API Contract - -Contracts: - -- `src/ui/jedit-theme-palettes.ts` -- `src/ui/title-scene-lighting-tokens.ts` -- `src/ui/title-scene-material-colors.ts` - -`title-scene-lighting-tokens.ts` will export -`TITLE_SCENE_LIGHTING_VARIABLE` with: - -- `Spotlight`; -- `FloorDark`; -- `FloorLight`. - -`jedit-theme-palettes.ts` will keep authored palette data, including any -optional title-scene lighting rig, outside the main theme behavior module. - -`titleSceneMaterialColors(theme)` will: - -- use `title.scene.spotlight` when present, otherwise `accent`; -- use both `title.scene.floor.dark` and `title.scene.floor.light` when present; -- otherwise retain ordered `ink`/`muted` floor fallback; -- keep the existing `TitleSceneMaterialColors` return shape. - -## Lower Modes - -Not applicable. The change is deterministic theme data consumed by runtime -material-color derivation. - -## Data / State Model - -| Category | Description | -| ------------------------- | ---------------------------------------------------------- | -| Source of truth | Theme variables and `TITLE_SCENE_LIGHTING_VARIABLE`. | -| Derived state | `TitleSceneMaterialColors`. | -| Invalid states | Missing partial floor rig falls back to ordered ink/muted. | -| Reset behavior | No mutable state. | -| Serialization | No serialization changes. | -| Deterministic assumptions | Same theme variables produce same material colors. | - -```mermaid -flowchart LR - Theme[Theme variables] --> Tokens[title.scene lighting variables] - Tokens --> Materials[titleSceneMaterialColors] - Theme --> Fallback[accent / ink / muted fallback] - Fallback --> Materials - Materials --> Renderer[Title scene renderer] -``` - -## Accessibility Posture - -| Concern | Posture | -| --------------------------------- | ----------------------------------------------- | -| Semantic labels or facts | Lighting token names are exported constants. | -| Focus order or ownership | Not applicable. | -| Hidden or visual-only information | Tests inspect derived material colors directly. | -| Keyboard behavior | Not applicable. | -| Secret or redaction behavior | No secrets are read or emitted. | - -## Localization / Directionality Posture - -Not applicable. No visible strings are added or changed. - -## Agent Inspectability / Explainability Posture - -Agents can inspect: - -- exported lighting variable constants; -- theme variable maps; -- `titleSceneMaterialColors(theme)` outputs; -- focused specs for fallback and authored-rig behavior. - -## Linked Invariants - -- Tests are executable spec. -- Runtime truth beats type theater. -- Design should become repo truth. -- Files and previews are projections. -- Echo authority remains outside jedit product nouns. - -## Design Alternatives Considered - -### Option A: Theme Variables As Lighting Rig - -Pros: - -- Fits the existing theme boundary. -- Reuses theme-builder RGB validation. -- Keeps renderer code declarative. -- Allows incremental per-theme adoption. - -Cons: - -- Only covers color rig fields in this cycle. - -### Option B: New `titleSceneLighting` Object On `JeditTheme` - -Pros: - -- More explicit object shape. - -Cons: - -- Larger theme API migration for a small first rig. -- Requires generated or builder-wide changes before proving value. - -### Option C: Renderer Branches Per Theme - -Pros: - -- Fast to make one theme look different. - -Cons: - -- Violates the issue's no-conditionals intent. -- Makes future theme authoring hard to inspect. - -## Decision - -Choose Option A. Title-scene lighting starts as optional theme variables with -current fallback behavior preserved. - -## Implementation Slices - -- [x] Slice 1: Commit this design packet. Commit message: - `docs: design theme authored title lighting`. -- [x] Slice 2: Add RED specs for fallback and authored lighting variables. -- [x] Slice 3: Add lighting variable constants and material-color derivation. -- [x] Slice 4: Author one built-in theme rig. -- [x] Slice 5: Verify focused specs, title render specs, build, quality, and - formatting. -- [ ] Slice 6: Push, mark PR ready, and merge when eligible. - -## Tests To Write First - -Behavior tests required: - -- [x] `spec/title-scene-lighting-rig.spec.mjs` fails before lighting variables - are consumed and passes after implementation. -- [x] Existing title-screen optics tests still prove spotlight behavior. -- [x] Existing title-scene render contrast tests stay green. -- [x] `npm run quality` stays green. - -Documentation and process tests: - -- [x] Prettier validates this design doc. - -Rule: documentation tests cannot be the only proof for implementation work. - -## Acceptance Criteria - -The work is done when: - -- [x] Fallback themes still derive spotlight from accent. -- [x] One authored theme derives spotlight/floor colors from `title.scene.*` - variables. -- [x] Floor dark/light contrast remains ordered for all built-in themes. -- [x] No renderer branch keys off a theme name. -- [x] Issue and PR are linked correctly. -- [x] Local validation is green. -- [ ] CI is green before merge. - -## Validation Plan - -Commands expected before PR: - -```bash -npm run build -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-lighting-rig.spec.mjs spec/title-screen-optics.spec.mjs spec/title-scene-render.spec.mjs -JEDIT_DIST_PREBUILT=1 npm run ci:shard -- title-rendering -npm run quality -npx --no-install prettier --check docs/design/0044-theme-authored-title-lighting-rigs.md src/ui/title-scene-lighting-tokens.ts src/ui/title-scene-material-colors.ts src/ui/jedit-themes.ts src/ui/jedit-theme-palettes.ts spec/title-scene-lighting-rig.spec.mjs spec/title-screen-optics.spec.mjs spec/title-scene-render.spec.mjs spec/theme-switch.spec.mjs -``` - -## Playback / Witness - -Reviewers can run: - -```bash -JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-lighting-rig.spec.mjs -``` - -## Risks - -Known risks: - -- A partial authored floor rig could reduce contrast. -- Adding variables in the theme file can grow line count near the cap. - -Mitigations: - -- Use authored floor colors only when both dark and light tokens exist. -- Keep the authored rig to one built-in theme in this cycle. -- Retain existing floor contrast tests. - -## Follow-On Debt - -No follow-on debt is introduced by this cycle. Intensity, ambient, rim, or sky -lighting variables can be separate issues after color rigs prove stable. - -## Retrospective - -What changed from the design: - -- Implementation matched the design. The first authored rig is Monokai, using - `title.scene.spotlight`, `title.scene.floor.dark`, and - `title.scene.floor.light` variables. The authored palette table now lives in - `src/ui/jedit-theme-palettes.ts` so `src/ui/jedit-themes.ts` stays under the - quality gate line cap. - -What the tests proved: - -- `spec/title-scene-lighting-rig.spec.mjs` proved RED missing-token behavior, - fallback spotlight derivation, authored spotlight derivation, authored floor - colors, and authored floor contrast. -- `spec/title-screen-optics.spec.mjs` proved spotlight behavior still works - through the existing optics without theme-name renderer branches. -- `spec/title-scene-render.spec.mjs` proved built-in floor light/dark contrast - stays ordered. -- `spec/theme-switch.spec.mjs` proved built-in themes still expose the canonical - editor palette while permitting only the authored title-scene lighting - variables as optional rig data. -- `npm run build`, `JEDIT_DIST_PREBUILT=1 npm run ci:shard -- title-rendering`, - `npm run quality`, Prettier, and `git diff --check` stayed green locally. - -What remains open: - -- CI must pass before merge. - -PR: - -- https://github.com/flyingrobots/jedit/pull/95 diff --git a/docs/design/0045-terminal-scene-recording-exports.md b/docs/design/0045-terminal-scene-recording-exports.md deleted file mode 100644 index 6caf03d5..00000000 --- a/docs/design/0045-terminal-scene-recording-exports.md +++ /dev/null @@ -1,410 +0,0 @@ ---- -title: "DX-0045 - Terminal Scene Recording Exports" -legend: "DX" -lane: "design" -issue: "https://github.com/flyingrobots/jedit/issues/45" -status: "active" -owners: - - "@flyingrobots" -created: "2026-06-04" -updated: "2026-06-04" ---- - -# DX-0045 - Terminal Scene Recording Exports - -## Linked Issue - -- https://github.com/flyingrobots/jedit/issues/45 - -## Decision Summary - -Jedit will add a deterministic title-scene recording CLI that renders the -existing terminal title screen through `renderTitleScreen` and exports fixed -frame sequences as JSON, plain glyph text, compact HTML, or ANSI terminal -frames. The recorder owns review/share artifacts for the title scene; it does -not introduce a second renderer or product UI. - -## Sponsored Human - -A reviewer wants to inspect and share the animated title scene as terminal -artifacts so that title-screen changes can be reviewed without launching an -interactive TUI, without depending on screenshots or local timing. - -## Sponsored Agent - -An agent needs deterministic frame exports with glyph rows, color metadata, and -render parameters so it can compare title-scene output, without scraping pixels -or inferring terminal-cell colors from screenshots. - -## Hill - -By the end of this cycle, a reviewer can run `npm run title:record -- --format -json --frames 2`, get deterministic title-scene frames rendered through the -same title-screen path, and the repo proves determinism and headless execution -with a focused CLI spec. - -## Current Truth - -The merge target for this cycle is `origin/main` at -`50a41506ea666919814cbcf0a634aeae47c13419`. - -Current anchors: - -- `package.json` exposes `title:preview`, but there is no `title:record` script: - [package.json#L16:50a41506ea666919814cbcf0a634aeae47c13419](https://github.com/flyingrobots/jedit/blob/50a41506ea666919814cbcf0a634aeae47c13419/package.json#L16). -- The preview CLI already loads built-in title scenes, themes, preview session - options, and `renderTitleScreen` from `dist`: - [scripts/title-scene-preview.mjs#L5:50a41506ea666919814cbcf0a634aeae47c13419](https://github.com/flyingrobots/jedit/blob/50a41506ea666919814cbcf0a634aeae47c13419/scripts/title-scene-preview.mjs#L5). -- The preview CLI renders a frame by calling `renderTitleScreen` with a scene - override and preview render options: - [scripts/title-scene-preview.mjs#L215:50a41506ea666919814cbcf0a634aeae47c13419](https://github.com/flyingrobots/jedit/blob/50a41506ea666919814cbcf0a634aeae47c13419/scripts/title-scene-preview.mjs#L215). -- The preview CLI currently serializes glyph rows only, dropping terminal-cell - foreground/background metadata: - [scripts/title-scene-preview.mjs#L229:50a41506ea666919814cbcf0a634aeae47c13419](https://github.com/flyingrobots/jedit/blob/50a41506ea666919814cbcf0a634aeae47c13419/scripts/title-scene-preview.mjs#L229). -- The title renderer accepts render mode, camera, scene seed, mesh, scene - override, ASCII palette, and text direction as explicit options: - [src/ui/title-screen.ts#L94:50a41506ea666919814cbcf0a634aeae47c13419](https://github.com/flyingrobots/jedit/blob/50a41506ea666919814cbcf0a634aeae47c13419/src/ui/title-screen.ts#L94). -- The existing preview CLI spec proves JSON inspection and plain frame output, - but not deterministic multi-frame recordings or color metadata: - [spec/title-scene-preview-cli.spec.mjs#L14:50a41506ea666919814cbcf0a634aeae47c13419](https://github.com/flyingrobots/jedit/blob/50a41506ea666919814cbcf0a634aeae47c13419/spec/title-scene-preview-cli.spec.mjs#L14). -- `.gitignore` ignores generated build/cache artifacts but has no dedicated - title-recording artifact directory: - [.gitignore#L1:50a41506ea666919814cbcf0a634aeae47c13419](https://github.com/flyingrobots/jedit/blob/50a41506ea666919814cbcf0a634aeae47c13419/.gitignore#L1). - -## Problem - -The title scene is terminal-cell output, so screenshots are a lossy review -surface and the existing preview CLI cannot export deterministic multi-frame -recordings with color metadata. That makes title-scene PR review and visual -debugging harder than it needs to be. - -## Scope - -This cycle includes: - -- Adding `scripts/title-scene-record.mjs`. -- Adding `npm run title:record`. -- Rendering fixed frame sequences through `renderTitleScreen`. -- Emitting deterministic `json`, `text`, `html`, and `ansi` formats. -- Including glyph rows plus RGB foreground/background metadata in JSON output. -- Supporting explicit width, height, theme, scene, render mode, start time, - frame count, frame step, camera angle, and camera radius flags. -- Writing to stdout by default and only writing files when `--output` is passed. -- Ignoring the default explicit recording artifact directory. -- Adding focused CLI tests for deterministic JSON, text output, and output-file - behavior. - -## Non-Goals - -This cycle does not include: - -- Interactive preview controls; `title:preview` continues to own that. -- Visual diffing or color-distance comparison between recordings. -- A new title renderer, image/video encoding, GIF export, or screenshot capture. -- Persisting recordings in Echo, WSC, or workspace state. -- Changing title intro timing, title scene materials, or startup modal behavior. - -## User Experience / Product Shape - -The recorder is a CLI surface. A developer runs: - -```bash -npm run title:record -- --format json --frames 2 --width 80 --height 24 -npm run title:record -- --format html --output title-recordings/title.html -npm run title:record -- --format ansi -``` - -The command writes to stdout unless `--output` is supplied. JSON output includes -metadata and frame records. Text output is easy to paste into an issue. HTML -output preserves the terminal-cell grid in a compact `
`-style document.
-ANSI output can be replayed in a terminal.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[Reviewer needs title scene evidence] --> Command[Run title:record]
-  Command --> Stdout[No output flag writes recording to stdout]
-  Command --> File[Output flag writes recording artifact]
-  Stdout --> Inspect[Review deterministic glyph and color data]
-  File --> Attach[Attach ignored artifact to release or PR evidence]
-  Command --> Usage[Invalid flag prints usage and exits non-zero]
-```
-
-### Wide UI Mockup
-
-Not applicable. This cycle adds a terminal artifact export, not rendered
-application UI.
-
-### Narrow UI Mockup
-
-Not applicable. The recorder supports width and height flags, but does not add
-new TUI layout.
-
-### Accessibility Considerations
-
-The text and JSON formats provide non-visual access to the title-scene glyphs
-and color metadata. The HTML format must retain glyph text in document order
-instead of encoding the scene only as an image.
-
-## Runtime / API Contract
-
-Contract: `scripts/title-scene-record.mjs`.
-
-CLI inputs:
-
-- `--format json|text|html|ansi`, default `json`;
-- `--frames `, default `1`;
-- `--width `, default `96`;
-- `--height `, default `28`;
-- `--start `, default `0`;
-- `--step `, default `0.5`;
-- `--theme `;
-- `--scene `;
-- `--render-mode braille|ascii`;
-- `--camera-angle `;
-- `--camera-radius `;
-- `--output `;
-- `--help`.
-
-JSON output:
-
-- top-level `recording` metadata with format, dimensions, timing, scene, theme,
-  render mode, camera, and frame count;
-- `frames[]` records with stable `index`, `timeSeconds`, `glyphRows`, and
-  `colorRows`;
-- `colorRows` has one row per terminal row and one object per cell containing
-  foreground RGB and background RGB.
-
-Error behavior:
-
-- invalid options print usage to stderr and exit with code `2`;
-- runtime load/render failures print the error message and exit non-zero.
-
-## Lower Modes
-
-Lower-mode outputs:
-
-- `json`: machine-readable witness for agents and tests;
-- `text`: glyph-only terminal frame dump for issues and notes;
-- `html`: compact browser-viewable artifact that keeps text accessible;
-- `ansi`: terminal-native colored output.
-
-The command is headless and must not require terminal raw mode, Bijou app
-startup, or an interactive TTY.
-
-## Data / State Model
-
-| Category                  | Description                                             |
-| ------------------------- | ------------------------------------------------------- |
-| Source of truth           | `renderTitleScreen` output for each deterministic time. |
-| Derived state             | Serialized glyph rows and RGB cell metadata.            |
-| Invalid states            | Non-positive dimensions/frames or non-finite numbers.   |
-| Reset behavior            | Each invocation starts with no retained state.          |
-| Serialization             | JSON, plain text, HTML, ANSI, or explicit file path.    |
-| Deterministic assumptions | Fixed inputs produce byte-identical output.             |
-
-```mermaid
-flowchart LR
-  Flags[CLI flags] --> Model[Preview model inputs]
-  Model --> Render[renderTitleScreen]
-  Render --> Surface[Bijou Surface cells]
-  Surface --> Serialize[Recorder serializer]
-  Serialize --> Stdout[stdout]
-  Serialize --> File[optional output file]
-```
-
-## Accessibility Posture
-
-| Concern                           | Posture                                        |
-| --------------------------------- | ---------------------------------------------- |
-| Semantic labels or facts          | JSON metadata names scene, theme, and timing.  |
-| Focus order or ownership          | Not applicable; the command is noninteractive. |
-| Hidden or visual-only information | Glyph rows and RGB colors are serializable.    |
-| Keyboard behavior                 | Not applicable; no interactive controls.       |
-| Secret or redaction behavior      | No secrets are read or emitted.                |
-
-## Localization / Directionality Posture
-
-Not applicable. The recorder adds CLI option strings only; it does not add
-localized product copy. Title logo directionality remains whatever
-`renderTitleScreen` receives through existing render options.
-
-## Agent Inspectability / Explainability Posture
-
-Agents can parse JSON output and inspect:
-
-- dimensions;
-- format;
-- scene name;
-- theme name;
-- render mode;
-- camera posture;
-- exact frame times;
-- glyph rows;
-- foreground and background RGB cells.
-
-No pixel scraping, screenshot OCR, or private renderer hooks are required.
-
-## Linked Invariants
-
-- Tests are executable spec.
-- Runtime truth beats type theater.
-- Design should become repo truth.
-- Files and previews are projections.
-- Echo authority remains outside jedit product nouns.
-- The recorder must reuse the title renderer instead of introducing a second
-  rendering law.
-
-## Design Alternatives Considered
-
-### Option A: Extend `title:preview`
-
-Pros:
-
-- Reuses the existing script entry point.
-- Keeps title-scene command count small.
-
-Cons:
-
-- Mixes interactive preview inspection with recording/export semantics.
-- Makes the preview CLI harder to reason about.
-- Risks coupling key-step preview state to deterministic artifact production.
-
-### Option B: Add A Dedicated Recorder CLI
-
-Pros:
-
-- Gives recording exports a focused contract and test surface.
-- Keeps deterministic serialization separate from interactive preview controls.
-- Allows future compare/diff modes without bloating preview.
-
-Cons:
-
-- Some scene/theme loading logic overlaps the preview script.
-- Adds another npm script.
-
-## Decision
-
-Choose Option B. A dedicated recorder CLI is the cleanest boundary because
-recording is an artifact-production workflow, not a preview-control workflow.
-The script may share loading patterns with `title-scene-preview.mjs`, but the
-observable contract is deterministic frame serialization.
-
-## Implementation Slices
-
-- [x] Slice 1: Write this design document and open the cycle PR.
-- [x] Slice 2: Add a failing CLI spec for deterministic JSON recording.
-- [x] Slice 3: Add `scripts/title-scene-record.mjs` and `npm run title:record`.
-- [x] Slice 4: Add text, HTML, ANSI, and explicit output-file serialization.
-- [x] Slice 5: Ignore explicit title recording artifacts and update the
-      retrospective with validation evidence.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [x] `spec/title-scene-record-cli.spec.mjs` proves fixed JSON inputs produce
-      byte-identical output on repeated runs.
-- [x] `spec/title-scene-record-cli.spec.mjs` proves text output emits expected
-      frame labels and glyph rows.
-- [x] `spec/title-scene-record-cli.spec.mjs` proves `--output` writes the
-      chosen artifact and leaves stdout quiet.
-
-Documentation and process tests:
-
-- [x] Prettier checks this design doc.
-
-Rule: documentation tests cannot be the only proof for implementation work.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [x] `npm run title:record` exists and builds before running the recorder.
-- [x] JSON recording output is deterministic for fixed inputs.
-- [x] JSON frames include glyph rows plus RGB foreground/background metadata.
-- [x] Recorder output defaults to stdout and writes files only with `--output`.
-- [x] Generated title recording artifacts are ignored unless explicitly staged.
-- [x] The recorder uses `renderTitleScreen`.
-- [x] The recorder runs headless in local and CI test processes.
-- [x] Issue and PR are linked correctly.
-- [x] Local validation is green; remote CI remains the PR merge gate.
-
-## Validation Plan
-
-Commands expected before PR completion:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-record-cli.spec.mjs
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- title-rendering
-npm run quality
-npx --no-install prettier --check docs/design/0045-terminal-scene-recording-exports.md scripts/title-scene-record.mjs spec/title-scene-record-cli.spec.mjs package.json
-git diff --check
-```
-
-## Playback / Witness
-
-Reviewer commands:
-
-```bash
-npm run title:record -- --format json --frames 2 --width 64 --height 18
-npm run title:record -- --format text --frames 2 --render-mode ascii
-npm run title:record -- --format html --output title-recordings/title.html
-npm run title:record -- --format ansi
-```
-
-The JSON command is the primary machine-readable witness.
-
-## Risks
-
-Known risks:
-
-- Scene/theme loading may duplicate preview CLI logic.
-- Full-cell JSON color metadata can be large.
-- ANSI output varies by terminal support even if emitted bytes are stable.
-
-Mitigations:
-
-- Keep the first recorder small and reuse existing title preview/load patterns.
-- Default dimensions and frame counts remain modest.
-- Treat JSON as the canonical witness and ANSI as terminal playback.
-
-## Follow-On Debt
-
-Future visual diff or color-distance comparison belongs in a separate issue if
-recorded artifacts become a regular review gate.
-
-## Retrospective
-
-What changed from the design:
-
-- The implementation matched the planned dedicated recorder CLI.
-- `title-recordings/` was added to `.gitignore` as the default explicit
-  artifact directory.
-- The validation plan dropped `.gitignore` from the Prettier command because
-  this repo's Prettier setup does not infer a parser for that file.
-
-What the tests proved:
-
-- RED:
-  `JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-record-cli.spec.mjs`
-  failed because `scripts/title-scene-record.mjs` did not exist.
-- GREEN:
-  `JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-record-cli.spec.mjs`
-  passed with 3 tests.
-- `JEDIT_DIST_PREBUILT=1 npm run ci:shard -- title-rendering` passed with 97
-  tests.
-- `npm run title:record -- --format text --frames 1 --width 24 --height 8 --scene sphere.jedit-scene --theme graphite --render-mode ascii`
-  built and emitted a terminal text recording.
-- `npm run quality`, Prettier, and `git diff --check` passed.
-
-What remains open:
-
-- Visual diff or color-distance comparison remains deferred follow-on work.
-- Remote CI and review gates are handled by PR #98.
-
-PR:
-
-- https://github.com/flyingrobots/jedit/pull/98
diff --git a/docs/design/0046-title-scene-material-lab.md b/docs/design/0046-title-scene-material-lab.md
deleted file mode 100644
index 54ec141f..00000000
--- a/docs/design/0046-title-scene-material-lab.md
+++ /dev/null
@@ -1,406 +0,0 @@
----
-title: "DX-0046 - Title Scene Material Lab"
-legend: "DX"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/46"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-06-04"
-updated: "2026-06-04"
----
-
-# DX-0046 - Title Scene Material Lab
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/46
-
-## Decision Summary
-
-Jedit will add a deterministic, non-default built-in title scene named
-`material-lab.jedit-scene`. The scene will arrange labeled material lanes under
-one lighting/floor environment so agents and maintainers can compare matte,
-mirror, transparent, refractive, rim-lit, and spotlight-responsive objects
-without changing the user startup default or scraping pixels.
-
-## Sponsored Human
-
-A maintainer tuning the title renderer wants a compact material comparison scene
-so that optics changes can be judged against controlled samples, without
-manually editing ad hoc scene JSON or guessing which default-scene object
-exercises which material path.
-
-## Sponsored Agent
-
-An agent needs labeled scene objects, bounded material fields, and focused
-render/loader witnesses so it can verify material coverage, without inferring
-semantics from array positions or visual appearance alone.
-
-## Hill
-
-By the end of this cycle, a reviewer can load `material-lab.jedit-scene` through
-the built-in title-scene loader and prove that its labeled lanes exercise matte,
-mirror, transparent, refractive, rim, spotlight, and floor effects through
-focused specs.
-
-## Current Truth
-
-The merge target for this cycle is `origin/main` at
-`31f551d329e3183e67d4e33e7d8077c6bac0dfba`.
-
-Current anchors:
-
-- Built-in scene names are an explicit registry, and the first entry controls
-  the default scene order:
-  [src/ports/title-scene-loader.ts#L10:31f551d329e3183e67d4e33e7d8077c6bac0dfba](https://github.com/flyingrobots/jedit/blob/31f551d329e3183e67d4e33e7d8077c6bac0dfba/src/ports/title-scene-loader.ts#L10).
-- Scene JSON already decodes bounded optical material fields,
-  `transparency` and `refractiveIndex`:
-  [src/adapters/title-scene-loader.ts#L183:31f551d329e3183e67d4e33e7d8077c6bac0dfba](https://github.com/flyingrobots/jedit/blob/31f551d329e3183e67d4e33e7d8077c6bac0dfba/src/adapters/title-scene-loader.ts#L183).
-- Existing built-in scenes can author lighting, floor, walls, and material
-  values, but they are composed as product scenes rather than controlled test
-  lanes:
-  [scenes/teapot-gallery.jedit-scene#L1:31f551d329e3183e67d4e33e7d8077c6bac0dfba](https://github.com/flyingrobots/jedit/blob/31f551d329e3183e67d4e33e7d8077c6bac0dfba/scenes/teapot-gallery.jedit-scene#L1).
-- The preview inspector exposes selected object facts such as kind, radius,
-  reflectivity, color, and center, but not a semantic label or optical material
-  fields:
-  [src/app/title-scene-preview-session.ts#L89:31f551d329e3183e67d4e33e7d8077c6bac0dfba](https://github.com/flyingrobots/jedit/blob/31f551d329e3183e67d4e33e7d8077c6bac0dfba/src/app/title-scene-preview-session.ts#L89).
-- Issue #46 asks for a focused material lab that is deterministic, not default,
-  named/validated by lane, and covered by focused witnesses:
-  https://github.com/flyingrobots/jedit/issues/46.
-
-## Problem
-
-The title renderer has several optical paths, but no controlled scene that
-names and places comparable samples for each material behavior. Existing product
-scenes prove rendering works, but they do not provide a small inspectable
-fixture for material tuning or regression review.
-
-## Scope
-
-This cycle includes:
-
-- Adding `material-lab.jedit-scene` under `scenes/`.
-- Registering it as a built-in title scene without making it the first/default
-  scene.
-- Adding optional scene-object labels to the runtime object model and loader.
-- Exposing object label, transparency, and refractive index through the preview
-  inspector.
-- Adding focused specs for registry order, scene labels, optical material lanes,
-  floor/light environment, and one render/optics witness.
-
-## Non-Goals
-
-This cycle does not include:
-
-- Changing the default title startup scene.
-- Adding a new TUI control, modal, or visible string.
-- Adding a material editor UI.
-- Adding mesh placement transforms.
-- Expanding the scene JSON format beyond optional labels.
-- Creating a full golden image fixture for every material lane.
-
-## User Experience / Product Shape
-
-Normal startup behavior is unchanged. Developers and agents can select or load
-`material-lab.jedit-scene` through the existing built-in scene registry and
-preview tooling. The scene is intentionally compact: a row/grid of named objects
-under one stable floor and lighting rig.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[Maintainer opens preview or loader] --> Select[Select material-lab.jedit-scene]
-  Select --> Inspect[Inspect labeled material lanes]
-  Inspect --> Render[Render deterministic frame]
-  Render --> Compare[Compare material behavior under one rig]
-  Inspect --> Failure[Missing lane or invalid material field]
-  Failure --> Fix[Adjust scene JSON or loader decoding]
-  Fix --> Inspect
-```
-
-### Wide UI Mockup
-
-Not applicable. This cycle adds a built-in scene and inspectable runtime facts,
-not a new rendered UI control. The visible result is reproduced through the
-existing title-scene preview command.
-
-### Narrow UI Mockup
-
-Not applicable. No layout, drawer, modal, footer, or narrow-terminal behavior
-changes in this cycle.
-
-### Accessibility Considerations
-
-The scene remains visual, but semantic lane labels and material facts are
-available through runtime objects and preview inspector output so agents and
-screen-reader-adjacent tooling do not need to infer meaning from pixels.
-
-## Runtime / API Contract
-
-Contracts:
-
-- `scenes/material-lab.jedit-scene`
-- `src/ports/title-scene-loader.ts`
-- `src/adapters/title-scene-loader.ts`
-- `src/ui/title-scene.ts`
-- `src/app/title-scene-preview-session.ts`
-
-`scenes/material-lab.jedit-scene` will contain labeled object lanes:
-
-- `matte`;
-- `mirror`;
-- `transparent`;
-- `refractive`;
-- `rim-column`;
-- `spotlight-target`.
-
-`TitleSceneObject` will allow an optional `label?: string`. The scene loader
-will decode an optional object `label` string and reject non-string labels. The
-preview object inspector will include optional `label`, `transparency`, and
-`refractiveIndex` fields when present on the selected object.
-
-`BUILT_IN_TITLE_SCENE_NAMES` will include `material-lab.jedit-scene`, but not at
-index zero.
-
-## Lower Modes
-
-The lower mode is deterministic loader and preview-inspector output:
-
-- `parseTitleSceneJson` and `loadBuiltInTitleScene` expose runtime objects with
-  labels and material fields.
-- `titleScenePreviewInspector` exposes selected-object label and optical fields.
-- The scene can be rendered through the existing preview CLI without a TUI.
-
-## Data / State Model
-
-| Category                  | Description                                                    |
-| ------------------------- | -------------------------------------------------------------- |
-| Source of truth           | `scenes/material-lab.jedit-scene` and built-in scene registry. |
-| Derived state             | Runtime `TitleSceneObject` labels and preview inspector facts. |
-| Invalid states            | Non-string labels or out-of-range material fields.             |
-| Reset behavior            | Static scene asset; no mutable state.                          |
-| Serialization             | JSON scene file copied to `dist/scenes/` during build.         |
-| Deterministic assumptions | Same scene JSON, theme, and render time produce same witness.  |
-
-```mermaid
-flowchart LR
-  Scene[material-lab.jedit-scene] --> Loader[title scene loader]
-  Registry[Built-in scene registry] --> Loader
-  Loader --> Runtime[TitleScene objects]
-  Runtime --> Inspector[Preview inspector facts]
-  Runtime --> Renderer[Title renderer witness]
-```
-
-## Accessibility Posture
-
-| Concern                           | Posture                                          |
-| --------------------------------- | ------------------------------------------------ |
-| Semantic labels or facts          | Material lanes expose `label` on runtime object. |
-| Focus order or ownership          | Not applicable; no focus change.                 |
-| Hidden or visual-only information | Optical fields are inspector facts.              |
-| Keyboard behavior                 | Existing scene preview controls only.            |
-| Secret or redaction behavior      | No secrets are read or emitted.                  |
-
-## Localization / Directionality Posture
-
-Not applicable. No user-visible localized copy changes. The scene filename and
-object labels are developer/agent identifiers, not catalog copy.
-
-## Agent Inspectability / Explainability Posture
-
-Agents can inspect:
-
-- `BUILT_IN_TITLE_SCENE_NAMES` for the non-default registered scene;
-- loaded `TitleSceneObject.label` values;
-- loaded `reflectivity`, `transparency`, and `refractiveIndex` values;
-- preview inspector facts for selected objects;
-- focused render/optics assertions proving the lab exercises floor and light
-  behavior.
-
-## Linked Invariants
-
-- Tests are executable spec.
-- Runtime truth beats type theater.
-- Design should become repo truth.
-- Files and previews are projections.
-- Echo authority remains outside jedit product nouns.
-
-## Design Alternatives Considered
-
-### Option A: Registered Built-In Scene With Object Labels
-
-Pros:
-
-- Uses the existing scene loader and preview surfaces.
-- Keeps the scene deterministic and easy to inspect.
-- Makes material lanes machine-readable.
-- Avoids renderer branches.
-
-Cons:
-
-- Adds a tiny JSON schema field for labels.
-
-### Option B: Dedicated TypeScript Scene Factory
-
-Pros:
-
-- Stronger compile-time control over lane construction.
-
-Cons:
-
-- Bypasses the JSON scene path this feature should validate.
-- Adds more runtime code for static scene data.
-
-### Option C: Preview-Only Script Fixture
-
-Pros:
-
-- Keeps the built-in scene registry unchanged.
-
-Cons:
-
-- Harder to discover.
-- Does not prove built-in scene loading or asset copying.
-- Makes the lab a script artifact instead of repo truth.
-
-## Decision
-
-Choose Option A. The material lab is a registered, non-default JSON scene with
-runtime labels and focused specs.
-
-## Implementation Slices
-
-- [x] Slice 1: Commit this design packet. Commit message:
-      `docs: design title scene material lab`.
-- [x] Slice 2: Add RED specs for missing material lab registration, labels, and
-      inspector facts.
-- [x] Slice 3: Add optional object labels to scene object model and loader.
-- [x] Slice 4: Add `material-lab.jedit-scene` and register it as non-default.
-- [x] Slice 5: Add focused render/optics witness for material lab floor/light
-      behavior.
-- [x] Slice 6: Verify build, focused specs, title-rendering shard, quality,
-      and formatting.
-- [ ] Slice 7: Push, mark PR ready, and merge when eligible.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [x] `spec/title-scene-material-lab.spec.mjs` fails before the scene is
-      registered and passes after implementation.
-- [x] Loader test fails before labels decode and passes after implementation.
-- [x] Preview inspector test fails before label/optical fields are exposed and
-      passes after implementation.
-- [x] Focused render/optics test proves floor/light behavior using the material
-      lab scene.
-
-Documentation and process tests:
-
-- [x] Prettier validates this design doc.
-
-Rule: documentation tests cannot be the only proof for implementation work.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [x] `material-lab.jedit-scene` is registered but not first/default.
-- [x] Loaded material lab objects include the expected lane labels.
-- [x] The lab includes matte, mirror, transparent, refractive, rim, spotlight,
-      and floor coverage.
-- [x] Preview inspector exposes selected object label and optical fields.
-- [x] Focused render/optics witness proves material lab light/floor behavior.
-- [x] Issue and PR are linked correctly.
-- [x] Local validation is green.
-- [ ] CI is green before merge.
-
-## Validation Plan
-
-Commands expected before PR:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-material-lab.spec.mjs spec/title-scene-loader.spec.mjs spec/title-scene-preview-session.spec.mjs
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- title-rendering
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- workspace-ui
-npm run quality
-npx --no-install prettier --check docs/design/0046-title-scene-material-lab.md src/ports/title-scene-loader.ts src/adapters/title-scene-loader.ts src/adapters/title-scene-json-decoder.ts src/adapters/title-scene-environment-decoder.ts src/ui/title-scene.ts src/ui/title-scene-hit.ts src/app/title-scene-preview-session.ts spec/title-scene-material-lab.spec.mjs spec/workspace-runtime.spec.mjs
-npx --no-install prettier --parser json --check scenes/material-lab.jedit-scene
-git diff --check
-```
-
-Executed local validation:
-
-```bash
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-material-lab.spec.mjs
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-material-lab.spec.mjs spec/title-scene-loader.spec.mjs spec/title-scene-preview-session.spec.mjs
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- title-rendering
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- workspace-ui
-npm run quality
-npx --no-install prettier --check docs/design/0046-title-scene-material-lab.md src/ports/title-scene-loader.ts src/adapters/title-scene-loader.ts src/adapters/title-scene-json-decoder.ts src/adapters/title-scene-environment-decoder.ts src/ui/title-scene.ts src/ui/title-scene-hit.ts src/app/title-scene-preview-session.ts spec/title-scene-material-lab.spec.mjs spec/workspace-runtime.spec.mjs
-npx --no-install prettier --parser json --check scenes/material-lab.jedit-scene
-git diff --check
-```
-
-## Playback / Witness
-
-Reviewers can run:
-
-```bash
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-material-lab.spec.mjs
-npm run title:preview -- --scene material-lab.jedit-scene --json
-```
-
-## Risks
-
-Known risks:
-
-- Adding labels could become a generic application metadata system.
-- Adding another built-in scene could accidentally become the default scene.
-- A render witness could become too broad and duplicate the full title suite.
-
-Mitigations:
-
-- Labels are optional plain strings only, with no behavior attached.
-- Specs assert the material lab is not first in the built-in registry.
-- Keep render proof to one focused material-lab assertion.
-
-## Follow-On Debt
-
-No follow-on debt is introduced by this cycle. A future material editor UI,
-per-lane golden fixtures, or richer material metadata should be separate issues.
-
-## Retrospective
-
-What changed from the design:
-
-- Implemented the material lab as a non-default built-in JSON scene with six
-  labeled lanes.
-- Added optional object labels to the scene object model and loader.
-- Exposed label, transparency, and refractive index through preview inspector
-  facts.
-- Split scene JSON/environment decoding and ray-hit geometry into focused
-  helper modules so the implementation remains below quality-gate line limits.
-
-What the tests proved:
-
-- RED: `spec/title-scene-material-lab.spec.mjs` failed while
-  `material-lab.jedit-scene` was not registered.
-- GREEN: focused specs proved registration order, expected labels, material
-  fields, inspector facts, and floor/light behavior.
-- The `title-rendering` shard passed with the new scene included in built-in
-  coverage.
-- CI RED: `workspace-ui` initially failed because the workspace scene-picker
-  registry fixture did not include the new authored scene.
-- CI GREEN: `workspace-ui` passed after the scene-picker witness was updated.
-
-What remains open:
-
-- Remote CI still has to run before merge.
-
-PR:
-
-- https://github.com/flyingrobots/jedit/pull/96
diff --git a/docs/design/0078-startup-scene-performance-governor.md b/docs/design/0078-startup-scene-performance-governor.md
deleted file mode 100644
index 0257f745..00000000
--- a/docs/design/0078-startup-scene-performance-governor.md
+++ /dev/null
@@ -1,408 +0,0 @@
----
-title: "DX-0078 - Startup Scene Performance Governor"
-legend: "DX"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/78"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-06-04"
-updated: "2026-06-05"
----
-
-# DX-0078 - Startup Scene Performance Governor
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/78
-
-## Decision Summary
-
-Jedit will add a small startup title-scene performance governor that owns the
-choice between live ray tracing and low-rate cached backdrop reuse for slow idle
-title screens. The startup file browser remains a live title-scene overlay:
-ray tracing and camera motion continue while the browser is open, and rendering
-stops only after a file opens and the editor becomes the active surface.
-
-## Sponsored Human
-
-A user browsing files from the title screen wants the startup browser to feel
-like part of the animated scene so that opening a file feels continuous,
-without the Dragon camera or ray-traced material preview freezing underneath
-the drawer.
-
-## Sponsored Agent
-
-An agent needs a stable render-posture contract so it can verify startup render
-cost decisions, without inferring whether rays were traced from pixels, frame
-timing noise, or private renderer state.
-
-## Hill
-
-By the end of this cycle, a reviewer can render the startup title surface,
-inspect the renderer's title-scene performance facts, and prove through specs
-that the startup browser keeps live tracing while slow idle title frames refresh
-at a bounded low rate.
-
-## Current Truth
-
-The merge target for this cycle is `origin/main` at
-`6fc1905ff731a08d57ffde988cad9812709c7a91`.
-
-Current anchors:
-
-- The viewer currently keeps `frozenTitleBackdrop` inside
-  `viewer-content.ts`, but the render policy is encoded directly in
-  `renderTitleBackdrop`:
-  [src/app/workspace/viewer-content.ts#L22:6fc1905ff731a08d57ffde988cad9812709c7a91](https://github.com/flyingrobots/jedit/blob/6fc1905ff731a08d57ffde988cad9812709c7a91/src/app/workspace/viewer-content.ts#L22).
-- The current modal freeze behavior is tested by counting title-renderer calls
-  while modal input changes:
-  [spec/workspace-title-screen.spec.mjs#L184:6fc1905ff731a08d57ffde988cad9812709c7a91](https://github.com/flyingrobots/jedit/blob/6fc1905ff731a08d57ffde988cad9812709c7a91/spec/workspace-title-screen.spec.mjs#L184).
-- The earlier startup browser design treated backdrop retention as a
-  render-performance posture, not workspace or Echo state:
-  [docs/design/0036-title-intro-startup-file-modal.md#L75:6fc1905ff731a08d57ffde988cad9812709c7a91](https://github.com/flyingrobots/jedit/blob/6fc1905ff731a08d57ffde988cad9812709c7a91/docs/design/0036-title-intro-startup-file-modal.md#L75).
-- The workspace model already tracks `frameTimeMs` and `frameTimeHistory`, but
-  title rendering does not consume those fields for a named posture:
-  [src/app/workspace/model.ts#L67:6fc1905ff731a08d57ffde988cad9812709c7a91](https://github.com/flyingrobots/jedit/blob/6fc1905ff731a08d57ffde988cad9812709c7a91/src/app/workspace/model.ts#L67).
-
-## Problem
-
-The startup scene needs named render facts so agents can distinguish live
-tracing from slow idle cached reuse. The startup browser used to freeze the
-title scene for input responsiveness, but the product direction now requires
-the browser to keep the ray tracer and camera motion running until a file is
-open.
-
-## Scope
-
-This cycle includes:
-
-- Adding a focused startup title-scene performance governor module.
-- Routing workspace title backdrop rendering through the governor.
-- Storing the cached backdrop render time so low-rate refresh can make bounded
-  cache-age decisions.
-- Exposing the last title-scene performance posture through
-  `ViewerContentRenderer`.
-- Adding focused specs for startup-browser live tracing, intro live tracing,
-  and slow idle low-rate reuse.
-- Updating the #78 design retrospective and PR validation evidence.
-
-## Non-Goals
-
-This cycle does not include:
-
-- New visible UI, copy, settings, or keyboard controls.
-- A full adaptive renderer, quality ladder, or ray-resolution scaler.
-- Persisting performance state in Echo, WSC, or workspace model state.
-- Changing the title intro timeline or startup browser layout.
-- Changing profiler trace file format.
-
-## User Experience / Product Shape
-
-There is no new visible control. The user-visible behavior is that the startup
-browser opens over the live title scene and the Dragon camera/material preview
-keeps moving behind it. During the intro, the title scene renders live frames.
-After the intro, if the terminal is slow and a fresh cached title
-backdrop exists, the governor may reuse that cached backdrop for a short bounded
-interval before tracing a new frame.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[User starts jedit] --> Intro[Intro title scene traces live]
-  Intro --> Browser[Startup file browser opens]
-  Browser --> Type[User types in browser input]
-  Type --> Live[Title scene keeps tracing]
-  Live --> Open[User opens a file]
-  Intro --> SlowIdle[Intro complete and no browser/editor]
-  SlowIdle --> CacheFresh[Recent backdrop is fresh]
-  CacheFresh --> LowRate[Reuse backdrop for bounded low-rate frame]
-  CacheFresh --> Refresh[Trace when cache age exceeds refresh window]
-```
-
-### Wide UI Mockup
-
-Not applicable. This cycle changes render scheduling and inspectable facts, not
-layout or visible browser chrome.
-
-### Narrow UI Mockup
-
-Not applicable. Small-terminal rendering remains owned by the existing
-workspace small-terminal notice and startup browser layout.
-
-### Accessibility Considerations
-
-The visual title backdrop remains decorative. The meaningful state added here
-is exposed as structured performance facts rather than hidden in pixels.
-
-## Runtime / API Contract
-
-Contracts:
-
-- `src/app/workspace/title-scene-performance-governor.ts`
-- `src/app/workspace/viewer-content.ts`
-
-The governor will export:
-
-- posture constants for `live-trace` and `low-rate-frozen-backdrop`;
-- `governTitleSceneRender(input)` returning a render decision;
-- `titleScenePerformanceFacts(decision)` returning machine-readable facts;
-- frame-budget constants used by the decision.
-
-`ViewerContentRenderer` will expose:
-
-- `titleScenePerformanceFacts()` returning the last title-scene render posture.
-
-Decision semantics:
-
-- Intro active: always live trace.
-- Startup browser open: live trace and retain the rendered backdrop.
-- Idle title screen over frame budget with fresh cache: reuse cached backdrop
-  until the refresh window expires.
-- Otherwise: live trace and retain the rendered backdrop.
-
-## Lower Modes
-
-Lower mode is the structured renderer facts:
-
-- posture id;
-- whether rays were traced;
-- whether a frozen backdrop was used;
-- whether a rendered frame was retained for future reuse;
-- input-latency posture;
-- frame-budget posture.
-
-No-color and small-terminal rendering behavior are unchanged.
-
-## Data / State Model
-
-| Category                  | Description                                              |
-| ------------------------- | -------------------------------------------------------- |
-| Source of truth           | Runtime workspace model plus renderer-local cache.       |
-| Derived state             | Governor decision and performance facts.                 |
-| Invalid states            | Negative cache age or non-finite frame time.             |
-| Reset behavior            | Clearing the renderer cache resets facts to no backdrop. |
-| Serialization             | None; render posture is process-local evidence.          |
-| Deterministic assumptions | Same model time/frame/cache inputs produce same posture. |
-
-```mermaid
-stateDiagram-v2
-  [*] --> LiveTrace
-  LiveTrace --> LiveTrace: browser open
-  LiveTrace --> LowRateFrozen: idle + over budget + fresh cache
-  LowRateFrozen --> LiveTrace: cache age expires
-```
-
-## Accessibility Posture
-
-| Concern                           | Posture                                        |
-| --------------------------------- | ---------------------------------------------- |
-| Semantic labels or facts          | Performance facts expose named render posture. |
-| Focus order or ownership          | Browser focus behavior is unchanged.           |
-| Hidden or visual-only information | Trace/frozen state is available structurally.  |
-| Keyboard behavior                 | Existing startup browser keys are unchanged.   |
-| Secret or redaction behavior      | No secrets are read or emitted.                |
-
-## Localization / Directionality Posture
-
-Not applicable. No user-visible strings change.
-
-## Agent Inspectability / Explainability Posture
-
-Agents can inspect the renderer's last title-scene performance facts without
-scraping pixels:
-
-- stable posture id;
-- ray-trace boolean;
-- frozen-backdrop boolean;
-- retained-backdrop boolean;
-- input-latency posture;
-- frame-budget posture.
-
-## Linked Invariants
-
-- Tests are executable spec.
-- Runtime truth beats type theater.
-- Design should become repo truth.
-- Layout owns interaction geometry.
-- Files and previews are projections.
-- Echo authority remains outside jedit product nouns.
-
-## Design Alternatives Considered
-
-### Option A: Extract A Pure Governor And Expose Renderer Facts
-
-Pros:
-
-- Makes the policy testable without terminal pixels.
-- Keeps cache state local to the renderer.
-- Preserves existing modal rendering behavior while naming it.
-- Gives future slow-terminal work a single decision boundary.
-
-Cons:
-
-- Adds one more small workspace module.
-
-### Option B: Keep The Existing Inline Branch And Add More Tests
-
-Pros:
-
-- Smallest code movement.
-
-Cons:
-
-- Keeps render-cost policy hidden in the view function.
-- Does not provide agent-readable facts.
-- Makes future low-rate behavior harder to add cleanly.
-
-### Option C: Put Performance Policy In WorkspaceModel
-
-Pros:
-
-- The runtime model would make posture visible everywhere.
-
-Cons:
-
-- Persists render-cache concerns into workspace state.
-- Makes a decorative renderer cache look like product state.
-- Conflicts with the prior design that backdrop retention is not workspace or
-  Echo state.
-
-## Decision
-
-Choose Option A. The governor is a pure runtime helper, while the cached surface
-stays renderer-local.
-
-## Implementation Slices
-
-- [x] Slice 1: Commit this design packet. Commit message:
-      `docs: design startup scene performance governor`.
-- [x] Slice 2: Add RED specs for the missing governor contract and renderer
-      performance facts.
-- [x] Slice 3: Implement the governor decision and facts module.
-- [x] Slice 4: Route `viewer-content` title backdrop rendering through the
-      governor and retain cache render time.
-- [x] Slice 5: Add low-rate idle cache reuse tests and startup-browser live
-      tracing tests.
-- [x] Slice 6: Verify build, focused specs, title-rendering/workspace-ui
-      shards, quality, and formatting.
-- [ ] Slice 7: Push, mark PR ready, and merge when eligible.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [x] Governor pure spec fails before
-      `title-scene-performance-governor.js` exists.
-- [x] Renderer inspector spec fails before
-      `titleScenePerformanceFacts()` exists.
-- [x] Startup browser regression proves browser input keeps tracing rays.
-- [x] Slow idle title regression proves fresh cache reuse and bounded refresh.
-
-Documentation and process tests:
-
-- [x] Prettier validates this design doc.
-
-Rule: documentation tests cannot be the only proof for implementation work.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [x] Render posture decisions are centralized in a governor module.
-- [x] Startup browser input continues invoking the title renderer.
-- [x] Slow idle title rendering can reuse a fresh cached backdrop and refreshes
-      after the bounded interval.
-- [x] Renderer performance facts are inspectable without pixel scraping.
-- [x] Existing startup browser behavior still passes.
-- [x] Issue and PR are linked correctly.
-- [x] Local validation is green.
-- [ ] CI is green before merge.
-
-## Validation Plan
-
-Commands expected before PR:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/workspace-title-performance-governor.spec.mjs spec/workspace-title-screen.spec.mjs
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- title-rendering
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- workspace-ui
-npm run quality
-npx --no-install prettier --check docs/design/0078-startup-scene-performance-governor.md src/app/workspace/title-scene-performance-governor.ts src/app/workspace/viewer-content.ts spec/workspace-title-performance-governor.spec.mjs spec/workspace-title-screen.spec.mjs
-git diff --check
-```
-
-Executed local validation:
-
-```bash
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/workspace-title-performance-governor.spec.mjs
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/workspace-title-performance-governor.spec.mjs spec/workspace-title-screen.spec.mjs
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- title-rendering
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- workspace-ui
-npm run quality
-npx --no-install prettier --check docs/design/0078-startup-scene-performance-governor.md src/app/workspace/title-scene-performance-governor.ts src/app/workspace/viewer-content.ts spec/workspace-title-performance-governor.spec.mjs spec/workspace-title-screen.spec.mjs
-git diff --check
-```
-
-## Playback / Witness
-
-Reviewers can run:
-
-```bash
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/workspace-title-performance-governor.spec.mjs
-```
-
-The spec exposes the render posture without relying on a terminal screenshot.
-
-## Risks
-
-Known risks:
-
-- Low-rate cache reuse could accidentally freeze the intro.
-- Render facts could become a public user-facing API too early.
-- A cache-age threshold could become magic if not named and tested.
-
-Mitigations:
-
-- Intro active always wins and forces live tracing.
-- Facts remain on the renderer test/runtime boundary, not visible UI copy.
-- Thresholds are exported constants and covered by focused tests.
-
-## Follow-On Debt
-
-No follow-on issue is required for the core #78 acceptance. A future adaptive
-ray-quality ladder or user-visible performance setting should be separate work.
-
-## Retrospective
-
-What changed from the design:
-
-- Implemented the governor as `title-scene-performance-governor.ts`.
-- Routed `viewer-content` through the governor and retained cached backdrop
-  render time.
-- Exposed `titleScenePerformanceFacts()` on `ViewerContentRenderer`.
-- Normalized missing JS-test `frameTimeMs` to zero at the viewer boundary so
-  older test models remain valid while the runtime model keeps the typed field.
-
-What the tests proved:
-
-- RED: the new focused spec failed before
-  `title-scene-performance-governor.js` existed and before renderer facts were
-  exposed.
-- GREEN: governor specs prove intro live, browser-open live, and low-rate idle
-  decisions.
-- GREEN: renderer specs prove browser input continues tracing and slow idle
-  title screens reuse a fresh cache until the refresh window expires.
-- Existing title-screen startup browser tests still pass.
-- `title-rendering` and `workspace-ui` shards both pass locally.
-
-What remains open:
-
-- Remote CI still has to run before merge.
-
-PR:
-
-- https://github.com/flyingrobots/jedit/pull/97
diff --git a/docs/design/0099-source-editor-background-fill.md b/docs/design/0099-source-editor-background-fill.md
deleted file mode 100644
index f5463137..00000000
--- a/docs/design/0099-source-editor-background-fill.md
+++ /dev/null
@@ -1,341 +0,0 @@
----
-title: "DX-0099 - Source Editor Background Fill"
-legend: "DX"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/99"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-06-04"
-updated: "2026-06-04"
----
-
-# DX-0099 - Source Editor Background Fill
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/99
-
-## Decision Summary
-
-The source editor painter will preserve or apply theme-owned background style
-for every painted source cell. Syntax highlighting may override foreground,
-modifiers, and explicit token backgrounds, but unhighlighted text, whitespace,
-and blank viewport rows must retain `theme.surface.workspace` instead of
-clearing the already-filled surface background.
-
-## Sponsored Human
-
-A person editing source code wants the editor body to look like one coherent
-themed surface so that code is readable across terminals, without seeing
-terminal-default background holes around normal text or blank rows.
-
-## Sponsored Agent
-
-An agent needs inspectable cell-level style evidence so it can verify source
-editor background ownership, without inferring visual correctness from a
-screenshot or terminal palette.
-
-## Hill
-
-By the end of this cycle, the source highlight/editor specs prove that
-unhighlighted source cells, highlighted source cells, whitespace, and blank
-viewport rows all carry deterministic background style from the active theme.
-
-## Current Truth
-
-The merge target for this cycle is `origin/main` at
-`8ef5b8ad3170aca02b7fe1ec5c67e4f6ec3d27ab`.
-
-Current anchors:
-
-- The workspace source viewer path creates a fresh surface and fills it with
-  `model.jeditTheme.surface.workspace` before rendering editor content:
-  [src/app/workspace/viewer-content.ts#L114:8ef5b8ad3170aca02b7fe1ec5c67e4f6ec3d27ab](https://github.com/flyingrobots/jedit/blob/8ef5b8ad3170aca02b7fe1ec5c67e4f6ec3d27ab/src/app/workspace/viewer-content.ts#L114).
-- Source viewer delegates source body painting to
-  `paintHighlightedSourceWindow`:
-  [src/ui/source-viewer.ts#L44:8ef5b8ad3170aca02b7fe1ec5c67e4f6ec3d27ab](https://github.com/flyingrobots/jedit/blob/8ef5b8ad3170aca02b7fe1ec5c67e4f6ec3d27ab/src/ui/source-viewer.ts#L44).
-- `paintHighlightedSourceWindow` calls `surface.set` with only `char`, optional
-  highlight style, and `empty: false`:
-  [src/ui/source-highlight.ts#L40:8ef5b8ad3170aca02b7fe1ec5c67e4f6ec3d27ab](https://github.com/flyingrobots/jedit/blob/8ef5b8ad3170aca02b7fe1ec5c67e4f6ec3d27ab/src/ui/source-highlight.ts#L40).
-- When no highlight span covers a cell, `styleAt` returns an empty object,
-  which means the source painter can erase the pre-filled background:
-  [src/ui/source-highlight.ts#L60:8ef5b8ad3170aca02b7fe1ec5c67e4f6ec3d27ab](https://github.com/flyingrobots/jedit/blob/8ef5b8ad3170aca02b7fe1ec5c67e4f6ec3d27ab/src/ui/source-highlight.ts#L60).
-- The current source highlight spec proves token foregrounds and modifiers, but
-  does not assert background preservation:
-  [spec/source-highlight.spec.mjs#L25:8ef5b8ad3170aca02b7fe1ec5c67e4f6ec3d27ab](https://github.com/flyingrobots/jedit/blob/8ef5b8ad3170aca02b7fe1ec5c67e4f6ec3d27ab/spec/source-highlight.spec.mjs#L25).
-
-## Problem
-
-The source editor is painted over a themed workspace background, but the source
-highlight painter overwrites each source body cell without first preserving the
-existing cell style or supplying a fallback background. Unhighlighted cells,
-whitespace cells, and blank rows can therefore become cells with no
-theme-owned background.
-
-## Scope
-
-This cycle includes:
-
-- Adding source-highlight regression coverage for unhighlighted source text,
-  trailing whitespace, blank viewport rows, and highlighted cells.
-- Updating the source highlight painter so every painted cell carries a
-  background.
-- Preserving token foregrounds and modifiers for highlighted spans.
-- Letting explicit highlight token backgrounds win when a token supplies one.
-- Falling back to `theme.surface.workspace` background when a highlighted token
-  has no background or no highlight span applies.
-
-## Non-Goals
-
-This cycle does not include:
-
-- Changing theme palettes or adding new theme tokens.
-- Changing cursor rendering.
-- Changing markdown preview rendering.
-- Changing terminal clear behavior, app frame layout, or Bijou surface
-  internals.
-- Solving every possible background issue in unrelated views.
-
-## User Experience / Product Shape
-
-The visible effect is that the source code editor body uses one coherent
-theme-colored background. Blank rows and padded cells no longer expose a
-terminal-default background. Syntax-highlighted spans keep their foreground
-colors and modifiers.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[User opens a source file] --> Paint[Workspace fills themed surface]
-  Paint --> Source[Source painter writes code cells]
-  Source --> Stable[Every editor cell keeps themed background]
-  Source --> Highlight[Highlighted spans keep token foregrounds]
-```
-
-### Wide UI Mockup
-
-Not applicable. This is a cell-style correctness fix; the layout is unchanged.
-
-### Narrow UI Mockup
-
-Not applicable. Narrow terminal geometry is unchanged; the same cell-style
-rules apply to the clipped viewport.
-
-### Accessibility Considerations
-
-Consistent background ownership improves contrast stability for terminals using
-custom default colors. No focus order, command, or spoken label changes.
-
-## Runtime / API Contract
-
-Contract: `paintHighlightedSourceWindow`.
-
-For every cell inside the requested source window rectangle:
-
-- the painter sets a visible character, using a space for missing source text;
-- the painter sets `empty: false`;
-- the painter preserves highlight token foreground and modifiers when a span
-  applies;
-- the painter uses an explicit highlight token background when available;
-- otherwise the painter uses `theme.surface.workspace.bg/bgRGB`.
-
-No exported type changes are required.
-
-## Lower Modes
-
-Lower-mode proof is cell inspection in Node specs. The test reads individual
-Bijou surface cells and asserts `bg` and `bgRGB` without relying on screenshots,
-terminal colors, or rendered pixels.
-
-## Data / State Model
-
-| Category                  | Description                                          |
-| ------------------------- | ---------------------------------------------------- |
-| Source of truth           | Active `JeditTheme` and source highlight spans.      |
-| Derived state             | Painted Bijou surface cells.                         |
-| Invalid states            | Painted source cells without theme-owned bg data.    |
-| Reset behavior            | Each render starts from the caller-owned surface.    |
-| Serialization             | None.                                                |
-| Deterministic assumptions | Same source/highlight/theme inputs paint same cells. |
-
-```mermaid
-flowchart LR
-  Theme[JeditTheme] --> Painter[paintHighlightedSourceWindow]
-  Highlight[Highlight spans] --> Painter
-  Reading[SourceWindowReading] --> Painter
-  Painter --> Cells[Surface cells with chars and bg style]
-```
-
-## Accessibility Posture
-
-| Concern                           | Posture                                    |
-| --------------------------------- | ------------------------------------------ |
-| Semantic labels or facts          | Not changed.                               |
-| Focus order or ownership          | Not changed.                               |
-| Hidden or visual-only information | Background style becomes cell-inspectable. |
-| Keyboard behavior                 | Not changed.                               |
-| Secret or redaction behavior      | No secrets are read or emitted.            |
-
-## Localization / Directionality Posture
-
-Not applicable. No user-visible strings change.
-
-## Agent Inspectability / Explainability Posture
-
-Agents can inspect source editor cells directly in the regression spec:
-
-- unhighlighted text cell background;
-- trailing whitespace background;
-- blank viewport row background;
-- highlighted token foreground/modifier plus background fallback.
-
-## Linked Invariants
-
-- Tests are executable spec.
-- Runtime truth beats type theater.
-- Layout owns interaction geometry.
-- Files and previews are projections.
-- Theme tokens own visible styling.
-
-## Design Alternatives Considered
-
-### Option A: Preserve Existing Cell Style Before Source Painting
-
-Pros:
-
-- Respects caller-owned pre-fill behavior.
-- Keeps source painter flexible for surfaces that intentionally supply a
-  different background.
-
-Cons:
-
-- Makes the source painter depend on the prior surface state.
-- Still needs fallback behavior if the prior cell has no background.
-
-### Option B: Use Theme Fallback In The Source Painter
-
-Pros:
-
-- Gives the source painter a direct, deterministic background contract.
-- Does not rely on the caller having pre-filled the surface correctly.
-- Matches the existing options object, which already provides `theme`.
-
-Cons:
-
-- Source painter now owns more of the source cell style contract.
-
-## Decision
-
-Choose Option B with preservation semantics for token-specific style. The source
-painter already owns every source body cell, so it should also guarantee that
-those cells carry a theme-owned background.
-
-## Implementation Slices
-
-- [x] Slice 1: File issue #99 and write this design document.
-- [x] Slice 2: Add failing source-highlight regression assertions for
-      background style.
-- [x] Slice 3: Update the source highlight painter to apply workspace
-      background fallback.
-- [x] Slice 4: Run focused and quality validation, update this retrospective,
-      and open the PR.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [x] `spec/source-highlight.spec.mjs` proves unhighlighted text cells carry the
-      workspace background.
-- [x] `spec/source-highlight.spec.mjs` proves trailing whitespace and blank rows
-      carry the workspace background.
-- [x] `spec/source-highlight.spec.mjs` proves highlighted cells keep token
-      foreground/modifiers and receive a background.
-
-Documentation and process tests:
-
-- [x] Prettier checks this design doc.
-
-Rule: documentation tests cannot be the only proof for implementation work.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [x] Source editor body cells do not erase the theme background.
-- [x] Highlighted cells keep existing source token behavior.
-- [x] Focused regression tests fail before the implementation and pass after.
-- [x] Issue and PR are linked correctly.
-- [x] Local validation is green; remote CI remains the PR merge gate.
-
-## Validation Plan
-
-Commands expected before PR completion:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/source-highlight.spec.mjs
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- workspace-ui
-npm run quality
-npx --no-install prettier --check docs/design/0099-source-editor-background-fill.md src/ui/source-highlight.ts spec/source-highlight.spec.mjs
-git diff --check
-```
-
-## Playback / Witness
-
-Focused witness:
-
-```bash
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/source-highlight.spec.mjs
-```
-
-The reviewer can also open any source file in jedit and inspect that blank
-editor cells use the active theme background instead of terminal defaults.
-
-## Risks
-
-Known risks:
-
-- A source token with an intentional background should not lose it.
-- Cursor styling should remain the final overlay.
-
-Mitigations:
-
-- Test highlighted spans separately from unhighlighted cells.
-- Leave cursor rendering untouched.
-
-## Follow-On Debt
-
-None planned. If other non-source views have similar background holes, file
-separate issues with the failing view and paint path.
-
-## Retrospective
-
-What changed from the design:
-
-- The implementation matched the design. `paintHighlightedSourceWindow` now
-  builds a workspace-surface base style for every source body cell and merges
-  defined syntax-token fields over that base.
-
-What the tests proved:
-
-- RED:
-  `JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/source-highlight.spec.mjs`
-  failed because unhighlighted and blank source cells had `bg: undefined`.
-- GREEN:
-  `JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/source-highlight.spec.mjs`
-  passed with 2 tests after the painter change.
-- `JEDIT_DIST_PREBUILT=1 npm run ci:shard -- workspace-ui` passed with 103
-  tests.
-- `npm run build`, `npm run quality`, Prettier, and `git diff --check` passed.
-
-What remains open:
-
-- Remote CI and review gates are handled by PR #100.
-- Other non-source views with background holes should get separate issues with
-  their failing paint paths.
-
-PR:
-
-- https://github.com/flyingrobots/jedit/pull/100
diff --git a/docs/design/0101-neon-dispersion-default-scene.md b/docs/design/0101-neon-dispersion-default-scene.md
deleted file mode 100644
index a1423487..00000000
--- a/docs/design/0101-neon-dispersion-default-scene.md
+++ /dev/null
@@ -1,434 +0,0 @@
----
-title: "DX-0101 - Neon Dispersion Default Scene"
-legend: "DX"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/101"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-06-04"
-updated: "2026-06-04"
----
-
-# DX-0101 - Neon Dispersion Default Scene
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/101
-
-## Decision Summary
-
-Jedit will add `neon-dispersion.jedit-scene` as the first built-in title scene
-and make it the production startup default by loading it into the initial
-workspace snapshot. The scene will use a single refractive Stanford Dragon mesh
-on a dark reflective title stage. Unsupported cinematic requests such as true
-emissive tube lights, wavelength dispersion, roughness maps, torus primitives,
-finite room geometry, and depth of field will be tracked as follow-on renderer
-work instead of implied by the scene asset.
-
-## Sponsored Human
-
-A person starting jedit wants the default title screen to demonstrate the ray
-tracer's optical personality so that startup feels intentional and visually
-distinct, without opening the scene picker or hand-selecting a demo scene.
-
-## Sponsored Agent
-
-An agent needs a named default-scene contract and inspectable scene object
-facts so it can verify the startup scene selection and optical material
-coverage, without scraping screenshots or guessing which generated scene
-loaded.
-
-## Hill
-
-By the end of this cycle, startup loads `neon-dispersion.jedit-scene` as the
-default title scene, the scene picker lists it first, and focused specs prove
-the scene's refractive Stanford Dragon mesh, environment, provenance, and
-render-variety posture.
-
-## Current Truth
-
-The merge target for this cycle is `origin/main` at
-`2be4470d1b1efeb4a4738ca42c5a061490d31943`.
-
-Current anchors:
-
-- `BUILT_IN_TITLE_SCENE_NAMES` is the authoritative registry and currently
-  starts with `teapot-cornell.jedit-scene`:
-  [src/ports/title-scene-loader.ts#L10:2be4470d1b1efeb4a4738ca42c5a061490d31943](https://github.com/flyingrobots/jedit/blob/2be4470d1b1efeb4a4738ca42c5a061490d31943/src/ports/title-scene-loader.ts#L10).
-- The production startup snapshot loads meshes, seed, theme, i18n, and entries,
-  but no authored scene:
-  [src/adapters/workspace-initial-model-snapshot.ts#L12:2be4470d1b1efeb4a4738ca42c5a061490d31943](https://github.com/flyingrobots/jedit/blob/2be4470d1b1efeb4a4738ca42c5a061490d31943/src/adapters/workspace-initial-model-snapshot.ts#L12).
-- Initial scene state exposes the built-in scene names and chooses a camera from
-  either the random generated scene or loaded bunny mesh, not from an authored
-  default scene:
-  [src/app/workspace/init.ts#L130:2be4470d1b1efeb4a4738ca42c5a061490d31943](https://github.com/flyingrobots/jedit/blob/2be4470d1b1efeb4a4738ca42c5a061490d31943/src/app/workspace/init.ts#L130).
-- The title renderer only uses authored scene JSON when `sceneOverride` is
-  supplied; otherwise it generates a seeded scene:
-  [src/ui/title-screen.ts#L156:2be4470d1b1efeb4a4738ca42c5a061490d31943](https://github.com/flyingrobots/jedit/blob/2be4470d1b1efeb4a4738ca42c5a061490d31943/src/ui/title-screen.ts#L156).
-- Existing scene-list tests assert the current scene order and asset
-  existence:
-  [spec/workspace-runtime.spec.mjs#L199:2be4470d1b1efeb4a4738ca42c5a061490d31943](https://github.com/flyingrobots/jedit/blob/2be4470d1b1efeb4a4738ca42c5a061490d31943/spec/workspace-runtime.spec.mjs#L199).
-- Existing material-lab tests show the pattern for proving built-in scene
-  registration, optical material facts, and render variety:
-  [spec/title-scene-material-lab.spec.mjs#L20:2be4470d1b1efeb4a4738ca42c5a061490d31943](https://github.com/flyingrobots/jedit/blob/2be4470d1b1efeb4a4738ca42c5a061490d31943/spec/title-scene-material-lab.spec.mjs#L20).
-
-## Problem
-
-The title renderer has richer authored-scene support than the startup default
-uses. Startup still falls back to generated/bunny scene state, so the most
-intentional ray-traced scenes only appear after manual scene-picker selection
-or preview commands.
-
-## Scope
-
-This cycle includes:
-
-- Adding `scenes/neon-dispersion.jedit-scene`.
-- Adding `src/ui/stanford_dragon_res4.obj` as a built-in title mesh asset with
-  provenance documentation.
-- Registering the `dragon` mesh ID and startup mesh loader.
-- Exporting a named default built-in title scene constant.
-- Registering Neon Dispersion first in the built-in scene registry.
-- Loading the default built-in scene into production startup snapshots.
-- Applying the default scene camera to initial workspace title camera state.
-- Adding focused tests proving scene facts, default startup selection, registry
-  order, render variety, and asset copying.
-- Creating follow-on issue debt for renderer features needed to make the full
-  cinematic prompt literal.
-
-## Non-Goals
-
-This cycle does not include:
-
-- Implementing real emissive light geometry.
-- Implementing spectral chromatic dispersion or wavelength splitting.
-- Adding torus or high-poly icosahedron primitives.
-- Adding roughness maps, texture maps, or depth of field.
-- Replacing the title ray tracer architecture.
-- Changing intro logo timing or startup file modal behavior.
-
-## User Experience / Product Shape
-
-On startup, before any editor is open, the title screen shows Neon Dispersion by
-default: a solo refractive Stanford Dragon mesh on a dark ray-traced light
-stage. The user does not need to press `ctrl+l` or use the scene picker. The
-scene picker still works and lists Neon Dispersion first.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[User starts jedit] --> Snapshot[Startup snapshot loads default scene]
-  Snapshot --> Title[Title renderer receives sceneOverride]
-  Title --> Neon[Neon Dispersion renders as startup title scene]
-  Neon --> Picker[User can open scene picker]
-  Picker --> First[Neon Dispersion appears first]
-  Picker --> Other[User can switch to another built-in scene]
-```
-
-### Wide UI Mockup
-
-Not applicable. This cycle changes the rendered ray-traced scene content, not
-TUI layout or controls.
-
-### Narrow UI Mockup
-
-Not applicable. Existing title renderer and startup modal small-screen behavior
-remain unchanged.
-
-### Accessibility Considerations
-
-The title scene is decorative startup art. The machine-readable proof is the
-scene JSON and test-inspected scene facts. No focus order or keyboard behavior
-changes.
-
-## Runtime / API Contract
-
-Contracts:
-
-- `src/ports/title-scene-loader.ts`
-- `src/adapters/title-scene-loader.ts`
-- `src/adapters/workspace-initial-model-snapshot.ts`
-- `src/app/workspace/init.ts`
-
-The title scene loader port will export:
-
-- `DEFAULT_BUILT_IN_TITLE_SCENE_NAME`.
-
-Startup snapshot behavior:
-
-- Production startup attempts to load `DEFAULT_BUILT_IN_TITLE_SCENE_NAME`.
-- If the scene loads, `WorkspaceInitialModelSnapshot.sceneOverride` contains
-  that scene.
-- If loading fails, startup remains usable and falls back to the generated
-  scene path while reporting a concise stderr message.
-
-Initial model behavior:
-
-- `availableScenes[0]` is `DEFAULT_BUILT_IN_TITLE_SCENE_NAME`.
-- When `sceneOverride` exists, `titleCamera` starts from the scene camera.
-- When `sceneOverride` is absent, existing seed/mesh camera behavior remains.
-
-## Lower Modes
-
-Lower-mode proof is through specs and CLI preview:
-
-- specs inspect scene object labels, optical fields, registry order, and initial
-  model state;
-- `npm run title:preview -- --scene neon-dispersion.jedit-scene --json`
-  provides machine-readable preview facts;
-- render tests inspect terminal surface color variety.
-
-## Data / State Model
-
-| Category                  | Description                                                                 |
-| ------------------------- | --------------------------------------------------------------------------- |
-| Source of truth           | `scenes/neon-dispersion.jedit-scene` and `src/ui/stanford_dragon_res4.obj`. |
-| Derived state             | Loaded `TitleScene`, dragon `TitleMesh`, and initial `sceneOverride`.       |
-| Invalid states            | Default scene or dragon mesh missing, malformed, or unregistered.           |
-| Reset behavior            | Scene can be changed through the existing picker.                           |
-| Serialization             | `.jedit-scene` JSON copied into `dist/scenes`; OBJ copied into `dist/ui`.   |
-| Deterministic assumptions | Same scene/theme/time renders same surface.                                 |
-
-```mermaid
-flowchart LR
-  Scene[neon-dispersion.jedit-scene] --> Loader[title scene loader]
-  Loader --> Snapshot[initial model snapshot]
-  Snapshot --> Model[WorkspaceModel.sceneOverride]
-  Model --> Renderer[renderTitleScreen]
-```
-
-## Accessibility Posture
-
-| Concern                           | Posture                                     |
-| --------------------------------- | ------------------------------------------- |
-| Semantic labels or facts          | Object labels identify scene design roles.  |
-| Focus order or ownership          | Not changed.                                |
-| Hidden or visual-only information | Scene facts are test- and preview-readable. |
-| Keyboard behavior                 | Existing scene picker controls remain.      |
-| Secret or redaction behavior      | No secrets are read or emitted.             |
-
-## Localization / Directionality Posture
-
-Not applicable. No user-visible localized strings change. The scene asset name
-is a developer/reviewer artifact and scene-picker row label.
-
-## Agent Inspectability / Explainability Posture
-
-Agents can inspect:
-
-- `DEFAULT_BUILT_IN_TITLE_SCENE_NAME`;
-- registry order;
-- scene object labels;
-- optical material fields;
-- environment fields;
-- initial model `sceneOverride`;
-- render surface color variety.
-
-## Linked Invariants
-
-- Tests are executable spec.
-- Runtime truth beats type theater.
-- Design should become repo truth.
-- Theme tokens own visible styling.
-- The default experience should feel intentional without requiring manual
-  setup.
-
-## Design Alternatives Considered
-
-### Option A: Put Neon Dispersion First In The Registry Only
-
-Pros:
-
-- Very small change.
-- Scene picker and preview default to the new scene.
-
-Cons:
-
-- Production startup would still render generated/bunny scene unless the user
-  manually loads a scene.
-- Does not satisfy "default title screen scene" in the app.
-
-### Option B: Load The Authored Scene In Startup Snapshot
-
-Pros:
-
-- Makes Neon Dispersion the actual app startup scene.
-- Keeps `renderTitleScreen` unchanged by using existing `sceneOverride`.
-- Lets failures fall back before the app runtime starts.
-
-Cons:
-
-- Requires a synchronous startup scene load path or snapshot adapter change.
-- Adds another startup asset to keep valid.
-
-## Decision
-
-Choose Option B. A default title scene should be true in the production app, not
-only in scene picker order. The startup snapshot is the correct boundary because
-it already owns startup assets, meshes, theme, entries, and seed.
-
-## Implementation Slices
-
-- [x] Slice 1: File issue #101 and write this design document.
-- [x] Slice 2: Add failing tests for default scene registry/startup behavior
-      and Neon Dispersion scene facts.
-- [x] Slice 3: Add `neon-dispersion.jedit-scene` and default scene loader
-      contract.
-- [x] Slice 4: Wire startup snapshot/model camera to the default scene.
-- [x] Slice 5: Validate render/preview, create follow-on renderer debt, update
-      retrospective, and open the PR.
-- [x] Slice 6: Replace the cube/neon cluster with a solo Stanford Dragon mesh
-      and prove the built-in dragon asset path.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [x] A Neon Dispersion scene spec fails until the built-in scene exists and is
-      registered first.
-- [x] A workspace startup spec fails until production initial snapshots carry
-      the default scene override.
-- [x] A render spec fails until the scene produces varied visible color output.
-- [x] Existing title-preview shard coverage proves the scene is copied and
-      preview-loadable.
-- [x] A title mesh spec fails until `stanford_dragon_res4.obj` is copied and
-      loadable as the `dragon` mesh.
-
-Documentation and process tests:
-
-- [x] Prettier checks this design doc and scene JSON.
-
-Rule: documentation tests cannot be the only proof for implementation work.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [x] `neon-dispersion.jedit-scene` exists under `scenes/`.
-- [x] `DEFAULT_BUILT_IN_TITLE_SCENE_NAME` is `neon-dispersion.jedit-scene`.
-- [x] `BUILT_IN_TITLE_SCENE_NAMES[0]` is the default scene.
-- [x] Production startup initial model has `sceneOverride` set to Neon
-      Dispersion.
-- [x] The initial title camera uses the default scene camera.
-- [x] The scene includes a single refractive Stanford Dragon mesh on a
-      dark-stage floor.
-- [x] Stanford Dragon provenance is documented.
-- [x] Focused tests fail before implementation and pass after.
-- [x] Follow-on renderer debt is tracked.
-- [x] Issue and PR are linked correctly.
-- [ ] CI and local validation are green.
-
-## Validation Plan
-
-Commands expected before PR completion:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-neon-dispersion.spec.mjs spec/title-scene.spec.mjs spec/title-scene-loader.spec.mjs
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- title-rendering
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- workspace-ui
-npm run title:preview -- --scene neon-dispersion.jedit-scene --json --no-frame
-npm run quality
-npx --no-install prettier --check docs/design/0101-neon-dispersion-default-scene.md docs/assets/stanford-dragon.md scripts/copy-assets.mjs spec/title-scene-loader.spec.mjs spec/title-scene-neon-dispersion.spec.mjs spec/title-scene.spec.mjs src/adapters/title-bunny-mesh.ts src/adapters/title-scene-loader.ts src/adapters/workspace-initial-model-snapshot.ts src/adapters/workspace-title-meshes.ts src/app/workspace/init.ts src/app/workspace/model.ts src/ports/title-scene-loader.ts src/ui/title-mesh.ts src/ui/title-mesh-library.ts
-npx --no-install prettier --parser json --check scenes/neon-dispersion.jedit-scene
-git diff --check
-```
-
-## Playback / Witness
-
-Reviewer commands:
-
-```bash
-npm run title:preview -- --scene neon-dispersion.jedit-scene --json
-npm run title:record -- --scene neon-dispersion.jedit-scene --format text --frames 1 --width 80 --height 24
-```
-
-Interactive witness:
-
-```bash
-npm start
-```
-
-The first startup title scene should be Neon Dispersion before opening a file.
-
-## Risks
-
-Known risks:
-
-- The user prompt asks for renderer features that do not exist yet.
-- Startup should not crash if a built-in scene asset is malformed or missing.
-- A richer default scene can increase startup ray-trace cost.
-
-Mitigations:
-
-- Encode only real current renderer primitives in scene JSON.
-- Fall back to generated scene if the default built-in scene cannot load.
-- Keep object count bounded and reuse the startup performance governor.
-
-## Follow-On Debt
-
-Follow-on renderer debt is tracked in
-https://github.com/flyingrobots/jedit/issues/103.
-
-## Retrospective
-
-What changed from the design:
-
-- The production startup snapshot now loads
-  `DEFAULT_BUILT_IN_TITLE_SCENE_NAME` through a synchronous built-in scene
-  adapter path and falls back to generated scene rendering if that asset is
-  unavailable.
-- The default scene uses current renderer primitives rather than pretending to
-  have physical emissive tubes, spectral dispersion, roughness maps, torus
-  geometry, or depth of field.
-- The initial dark-room approximation used authored wall planes, but those
-  planes are infinite in the current renderer and could occlude the whole
-  camera view from some orbit angles. The landed scene removes those walls and
-  treats the scene as a dark light stage until finite or one-sided room
-  geometry exists.
-- The final product direction narrowed the authored scene to a single
-  refractive Stanford Dragon mesh on a dark reflective grid stage.
-- Named mesh constructors and mesh IDs moved into `src/ui/title-mesh-library.ts`
-  so `src/ui/title-mesh.ts` stays a generic BVH/intersection engine under the
-  500-line quality ratchet.
-
-What the tests proved:
-
-- RED:
-  `node --test --test-concurrency=1 spec/title-scene-neon-dispersion.spec.mjs`
-  failed because `neon-dispersion.jedit-scene` was unknown and startup had no
-  `sceneOverride`.
-- GREEN:
-  `npm run build && JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-neon-dispersion.spec.mjs`
-  passed.
-- Adjacent checks passed:
-  `node --test --test-concurrency=1 spec/title-scene-loader.spec.mjs spec/workspace-runtime.spec.mjs spec/title-scene-material-lab.spec.mjs`,
-  `JEDIT_DIST_PREBUILT=1 npm run ci:shard -- title-rendering`,
-  `JEDIT_DIST_PREBUILT=1 npm run ci:shard -- workspace-ui`,
-  `npm run title:preview -- --scene neon-dispersion.jedit-scene --json --no-frame`,
-  `npm run quality`, and `git diff --check`.
-- A follow-up RED/GREEN regression proved Neon Dispersion no longer collapses
-  to a flat wall/background around the camera orbit.
-- A second follow-up RED/GREEN regression proved the default scene contains one
-  `stanford-dragon` mesh object, the `dragon` mesh asset is copied into `dist/`,
-  the Stanford Dragon source asset is loadable, and the scene loader accepts
-  `dragon` as a known mesh ID while still rejecting unknown mesh IDs.
-- Final local validation passed:
-  `npm run build`,
-  `JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/title-scene-neon-dispersion.spec.mjs spec/title-scene.spec.mjs spec/title-scene-loader.spec.mjs`,
-  `JEDIT_DIST_PREBUILT=1 npm run ci:shard -- title-rendering`,
-  `JEDIT_DIST_PREBUILT=1 npm run ci:shard -- workspace-ui`,
-  `npm run title:preview -- --scene neon-dispersion.jedit-scene --json --no-frame`,
-  `npm run quality`, focused Prettier checks, scene JSON Prettier check, and
-  `git diff --check`.
-
-What remains open:
-
-- CI still needs to run on PR #102 after the implementation commit is pushed.
-- Renderer feature debt remains in issue #103.
-
-PR:
-
-- https://github.com/flyingrobots/jedit/pull/102
diff --git a/docs/design/0102-vim-command-line-completion-surface.md b/docs/design/0102-vim-command-line-completion-surface.md
deleted file mode 100644
index 81f4e659..00000000
--- a/docs/design/0102-vim-command-line-completion-surface.md
+++ /dev/null
@@ -1,721 +0,0 @@
----
-title: "WF-0102 - Vim Command-Line Completion Surface"
-legend: "WF"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/107"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-06-05"
-updated: "2026-06-06"
----
-
-# WF-0102 - Vim Command-Line Completion Surface
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/107
-
-## Decision Summary
-
-Jedit will replace one-off startup file-search surfaces with a reusable
-Vim-shaped command-line and inline completion surface. Pressing `:` in Normal
-mode enters a command input context, command and file providers supply
-completions, `:edit ` opens files through the existing production
-Echo-backed file-open path, and the inline completion popup is a Bijou-shaped
-component that Jedit can also reuse for editor completions backed by Graft
-symbols, documentation, source definitions, or causal-history previews.
-
-## Sponsored Human
-
-A person editing in Jedit wants familiar Vim command entry and rich inline file
-or symbol completion so that opening files and discovering commands feels like
-one coherent editor interaction, without switching between unrelated drawers,
-startup-only pickers, or hidden key modes.
-
-## Sponsored Agent
-
-An agent needs command, completion, preview, and provider contracts with stable
-ids so it can verify command dispatch, file suggestions, Graft-backed symbol
-suggestions, and preview posture without scraping pixels or inferring private
-focus state.
-
-## Hill
-
-By the end of this cycle, a user can press `:` in Normal mode, type `edit`,
-see inline completions anchored to the command cursor, choose a file completion
-with an optional inline preview, open that file through the production text
-session, and the repo proves the same completion component can accept a
-Graft-backed editor provider without rendering a custom second UI.
-
-## Current Truth
-
-The merge target for this cycle is `origin/main` at
-`8c1cd49914abcdcc6696fa5d6a02694283ecbc5e`.
-
-This design is also responding to active title/startup work on branch commit
-`f0880078e0a0a93f171789ebc3747a8b7e7e6ff0`.
-
-Current anchors:
-
-- Workspace key dispatch currently routes quit confirmation, hard globals, the
-  startup file selector, settings, scene picker, title keys, global keys, then
-  focused-pane keys:
-  [src/app/workspace/key-bindings.ts#L22:f0880078e0a0a93f171789ebc3747a8b7e7e6ff0](https://github.com/flyingrobots/jedit/blob/f0880078e0a0a93f171789ebc3747a8b7e7e6ff0/src/app/workspace/key-bindings.ts#L22).
-- The startup file selector currently captures intro skip, reopen, input,
-  navigation, Escape, and Enter behavior as a separate key-binding mode:
-  [src/app/workspace/startup-file-modal-key-bindings.ts#L30:f0880078e0a0a93f171789ebc3747a8b7e7e6ff0](https://github.com/flyingrobots/jedit/blob/f0880078e0a0a93f171789ebc3747a8b7e7e6ff0/src/app/workspace/startup-file-modal-key-bindings.ts#L30).
-- The startup file selector currently opens or changes directory by calling
-  `openWorkspaceFileEntry`, which already routes file opens into production
-  text authority:
-  [src/app/workspace/startup-file-modal-key-bindings.ts#L101:f0880078e0a0a93f171789ebc3747a8b7e7e6ff0](https://github.com/flyingrobots/jedit/blob/f0880078e0a0a93f171789ebc3747a8b7e7e6ff0/src/app/workspace/startup-file-modal-key-bindings.ts#L101).
-- The startup selector renderer is already a Jedit-owned surface using Bijou
-  `drawer` and `browsableListSurface`, but its contract is title/startup
-  specific:
-  [src/ui/startup-file-modal.ts#L61:f0880078e0a0a93f171789ebc3747a8b7e7e6ff0](https://github.com/flyingrobots/jedit/blob/f0880078e0a0a93f171789ebc3747a8b7e7e6ff0/src/ui/startup-file-modal.ts#L61).
-- File opening from the standard file tree already converges through
-  `openWorkspaceFileEntry` and `createWorkspaceTextOpenCmd`:
-  [src/app/workspace/file-tree.ts#L99:f0880078e0a0a93f171789ebc3747a8b7e7e6ff0](https://github.com/flyingrobots/jedit/blob/f0880078e0a0a93f171789ebc3747a8b7e7e6ff0/src/app/workspace/file-tree.ts#L99).
-- Existing `WorkspaceKeys` does not define a colon key yet:
-  [src/app/workspace/workspace-key.ts#L3:f0880078e0a0a93f171789ebc3747a8b7e7e6ff0](https://github.com/flyingrobots/jedit/blob/f0880078e0a0a93f171789ebc3747a8b7e7e6ff0/src/app/workspace/workspace-key.ts#L3).
-- Graft is already modeled as a port in workspace dependencies and can become
-  a completion content provider without making the completion renderer know
-  Graft internals:
-  [src/app/workspace/file-tree.ts#L30:f0880078e0a0a93f171789ebc3747a8b7e7e6ff0](https://github.com/flyingrobots/jedit/blob/f0880078e0a0a93f171789ebc3747a8b7e7e6ff0/src/app/workspace/file-tree.ts#L30).
-
-## Problem
-
-Jedit has multiple file-opening experiences that compete for user intent. The
-standard `ctrl+b` files drawer respects the Bijou app frame, but it does not
-offer type-to-search. The startup file selector offers type-to-search, but it is
-title-specific and duplicates file-opening interaction. Neither surface creates
-the Vim-shaped command-line interaction needed for `:edit`, `:write`, `:quit`,
-or later editor completions.
-
-The likely long-term surface is not another drawer. It is a provider-backed
-inline completion popup that can be anchored to the active text cursor or the
-command-line cursor, flip above when there is no room below, and optionally show
-an adjacent preview.
-
-## Scope
-
-This cycle includes:
-
-- A Normal-mode `:` command-line context.
-- A command registry for Vim-shaped commands and aliases.
-- A reusable Jedit-hosted, Bijou-shaped inline completion component.
-- Command completions for `edit`, `write`, `quit`, `wq`, and aliases.
-- File completions for `:edit ` from the current workspace directory.
-- Optional inline preview for the selected file completion when geometry allows.
-- A provider seam that can be exercised with a fake Graft-backed editor
-  completion provider.
-- Opening files through the existing production text session command path.
-- Footer, focus, Escape, Enter, Tab, and arrow-key behavior for command mode.
-- Narrow-terminal fallback and no-preview lower mode.
-- Documentation and technical-teardown updates for Vim command behavior.
-
-## Non-Goals
-
-This cycle does not include:
-
-- Implementing every Vim ex command.
-- Implementing insert-mode language-server completion.
-- Replacing Graft's API or changing Graft semantics.
-- Adding mouse support.
-- Adding a new recent-workspace database.
-- Moving command-line UI into Echo.
-- Moving Graft nouns into the completion renderer.
-- Removing the standard files drawer before `:edit` is proven.
-- Solving causal-history symbol previews beyond an inspectable provider
-  posture and placeholder preview type.
-
-## User Experience / Product Shape
-
-The user presses `:` while in Normal mode. The footer changes into a command
-line. As the user types, an inline completion popup appears anchored to the
-command cursor. If there is room below the cursor, suggestions appear below; if
-not, they flip above. The selected completion can show a preview beside the
-suggestion list when there is room.
-
-For `:edit`, completions are file paths. Selecting a file shows a short preview
-of its contents or a compact unavailable preview. Pressing Enter opens the file
-through the existing production Echo-backed text session path. Pressing Escape
-closes command mode and restores Normal mode without dispatching a command.
-
-The same completion popup is later reusable in an editor buffer. In that mode,
-the content provider can be Graft: suggestions may be symbols, definitions,
-documentation, source snippets, or causal-history summaries. The renderer sees
-only completion items and preview documents, not Graft internals.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[User is in Normal mode] --> Colon[User presses :]
-  Colon --> CommandLine[Footer owns command input]
-  CommandLine --> CommandSuggest[Inline command completions appear]
-  CommandSuggest --> Edit[User selects or types edit]
-  Edit --> FileSuggest[File path completions appear]
-  FileSuggest --> Preview[Selected item shows adjacent preview when space allows]
-  FileSuggest --> Enter[User presses Enter]
-  Enter --> Open[Existing production file-open command runs]
-  CommandLine --> Escape[User presses Escape]
-  Escape --> Normal[Normal mode restored without dispatch]
-```
-
-### Wide UI Mockup
-
-```text
-+------------------------------------------------------------+
-| src/app/workspace/key-bindings.ts                          |
-|                                                            |
-| 17 export function updateFromKey(...) {                    |
-| 18   return updateQuitConfirmationKey(...)                 |
-| 19     ?? updateHardGlobalWorkspaceKey(...)                |
-|                                                            |
-| :edit src/app/workspace/ke                                 |
-|       key-bindings.ts       F  src/app/workspace/...       |
-|       key-binding-context.ts F  import type { ...          |
-|       workspace-key.ts       F  export const WorkspaceKeys |
-+------------------------------------------------------------+
-```
-
-The popup is inline and cursor-anchored. It is not a side panel and not the
-files drawer. The preview floats beside the selected completion only when the
-terminal has enough room.
-
-### Narrow UI Mockup
-
-```text
-+--------------------------------+
-| :edit src/app/workspace/ke     |
-| key-bindings.ts       F        |
-| key-binding-context.ts F       |
-| workspace-key.ts      F        |
-+--------------------------------+
-```
-
-The narrow view suppresses the preview and keeps the suggestion list clipped to
-available width. If there is no room below the command line, the list flips
-above it.
-
-### Accessibility Considerations
-
-Command mode is keyboard-only. The focused completion, item count, selected
-index, provider id, preview availability, and command dispatch posture are
-model facts that agents can inspect. The preview is redundant to item labels
-and never required to execute the command.
-
-## Runtime / API Contract
-
-Contract: command-line mode, inline completion, and provider-backed preview.
-
-Relevant exported shapes:
-
-- `WorkspaceCommandLineState`
-  - mode: closed or active;
-  - input text;
-  - cursor index;
-  - selected completion index;
-  - provider id;
-  - optional dispatch posture.
-- `WorkspaceCommandDescriptor`
-  - stable command id;
-  - canonical name;
-  - aliases;
-  - argument posture;
-  - dispatch function.
-- `InlineCompletionItem`
-  - stable id;
-  - label;
-  - detail;
-  - kind;
-  - replacement range in the active input surface;
-  - provider id;
-  - optional preview request.
-- `InlineCompletionPreview`
-  - preview kind: file, documentation, source definition, causal history, or
-    unavailable;
-  - stable title;
-  - bounded lines;
-  - evidence posture when provided by Echo or Graft.
-- `InlineCompletionProvider`
-  - receives input context, cursor coordinate, workspace facts, and budget;
-  - returns deterministic items and optional preview data;
-  - does not render UI.
-- `renderInlineCompletionPopup`
-  - receives theme tokens, geometry, items, selected index, command cursor
-    coordinate, and optional preview;
-  - returns a Bijou `Surface`;
-  - owns flipping and clipping behavior.
-
-Behavior:
-
-- `:` in Normal mode opens command mode when no higher-priority modal or drawer
-  owns focus.
-- Escape exits command mode and dispatches nothing.
-- Enter dispatches the parsed command when valid.
-- Tab accepts the focused completion when completions exist.
-- Arrow keys move the focused completion while command mode owns input.
-- `:edit ` resolves through the file provider and then calls the existing
-  production open path.
-- `:q`, `:quit`, `:w`, `:write`, `:wq`, and `:q!` map to existing quit/save
-  postures where those postures are already available.
-- Editor-mode providers may use Graft, but the renderer consumes only the
-  provider-neutral completion and preview contracts.
-
-## Lower Modes
-
-| Concern                       | Posture                                                                                           |
-| ----------------------------- | ------------------------------------------------------------------------------------------------- |
-| Small terminal                | Completion list clips to available rows; preview is omitted first.                                |
-| No color                      | Labels, kind glyphs, and selected index remain readable without color.                            |
-| Keyboard-only                 | All interactions are keyboard-owned.                                                              |
-| Pipe or fixture output        | Completion providers expose deterministic items for focused tests.                                |
-| Optional adapters unavailable | Graft-backed providers return unavailable preview posture; command and file providers still work. |
-| Echo or file evidence partial | File preview may be unavailable; file open still uses the production obstruction path.            |
-
-## Data / State Model
-
-| Category                  | Description                                                                                                                |
-| ------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
-| Source of truth           | Command-line state in `WorkspaceModel`; provider responses are derived.                                                    |
-| Derived state             | Parsed command, active provider, completion list, selected item, popup geometry, preview content.                          |
-| Invalid states            | Command mode active while a higher-priority modal owns focus; dispatching invalid commands; preview required for dispatch. |
-| Reset behavior            | Escape closes command mode; successful command dispatch closes command mode unless command opts to remain open.            |
-| Serialization             | No serialized state in this cycle.                                                                                         |
-| Deterministic assumptions | Providers receive explicit context and budget; render geometry is pure over width, height, cursor coordinate, and theme.   |
-
-```mermaid
-stateDiagram-v2
-  [*] --> Normal
-  Normal --> CommandLine: ":"
-  CommandLine --> Completing: provider returns items
-  Completing --> CommandLine: input changes
-  Completing --> Dispatching: Enter
-  CommandLine --> Normal: Escape
-  Dispatching --> Normal: success or obstruction
-```
-
-## Accessibility Posture
-
-| Concern                           | Posture                                                                                            |
-| --------------------------------- | -------------------------------------------------------------------------------------------------- |
-| Semantic labels or facts          | Command input, provider id, selected completion, item count, and preview kind are model facts.     |
-| Focus order or ownership          | Command line owns focus while active; completion popup follows that focus.                         |
-| Hidden or visual-only information | Preview content is optional and reflected by preview availability facts.                           |
-| Keyboard behavior                 | `:`, Escape, Enter, Tab, arrows, Backspace, and printable keys are covered by tests.               |
-| Secret or redaction behavior      | Providers must redact or omit previews through preview posture, not through renderer conditionals. |
-
-## Localization / Directionality Posture
-
-This cycle adds user-visible strings for command names, command descriptions,
-completion unavailable messages, and preview titles.
-
-| Concern                    | Posture                                                                                                                   |
-| -------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
-| User-visible strings       | Command descriptions, preview headings, invalid-command messages.                                                         |
-| Catalog keys               | Add under command-line and inline-completion namespaces.                                                                  |
-| Supported locales updated  | Existing generated locales must remain complete.                                                                          |
-| Directionality assumptions | Popup opens to the right in LTR and to the left in RTL when preview geometry permits; list text follows locale direction. |
-| Validation command         | `npm run quality` and focused i18n completeness checks that exist at implementation time.                                 |
-
-## Agent Inspectability / Explainability Posture
-
-Agents can inspect:
-
-- stable command ids and aliases;
-- command-line state in the workspace model;
-- provider ids and completion item ids;
-- selected completion index and replacement range;
-- preview kind and evidence posture;
-- rendered `Surface` geometry for above/below and preview left/right decisions;
-- file-open command dispatch through the production text session witness.
-
-## Linked Invariants
-
-- Tests are executable spec.
-- Runtime truth beats type theater.
-- Design should become repo truth.
-- Buffers, panes, panels, and lenses are different things.
-- Files and previews are projections.
-- Echo authority remains outside jedit product nouns.
-- UI surfaces are Bijou-shaped components, even when they live in Jedit.
-- Providers supply content; components render content; command dispatch changes
-  state.
-
-## Design Alternatives Considered
-
-### Option A: Improve Both Drawers
-
-Pros:
-
-- Lowest migration cost from current UI.
-- Keeps `ctrl+b` and startup selector behavior familiar.
-
-Cons:
-
-- Preserves duplicate file-opening concepts.
-- Does not create Vim command mode.
-- Does not solve editor autocomplete reuse.
-- Makes future Graft completion likely to become a third UI.
-
-### Option B: Standard Files Drawer With Search
-
-Pros:
-
-- Reuses the standard app frame.
-- Good for broad browsing and directory navigation.
-
-Cons:
-
-- Still panel-oriented rather than command-oriented.
-- Does not match `:edit` or Vim command flow.
-- Popup completion for editor symbols would still need another component.
-
-### Option C: Reusable Inline Completion For Command And Editor Contexts
-
-Pros:
-
-- Matches Vim command-line flow.
-- Creates one reusable completion component.
-- Lets file, command, Graft, source, documentation, and causal-history
-  providers share a UI contract.
-- Keeps content providers separate from rendering.
-
-Cons:
-
-- Requires a real command-line state machine.
-- Requires careful geometry tests.
-- Startup browser retirement needs a phased migration.
-
-## Decision
-
-Choose Option C.
-
-Jedit will build a reusable inline completion component and provider contract
-first, then use it for `:` command mode and `:edit`. The standard files drawer
-remains for browse-mode file navigation until command-line file opening is
-proven. The startup file selector becomes temporary transition UI and should be
-removed or reduced to a command-line entry path after the command surface lands.
-
-## Goalposts And Slices
-
-### Goalpost 1: Command-Line Spine
-
-Outcome:
-
-Normal mode has a real command-line context with deterministic focus, input,
-cancel, and dispatch posture.
-
-Witnesses:
-
-- focused key-binding spec for `:` entering command mode;
-- focused key-binding spec for printable input, Backspace, Escape, and Enter;
-- model-state spec proving command mode loses to higher-priority modals.
-
-Slices:
-
-- [x] Slice 1: Add `WorkspaceKeys.Colon` and command-line state.
-      Commit: `UX: add command-line workspace state`.
-- [x] Slice 2: Add command-line key-binding priority and Escape cancel.
-      Commit: `UX: enter and cancel command mode`.
-- [x] Slice 3: Add command input editing and cursor movement.
-      Commit: `UX: edit command-line input`.
-- [x] Slice 4: Add command parser and invalid-command obstruction.
-      Commit: `UX: parse command-line commands`.
-
-### Goalpost 2: Bijou Inline Completion Component
-
-Outcome:
-
-A reusable Jedit-hosted component renders inline suggestions and optional
-preview as a Bijou-shaped surface, with geometry tests for below, above,
-preview right, preview left, and narrow no-preview modes.
-
-Witnesses:
-
-- pure render spec for below-cursor placement;
-- pure render spec for above-cursor flip;
-- pure render spec for adjacent preview placement;
-- pure render spec proving theme-token use and no ad hoc colors.
-
-Slices:
-
-- [x] Slice 5: Define provider-neutral completion item and preview types.
-      Commit: `UI: define inline completion contracts`.
-- [x] Slice 6: Render completion list as a Bijou-shaped component.
-      Commit: `UI: render inline completion list`.
-- [x] Slice 7: Add preview pane geometry and narrow fallback.
-      Commit: `UI: add inline completion preview`.
-- [x] Slice 8: Integrate completion popup into workspace overlays.
-      Commit: `UI: show command-line completions`.
-
-### Goalpost 3: Command And File Providers
-
-Outcome:
-
-Command mode offers command completions and `:edit ` offers file
-completions with optional preview. Dispatch opens files through existing
-production text authority.
-
-Witnesses:
-
-- provider spec for command names and aliases;
-- provider spec for file path filtering and directory/file labels;
-- file-preview spec with bounded lines and unavailable posture;
-- integration spec proving `:edit ` calls production open.
-
-Slices:
-
-- [x] Slice 9: Add command registry and command completion provider.
-      Commit: `UX: complete command names`.
-- [x] Slice 10: Add file completion provider for `:edit`.
-      Commit: `UX: complete edit paths`.
-- [x] Slice 11: Add bounded file preview provider.
-      Commit: `UX: preview edit path completions`.
-- [x] Slice 12: Dispatch `:edit`, `:write`, `:quit`, `:wq`, and aliases.
-      Commit: `UX: dispatch vim command-line commands`.
-
-### Goalpost 4: Graft-Backed Editor Provider Seam
-
-Outcome:
-
-The same completion component can render an editor-context provider result.
-Graft is the content provider for symbols, docs, definitions, or causal-history
-preview posture, but the renderer remains provider-neutral.
-
-Witnesses:
-
-- fake Graft provider spec proving symbol/docs/source/history preview shapes;
-- render spec proving editor-context items use the same popup component;
-- adapter-unavailable spec proving no crash and honest preview posture.
-
-Slices:
-
-- [x] Slice 13: Add editor completion context and provider registry seam.
-      Commit: `UX: add editor completion provider seam`.
-- [x] Slice 14: Add fake Graft symbol provider witness.
-      Commit: `UX: witness graft completion provider`.
-- [x] Slice 15: Render documentation, source-definition, and causal-history
-      preview kinds through the same component.
-      Commit: `UI: render completion preview kinds`.
-- [x] Slice 16: Add unavailable-adapter lower-mode posture.
-      Commit: `UX: handle unavailable completion providers`.
-
-### Goalpost 5: Surface Consolidation
-
-Outcome:
-
-Overlapping startup/file-browser behavior is reduced. Command-line file open is
-the primary type-to-open surface, and the technical teardown explains Vim
-controls and completion reuse.
-
-Witnesses:
-
-- regression spec proving `ctrl+b` remains the standard files drawer;
-- regression spec proving startup flow does not own a second type-to-search
-  browser after command-line open is available;
-- documentation spec or focused text assertion for the teardown updates.
-
-Slices:
-
-- [x] Slice 17: Route startup post-intro open affordance toward command mode or
-      the standard files drawer.
-      Commit: `UX: consolidate startup file opening`.
-- [x] Slice 18: Remove duplicate startup type-to-search code that command mode
-      replaces.
-      Commit: `UX: retire duplicate startup search`.
-- [x] Slice 19: Update footer hints and localized command copy.
-      Commit: `Docs: update command-line copy`.
-- [x] Slice 20: Update technical teardown, retrospective, and playback witness.
-      Commit: `Docs: document vim command completion`.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [x] `:` in Normal mode enters command-line mode and owns focus.
-- [x] Escape cancels command mode without dispatching.
-- [x] Printable input, Backspace, selected completion movement, and Tab accept
-      behave deterministically.
-- [x] Inline completion popup flips above when the command line is near the
-      bottom of the terminal.
-- [x] Inline completion preview is omitted on narrow terminals.
-- [x] `:edit ` opens through `createWorkspaceTextOpenCmd`.
-- [x] Invalid commands produce an obstruction or toast without mutating editor
-      state.
-- [x] A fake Graft provider can render symbol documentation/source/history
-      previews through the same component.
-
-Documentation and process tests:
-
-- [x] Technical teardown explains command-line mode, `:edit`, `:write`, `:quit`,
-      and provider-backed completion reuse.
-- [x] Design retrospective records which startup/browser surfaces remain.
-
-Rule: documentation tests cannot be the only proof for implementation work.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [x] Behavior tests prove command-line state, input, completion, preview, and
-      dispatch.
-- [x] Render tests prove inline popup geometry and theme-token posture.
-- [x] `:edit ` opens a file through production text authority.
-- [x] `:write`, `:quit`, `:wq`, and aliases use existing save/quit postures.
-- [x] The same popup component renders fake Graft-backed editor completions.
-- [x] Lower modes cover small terminals and unavailable providers.
-- [x] New strings have supported translations or tracked localization follow-up
-      if the CSV localization migration lands first.
-- [x] Docs and technical teardown are updated.
-- [x] Issue and PR are linked correctly.
-- [x] CI and local validation are green.
-
-## Validation Plan
-
-Commands expected before PR:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test spec/workspace-command-line.spec.mjs
-JEDIT_DIST_PREBUILT=1 node --test spec/inline-completion-popup.spec.mjs
-JEDIT_DIST_PREBUILT=1 node --test spec/workspace-command-completion.spec.mjs
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- workspace-ui
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- misc-fast
-npm run quality
-git diff --check
-```
-
-Trim commands that do not apply after the final slice plan lands.
-
-## Playback / Witness
-
-Manual playback:
-
-```bash
-npm run build
-npm run jedit
-```
-
-Then:
-
-- open Jedit into an editor buffer;
-- press `:`;
-- type `edit src/app/workspace/`;
-- use arrows to select a file completion;
-- verify the inline list appears above the command line when needed;
-- verify preview appears only when terminal width allows;
-- press Enter and confirm the selected file opens;
-- press `:` again, type `q`, and confirm quit behavior follows the normal quit
-  confirmation posture unless a force command explicitly bypasses it.
-
-Editor-provider playback after Goalpost 4:
-
-- open a source file;
-- invoke the editor completion key chosen during implementation;
-- verify fake or real Graft provider items render through the same inline popup;
-- verify selected symbol previews can show documentation, source definition, or
-  causal-history posture without a separate panel implementation.
-
-Automated closeout playback:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test \
-  spec/workspace-command-line.spec.mjs \
-  spec/workspace-command-completion.spec.mjs \
-  spec/inline-completion-popup.spec.mjs \
-  spec/workspace-title-screen.spec.mjs \
-  spec/wf-0102-docs-closeout.spec.mjs
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- workspace-ui
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- docs-release
-npm run quality
-git diff --check
-```
-
-This playback proves the command line can be entered from a file buffer and the
-title screen, accepts Enter and Tab completion, preserves the original command
-anchor while typing, dispatches file opens through production text authority,
-renders invalid command feedback, keeps Graft-backed provider preview reuse, and
-records the teardown/retrospective closeout text.
-
-## Risks
-
-Known risks:
-
-- Command-line mode can accidentally preempt higher-priority modal or drawer
-  keys.
-- Inline popup geometry can become brittle across small terminals and RTL
-  locales.
-- File preview can block input if it reads too much synchronously.
-- Reusing the popup for Graft-backed editor completions can tempt provider
-  details into UI code.
-- Retiring startup search too early can make no-file startup less useful.
-
-Mitigations:
-
-- Key-binding priority gets focused tests before rendering work.
-- Geometry is pure and covered by render fixtures.
-- Preview providers are budgeted and bounded.
-- Provider-neutral contracts keep renderer independent.
-- Startup consolidation waits until `:edit` is proven with executable tests.
-
-## Follow-On Debt
-
-Create GitHub issues for anything deferred:
-
-- Full insert-mode language completion.
-- Real Graft symbol/documentation provider.
-- Real causal-history symbol preview.
-- CSV localization migration if command-line strings land before issue #53.
-- Fuzzy path scoring if simple prefix and substring matching is not enough.
-
-## Retrospective
-
-What changed from the design:
-
-- The popup component stayed provider-neutral, but the implementation needed a
-  stricter command-line validation path so `:exi`-style fragments show live
-  feedback instead of only failing after Enter.
-- Enter now accepts the selected completion before dispatching, matching the Tab
-  acceptance path.
-- Command completions pin to the command line's original anchor instead of
-  moving as the user types.
-- `:edit` acceptance inserts a trailing space and immediately repopulates with
-  file completions.
-- The startup file selector remains available as a title/current-directory
-  affordance, but its duplicate type-to-search input was retired. The standard
-  `ctrl+b` files drawer remains the explicit browsable file surface.
-- Graft-backed editor completion work landed as a fake-provider proof and
-  unavailable-adapter lower mode, not a full language-completion feature.
-
-What the tests proved:
-
-- Command mode owns `:`, printable input, Escape, arrows, Tab, Enter, space
-  insertion, invalid command feedback, and title-screen entry.
-- `:edit ` opens through the existing production text open command path,
-  and `:write`, `:quit`, and `:wq` reuse existing save/quit postures.
-- The inline completion popup flips above the command line, pins to the opening
-  anchor, omits previews on narrow terminals, and renders command, file,
-  directory, documentation, source-definition, causal-history, and unavailable
-  preview postures.
-- The startup selector no longer owns printable type-to-search input.
-- Documentation closeout is covered by a docs-release spec that asserts the
-  technical teardown and this retrospective name the final command/file surfaces.
-
-What remains open:
-
-- Real Graft language completion and causal-history preview providers remain
-  follow-on work.
-- The startup drawer can be removed or redesigned later, but it no longer
-  competes with command-line type-to-open behavior.
-- Path completion uses bounded, pragmatic fuzzy matching; richer scoring belongs
-  in a future slice if users need it.
-- `:help` copy is referenced by invalid-command guidance but does not yet open a
-  command-help surface.
-
-PR:
-
-- PR #111: https://github.com/flyingrobots/jedit/pull/111
diff --git a/docs/design/0103-title-braille-dither-modes.md b/docs/design/0103-title-braille-dither-modes.md
deleted file mode 100644
index 401bd4be..00000000
--- a/docs/design/0103-title-braille-dither-modes.md
+++ /dev/null
@@ -1,408 +0,0 @@
----
-title: "WF-0103 - Title Braille Dither Modes"
-legend: "WF"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/108"
-status: "draft"
-owners:
-  - "@flyingrobots"
-created: "2026-06-05"
-updated: "2026-06-05"
----
-
-# WF-0103 - Title Braille Dither Modes
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/108
-
-## Decision Summary
-
-The title-screen Braille renderer should gain optional renderer-native dither
-modes over its resolved Braille subpixel luminance field. The dither boundary
-belongs in the Bijou/jedit surface renderer, not in a browser canvas, DOM image
-pipeline, title scene object model, or Echo text authority path.
-
-## Sponsored Human
-
-A jedit user wants the animated title scene to show smoother tone, shadows, and
-soft gradients so that the ray-traced scene reads as intentional terminal art,
-without having to switch to ASCII mode or tolerate harsh thresholded Braille
-dots.
-
-## Sponsored Agent
-
-An agent needs a deterministic renderer option and visual witness surface so it
-can compare dither modes, capture render facts, and detect regressions, without
-inferring visual quality from screenshots alone.
-
-## Hill
-
-By the end of this cycle, a reviewer can choose a title Braille dither mode
-through a typed renderer option, render the title scene through the existing
-Bijou surface path, and the repo proves the behavior with focused renderer
-tests, visual witness fixture updates, and title-rendering shard coverage.
-
-## Current Truth
-
-The Braille title renderer is a pure Bijou surface renderer. Its shader returns
-`BrailleShaderSample` values with `on`, `fgRGB`, `bgRGB`, optional ray stats,
-and optional modifiers
-([src/ui/averaging-braille-canvas.ts#11:8c1cd49914abcdcc6696fa5d6a02694283ecbc5e](https://github.com/flyingrobots/jedit/blob/8c1cd49914abcdcc6696fa5d6a02694283ecbc5e/src/ui/averaging-braille-canvas.ts#L11)).
-
-Each terminal cell is resolved from eight Braille subpixels, arranged as two
-columns by four rows
-([src/ui/averaging-braille-canvas.ts#79:8c1cd49914abcdcc6696fa5d6a02694283ecbc5e](https://github.com/flyingrobots/jedit/blob/8c1cd49914abcdcc6696fa5d6a02694283ecbc5e/src/ui/averaging-braille-canvas.ts#L79)).
-`collapseBrailleCell` currently packs those subpixel booleans directly into a
-Unicode Braille code point and averages foreground/background RGB values
-([src/ui/averaging-braille-canvas.ts#181:8c1cd49914abcdcc6696fa5d6a02694283ecbc5e](https://github.com/flyingrobots/jedit/blob/8c1cd49914abcdcc6696fa5d6a02694283ecbc5e/src/ui/averaging-braille-canvas.ts#L181)).
-
-The Braille path already has temporal sampling support. `BrailleSampleCache`
-retains resolved subpixel samples, and `BrailleTraceBudget` controls whether a
-frame traces all dots or reuses prior samples
-([src/ui/averaging-braille-canvas.ts#24:8c1cd49914abcdcc6696fa5d6a02694283ecbc5e](https://github.com/flyingrobots/jedit/blob/8c1cd49914abcdcc6696fa5d6a02694283ecbc5e/src/ui/averaging-braille-canvas.ts#L24)).
-
-The ASCII title renderer already has a small ordered dither option for one ASCII
-palette using a 4x4 Bayer matrix
-([src/ui/averaging-ascii-canvas.ts#65:8c1cd49914abcdcc6696fa5d6a02694283ecbc5e](https://github.com/flyingrobots/jedit/blob/8c1cd49914abcdcc6696fa5d6a02694283ecbc5e/src/ui/averaging-ascii-canvas.ts#L65)).
-That implementation proves the repo already accepts deterministic renderer-side
-dithering, but it is ASCII-specific and maps averaged luminance to ramp
-characters rather than packing Braille dots.
-
-## Problem
-
-The title Braille renderer currently treats each subpixel as an already-binary
-dot. That keeps the renderer simple, but it makes soft ray-traced effects look
-coarse: caustics, soft shadows, low-contrast material transitions, and floor
-gradients can collapse into abrupt on/off texture. A direct image-processing
-port of browser canvas dithering would sit at the wrong boundary because jedit's
-renderer works from shader samples and Bijou cells, not DOM image pixels.
-
-## Scope
-
-This cycle includes:
-
-- Adding a typed title Braille dither mode contract.
-- Adding a pure renderer dither module for threshold, ordered Bayer 4x4, and
-  Atkinson.
-- Applying dither over the full Braille subpixel plane before 2x4 cell packing.
-- Preserving existing foreground/background RGB averaging, modifiers, ray stats,
-  temporal cache behavior, and adaptive trace budgets.
-- Adding focused renderer tests and title-scene visual witness updates.
-
-## Non-Goals
-
-This cycle does not include:
-
-- Browser canvas, DOM, `ImageData`, or HTML image ingestion.
-- Dithering the editor text buffer, file browser, Graft drawer, footer, or
-  normal UI components.
-- Making dithering an Echo event or Echo-owned setting.
-- Replacing the ASCII renderer's existing palette system.
-- Optimizing mesh traversal, BVH, title scene materials, or camera movement.
-- Interrupting the active Vim command-line completion plan.
-
-## User Experience / Product Shape
-
-The title screen remains a live ray-traced terminal scene. A dither mode changes
-only how resolved Braille dots represent fractional tone. The user should see
-smoother gradients and less harsh thresholding without losing the cell color
-styling that makes neon lighting and material tint visible.
-
-The first implementation should not add a new default keybinding. Dither modes
-should be renderer options and preview-session controls first. A later cycle may
-decide whether title-screen keys, scene metadata, or settings expose the mode.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[Reviewer opens title scene preview] --> Mode[Reviewer selects a dither mode]
-  Mode --> Render[Renderer resolves title scene to Bijou surface]
-  Render --> Compare[Reviewer compares deterministic output]
-  Compare --> Accept[Visual witness and tests prove stable behavior]
-  Compare --> Reject[Reviewer selects another mode or disables dithering]
-```
-
-### Wide UI Mockup
-
-Not applicable for this draft. The work changes the rendering algorithm for an
-existing full-screen title scene rather than adding a new layout surface.
-
-### Narrow UI Mockup
-
-Not applicable for this draft. Narrow terminal behavior should use the same
-renderer contract and should be covered by existing title-rendering tests if the
-mode becomes user-selectable.
-
-### Accessibility Considerations
-
-Dithering must not be the only source of state. If the selected mode becomes
-user-visible later, it needs a text label in preview output, footer/status copy,
-or deterministic JSON facts. The rendered Braille texture itself is visual-only.
-
-## Runtime / API Contract
-
-Contract: `TitleBrailleDitherMode`.
-
-Relevant exported surface:
-
-- `BRAILLE_DITHER_MODE.None`
-- `BRAILLE_DITHER_MODE.Threshold`
-- `BRAILLE_DITHER_MODE.OrderedBayer4`
-- `BRAILLE_DITHER_MODE.Atkinson`
-- `ditherBrailleSubpixels(input)`
-- `AveragingBrailleCanvasOptions.ditherMode`
-
-Expected behavior:
-
-- `None` preserves the current `sample.on` packing behavior.
-- `Threshold` converts scalar luminance or coverage to binary dots with a fixed
-  threshold.
-- `OrderedBayer4` applies a deterministic 4x4 ordered matrix across the full
-  Braille subpixel plane.
-- `Atkinson` applies error diffusion across the full Braille subpixel plane,
-  including across terminal-cell boundaries.
-- Unknown external mode names are rejected at adapter boundaries, not accepted
-  into renderer core.
-
-The title screen may later thread this mode through preview controls, scene
-metadata, or settings, but the first implementation should prove the renderer
-contract before product controls are added.
-
-## Lower Modes
-
-- Terminal size constraints: dither operates over `cols * 2` by `rows * 4`
-  subpixels and must handle zero or negative dimensions by returning the current
-  empty surface behavior.
-- No-color output: dither changes dot on/off decisions only; it must not require
-  color support.
-- JSON/fixture output: title preview/profile/record commands should expose the
-  selected mode once wired into those tools.
-- Keyboard-only operation: no required change in the first renderer slice.
-- Partial adapters: if preview controls are not available, the renderer default
-  remains `None`.
-
-## Data / State Model
-
-| Category                  | Description                                                                   |
-| ------------------------- | ----------------------------------------------------------------------------- |
-| Source of truth           | Renderer option passed into `averagingBrailleCanvas`.                         |
-| Derived state             | Full-frame scalar subpixel plane and binary dithered dot plane.               |
-| Invalid states            | Unknown dither mode, mismatched plane dimensions, non-finite scalar values.   |
-| Reset behavior            | Dither work is per frame; no persistent renderer state is required.           |
-| Serialization             | Optional future preview/profile facts may serialize the selected mode string. |
-| Deterministic assumptions | Same shader samples, dimensions, time, and mode produce the same surface.     |
-
-```mermaid
-flowchart LR
-  Samples[Resolved shader samples] --> Scalars[Subpixel scalar plane]
-  Scalars --> Dither[Dither mode]
-  Dither --> Dots[Binary dot plane]
-  Dots --> Pack[2x4 Braille packing]
-  Samples --> Style[RGB and modifier averaging]
-  Pack --> Surface[Bijou surface cell]
-  Style --> Surface
-```
-
-## Accessibility Posture
-
-| Concern                           | Posture                                                                 |
-| --------------------------------- | ----------------------------------------------------------------------- |
-| Semantic labels or facts          | Future preview/profile output should name the selected dither mode.     |
-| Focus order or ownership          | No focus changes in the renderer-only slice.                            |
-| Hidden or visual-only information | Dither texture remains visual-only and must not encode state by itself. |
-| Keyboard behavior                 | No new keybinding in the first implementation.                          |
-| Secret or redaction behavior      | Not applicable.                                                         |
-
-## Localization / Directionality Posture
-
-Not applicable for the renderer-only slice. If later controls expose mode names
-to users, those strings must follow the repo's localization path and remain
-direction-neutral. Error diffusion scan order should be deterministic and should
-not depend on locale direction unless a later product decision explicitly
-requires direction-aware visual texture.
-
-## Agent Inspectability / Explainability Posture
-
-An agent should be able to inspect dither behavior without scraping screenshots:
-
-- stable mode ids;
-- deterministic title preview JSON fields;
-- renderer tests over small scalar fixtures;
-- visual witness fixture names that include the mode;
-- profile facts that report dither mode when enabled.
-
-## Linked Invariants
-
-- Tests are executable spec.
-- Runtime truth beats type theater.
-- Design should become repo truth.
-- Layout owns interaction geometry.
-- Files and previews are projections.
-- Echo authority remains outside jedit product nouns.
-
-## Design Alternatives Considered
-
-### Option A: Browser Canvas Port
-
-Pros:
-
-- Existing examples and kernels can be copied mechanically.
-- Easy to reason about if the input is already image-like.
-
-Cons:
-
-- Wrong runtime boundary for jedit.
-- Pulls DOM and `ImageData` assumptions into a terminal renderer.
-- Loses jedit's shader sample facts, ray stats, modifiers, and Bijou cell model.
-
-### Option B: Per-Cell Error Diffusion
-
-Pros:
-
-- Simple to fit into the current `collapseBrailleCell` function.
-- Low memory overhead.
-
-Cons:
-
-- Produces 2x4-cell artifacts.
-- Prevents error diffusion from crossing cell boundaries.
-- Makes Atkinson/Floyd-Steinberg/Stucki behave unlike their intended kernels.
-
-### Option C: Full Subpixel Plane Dither
-
-Pros:
-
-- Keeps the renderer native to Bijou/jedit.
-- Preserves existing cell style averaging.
-- Allows ordered and error-diffusion algorithms to behave across cell
-  boundaries.
-- Provides a clean contract for future preview controls.
-
-Cons:
-
-- Requires a frame-local scalar plane before cell packing.
-- Needs careful interaction with temporal sample reuse to avoid shimmer.
-
-## Decision
-
-Choose Option C. Implement dither as a pure renderer stage over the full Braille
-subpixel plane. Start with `None`, `Threshold`, `OrderedBayer4`, and `Atkinson`.
-Keep Floyd-Steinberg and Stucki out of the first implementation unless the
-initial tests show Atkinson is insufficient.
-
-## Implementation Slices
-
-- [ ] Slice 1: Add `TitleBrailleDitherMode` and scalar-plane fixture tests.
-      Commit: `Render: add Braille dither mode contract`.
-- [ ] Slice 2: Implement threshold and ordered Bayer over the full subpixel
-      plane. Commit: `Render: add ordered Braille dithering`.
-- [ ] Slice 3: Implement Atkinson error diffusion across cell boundaries.
-      Commit: `Render: add Atkinson Braille dithering`.
-- [ ] Slice 4: Thread mode through title preview/profile/record lower modes
-      without adding title-screen keybindings. Commit: `Tools: expose title
-Braille dither facts`.
-- [ ] Slice 5: Update visual witnesses and decide whether any mode should
-      become the title default. Commit: `Test: witness title Braille dithering`.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [ ] Renderer fixture proving `None` preserves current Braille output.
-- [ ] Renderer fixture proving ordered Bayer is deterministic for a gradient.
-- [ ] Renderer fixture proving Atkinson diffuses across terminal-cell
-      boundaries.
-- [ ] Renderer fixture proving dither does not change averaged foreground and
-      background RGB styling.
-- [ ] Temporal-cache fixture proving repeated cached sample fields produce
-      deterministic dithered output.
-
-Documentation and process tests, only if relevant:
-
-- [ ] Existing design-cycle policy test continues to recognize the design doc.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [ ] Behavior tests prove each implemented mode.
-- [ ] Rendered output proves the title scene can use the selected mode.
-- [ ] Lower-mode preview/profile/record facts report the selected mode, if
-      wired.
-- [ ] No new user-visible strings are added without localization coverage.
-- [ ] Visual witnesses are updated only after the behavior tests pass.
-- [ ] Issue and PR are linked correctly.
-- [ ] CI and local validation are green.
-
-## Validation Plan
-
-Commands expected before PR:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/averaging-braille-dither.spec.mjs
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- title-rendering
-npm run quality
-git diff --check
-```
-
-## Playback / Witness
-
-Reviewer playback should include one deterministic CLI or fixture path, for
-example:
-
-```bash
-npm run title:preview -- --scene neon-dispersion.jedit-scene --render braille --dither ordered-bayer-4 --json
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/averaging-braille-dither.spec.mjs
-```
-
-If a visual witness is updated, include terminal size, theme, scene, camera
-radius, dither mode, and time in the fixture name or metadata.
-
-## Risks
-
-Known risks:
-
-- Error diffusion may shimmer during camera motion.
-- Full-plane dithering may allocate more than the current direct cell path.
-- Dithered dots may fight temporal phase reuse when the renderer traces only a
-  subset of Braille samples.
-- Better tone can hide actual ray-tracing regressions if witnesses become too
-  forgiving.
-
-Mitigations:
-
-- Keep `None` as a stable baseline.
-- Prefer ordered Bayer for animated default behavior.
-- Test temporal-cache determinism explicitly.
-- Keep visual witness thresholds strict and fixture-specific.
-
-## Follow-On Debt
-
-- Decide later whether Floyd-Steinberg and Stucki should be implemented.
-- Decide later whether a keybinding, scene metadata field, or settings row
-  should expose the mode in the live title screen.
-- Decide later whether dither mode belongs in profile/perf overlay facts.
-
-## Retrospective
-
-What changed from the design:
-
-- Draft only. Implementation has not started.
-
-What the tests proved:
-
-- No product/runtime tests yet. This document defines the future executable
-  witnesses.
-
-What remains open:
-
-- All implementation slices remain open.
-- Vim command-line completion remains the active priority after this parking
-  document.
-
-PR:
-
-- Not opened for this deferred idea.
diff --git a/docs/design/0104-title-zero-allocation-ray-tracing.md b/docs/design/0104-title-zero-allocation-ray-tracing.md
deleted file mode 100644
index def66928..00000000
--- a/docs/design/0104-title-zero-allocation-ray-tracing.md
+++ /dev/null
@@ -1,530 +0,0 @@
----
-title: "WF-0104 - Title Zero Allocation Ray Tracing"
-legend: "WF"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/112"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-06-06"
-updated: "2026-06-06"
----
-
-# WF-0104 - Title Zero Allocation Ray Tracing
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/112
-
-## Decision Summary
-
-Jedit should make the live title-screen ray tracer allocate zero ordinary
-JavaScript objects in the per-frame ray hot path after warmup.
-
-The existing title performance work reduced how often expensive samples are
-traced. This cycle targets a different failure mode: V8 nursery exhaustion from
-thousands of short-lived vectors, colors, hit objects, shader parameter objects,
-and cell accumulators created inside the render loop.
-
-The target is not merely lower memory use. The target is a renderer contract:
-after scratch storage, mesh traversal state, sample cache, and output surfaces
-are prepared, tracing a Braille frame should mutate preallocated state rather
-than creating new object graphs for each ray.
-
-## Sponsored Human
-
-A jedit user wants the animated bunny title scene to remain smooth and
-responsive so that startup feels like a polished terminal application, without
-periodic freezes caused by garbage collection.
-
-## Sponsored Agent
-
-An agent needs inspectable allocation and render facts so it can distinguish
-between reduced ray-tracing frequency and true hot-loop allocation elimination,
-without relying on subjective animation smoothness or one-off heap snapshots.
-
-## Hill
-
-By the end of this cycle, a reviewer can run a title-rendering allocation
-witness, see bounded or zero hot-loop allocations after warmup, and verify that
-the Braille bunny title scene still renders through the same Bijou surface
-contract.
-
-## Current Truth
-
-Jedit already has two performance mitigations:
-
-- `title-scene-performance-governor.ts` can reuse a retained title backdrop on
-  slow idle frames.
-- `title-braille-sampling.ts` and `BrailleSampleCache` can trace a reduced
-  phase set and reuse resolved Braille samples.
-
-Those mitigations reduce work, but they do not prove zero allocation.
-
-The current hot path still allocates ordinary objects:
-
-- `averagingBrailleCanvas` creates a new Bijou `Surface` per rendered frame.
-- Each Braille cell calls `collapseBrailleCell` with a newly created options
-  object.
-- Each cell creates a new accumulator object and modifier array.
-- Each traced subpixel calls the shader with a newly created params object.
-- The title scene shader constructs a ray context object for each sample.
-- Vector helpers such as `add`, `sub`, `scale`, `cross`, `normalize`, and
-  color helpers return fresh arrays.
-- Hit helpers return fresh hit objects for object, mesh, floor, and wall hits.
-- Environment floor and wall tests create point, normal, color, and hit arrays
-  on the traced path.
-
-This is consistent with minor GC events firing every few milliseconds with
-`allocation failure` while rendering a dense Braille terminal grid.
-
-## Problem
-
-The title renderer currently pays allocation cost proportional to the number of
-traced subpixels, not just proportional to terminal dimensions or scene
-complexity. At a 191x48 terminal, the Braille surface has 9,168 cells and
-73,344 subpixels. Even with adaptive trace budgets, a live frame can allocate
-large numbers of temporary arrays and objects.
-
-This creates severe GC pressure:
-
-- V8 new-space fills rapidly.
-- Minor GC runs repeatedly during animation.
-- Surviving objects occasionally promote and trigger larger collections.
-- The UI can stutter even when raw ray math is acceptable.
-
-Sampling and frozen-backdrop reuse are still useful, but they are not a
-substitute for making the traced hot path allocation-free.
-
-## Scope
-
-This cycle includes:
-
-- Adding a title allocation witness for Braille ray tracing.
-- Introducing reusable scratch state for vectors, colors, ray context, hit
-  results, Braille accumulation, and shader sample output.
-- Replacing per-sample shader params objects with primitive parameters or a
-  mutable params record.
-- Replacing array-returning vector and color helpers in the traced title path
-  with scalar or scratch-output helpers.
-- Replacing hit-object returns in the traced title path with mutable hit records
-  or sentinel status values.
-- Reusing Braille cell accumulator state inside a frame.
-- Preserving existing title render visuals and existing adaptive sampling
-  semantics.
-- Keeping allocation facts inspectable through tests or profile output.
-
-## Non-Goals
-
-This cycle does not include:
-
-- Removing the title scene, bunny mesh, Braille renderer, or Bijou surface
-  output.
-- Replacing JavaScript rendering with native code, WASM, WebGL, Canvas, or DOM.
-- Changing Echo text authority, WSC storage, file lifecycle, Graft, or editor
-  behavior.
-- Making the title renderer visually simpler as the primary fix.
-- Adding new user-visible settings.
-- Continuing the Braille dither mode work.
-- Continuing Vim command-line completion work inside this branch.
-
-## User Experience / Product Shape
-
-There is no new visible control. The expected user-visible outcome is smoother
-title animation and fewer startup freezes. The title screen should still show
-the same bunny scene, lighting, camera motion, and Braille surface style.
-
-The product rule is: performance fixes must not silently change the title
-scene's meaning. Any accepted visual delta must be documented as an intentional
-rendering change, not hidden behind an allocation optimization.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[User starts jedit] --> Title[Animated bunny title scene renders]
-  Title --> Warmup[Renderer prepares scratch state and caches]
-  Warmup --> Live[Live frames trace rays without hot-loop object churn]
-  Live --> Input[User opens command/file flow]
-  Input --> Smooth[Input remains responsive because GC pressure is bounded]
-```
-
-### Wide UI Mockup
-
-Not applicable. This work changes renderer internals and inspectable
-performance facts, not layout or visible controls.
-
-### Narrow UI Mockup
-
-Not applicable. Small-terminal behavior remains owned by the existing
-workspace small-terminal notice and title renderer sizing.
-
-### Accessibility Considerations
-
-The title scene is decorative. Allocation and performance facts must be
-inspectable through commands, tests, or JSON output rather than encoded only in
-visual smoothness.
-
-## Runtime / API Contract
-
-Contract: `TitleRayAllocationPosture`.
-
-Relevant exported or inspectable shapes:
-
-- `TitleRayAllocationPosture`
-  - `unmeasured`
-  - `allocating`
-  - `bounded-after-warmup`
-  - `zero-hot-loop`
-- `TitleRayAllocationFacts`
-  - renderer name
-  - terminal width and height
-  - render mode
-  - warmup frame count
-  - measured frame count
-  - retained heap delta when forced-GC measurement is the only available signal
-  - total allocated bytes or allocation event count when available
-  - posture
-- title profiling CLI JSON facts
-- focused allocation witness spec
-
-Expected behavior:
-
-- Before measurement support lands, allocation posture is `unmeasured`.
-- During migration, traced paths may be `allocating`, but regressions must be
-  visible in the witness.
-- The first hard gate is `bounded-after-warmup`: no unbounded per-ray object
-  growth and no runaway minor-GC pattern under the witness workload.
-- The final gate is `zero-hot-loop`: after warmup, traced rays do not allocate
-  ordinary JavaScript objects in the renderer's ray path.
-
-## Lower Modes
-
-- If allocation instrumentation is unavailable on the local runtime, the
-  witness should report `unmeasured` rather than claim success.
-- If a scene uses unsupported geometry, the renderer may fall back to the
-  allocating path only when the allocation posture reports that fallback.
-- If terminal dimensions change, scratch storage may be resized. Resize
-  allocation is allowed outside the hot-loop measurement window.
-- If theme, mesh, scene, or render mode changes, scratch identity may reset.
-  Rebuild allocation is allowed before the next warmup completes.
-
-## Authority And Boundaries
-
-- Runtime rendering behavior and allocation witnesses outrank design intent.
-- Pixel snapshots prove visual stability but not allocation posture.
-- Heap snapshots and GC logs are evidence only when tied to a deterministic
-  command, dimensions, scene, and frame count.
-- Echo does not own title-render scratch state.
-- WSC does not persist title-render scratch state.
-- The renderer may retain scratch buffers between frames, but those buffers are
-  process-local performance state only.
-
-## Technical Plan
-
-### Phase 1: Witness Before Refactor
-
-Add a deterministic allocation witness around a small but representative title
-render workload.
-
-The witness should:
-
-- run a warmup frame set;
-- run a measured frame set;
-- exercise Braille bunny rendering, not only an empty scene;
-- fix terminal dimensions, theme, scene seed, render mode, and camera posture;
-- record allocation posture as structured facts;
-- fail only when the runtime can measure allocations with enough precision.
-
-### Phase 2: Braille Cell Scratch
-
-Remove per-cell allocation in `averaging-braille-canvas.ts`.
-
-Changes:
-
-- Replace per-cell options objects with primitive parameters or a reusable
-  frame context.
-- Replace per-cell accumulator allocation with one mutable accumulator reused
-  for each cell.
-- Replace `averageRgb` array allocation with direct cell channel assignment.
-- Avoid allocating modifier arrays when no modifier changes are present.
-
-### Phase 3: Shader Params And Sample Output
-
-Remove per-subpixel shader object allocation.
-
-Changes:
-
-- Replace `shader({ u, v, time })` with `shaderSampleAt(u, v, time, out)`.
-- Reuse one mutable sample record per traced subpixel.
-- Cache sample records in `BrailleSampleCache` only when the record must
-  survive across frames; otherwise copy scalar fields into typed storage.
-- Consider replacing `BrailleSampleCache.samples` object slots with parallel
-  typed arrays for `on`, `fg`, `bg`, `rayCount`, and `intersectionCount`.
-
-### Phase 4: Ray Context Scratch
-
-Remove per-ray vector and context allocation in `title-screen.ts`.
-
-Changes:
-
-- Store origin, target, ray, light direction, spotlight vectors, and temporary
-  vectors in a mutable `TitleRayScratch`.
-- Compute ray direction with scalar math into scratch arrays.
-- Avoid allocating screen coordinate vectors.
-- Reuse spotlight context for frames where camera and scene identity are stable.
-
-### Phase 5: Hit Records
-
-Remove per-hit allocation across object, mesh, floor, wall, shadow, reflection,
-and refraction checks.
-
-Changes:
-
-- Replace hit-object return values with mutable `out` records plus boolean
-  success.
-- Store nearest hit state in scratch during traversal.
-- Use scalar point/normal fields or fixed scratch arrays.
-- Keep public convenience wrappers only outside the hot path.
-
-### Phase 6: Profile Gate
-
-Add the final gate:
-
-- the witness runs warmup frames;
-- the measured traced frame loop reports `zero-hot-loop` when instrumentation is
-  available;
-- title-rendering shard covers the renderer contract;
-- `npm run quality` remains green.
-
-## Data Model
-
-```text
-TitleRayAllocationFacts = {
-  renderer: "title-braille-bunny",
-  width: PositiveInteger,
-  height: PositiveInteger,
-  renderMode: "braille",
-  warmupFrames: NonNegativeInteger,
-  measuredFrames: PositiveInteger,
-  posture:
-    | "unmeasured"
-    | "allocating"
-    | "bounded-after-warmup"
-    | "zero-hot-loop",
-  retainedHeapDeltaBytes?: NonNegativeInteger,
-  allocatedBytes?: NonNegativeInteger,
-  allocationEvents?: NonNegativeInteger,
-  notes: string[]
-}
-```
-
-## Relationship Model
-
-```mermaid
-flowchart TD
-  CLI[Title Profile CLI] --> Witness[Allocation Witness]
-  Witness --> Renderer[Title Braille Renderer]
-  Renderer --> Scratch[Reusable Scratch State]
-  Renderer --> Surface[Bijou Surface]
-  Scratch --> Ray[Ray Context]
-  Scratch --> Hit[Hit Records]
-  Scratch --> Sample[Braille Sample Records]
-  Sample --> Cache[Braille Sample Cache]
-  Surface --> Visual[Visual Witness]
-```
-
-## Alternatives Considered
-
-### Keep Adaptive Sampling Only
-
-Pros:
-
-- Already exists.
-- Reduces traced sample count under pressure.
-
-Cons:
-
-- Does not eliminate object churn for samples that are traced.
-- Can still thrash GC on large terminals, motion frames, cold cache, or high
-  pressure scenes.
-
-### Freeze More Frames
-
-Pros:
-
-- Simple.
-- Reduces CPU and allocation frequency.
-
-Cons:
-
-- Reduces animation quality and input feel.
-- Hides the allocator problem instead of fixing it.
-
-### Rewrite In Native Or WASM
-
-Pros:
-
-- Could move allocation away from V8.
-
-Cons:
-
-- Too large for this cycle.
-- Adds portability and build complexity.
-- Avoids proving that the current renderer boundary is efficient.
-
-### Zero Allocation JavaScript Hot Path
-
-Pros:
-
-- Keeps the current renderer architecture.
-- Directly targets nursery exhaustion.
-- Produces measurable facts and keeps visual output inspectable.
-
-Cons:
-
-- Requires careful refactoring.
-- Scratch-state code is less casually readable than pure array-return helpers.
-
-Decision: choose zero allocation JavaScript hot path.
-
-## Goalposts
-
-### Goalpost 1: Allocation Witness
-
-Outcome:
-
-The repo can measure or honestly report title-ray allocation posture for a
-deterministic Braille bunny workload.
-
-Slices:
-
-- [x] Slice 1: Add title allocation facts contract.
-      Commit: `Perf: define title allocation facts`.
-- [x] Slice 2: Add allocation witness command or spec.
-      Commit: `Perf: witness title allocation posture`.
-
-### Goalpost 2: Braille Cell And Sample Scratch
-
-Outcome:
-
-Braille cell collapse and shader invocation stop allocating ordinary objects in
-the per-cell and per-subpixel path.
-
-Slices:
-
-- [ ] Slice 3: Reuse Braille cell accumulator state.
-      Commit: `Perf: reuse Braille cell scratch`.
-- [ ] Slice 4: Remove per-sample shader params allocation.
-      Commit: `Perf: pass shader samples through scratch`.
-- [ ] Slice 5: Move sample cache storage toward scalar or typed storage.
-      Commit: `Perf: store Braille samples without objects`.
-
-### Goalpost 3: Title Ray Scratch
-
-Outcome:
-
-The title scene ray context uses mutable scratch state instead of fresh vectors,
-colors, and context objects per sample.
-
-Slices:
-
-- [ ] Slice 6: Add `TitleRayScratch`.
-      Commit: `Perf: add title ray scratch`.
-- [ ] Slice 7: Rewrite camera ray direction into scratch.
-      Commit: `Perf: reuse title ray vectors`.
-- [ ] Slice 8: Rewrite color helpers into scalar or scratch output.
-      Commit: `Perf: reuse title color scratch`.
-
-### Goalpost 4: Hit Record Scratch
-
-Outcome:
-
-Object, mesh, floor, wall, reflection, refraction, and shadow hit checks update
-scratch hit records instead of returning new hit objects in the traced path.
-
-Slices:
-
-- [ ] Slice 9: Add mutable title hit records.
-      Commit: `Perf: add title hit records`.
-- [ ] Slice 10: Rewrite primitive hit checks to use hit records.
-      Commit: `Perf: reuse primitive hit scratch`.
-- [ ] Slice 11: Rewrite environment hit checks to use hit records.
-      Commit: `Perf: reuse environment hit scratch`.
-- [ ] Slice 12: Rewrite mesh hit traversal to use hit records where practical.
-      Commit: `Perf: reuse mesh hit scratch`.
-- [ ] Slice 13: Rewrite reflection, refraction, and shadow checks.
-      Commit: `Perf: reuse secondary ray scratch`.
-
-### Goalpost 5: Gate And Retrospective
-
-Outcome:
-
-The renderer has a stable allocation gate and the design records measured
-results.
-
-Slices:
-
-- [ ] Slice 14: Add final allocation gate to title-rendering validation.
-      Commit: `Perf: gate title allocation posture`.
-- [ ] Slice 15: Update title performance docs and retrospective.
-      Commit: `Docs: record title allocation results`.
-
-## Tests To Write First
-
-- [x] Allocation facts contract rejects impossible dimensions and frame counts.
-- [x] Allocation witness reports `unmeasured` when instrumentation is absent.
-- [x] Allocation witness records a deterministic title Braille bunny workload.
-- [ ] Braille cell rendering keeps existing visual fixture output.
-- [ ] Shader scratch path preserves ray stats and sample cache behavior.
-- [ ] Ray scratch path preserves camera ray direction facts.
-- [ ] Primitive hit scratch preserves sphere, column, cube, and mesh hit facts.
-- [ ] Environment hit scratch preserves floor and wall facts.
-- [ ] Final gate proves bounded or zero hot-loop allocation after warmup.
-
-## Acceptance Criteria
-
-- [x] The title allocation witness exists and emits structured facts.
-- [ ] The Braille ray hot path does not allocate per-cell options objects.
-- [ ] The Braille ray hot path does not allocate per-subpixel shader params.
-- [ ] Title ray context math uses reusable scratch state.
-- [ ] Hit checks use reusable hit records on the traced path.
-- [ ] Existing title visual and behavior specs still pass.
-- [ ] Allocation posture reaches `zero-hot-loop` when instrumentation is
-      available.
-- [ ] `npm run quality` passes.
-
-## Validation Plan
-
-Expected validation for implementation PRs:
-
-```text
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test spec/title-allocation-facts.spec.mjs
-JEDIT_DIST_PREBUILT=1 node --test spec/averaging-braille-cache.spec.mjs
-JEDIT_DIST_PREBUILT=1 node --test spec/workspace-title-braille-sampling.spec.mjs
-JEDIT_DIST_PREBUILT=1 npm run ci:shard -- title-rendering
-npm run quality
-git diff --check
-```
-
-Design-only validation:
-
-```text
-npx --yes markdownlint-cli docs/design/0104-title-zero-allocation-ray-tracing.md
-git diff --check
-```
-
-## Risks
-
-- Scratch-state code can become harder to reason about than pure helper
-  returns.
-- Allocation instrumentation can be runtime-sensitive.
-- Visual output can drift if scalar rewrites change math order or rounding.
-- Mesh traversal may need a staged migration because public helpers currently
-  return object-shaped hits.
-- Typed arrays can reduce object allocation but introduce indexing mistakes.
-
-## Retrospective
-
-To be completed after implementation.
diff --git a/docs/design/0105-vim-power-moves-causal-parity.md b/docs/design/0105-vim-power-moves-causal-parity.md
deleted file mode 100644
index b40aa7ef..00000000
--- a/docs/design/0105-vim-power-moves-causal-parity.md
+++ /dev/null
@@ -1,1318 +0,0 @@
----
-title: "WF-0105 - Vim Power Moves Causal Parity"
-legend: "WF"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/128"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-06-09"
-updated: "2026-06-13"
----
-
-# WF-0105 - Vim Power Moves Causal Parity
-
-## Linked Issue
-
-- [#128 WF-0105: Search and structural motion parity](https://github.com/flyingrobots/jedit/issues/128)
-
-## Decision Summary
-
-Jedit should grow from a Vim-shaped editor into a comprehensive Vim power-move
-surface whose operators, motions, text objects, search commands, marks,
-registers, macros, repeat, undo, visual selections, and ex commands compile
-into explicit jedit edit intents over Echo-backed causal text truth.
-
-The goal is not to clone Vim internals. The goal is behavioral parity where
-users expect Vim muscle memory, plus causal movements where jedit can do better:
-operator ranges are captured against a reading basis, text objects can be
-backed by Graft structure, repeat can transform intent across changing text,
-undo can become inverse causal input, search/replace can preview as a strand,
-and macros can replay as a receipt-bearing causal script rather than raw key
-sleep.
-
-After the search and structural motion lane landed, WF-0105 remains the broad
-Vim/Jim substrate roadmap. It is no longer the only active product signpost.
-The next pinned product cycle is
-[WF-0108 Jim Command Provenance And :why](0108-causal-command-provenance-surface.md),
-which should choose Vim slices by whether they strengthen provenance, preview,
-replay, safe destructive edits, agent witnesses, structural objects, or user
-trust.
-
-This document also locks the product naming direction: `jim` is the intended
-future user-facing command and editor name for the Vim-shaped application,
-while `jedit` remains the repository, package, and internal migration name until
-the Echo-powered proof and compatibility plan make the rename safe.
-
-## Naming Lock
-
-`jim` is the product name for the modal editor that grows out of `jedit`.
-
-The name works because:
-
-- `jedit` started as "James + edit";
-- the modal/Vim-shaped product can be shortened to `jim`;
-- `jim` is a good terminal command: `jim .`, `jim README.md`, `jim src/main.ts`;
-- `JIM = Jedit Is Modal` is the standing backronym.
-
-Transition policy:
-
-- Do not rename the repository in this arc.
-- Do not rename internal jedit contracts, package descriptors, WSC directories,
-  or release gates until the powered-by-Echo closeout is complete.
-- Add `jim` first as a user-facing binary/command alias when implementation
-  starts.
-- Keep `jedit` as a compatibility command during migration.
-- Documentation may say "jim, formerly jedit" only after the alias exists.
-- Echo must not learn either name as product semantics; Echo still sees generic
-  package, operation, receipt, retention, and WSC facts.
-
-## Sponsored Human
-
-A developer wants Vim's composable power moves in jedit so that text editing
-feels precise, fast, and expressive, without falling back to a weak subset that
-breaks muscle memory the moment the user reaches for `ci"`, `gqap`, `:g`,
-macros, registers, marks, or dot repeat.
-
-## Sponsored Agent
-
-An agent needs stable command, operator, motion, range, text-object, register,
-macro, strand, and replay facts so it can exercise Vim workflows through the
-same production authority path as the TUI, without scraping terminal pixels or
-guessing whether a key sequence became a causal edit.
-
-## Hill
-
-By the end of this roadmap, a user can perform common and advanced Vim editing
-workflows in jedit, including operator-motion commands, text objects, visual
-mode edits, search/replace, registers, macros, repeat, undo/redo, marks, jumps,
-and ex commands, and the repo proves those workflows with deterministic
-usability witnesses that report Echo-backed receipts, reading bases, transformed
-ranges, causal anchors, and WSC history evidence.
-
-## Current Truth
-
-Jedit currently has a meaningful but incomplete Vim layer:
-
-- Normal and Insert modes exist.
-- Basic motions exist, including line, character, and word-shaped movement.
-- Pending operators exist for delete, change, yank, and goto flows.
-- Some line and word operator combinations exist, including `dd`, `cw`, and
-  related focused behavior.
-- Vim command-line mode exists for `:edit`, `:write`, `:quit`, and `:wq`.
-- Inline command/file completion exists and is backed by provider-neutral
-  completion items.
-- Unknown command feedback exists for the command line.
-- Production text changes route through the Echo-backed production text
-  session rather than local mutable line truth.
-- WSC history listing, current export, historical export, and replay closeout
-  exist as agent-facing JSON surfaces.
-
-Important current caveats:
-
-- Vim parity is not complete.
-- Motions are mostly imperative UI cursor operations, not a first-class motion
-  algebra.
-- Operator ranges are not yet a complete compiled intent model.
-- Text objects are not comprehensive.
-- Visual mode and blockwise edits are not production-complete.
-- Registers, macros, repeat, marks, jumps, folds, quickfix/location lists, and
-  most ex commands are not parity-complete.
-- Undo/redo is only honest when modeled as explicit causal input; hidden local
-  snapshot rollback cannot be production text authority.
-- Graft-backed structural text objects and causal-history previews are design
-  direction, not complete runtime truth.
-
-Relevant existing design anchors:
-
-- [0102 Vim Command-Line Completion Surface](0102-vim-command-line-completion-surface.md)
-- [Text Edit Algebra](text-edit-algebra.md)
-- [Why Echo](why-echo.md)
-- [Causal Event Model](causal-event-model.md)
-- [0106 Emacs Ideas To Steal Causally](0106-emacs-ideas-to-steal-causally.md)
-- [Technical Teardown: The Vim Editor Layer](../technical-teardown.md#12-the-vim-editor-layer)
-
-Slice 2 adds the first machine-readable inventory:
-
-- [0105 Vim Power Moves Parity Matrix](0105-vim-power-moves-parity-matrix.json)
-
-That matrix is current-state truth for the power-move surface. It names what is
-supported, partial, unsupported, or intentionally causally enhanced, and it
-records the proof gaps that later slices must close.
-
-Slice 3 adds the target workflow fixture set:
-
-- [0105 Vim Power Target Usability Fixtures](0105-vim-power-target-usability-fixtures.json)
-
-Those fixtures keep human workflow descriptions separate from future executable
-witness inputs. Each workflow references parity matrix row ids so target tests
-stay connected to the inventory.
-
-## Problem
-
-Vim's power comes from composition:
-
-```text
-operator + motion
-operator + text object
-count + operator + motion
-selection + operator
-ex range + command
-macro + repeat
-search result set + command
-```
-
-Jedit currently has pieces of this model, but not the full language. If jedit
-keeps adding one-off commands, it will miss the thing that makes Vim feel
-powerful: users can express editing intent in a compact grammar, and the editor
-can apply that grammar consistently across text, structure, ranges, registers,
-search results, and history.
-
-Echo raises the bar further. In jedit, a Vim command should not merely mutate a
-local string. A command should compile into an auditable causal operation:
-
-- what command was expressed;
-- what basis it was interpreted against;
-- what motion or text object resolved to;
-- what range or set of ranges was touched;
-- what receipt was produced;
-- what reading proves the resulting text;
-- what history can replay or explain it.
-
-Without that contract, jedit will feel like a terminal editor skin over ad hoc
-state, not a causal editor.
-
-## Scope
-
-This roadmap includes:
-
-- A Vim key grammar and parser for Normal, Operator-pending, Visual, Select,
-  Insert, Replace, and Command-line contexts.
-- Counts, registers, motions, text objects, operators, modifiers, and command
-  prefixes as typed syntax.
-- A motion algebra that resolves cursor moves and operator ranges against a
-  specific reading basis.
-- Comprehensive text-object coverage for words, WORDs, sentences, paragraphs,
-  quotes, brackets, braces, tags, comments, functions, classes, blocks,
-  indentation, and Graft-backed structural objects.
-- Operator parity for delete, change, yank, put, replace, indent, outdent,
-  format, case transform, join, filter, sort, substitute, and external command
-  hooks where appropriate.
-- Visual charwise, linewise, and blockwise selections.
-- Registers, yank/delete history, black-hole register, system clipboard seam,
-  numbered registers, expression register posture, and causal register
-  provenance.
-- Dot repeat as transformed intent replay, not byte-for-byte key replay.
-- Macros as causal scripts over parsed editor intents.
-- Marks, jump list, change list, search history, command history, and recorded
-  navigation receipts.
-- Search, substitute, global, vglobal, arglist-like, quickfix-like, and
-  location-list-like workflows.
-- Causal enhancements: strand preview, braid comparison, partial admission,
-  causal undo, transformed repeat, anchor-based marks, and history-aware
-  command previews.
-- Agent-facing JSON witnesses for common workflows and power moves.
-- A parity matrix that can become a release gate.
-
-## Non-Goals
-
-This roadmap does not include:
-
-- Reimplementing Vim's source code or compatibility bugs.
-- Supporting Vimscript as a first-class extension language in this cycle.
-- Claiming compatibility with every plugin ecosystem behavior.
-- Making Echo understand Vim, text, operators, motions, buffers, or editor
-  nouns.
-- Making Graft the source of editable truth.
-- Giving app code Echo tick, drain, scheduler, or lifecycle authority.
-- Replacing filesystem or Git interop with Echo-only behavior in this cycle.
-- Building a full collaborative network protocol before local causal parity is
-  proven.
-
-## User Experience / Product Shape
-
-The user should be able to use jedit like a powerful Vim-shaped editor:
-
-- `daw`, `ci"`, `gqap`, `>ip`, `yG`, `gg=G`, `:%s/foo/bar/g`
-- `qa...q`, `@a`, `@@`
-- `.` to repeat the last meaningful edit intent
-- marks and jumps with `ma`, `` `a ``, `''`, `ctrl-o`, `ctrl-i`
-- search and substitute with `/`, `?`, `n`, `N`, `:s`, `:g`, `:v`
-- visual char, line, and block selection with `v`, `V`, `ctrl-v`
-- registers with `"ay`, `"ap`, `"_d`, `"+y`
-- text objects with `iw`, `aw`, `i(`, `a{`, `it`, `af`, `ic`
-
-Jedit should communicate causal state without making the user read a debug log.
-The primary editor remains quiet. Causal facts appear in focused places:
-
-- a footer posture when a command is pending or obstructed;
-- a command preview when an ex operation spans many edits;
-- an optional history drawer or preview for causal strands and braids;
-- JSON witnesses and history export for agents.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[User opens file in jedit] --> Normal[Normal mode]
-  Normal --> Chord[User enters Vim chord]
-  Chord --> Parse[Key grammar parses count register operator motion object]
-  Parse --> Resolve[Motion/text object resolves against reading basis]
-  Resolve --> Intent[Jedit builds typed edit intent]
-  Intent --> Echo[Echo admits scheduler-owned work]
-  Echo --> Receipt[Receipt and reading evidence return]
-  Receipt --> Render[Workspace updates reading cache and cursor]
-  Receipt --> History[WSC retains causal history]
-  History --> Repeat[Dot repeat can transform intent on a later basis]
-  History --> Strand[Large edits can preview as a strand before admission]
-```
-
-### Wide UI Mockup
-
-```text
-+----------------------------------------------------------------------------+
-| src/app/example.ts                                                          |
-|                                                                            |
-|   describe("alpha", () => {                                                 |
-|     it("moves fast", () => {                                                |
-|       expect(run()).toEqual("old")                                          |
-|     })                                                                     |
-|   })                                                                       |
-|                                                                            |
-| NORMAL  ci"  object=inside-quote  basis=reading:41  range=82..85           |
-| receipt=pending  [Enter accepts preview strand] [Esc cancels]              |
-+----------------------------------------------------------------------------+
-```
-
-The footer is compact. It names the parsed operation and causal basis only when
-that helps explain state. For ordinary single-buffer edits, the command should
-feel instantaneous and not require a preview.
-
-### Narrow UI Mockup
-
-```text
-+--------------------------------------+
-| expect(run()).toEqual("old")         |
-|                                      |
-| NORMAL ci" range=82..85 pending      |
-+--------------------------------------+
-```
-
-Narrow terminals suppress optional causal detail first. The editor must keep
-the command state, error posture, and user path readable before showing
-diagnostic evidence.
-
-### Accessibility Considerations
-
-Every pending command and completed operation must have a model fact summary:
-
-- current mode;
-- pending operator;
-- count;
-- register;
-- motion or text object;
-- resolved range;
-- operation status;
-- receipt id when applicable;
-- reading id when applicable;
-- obstruction reason when applicable.
-
-No power move should require visual-only discovery. Agent and screen-reader
-adjacent tooling should be able to ask "what is pending?" and "what happened?"
-without reading pixels.
-
-## Runtime / API Contract
-
-Contract: `VimPowerMoveIntent`.
-
-The runtime should distinguish syntax, resolution, and execution:
-
-```text
-Raw key input
-  -> VimChordSyntax
-    -> VimCommandIntent
-      -> ResolvedEditTarget
-        -> Echo-backed production text command
-          -> Receipt + reading + WSC history
-```
-
-Core public shapes:
-
-```text
-VimChordSyntax = {
-  mode,
-  count?,
-  register?,
-  operator?,
-  motion?,
-  textObject?,
-  commandLine?,
-  visualSelection?,
-  repeatPolicy
-}
-
-VimResolvedTarget = {
-  basisId,
-  readingId,
-  cursorBefore,
-  cursorAfter?,
-  range?,
-  ranges?,
-  linewise,
-  blockwise,
-  inclusivity,
-  affinity,
-  textObjectId?,
-  structuralProviderId?
-}
-
-VimPowerMoveIntent = {
-  commandId,
-  syntax,
-  target,
-  editKind,
-  registerWrite?,
-  registerRead?,
-  repeatIdentity?,
-  macroIdentity?,
-  causalPreview?
-}
-
-VimPowerMoveResult = {
-  status: "applied" | "previewed" | "obstructed" | "unsupported",
-  receiptId?,
-  readingId?,
-  basisId?,
-  exportEvidenceId?,
-  obstruction?,
-  repeatIdentity?,
-  registerEvidence?,
-  strandId?,
-  braidId?
-}
-```
-
-### Register And Transaction Doctrine
-
-Classic Vim registers are user-addressable editing state, not the undo stack.
-They are closer to named clipboards plus macro storage than to Git refs. Jim
-still needs registers because Vim workflows depend on explicit register
-selection:
-
-- `"` chooses a register for the next operator.
-- `y`, `d`, and `c` write deleted or yanked material into registers.
-- `p` and `P` read register material back into the buffer.
-- `_` discards without overwriting the unnamed register.
-- `+` and `*` bridge optional host clipboard state.
-- `q{register}` records macros into register-like storage.
-- `@{register}` replays macro material by name.
-
-Echo's retained evidence and causal history can back register provenance, but
-they do not replace registers as a user-facing Vim language feature. The product
-contract is:
-
-```text
-RegisterState = app-owned causal projection over Echo-backed text evidence
-```
-
-Register entries should carry:
-
-- register name;
-- source basis;
-- source range or range set;
-- material digest;
-- optional retained material reference;
-- linewise, charwise, or blockwise shape;
-- producing command id;
-- producing receipt id when the source came from an admitted mutation.
-
-Commands that read editor state to choose a mutation target must be
-transactional. `di"` is the canonical example:
-
-```text
-Raw keys: d i "
-Parse: delete + innerQuote
-Read: locate quote pair on basis A
-Resolve: range inside that pair on basis A
-Write: delete range and update registers
-```
-
-The forbidden implementation is:
-
-```text
-read basis A -> resolve byte range -> later write that range on basis B
-```
-
-The required implementation is one of:
-
-```text
-resolve and apply inside one atomic transaction optic
-resolve on basis A and submit a basis-bound intent that obstructs if stale
-resolve on basis A and intentionally transform/re-resolve onto basis B
-```
-
-For first implementation, a basis-bound compiled `replaceRange` intent is
-acceptable only if stale basis produces a typed obstruction and no register,
-repeat, jump, or text mutation state is half-applied. The target architecture is
-an Echo `TransactionOptic`-shaped operation:
-
-```text
-VimSemanticIntent
-  -> atomic evaluation over one basis
-  -> resolve motion/text object
-  -> update app-owned register/repeat/jump facts
-  -> admit text mutation if needed
-  -> one receipt or obstruction bundle
-```
-
-Macro replay should not be assumed atomic in the classic Vim sense. Jim can do
-better by treating macro replay as a causal script made of semantic entries.
-The default macro posture should be:
-
-- record parsed commands where known;
-- record bounded raw insert spans only when necessary;
-- replay entries through the same production command path;
-- stop at first obstruction;
-- emit a macro replay report with applied count, receipt ids, and obstructed
-  entry;
-- group replay as one user-facing edit group when safe, without hiding
-  per-command receipts.
-
-Full all-or-nothing macro transactions are powerful, but they should follow the
-operator/text-object transaction gate. They are a later hardening target, not a
-shortcut around atomic operator semantics.
-
-### Grammar Boundary
-
-The key grammar owns:
-
-- mode-specific key interpretation;
-- counts and numeric prefixes;
-- register prefixes;
-- operator-pending state;
-- text object prefixes;
-- command-line dispatch;
-- macro record/replay syntax;
-- dot repeat identity.
-
-The grammar does not own:
-
-- text storage;
-- Echo admission;
-- Graft structural reads;
-- filesystem save/export;
-- rendering;
-- trusted lifecycle control.
-
-### Motion Algebra
-
-Motions should be pure range resolvers over a reading:
-
-```text
-resolveMotion(reading, cursor, motion, count) -> ResolvedMotion
-```
-
-Examples:
-
-| Motion | Meaning | Causal note |
-| --- | --- | --- |
-| `h` `j` `k` `l` | character/line moves | UI cursor only unless paired with operator |
-| `w` `b` `e` | word motions | range uses reading basis |
-| `W` `B` `E` | WORD motions | same resolver, different tokenization |
-| `0` `^` `$` | line boundary moves | preserves byte/grapheme distinction |
-| `gg` `G` | file boundary moves | uses bounded/full reading posture |
-| `%` | matching delimiter | text fallback records pair identity; parser/Graft provider can extend it |
-| `/` `?` | search motion | repeat search carries basis and match id; UI entry remains separate |
-| `}` `{` | paragraph motion | resolver owns blank-line policy |
-| `]]` `[[` | section motion | Graft-backed when structural data exists |
-
-### Text Object Algebra
-
-Text objects should be resolvers over text and optional structure:
-
-```text
-resolveTextObject(reading, cursor, object, count) -> ResolvedObject
-```
-
-Required parity set:
-
-| Object | Required parity | Causal opportunity |
-| --- | --- | --- |
-| `iw` `aw` | word inner/around | token range evidence |
-| `iW` `aW` | WORD inner/around | tokenization policy evidence |
-| `is` `as` | sentence | sentence boundary witness |
-| `ip` `ap` | paragraph | paragraph range witness |
-| `i"` `a"` | quotes | delimiter-pair evidence |
-| `i'` `a'` | single quotes | delimiter-pair evidence |
-| backtick quote objects | backticks inner/around | delimiter-pair evidence |
-| `i(` `a(` | parentheses | balanced pair provider |
-| `i[` `a[` | brackets | balanced pair provider |
-| `i{` `a{` | braces | balanced pair provider |
-| `it` `at` | tags | Graft/tree provider where available |
-| `if` `af` | function | Graft structural object |
-| `ic` `ac` | class | Graft structural object |
-| `i/` `a/` | comment | source-language provider |
-| indentation block | indentation scope | fallback structural object |
-
-Jedit extension objects can exist, but they should not steal Vim meanings.
-Examples: causal strand object, last receipt object, changed range object, and
-diagnostic object.
-
-### Operator Parity
-
-Operators should compile over resolved targets:
-
-| Operator | Vim parity target | Echo-backed behavior |
-| --- | --- | --- |
-| `d` | delete | replace target with empty fragment |
-| `c` | change | delete then enter Insert with causal edit group |
-| `y` | yank | write register without mutating text authority |
-| `p` `P` | put | insert register material as new fragment |
-| `r` | replace character | replace grapheme/byte-safe target |
-| `R` | replace mode | stream replacement intents |
-| `>` `<` | indent/outdent | linewise transform intent |
-| `=` | reindent | formatter/provider-backed transform |
-| `gq` | format | format range or obstruct honestly |
-| `gu` `gU` `g~` | case transforms | deterministic text transform intent |
-| `J` `gJ` | join lines | line join transform intent |
-| `!` | filter through external command | explicit host boundary and obstruction |
-| `:` range command | ex command over range set | batch intent or preview strand |
-
-### Repeat, Macros, And Causality
-
-Dot repeat should replay semantic intent against the current basis:
-
-```text
-last edit: ci" -> replace inside quote at basis A
-current text: another quote at basis B
-dot repeat: resolve inside quote at cursor on basis B, then apply same insert
-```
-
-That is different from replaying raw keys blindly. Raw key replay can remain an
-implementation detail for simple cases, but the product contract should be
-semantic repeat where possible.
-
-Macros should record parsed intents and fallback key events:
-
-- semantic entries for known Vim commands;
-- raw key entries only for unsupported or insert text spans;
-- basis-sensitive replay posture;
-- obstruction when replay cannot safely transform.
-
-Macro replay should emit a causal script report:
-
-```text
-macroId
-entries
-appliedCount
-obstructedEntry?
-receiptIds
-finalReadingId
-```
-
-### Undo And Redo
-
-Undo is not time travel. In production, undo should be an explicit inverse
-causal input:
-
-```text
-u -> derive inverse intent from last applied edit group -> submit inverse
-ctrl-r -> derive redo intent from inverse history -> submit explicit redo
-```
-
-This preserves history:
-
-- original edit remains in WSC;
-- undo receipt exists;
-- redo receipt exists;
-- replay can explain all three.
-
-### Search, Substitute, Global
-
-Search and replace are where Vim parity and causality can flex hardest.
-
-Required parity:
-
-- `/pattern`, `?pattern`, `n`, `N`
-- `*`, `#`, `g*`, `g#`
-- `:s/pat/repl/flags`
-- `:%s/pat/repl/flags`
-- `:g/pat/cmd`
-- `:v/pat/cmd`
-- confirmation flow for `c` flag
-
-Causal extension:
-
-- `:%s` can preview as a strand before admission.
-- `:g` can emit a range set with stable match ids.
-- confirmation can admit selected replacements as strand slices.
-- failed replacements remain typed obstructions, not partial silent edits.
-
-### Registers
-
-Registers should be app-owned state with provenance:
-
-| Register | Required posture |
-| --- | --- |
-| unnamed | latest yank/delete material |
-| numbered | delete/yank rotation |
-| named `a-z` | user-selected material |
-| append `A-Z` | append to named register |
-| black-hole `_` | discard without changing unnamed |
-| system `+` `*` | host clipboard adapter, optional |
-| expression `=` | unsupported until expression evaluator exists |
-| small delete `-` | line/char policy documented |
-
-Register material should carry:
-
-- source basis;
-- source range;
-- linewise/charwise/blockwise posture;
-- content digest;
-- optional receipt id.
-
-### Marks, Jumps, And Anchors
-
-Marks should be modeled as causal anchors, not fixed row/column guesses.
-
-Required parity:
-
-- `m{a-zA-Z}` set mark;
-- `` `{mark}`` exact jump;
-- `'{mark}` line jump;
-- `''` previous jump;
-- `ctrl-o` and `ctrl-i` jump list traversal;
-- change list traversal where feasible.
-
-Causal extension:
-
-- marks transform through edit receipts using anchor bias;
-- stale marks report obstruction or degraded posture;
-- agent JSON can explain why a mark moved.
-
-### Visual And Block Mode
-
-Required parity:
-
-- `v` charwise visual;
-- `V` linewise visual;
-- `ctrl-v` blockwise visual;
-- operator over visual selection;
-- `o` to swap selection anchor;
-- block insert/append where feasible.
-
-Causal extension:
-
-- visual selection is an explicit range aperture over a reading basis;
-- block selection materializes as a range set;
-- block edits emit one grouped causal intent with per-line receipts or one
-  receipt carrying a range-set result, depending on Echo contract support.
-
-## Lower Modes
-
-- If Graft is unavailable, structural objects return typed unavailable posture
-  and text-only objects still work.
-- If full-file reading is unavailable, commands requiring full-buffer scope
-  report bounded-reading obstruction or request an expanded aperture.
-- If system clipboard is unavailable, `+` and `*` registers report host
-  clipboard obstruction.
-- If a macro replay becomes unsafe after text drift, replay stops at the first
-  obstructed entry and reports the divergent coordinate.
-- If color is unavailable, command and obstruction states still appear as text
-  facts in the footer and JSON witnesses.
-- If the terminal is too narrow, optional causal detail collapses before the
-  command line or pending operator becomes unreadable.
-
-## Data / State Model
-
-| Category | Description |
-| --- | --- |
-| Source of truth | Echo-backed text worldline and WSC-retained causal history. |
-| Derived state | Cursor, viewport, selections, pending grammar state, completion preview, local render cache. |
-| App-owned mutable state | Registers, marks, jump list, command history, search history, macro definitions, repeat identity. |
-| Invalid states | Applied text mutation without Echo receipt, hidden local undo in production, macro replay claiming success after obstruction. |
-| Reset behavior | Pending grammar clears on Escape, mode change, pane focus transfer, or obstruction acknowledgement. |
-| Serialization | WSC for causal text history; app-owned session/history storage for registers, marks, macros, and command history where appropriate. |
-| Deterministic assumptions | Motions and text objects resolve against explicit reading basis and documented tokenization/structure providers. |
-
-```mermaid
-erDiagram
-  READING ||--o{ RESOLVED_TARGET : resolves
-  VIM_SYNTAX ||--|| VIM_INTENT : compiles_to
-  VIM_INTENT ||--|| RESOLVED_TARGET : targets
-  VIM_INTENT ||--o{ REGISTER_EVENT : reads_or_writes
-  VIM_INTENT ||--o{ MACRO_ENTRY : records
-  VIM_INTENT ||--o{ RECEIPT : produces
-  RECEIPT ||--|| READING : proves
-  RECEIPT ||--o{ ANCHOR_TRANSFORM : moves
-  RECEIPT ||--o{ WSC_RECORD : retains
-  STRAND ||--o{ VIM_INTENT : previews
-  BRAID ||--o{ STRAND : compares
-
-  VIM_SYNTAX {
-    string mode
-    string keys
-    int count
-    string operator
-  }
-
-  RESOLVED_TARGET {
-    string basisId
-    string readingId
-    string rangeShape
-  }
-
-  RECEIPT {
-    string receiptId
-    string status
-  }
-```
-
-## Accessibility Posture
-
-| Concern | Posture |
-| --- | --- |
-| Semantic labels or facts | Pending and completed Vim commands expose mode, operator, motion, target, and status facts. |
-| Focus order or ownership | Vim key grammar runs only when no modal/drawer/command field owns input. |
-| Hidden or visual-only information | Range, receipt, register, macro, and obstruction facts are model-visible. |
-| Keyboard behavior | All workflows are keyboard-first; mouse is optional and cannot be required for parity. |
-| Secret or redaction behavior | Registers and macros may contain sensitive text; JSON witnesses should support redacted content digests where needed. |
-
-## Localization / Directionality Posture
-
-| Concern | Posture |
-| --- | --- |
-| User-visible strings | Error, obstruction, preview, and help text must use catalog keys. |
-| Catalog keys | New keys for pending command summaries, obstruction messages, and causal preview labels. |
-| Supported locales updated | English first; other locales may fall back until catalog updates land. |
-| Directionality assumptions | Vim key syntax remains left-to-right command text; surrounding labels must render through normal Bijou directionality. |
-| Validation command | i18n/catalog checks plus focused footer/help rendering specs. |
-
-## Agent Inspectability / Explainability Posture
-
-Agents should be able to run witnesses such as:
-
-```bash
-node scripts/jedit-vim-power-witness.mjs --json --workflow open-edit-save
-node scripts/jedit-vim-power-witness.mjs --json --workflow text-objects
-node scripts/jedit-vim-power-witness.mjs --json --workflow search-substitute
-node scripts/jedit-vim-power-witness.mjs --json --workflow macro-repeat
-node scripts/jedit-vim-power-witness.mjs --json --workflow causal-strand-preview
-```
-
-The JSON report should include:
-
-- workflow id;
-- input key sequence;
-- parsed syntax sequence;
-- resolved target facts;
-- register and macro facts;
-- receipt ids;
-- reading ids;
-- WSC basis ids;
-- obstruction facts;
-- final materialized text digest;
-- optional redacted before/after snippets.
-
-This witness can later be wrapped by MCP tools, but the JSON command should be
-the first source of truth.
-
-## Linked Invariants
-
-- Runtime behavior and saved output outrank design prose.
-- Echo remains generic and owns admission, scheduling, receipts, retained
-  evidence, and replay posture.
-- Jedit owns Vim grammar, editor nouns, text objects, registers, macros,
-  viewports, selections, and user-facing command policy.
-- Graft provides structural readings, not editable text authority.
-- Files and previews are projections.
-- Undo, redo, retry, repeat, macro replay, and strand admission are explicit
-  causal input, not hidden state mutation.
-- Tests and witnesses prove implementation; this design only defines intent.
-
-## Design Alternatives Considered
-
-### Option A: Implement Vim Commands One By One
-
-Pros:
-
-- Fast for a few common commands.
-- Easy to test locally.
-- Fits current command table style.
-
-Cons:
-
-- Does not scale to comprehensive parity.
-- Repeats range resolution logic.
-- Makes dot repeat, macros, and text objects inconsistent.
-- Hides causal basis and range semantics inside handlers.
-
-### Option B: Embed A Vim Engine
-
-Pros:
-
-- Potentially high parity quickly.
-- Existing Vim edge cases already modeled.
-
-Cons:
-
-- Hard to align with Echo-backed causal authority.
-- Likely owns mutable buffer truth internally.
-- Hard to expose jedit-specific causal facts.
-- Hard to keep Graft/Echo boundaries clean.
-
-### Option C: Build A jedit Vim Algebra
-
-Pros:
-
-- Preserves Vim's compositional language.
-- Makes operator/motion/text-object resolution testable.
-- Compiles naturally into Echo-backed production text commands.
-- Gives agents typed facts.
-- Creates room for causal improvements.
-
-Cons:
-
-- More upfront design and testing.
-- Requires deliberate compatibility decisions.
-- Will uncover edge cases Vim users expect immediately.
-
-Decision: choose Option C.
-
-## Implementation Slices
-
-This arc intentionally uses 30 slices. The original shape was 15 broad slices;
-doubling it keeps each implementation step reviewable, gives every risky Vim
-feature a focused RED test, and leaves room for causal proof rather than
-shipping a shallow compatibility checklist.
-
-### Slice 1: Jim Naming And Command Alias Design Lock
-
-- Preserve `jedit` as the repo/package/internal name.
-- Define `jim` as the future user-facing binary and editor name.
-- Add migration acceptance criteria for command aliases and docs.
-
-### Slice 2: Parity Inventory Matrix
-
-- Build a machine-readable parity matrix for motions, operators, text objects,
-  visual modes, registers, marks, macros, repeat, search, and ex commands.
-- Mark each item as supported, partial, unsupported, or causally enhanced.
-- Gate the matrix with a focused schema and coverage spec.
-
-### Slice 3: Target Usability Witness Fixtures
-
-- Add representative user workflows as target usability tests.
-- Separate human workflow descriptions from executable witness fixtures.
-- Include open/edit/save, text-object surgery, search/substitute, macro/repeat,
-  marks/jumps, and causal strand preview.
-- Gate each workflow against the parity matrix row ids it exercises.
-
-### Slice 4: Transactional Register Doctrine And Token Model
-
-- Define tokens for counts, registers, operators, motions, text objects, mode
-  switches, visual prefixes, command-line invocations, and macro controls.
-- Define register state as a jedit-owned causal projection backed by Echo
-  evidence.
-- Define read-resolve-write commands such as `di"` as transaction-optic
-  candidates, with basis-bound obstruction as the minimum safe implementation.
-- Define macro replay as a causal script with edit-group posture, not as a
-  hidden all-or-nothing text mutation.
-- Keep tokens independent from runtime execution.
-- Add syntax fixture snapshots.
-
-### Slice 5: Vim Grammar Parser
-
-- Parse counts, registers, operators, motions, text objects, and mode-specific
-  key sequences into `VimChordSyntax`.
-- Keep raw key handling behind the grammar boundary.
-- Add syntax-only tests.
-
-### Slice 6: Normal/Operator-Pending State Machine
-
-- Make Normal and Operator-pending command accumulation explicit.
-- Preserve Escape, focus transfer, drawer, modal, and command-line ownership
-  rules.
-- Prove incomplete chords never mutate production text.
-
-### Slice 7: Reading-Basis Motion Resolver
-
-- Implement pure motion resolution over a reading basis.
-- Return `ResolvedMotion` with basis, cursor before/after, range shape, and
-  obstruction posture.
-- Return typed obstruction when the reading is too narrow.
-
-### Slice 8: Core Motion Parity
-
-- Cover `h`, `j`, `k`, `l`, `0`, `^`, `$`, `gg`, `G`, `w`, `b`, `e`, `W`,
-  `B`, and `E`.
-- Preserve byte/grapheme policy in target facts.
-- Prove UI-only movement does not mutate Echo history.
-
-### Slice 9: Search And Structural Motion Parity
-
-- Cover `/`, `?`, `n`, `N`, `%`, `{`, `}`, `[[`, `]]`, and related motions.
-- Use Graft-backed structural providers where available.
-- Return honest unavailable posture when providers are absent.
-
-### Slice 10: Text Object Resolver Spine
-
-- Implement text objects for words, quotes, brackets, braces, paragraphs, and
-  indentation.
-- Prove fallback and unavailable postures.
-
-### Slice 11: Core Text Object Parity
-
-- Cover `iw`, `aw`, `iW`, `aW`, `is`, `as`, `ip`, `ap`, quotes, brackets,
-  braces, parentheses, and backticks.
-- Add nesting and delimiter fixture tables.
-- Preserve inner/around inclusivity facts.
-
-### Slice 12: Graft-Backed Structural Text Objects
-
-- Add provider seam for functions, classes, tags, comments, and indentation
-  scopes.
-- Keep Graft as structural reader, not text authority.
-- Prove provider-unavailable lower mode.
-
-### Slice 13: Operator Compiler Spine
-
-- Compile operator plus resolved target into production text session commands.
-- Keep operator compilation separate from key parsing and target resolution.
-- Preserve register write/read evidence.
-
-### Slice 14: Delete, Change, Yank, Put
-
-- Cover `d`, `c`, `y`, `p`, and `P` over motions and text objects.
-- Route text mutations through `TextBufferSessionPort`.
-- Prove yank/register writes do not mutate text authority.
-
-### Slice 15: Replace, Join, Indent, Case, Format
-
-- Cover `r`, `R`, `J`, `gJ`, `>`, `<`, `=`, `gu`, `gU`, `g~`, `gq`, and
-  formatter obstruction posture.
-- Preserve linewise/charwise target semantics.
-- Add operator-result witness rows.
-
-### Slice 16: Visual Selection State
-
-- Model visual selections as range apertures.
-- Add charwise, linewise, and blockwise target resolution.
-- Preserve `o` anchor swapping and mode exits.
-
-### Slice 17: Visual Operators
-
-- Compile visual charwise, linewise, and blockwise selections through the same
-  operator compiler.
-- Cover block insert/append lower mode.
-- Prove range-set facts for block operations.
-
-### Slice 18: Register State Model
-
-- Add app-owned register state with source basis, range, shape, content digest,
-  and receipt provenance.
-- Cover unnamed, numbered, named, append, black-hole, small-delete, and optional
-  system registers.
-- Support redacted agent facts.
-
-### Slice 19: Register Operations And Clipboard Boundary
-
-- Wire register prefixes into operators and put commands.
-- Add optional host clipboard adapter for `+` and `*`.
-- Return typed obstruction when clipboard is unavailable.
-
-### Slice 20: Dot Repeat Identity
-
-- Capture semantic repeat identity from applied operations.
-- Exclude diagnostic prose, wall-clock timing, and raw key delay from repeat
-  identity.
-- Add first replay fixture rows.
-
-### Slice 21: Dot Repeat Transformed Replay
-
-- Replay semantic intent against the current reading basis.
-- Transform object/motion targets rather than replaying raw keys blindly.
-- Report typed obstruction when repeat cannot be safely transformed.
-
-### Slice 22: Macro Recording Model
-
-- Record macro entries as parsed intents plus fallback raw spans.
-- Track register target, recording status, entry summaries, and redacted text.
-- Keep Insert text spans bounded and explicit.
-
-### Slice 23: Macro Replay And Obstruction
-
-- Replay macros through the production command path.
-- Stop and report at first obstruction.
-- Emit causal script facts: macro id, entries, applied count, receipt ids, and
-  final reading id.
-
-### Slice 24: Marks As Causal Anchors
-
-- Model marks as transformable anchors.
-- Cover local marks, exact jumps, line jumps, and degraded stale mark posture.
-- Prove marks transform through edit receipts.
-
-### Slice 25: Jump List And Change List
-
-- Add jump list and change list posture.
-- Cover `''`, exact-mark jumps, line-mark jumps, `ctrl-o`, `ctrl-i`, and
-  change-list traversal where feasible.
-- Emit navigation receipt facts without mutating Echo text history.
-
-### Slice 26: Search History And Match Identity
-
-- Cover `/`, `?`, `n`, `N`, `*`, `#`, `g*`, and `g#`.
-- Record search history, match ids, basis ids, and obstruction posture.
-- Keep search movement separate from text mutation.
-
-### Slice 27: Substitute And Confirmation
-
-- Cover `:s`, `:%s`, flags, replacement escaping, and confirmation flow.
-- Emit range-set facts and admitted replacement rows.
-- Cover typed obstruction for partial or invalid substitutions.
-
-### Slice 28: Global, Vglobal, And Range Commands
-
-- Cover `:g`, `:v`, ex ranges, and command execution over match sets.
-- Add typed obstruction for unsupported nested commands.
-- Preserve deterministic range ordering.
-
-### Slice 29: Causal Strand And Braid Preview
-
-- Add preview posture for broad edits and suggestion-like transformations.
-- Compare alternatives as braid facts.
-- Admit selected strand slices into the target worldline.
-
-### Slice 30: Agent/MCP Witness And Parity Release Gate
-
-- Add JSON witness command for power workflows.
-- Wrap stable commands in MCP only after CLI witnesses are green.
-- Guard against trusted lifecycle/tick authority exposure.
-- Compose focused specs and witnesses into a Vim power-move gate.
-- Keep it separate from the Echo release gate until stable.
-- Update help, technical teardown, lower modes, and i18n posture.
-- Add final Code Lawyer review before declaring parity.
-
-## Tests To Write First
-
-- Parser tests for counts, registers, operators, motions, text objects, visual
-  mode, macros, and dot repeat.
-- Motion resolver table tests over fixed text fixtures.
-- Text object resolver table tests over punctuation, quotes, nesting, comments,
-  indentation, and structural fixtures.
-- Production command tests proving mutating commands route through
-  `TextBufferSessionPort`.
-- Register provenance tests.
-- Dot repeat transform tests.
-- Macro replay obstruction tests.
-- Mark/anchor transform tests.
-- Search/substitute/global range-set tests.
-- Strand preview/admission tests.
-- Agent JSON witness tests.
-- Static guard that no Vim implementation imports trusted Echo lifecycle
-  authority.
-
-## Acceptance Criteria
-
-- Common Vim power workflows from this doc have deterministic usability
-  witnesses.
-- Operator/motion/text-object commands compile through typed jedit intents.
-- Mutating commands use the Echo-backed production text session.
-- Non-mutating cursor movement does not mutate Echo causal history.
-- Registers, marks, macros, repeat, and search histories expose app-safe facts.
-- Dot repeat and macro replay report transformed intent or typed obstruction.
-- Broad search/substitute workflows can preview as a causal strand when
-  configured.
-- Undo/redo are explicit causal inputs or honestly unsupported.
-- Graft-backed structural objects are optional and never become text authority.
-- Agent JSON witnesses can verify behavior without scraping terminal pixels.
-- Echo contains no Vim, text, editor, buffer, cursor, register, macro, or file
-  nouns.
-
-## Validation Plan
-
-Local validation for implementation branches:
-
-```bash
-npm run build
-node --test --test-concurrency=1 spec/vim-power-grammar.spec.mjs
-node --test --test-concurrency=1 spec/vim-power-chord-syntax.spec.mjs
-node --test --test-concurrency=1 spec/vim-normal-state-machine.spec.mjs
-node --test --test-concurrency=1 spec/vim-power-motion-resolver.spec.mjs
-node --test --test-concurrency=1 spec/vim-power-text-objects.spec.mjs
-node --test --test-concurrency=1 spec/vim-power-operators.spec.mjs
-node --test --test-concurrency=1 spec/vim-power-registers.spec.mjs
-node --test --test-concurrency=1 spec/vim-power-repeat-macro.spec.mjs
-node --test --test-concurrency=1 spec/vim-power-search-substitute.spec.mjs
-node --test --test-concurrency=1 spec/vim-power-parity-matrix.spec.mjs
-node --test --test-concurrency=1 spec/vim-power-target-usability-fixtures.spec.mjs
-node scripts/jedit-vim-power-witness.mjs --json --workflow open-edit-save
-npm run --silent quality
-```
-
-Release validation:
-
-```bash
-npm run --silent release-gate:jedit-echo
-npm run --silent release-gate:vim-power
-```
-
-The second command does not exist yet. It is the intended parity gate once the
-witnesses are real.
-
-## Playback / Witness
-
-Current machine-readable planning witness:
-
-- [0105 Vim Power Moves Parity Matrix](0105-vim-power-moves-parity-matrix.json)
-- `spec/vim-power-parity-matrix.spec.mjs`
-- [0105 Vim Power Target Usability Fixtures](0105-vim-power-target-usability-fixtures.json)
-- `spec/vim-power-target-usability-fixtures.spec.mjs`
-
-Target usability witnesses:
-
-### Workflow 1: Open, Edit, Save, Reopen
-
-1. `cd /tmp/workspace`
-2. Run `jedit`.
-3. Press `:edit main.ts`.
-4. Use Normal motions.
-5. Press `i`, type ASCII punctuation and numbers.
-6. Escape to Normal.
-7. Run `:wq`.
-8. `cat main.ts` includes the edits.
-
-### Workflow 2: Text Object Surgery
-
-1. Open a source file with nested strings, parentheses, and blocks.
-2. Run `ci"`, `da(`, `gqap`, `>ip`, `yif`, and `p`.
-3. Witness records resolved text objects and receipts.
-
-### Workflow 3: Search And Substitute
-
-1. Run `/old`, `n`, `N`.
-2. Run `:%s/old/new/gc`.
-3. Confirm some replacements and reject others.
-4. Witness records match ids, admitted replacements, and final reading.
-
-### Workflow 4: Macro And Dot Repeat
-
-1. Record a macro that changes a field.
-2. Replay it across similar lines.
-3. Use `.` after moving to another compatible object.
-4. Witness records transformed intent and obstruction if a target is invalid.
-
-### Workflow 5: Causal Strand Preview
-
-1. Run a broad command such as format paragraph or substitute file.
-2. Preview as a strand.
-3. Compare current and proposed heads as a braid.
-4. Admit selected slices.
-5. Witness records strand id, braid id, admitted ranges, and receipts.
-
-## Retrospective
-
-Roadmap implementation is not complete. The planning and grammar window now has
-inspectable artifacts for Slice 2 Parity Inventory Matrix, Slice 3 Target
-Usability Witness Fixtures, Slice 4 Transactional Register Doctrine And Token
-Model, Slice 5 Vim Grammar Parser, and Slice 6 Normal/Operator-Pending State
-Machine.
-
-This branch also closes the first runtime execution package across the later
-power-move slices:
-
-- Slices 7 and 8: reading-basis motion resolution plus core word, line, file,
-  and character motion parity.
-- Slices 10 and 11: word, paragraph, quote, and bracket text-object resolution.
-- Slices 13 and 14: operator-pending execution through the Vim chord syntax
-  boundary plus delete, change, yank, and put execution.
-- Slice 15: `gu`/`gU`/`g~` case transforms and `J`/`gJ` joins.
-- Slices 20 and 21: basic dot repeat plus transformed-repeat metadata.
-- Slice 24: local marks with exact and line jumps.
-
-What the tests proved:
-
-- `spec/vim-power-parity-matrix.spec.mjs` proves the matrix has stable
-  metadata, covers the required WF-0105 categories, carries proof/boundary
-  fields for every row, and does not claim unsupported or causally enhanced work
-  as currently proven.
-- `spec/vim-power-target-usability-fixtures.spec.mjs` proves the target
-  workflows have stable metadata, separate human prose from structured witness
-  inputs, reference real parity matrix rows, and do not claim runtime proof
-  before implementation exists.
-- `spec/vim-power-grammar.spec.mjs` proves the runtime-independent token model
-  for counts, registers, operators, motions, text objects, mode switches, visual
-  prefixes, command-line invocations, macro controls, incomplete prefixes, and
-  unknown keys.
-- `spec/vim-power-chord-syntax.spec.mjs` proves tokens parse into
-  `VimChordSyntax` for complete chords, pending command fragments, pending
-  modifiers, command-line input, macro controls, standalone put commands,
-  invalid unknown keys, stray text objects, and trailing-token obstructions.
-- `spec/vim-normal-state-machine.spec.mjs` proves Normal and Operator-pending
-  command accumulation is explicit, Escape resets pending state, counts and
-  registers remain syntax-only until a command completes, invalid continuations
-  reset without execution readiness, and command-line, modal, drawer, insert,
-  and focus-transfer owners keep pending state inert.
-- `spec/vim-power-motion-text-object.spec.mjs`,
-  `spec/vim-power-operators-registers.spec.mjs`,
-  `spec/vim-power-normal-mode-integration.spec.mjs`, and
-  `spec/vim-power-transforms-marks.spec.mjs` prove the runtime execution
-  package: counted motion targets, delimiter text objects, operator-motion
-  deletes, text-object changes, named line registers, put without phantom blank
-  lines, pending Vim keys in Normal mode, dot repeat of the last edit,
-  transformed text-object repeat metadata, case-transform operators, joins, and
-  local marks with exact and line jumps.
-- `spec/workspace-command-line.spec.mjs` proves `:q!` and `:quit!` dispatch
-  forced quit commands without opening the dirty-file confirmation posture.
-
-What changed from the design:
-
-- The parity inventory now lives as a separate JSON document so later release
-  gates can consume it without scraping Markdown prose.
-- The target usability workflows now live as a separate JSON fixture document so
-  future witness scripts can consume workflow steps directly.
-- The Slice 4 token model lives in `src/app/workspace/vim-grammar.ts`, with the
-  stable vocabulary in `src/app/workspace/vim-grammar-vocabulary.ts` and syntax
-  snapshots in `spec/fixtures/vim-power-grammar-snapshots.json`.
-- The Slice 5 parser lives in `src/app/workspace/vim-chord-syntax.ts`, with
-  syntax snapshots in
-  `spec/fixtures/vim-power-chord-syntax-snapshots.json`.
-- The Slice 6 state machine lives in
-  `src/app/workspace/vim-normal-state.ts`. It is intentionally pure and not yet
-  wired into production text execution.
-- The first runtime execution package lives in
-  `src/app/workspace/vim-motion-resolver.ts`,
-  `src/app/workspace/vim-text-object-resolver.ts`, and
-  `src/app/workspace/vim-command-executor.ts`. `updateNormalMode` now tries the
-  Vim chord executor before falling back to legacy single-key commands.
-- The current runtime batch adds `src/app/workspace/vim-editor-operators.ts` for
-  reusable case-transform, join, and mark helpers. Repeat records
-  `sourceBasisDigest` and a `resolve-current-basis` replay policy so text-object
-  repeat is explicit instead of an unlabelled key replay.
-- The search and structural motion lane adds
-  `src/app/workspace/vim-paragraph-motion.ts`,
-  `src/app/workspace/vim-matching-pair-motion.ts`, and
-  `src/app/workspace/vim-motion-basis-digest.ts`; paragraph and `%` motions now
-  expose basis-bound runtime proof, with `%` carrying pair id, direction, and
-  bracket policy.
-- The same lane adds `src/app/workspace/vim-search-motion.ts`, plus
-  `src/app/workspace/vim-word-motion.ts` as a ratchet-preserving extraction.
-  Stored literal `n` and `N` search repeat now carries match id, pattern digest,
-  ordinal, direction, and wrap policy.
-- Section motions now report `unsupported-section-motion` so provider absence is
-  visible to tests and agents instead of collapsed into a generic unsupported
-  motion.
-
-Follow-up work:
-
-- `/` and `?` UI search entry, regex search policy, actual section providers,
-  tag pairs, comment pairs, and richer structural providers remain future work.
-- Full structural text objects such as functions, classes, comments, tags, and
-  Graft-backed objects remain future work.
-- Register append, black-hole, system clipboard, numbered registers, and
-  expression register policy remain future work.
-- Dot repeat now resolves stored semantic keys against the current basis for
-  supported motions and text objects; stale-basis obstruction and richer
-  transformed insertion payloads remain future work.
-- Marks now support local set, exact jump, and line jump; anchor transformation
-  through later edit receipts remains future work.
diff --git a/docs/design/0105-vim-power-moves-parity-matrix.json b/docs/design/0105-vim-power-moves-parity-matrix.json
deleted file mode 100644
index de4fbbb7..00000000
--- a/docs/design/0105-vim-power-moves-parity-matrix.json
+++ /dev/null
@@ -1,750 +0,0 @@
-{
-  "schemaVersion": 1,
-  "id": "wf-0105-vim-power-moves-parity-matrix",
-  "designDoc": "docs/design/0105-vim-power-moves-causal-parity.md",
-  "owner": "jedit",
-  "futureCommandName": "jim",
-  "statusVocabulary": [
-    "supported",
-    "partial",
-    "unsupported",
-    "causally-enhanced"
-  ],
-  "statusSemantics": {
-    "supported": "Current jedit behavior has executable or inspectable proof.",
-    "partial": "Current jedit behavior covers part of Vim's expected behavior but needs more grammar, target, or witness work.",
-    "unsupported": "Current jedit behavior should not be claimed as available.",
-    "causally-enhanced": "The target intentionally exceeds Vim baseline and remains planned until executable proof lands."
-  },
-  "echoBoundary": "Echo remains generic; Vim keys, motions, text objects, registers, macros, buffers, and editor names stay in jedit.",
-  "graftBoundary": "Graft may provide structural readings, but it is not editable text authority.",
-  "categories": [
-    {
-      "id": "motions",
-      "title": "Motions",
-      "items": [
-        {
-          "id": "motion.character",
-          "keys": ["h", "j", "k", "l"],
-          "status": "partial",
-          "targetSlices": [7, 8],
-          "targetParity": "Move by character and screen line in Normal and operator-pending contexts.",
-          "currentJedit": "Basic cursor movement exists, but it is not yet a first-class motion algebra.",
-          "currentProof": ["docs/design/0105-vim-power-moves-causal-parity.md#current-truth"],
-          "proofGap": "Needs ResolvedMotion facts with basis and obstruction posture.",
-          "causalOpportunity": "Non-mutating navigation can emit optional navigation facts without mutating Echo history.",
-          "echoBoundary": "Echo receives no admission for pure cursor movement."
-        },
-        {
-          "id": "motion.line-boundary",
-          "keys": ["0", "^", "$"],
-          "status": "partial",
-          "targetSlices": [7, 8],
-          "targetParity": "Move to line start, first non-blank, and line end.",
-          "currentJedit": "Line-shaped navigation exists in the UI path.",
-          "currentProof": ["docs/design/0105-vim-power-moves-causal-parity.md#current-truth"],
-          "proofGap": "Needs byte/grapheme policy facts and operator-pending range proof.",
-          "causalOpportunity": "Resolved ranges can preserve reading basis and affinity.",
-          "echoBoundary": "Echo sees only later edit intents that consume these ranges."
-        },
-        {
-          "id": "motion.file-boundary",
-          "keys": ["gg", "G"],
-          "status": "partial",
-          "targetSlices": [7, 8],
-          "targetParity": "Move to file start and file end, with count-aware line targeting.",
-          "currentJedit": "Goto-shaped behavior exists, but full Vim count semantics are not proven.",
-          "currentProof": ["docs/design/0105-vim-power-moves-causal-parity.md#current-truth"],
-          "proofGap": "Needs bounded-reading obstruction and full-reading expansion posture.",
-          "causalOpportunity": "File-scope commands can record the reading aperture used.",
-          "echoBoundary": "Echo remains unaware of cursor or viewport nouns."
-        },
-        {
-          "id": "motion.word",
-          "keys": ["w", "b", "e", "W", "B", "E"],
-          "status": "partial",
-          "targetSlices": [7, 8],
-          "targetParity": "Resolve word and WORD movement with counts and operator ranges.",
-          "currentJedit": "Word-shaped movement exists for some focused behavior.",
-          "currentProof": ["docs/design/0105-vim-power-moves-causal-parity.md#current-truth"],
-          "proofGap": "Needs table-driven tokenization policy for words, WORDs, and punctuation.",
-          "causalOpportunity": "Word ranges can carry token policy evidence in JSON witnesses.",
-          "echoBoundary": "Echo receives only the compiled mutation when a motion is paired with an operator."
-        },
-        {
-          "id": "motion.search",
-          "keys": ["/", "?", "n", "N"],
-          "status": "partial",
-          "targetSlices": [9, 26],
-          "targetParity": "Move by forward/backward search and repeat search direction.",
-          "currentJedit": "`n` and `N` can resolve a stored literal last-search state with match identity; `/` and `?` command entry are not complete.",
-          "currentProof": [
-            "spec/vim-power-motion-text-object.spec.mjs",
-            "spec/vim-power-operators-registers.spec.mjs"
-          ],
-          "proofGap": "Needs `/` and `?` UI command integration, regex policy, search history mutation, and rendered match feedback.",
-          "causalOpportunity": "Search results carry stable match ids, pattern digest, ordinal, direction, and basis facts for later range commands.",
-          "echoBoundary": "Echo does not parse patterns; jedit submits only chosen edit intents."
-        },
-        {
-          "id": "motion.matching-delimiter",
-          "keys": ["%"],
-          "status": "partial",
-          "targetSlices": [9, 12],
-          "targetParity": "Jump to matching delimiter, tag, or language pair where supported.",
-          "currentJedit": "Balanced bracket delimiter matching resolves with explicit pair identity; tag and language pairs remain unsupported.",
-          "currentProof": [
-            "spec/vim-power-motion-text-object.spec.mjs",
-            "spec/vim-power-operators-registers.spec.mjs"
-          ],
-          "proofGap": "Needs tag, comment, language-pair, and optional Graft structural providers.",
-          "causalOpportunity": "Resolved bracket pairs record the pair id, direction, policy, and reading basis beside the resolved range.",
-          "echoBoundary": "Echo remains generic; Graft and jedit own structure facts."
-        },
-        {
-          "id": "motion.paragraph-section",
-          "keys": ["{", "}", "[[", "]]"],
-          "status": "partial",
-          "targetSlices": [9],
-          "targetParity": "Move by paragraph and section boundaries.",
-          "currentJedit": "Paragraph movement resolves against blank-line boundaries; section movement reports a typed unsupported-section-motion obstruction.",
-          "currentProof": ["spec/vim-power-motion-text-object.spec.mjs"],
-          "proofGap": "Needs structural-section fixture tables and actual section motion resolver support.",
-          "causalOpportunity": "Section movement can degrade honestly when structural providers are absent.",
-          "echoBoundary": "Echo receives no structural nouns."
-        }
-      ]
-    },
-    {
-      "id": "operators",
-      "title": "Operators",
-      "items": [
-        {
-          "id": "operator.delete-change-yank",
-          "keys": ["d", "c", "y"],
-          "status": "partial",
-          "targetSlices": [13, 14],
-          "targetParity": "Compile delete, change, and yank over motions and text objects.",
-          "currentJedit": "Pending operators exist for delete, change, and yank in focused paths.",
-          "currentProof": ["docs/design/0105-vim-power-moves-causal-parity.md#current-truth"],
-          "proofGap": "Needs shared operator compiler and register provenance.",
-          "causalOpportunity": "Mutating operators can produce receipt and reading facts; yank stays non-mutating.",
-          "echoBoundary": "Echo admits only mutation intents, never raw Vim operators."
-        },
-        {
-          "id": "operator.put",
-          "keys": ["p", "P"],
-          "status": "unsupported",
-          "targetSlices": [14, 19],
-          "targetParity": "Put register material after or before the target position.",
-          "currentJedit": "Register-backed put parity is not complete.",
-          "currentProof": [],
-          "proofGap": "Needs register material shape and insertion target semantics.",
-          "causalOpportunity": "Put can preserve source register provenance in the emitted edit group.",
-          "echoBoundary": "Echo sees inserted material and receipt facts, not register names."
-        },
-        {
-          "id": "operator.replace",
-          "keys": ["r", "R"],
-          "status": "unsupported",
-          "targetSlices": [15],
-          "targetParity": "Replace one character or stream replacement text in Replace mode.",
-          "currentJedit": "Replace-mode parity is not complete.",
-          "currentProof": [],
-          "proofGap": "Needs grapheme/byte policy and repeated replacement intent.",
-          "causalOpportunity": "Replacement streams can be grouped as one causal edit.",
-          "echoBoundary": "Echo admits explicit replace ranges only."
-        },
-        {
-          "id": "operator.indent-format",
-          "keys": [">", "<", "=", "gq"],
-          "status": "unsupported",
-          "targetSlices": [15],
-          "targetParity": "Indent, outdent, reindent, and format resolved line ranges.",
-          "currentJedit": "Formatter-backed Vim operators are not production-complete.",
-          "currentProof": [],
-          "proofGap": "Needs provider boundary, linewise transform facts, and obstruction posture.",
-          "causalOpportunity": "Broad formatting can preview as a causal strand before admission.",
-          "echoBoundary": "Echo does not run formatters; jedit submits admitted text transforms."
-        },
-        {
-          "id": "operator.case",
-          "keys": ["gu", "gU", "g~"],
-          "status": "unsupported",
-          "targetSlices": [15],
-          "targetParity": "Lowercase, uppercase, or toggle case over resolved targets.",
-          "currentJedit": "Case-transform operators are not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs deterministic transform tables and locale posture.",
-          "causalOpportunity": "Case transforms can produce compact before/after digests.",
-          "echoBoundary": "Echo admits the final transform intent without knowing Vim syntax."
-        },
-        {
-          "id": "operator.join",
-          "keys": ["J", "gJ"],
-          "status": "unsupported",
-          "targetSlices": [15],
-          "targetParity": "Join lines with or without Vim's whitespace normalization.",
-          "currentJedit": "Join operators are not parity-complete.",
-          "currentProof": [],
-          "proofGap": "Needs linewise target resolution and whitespace policy fixtures.",
-          "causalOpportunity": "Join can report exact affected line ids and resulting digest.",
-          "echoBoundary": "Echo receives a text replacement intent."
-        },
-        {
-          "id": "operator.filter-range-command",
-          "keys": ["!", ":"],
-          "status": "causally-enhanced",
-          "targetSlices": [28, 29],
-          "targetParity": "Apply external filters or ex range commands over resolved ranges.",
-          "currentJedit": "Host filter and range-command operators are not implemented.",
-          "currentProof": [],
-          "proofGap": "Planned as explicit host-boundary work with strand preview for broad edits.",
-          "causalOpportunity": "External effects can be represented as reviewed strands before admission.",
-          "echoBoundary": "Echo never executes host commands; jedit owns the adapter boundary."
-        }
-      ]
-    },
-    {
-      "id": "transactionSemantics",
-      "title": "Transaction Semantics",
-      "items": [
-        {
-          "id": "transaction.read-resolve-write",
-          "keys": ["di\"", "ci\"", "daw", "gqap"],
-          "status": "causally-enhanced",
-          "targetSlices": [4, 10, 11, 13, 14],
-          "targetParity": "Read to resolve a target and write the resulting mutation without basis drift.",
-          "currentJedit": "Text-object operators are not implemented as atomic semantic transactions.",
-          "currentProof": [],
-          "proofGap": "Needs a basis-bound operation that resolves target and mutation together or obstructs stale basis.",
-          "causalOpportunity": "Read, resolution, register update, mutation, and receipt can share one causal boundary.",
-          "echoBoundary": "Echo owns transaction atomicity and stale-basis obstruction; jedit owns Vim semantics."
-        },
-        {
-          "id": "transaction.register-atomicity",
-          "keys": ["d", "c", "y", "p", "\"", "_"],
-          "status": "causally-enhanced",
-          "targetSlices": [4, 18, 19],
-          "targetParity": "Keep register writes and text mutations consistent for each semantic command.",
-          "currentJedit": "Full register provenance and atomic register/text grouping are not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs register state with source basis, material digest, shape, receipt, and obstruction policy.",
-          "causalOpportunity": "Registers can be app-owned projections backed by Echo retained evidence.",
-          "echoBoundary": "Echo does not learn register names; it stores text evidence and receipts."
-        },
-        {
-          "id": "transaction.macro-script",
-          "keys": ["q{register}", "@{register}", "@@"],
-          "status": "causally-enhanced",
-          "targetSlices": [4, 22, 23],
-          "targetParity": "Replay macros as causal scripts with explicit obstruction instead of hidden key timing.",
-          "currentJedit": "Macro recording and replay are not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs semantic macro entries, bounded raw insert spans, edit-group posture, and replay report.",
-          "causalOpportunity": "Macro replay can emit applied count, receipt ids, final reading, and obstructed entry.",
-          "echoBoundary": "Echo admits the resulting text operations; jedit owns macro language and grouping."
-        },
-        {
-          "id": "transaction.undo-redo",
-          "keys": ["u", "Ctrl-r"],
-          "status": "causally-enhanced",
-          "targetSlices": [4, 30],
-          "targetParity": "Undo and redo become explicit inverse causal inputs, not hidden snapshot rollback.",
-          "currentJedit": "Production undo and redo remain unsupported until modeled as causal input.",
-          "currentProof": [],
-          "proofGap": "Needs inverse intent derivation from receipts and a visible unsupported posture until then.",
-          "causalOpportunity": "Original edit, undo, and redo can all remain explainable causal history.",
-          "echoBoundary": "Echo owns receipts and inverse admission; jedit owns Vim undo command policy."
-        }
-      ]
-    },
-    {
-      "id": "textObjects",
-      "title": "Text Objects",
-      "items": [
-        {
-          "id": "text-object.word",
-          "keys": ["iw", "aw", "iW", "aW"],
-          "status": "unsupported",
-          "targetSlices": [10, 11],
-          "targetParity": "Resolve inner and around word or WORD objects.",
-          "currentJedit": "Text-object grammar is not complete.",
-          "currentProof": [],
-          "proofGap": "Needs resolver spine plus tokenization fixtures.",
-          "causalOpportunity": "Token ranges can include basis and tokenizer evidence.",
-          "echoBoundary": "Echo receives only the compiled edit range."
-        },
-        {
-          "id": "text-object.sentence-paragraph",
-          "keys": ["is", "as", "ip", "ap"],
-          "status": "unsupported",
-          "targetSlices": [10, 11],
-          "targetParity": "Resolve sentence and paragraph text objects.",
-          "currentJedit": "Sentence and paragraph objects are not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs boundary fixture tables and inclusive around policy.",
-          "causalOpportunity": "Paragraph edits can preview as broad causal changes.",
-          "echoBoundary": "Echo stays unaware of sentence or paragraph nouns."
-        },
-        {
-          "id": "text-object.quotes",
-          "keys": ["i\"", "a\"", "i'", "a'", "i`", "a`"],
-          "status": "unsupported",
-          "targetSlices": [10, 11],
-          "targetParity": "Resolve inner and around quote objects.",
-          "currentJedit": "Quote text objects such as ci\" are target workflows, not complete runtime truth.",
-          "currentProof": [],
-          "proofGap": "Needs delimiter-pair evidence and escape handling.",
-          "causalOpportunity": "Quote-pair identity can support transformed dot repeat.",
-          "echoBoundary": "Echo admits only the final text replacement."
-        },
-        {
-          "id": "text-object.brackets",
-          "keys": ["i(", "a(", "i[", "a[", "i{", "a{"],
-          "status": "unsupported",
-          "targetSlices": [10, 11],
-          "targetParity": "Resolve balanced pair objects for parentheses, brackets, and braces.",
-          "currentJedit": "Balanced pair text objects are not parity-complete.",
-          "currentProof": [],
-          "proofGap": "Needs nesting, imbalance, and cursor-position fixture tables.",
-          "causalOpportunity": "Balanced ranges can degrade honestly when malformed.",
-          "echoBoundary": "Echo does not own delimiter matching."
-        },
-        {
-          "id": "text-object.tags",
-          "keys": ["it", "at"],
-          "status": "causally-enhanced",
-          "targetSlices": [12],
-          "targetParity": "Resolve tag-like structural objects when language structure is available.",
-          "currentJedit": "Tag objects are not implemented.",
-          "currentProof": [],
-          "proofGap": "Planned through optional Graft structure provider.",
-          "causalOpportunity": "Provider identity and structural node ids can be included in witnesses.",
-          "echoBoundary": "Echo never stores tag semantics."
-        },
-        {
-          "id": "text-object.function-class",
-          "keys": ["if", "af", "ic", "ac"],
-          "status": "causally-enhanced",
-          "targetSlices": [12],
-          "targetParity": "Resolve functions and classes as structural objects.",
-          "currentJedit": "Function and class text objects are not implemented.",
-          "currentProof": [],
-          "proofGap": "Planned through optional Graft structure provider with unavailable lower mode.",
-          "causalOpportunity": "Structural object ids can support history-aware edits.",
-          "echoBoundary": "Echo receives no language-specific nouns."
-        },
-        {
-          "id": "text-object.comment-indent",
-          "keys": ["i/", "a/", "ii", "ai"],
-          "status": "causally-enhanced",
-          "targetSlices": [12],
-          "targetParity": "Resolve comments and indentation blocks.",
-          "currentJedit": "Comment and indentation text objects are not implemented.",
-          "currentProof": [],
-          "proofGap": "Planned as text fallback plus optional structural provider.",
-          "causalOpportunity": "Indent scopes can become causally stable range apertures.",
-          "echoBoundary": "Echo remains generic."
-        }
-      ]
-    },
-    {
-      "id": "visualModes",
-      "title": "Visual Modes",
-      "items": [
-        {
-          "id": "visual.charwise",
-          "keys": ["v"],
-          "status": "unsupported",
-          "targetSlices": [16, 17],
-          "targetParity": "Select charwise ranges and apply operators.",
-          "currentJedit": "Visual charwise mode is not production-complete.",
-          "currentProof": [],
-          "proofGap": "Needs explicit range aperture state and operator compilation.",
-          "causalOpportunity": "Selection can be a reading-basis range aperture.",
-          "echoBoundary": "Echo sees only admitted mutation intents."
-        },
-        {
-          "id": "visual.linewise",
-          "keys": ["V"],
-          "status": "unsupported",
-          "targetSlices": [16, 17],
-          "targetParity": "Select linewise ranges and apply operators.",
-          "currentJedit": "Visual linewise mode is not production-complete.",
-          "currentProof": [],
-          "proofGap": "Needs linewise target facts and mode exits.",
-          "causalOpportunity": "Linewise range sets can be emitted as witness facts.",
-          "echoBoundary": "Echo does not own selection state."
-        },
-        {
-          "id": "visual.blockwise",
-          "keys": ["Ctrl-v"],
-          "status": "unsupported",
-          "targetSlices": [16, 17],
-          "targetParity": "Select rectangular block ranges and apply operators.",
-          "currentJedit": "Blockwise visual mode is not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs block range-set representation and lower-mode posture.",
-          "causalOpportunity": "Block edits can be grouped as one causal range-set intent.",
-          "echoBoundary": "Echo admits the resulting range-set operation."
-        },
-        {
-          "id": "visual.anchor-swap",
-          "keys": ["o"],
-          "status": "unsupported",
-          "targetSlices": [16],
-          "targetParity": "Swap the active end of a visual selection.",
-          "currentJedit": "Visual anchor swapping is not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs selection anchor and focus state.",
-          "causalOpportunity": "Anchor facts can explain selection changes without pixels.",
-          "echoBoundary": "Echo is not involved."
-        }
-      ]
-    },
-    {
-      "id": "registers",
-      "title": "Registers",
-      "items": [
-        {
-          "id": "register.unnamed-numbered-small-delete",
-          "keys": ["\"", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "-"],
-          "status": "partial",
-          "targetSlices": [18, 19],
-          "targetParity": "Track unnamed, numbered, and small-delete registers.",
-          "currentJedit": "Yank/delete flows exist, but full register provenance is not complete.",
-          "currentProof": ["docs/design/0105-vim-power-moves-causal-parity.md#current-truth"],
-          "proofGap": "Needs app-owned register state with content digest and source basis.",
-          "causalOpportunity": "Register material can cite source basis and receipt provenance.",
-          "echoBoundary": "Echo does not store register names."
-        },
-        {
-          "id": "register.named",
-          "keys": ["a-z"],
-          "status": "unsupported",
-          "targetSlices": [18, 19],
-          "targetParity": "Read and write named registers.",
-          "currentJedit": "Named registers are not parity-complete.",
-          "currentProof": [],
-          "proofGap": "Needs register prefix grammar and storage.",
-          "causalOpportunity": "Named register facts can be redacted for agents.",
-          "echoBoundary": "Echo sees only text material in admitted operations."
-        },
-        {
-          "id": "register.append",
-          "keys": ["A-Z"],
-          "status": "unsupported",
-          "targetSlices": [18, 19],
-          "targetParity": "Append to named registers.",
-          "currentJedit": "Append registers are not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs append semantics and linewise/charwise preservation.",
-          "causalOpportunity": "Append history can cite multiple source ranges.",
-          "echoBoundary": "Echo remains generic."
-        },
-        {
-          "id": "register.black-hole",
-          "keys": ["_"],
-          "status": "unsupported",
-          "targetSlices": [18, 19],
-          "targetParity": "Discard operator output without changing unnamed register.",
-          "currentJedit": "Black-hole register is not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs register write suppression proof.",
-          "causalOpportunity": "Discard can still emit non-secret operation facts.",
-          "echoBoundary": "Echo sees only the text mutation, not discarded register policy."
-        },
-        {
-          "id": "register.system-clipboard",
-          "keys": ["+", "*"],
-          "status": "unsupported",
-          "targetSlices": [19],
-          "targetParity": "Bridge optional system clipboard registers.",
-          "currentJedit": "System clipboard register posture is not complete.",
-          "currentProof": [],
-          "proofGap": "Needs host clipboard adapter and unavailable posture.",
-          "causalOpportunity": "Clipboard import/export can carry redacted provenance.",
-          "echoBoundary": "Echo never talks to the host clipboard."
-        },
-        {
-          "id": "register.expression",
-          "keys": ["="],
-          "status": "unsupported",
-          "targetSlices": [18],
-          "targetParity": "Expression register remains unsupported until evaluator policy exists.",
-          "currentJedit": "Expression register is not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs explicit non-goal or evaluator design before implementation.",
-          "causalOpportunity": "Unsupported posture can prevent fake expression support.",
-          "echoBoundary": "Echo does not evaluate expressions."
-        }
-      ]
-    },
-    {
-      "id": "repeat",
-      "title": "Dot Repeat",
-      "items": [
-        {
-          "id": "repeat.identity",
-          "keys": ["."],
-          "status": "causally-enhanced",
-          "targetSlices": [20],
-          "targetParity": "Capture the last meaningful edit as semantic repeat identity.",
-          "currentJedit": "Dot repeat is not complete as semantic intent.",
-          "currentProof": [],
-          "proofGap": "Planned identity must exclude raw timing and diagnostic prose.",
-          "causalOpportunity": "Repeat can store command intent, basis, target kind, and inserted material digest.",
-          "echoBoundary": "Echo replays admitted jedit intents, not raw key delays."
-        },
-        {
-          "id": "repeat.transformed-replay",
-          "keys": ["."],
-          "status": "causally-enhanced",
-          "targetSlices": [21],
-          "targetParity": "Replay prior edit intent against the current reading basis.",
-          "currentJedit": "Transformed dot repeat is not implemented.",
-          "currentProof": [],
-          "proofGap": "Planned resolver must obstruct when the target cannot be transformed safely.",
-          "causalOpportunity": "This is a primary causal movement: same intent, new basis.",
-          "echoBoundary": "Echo only admits the newly compiled operation."
-        }
-      ]
-    },
-    {
-      "id": "macros",
-      "title": "Macros",
-      "items": [
-        {
-          "id": "macro.record",
-          "keys": ["q{register}", "q"],
-          "status": "unsupported",
-          "targetSlices": [22],
-          "targetParity": "Record macro entries into a named register.",
-          "currentJedit": "Macro recording is not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs parsed intent entries plus bounded raw insert spans.",
-          "causalOpportunity": "Macro entries can retain semantic intent instead of sleeps.",
-          "echoBoundary": "Echo does not know macro registers."
-        },
-        {
-          "id": "macro.replay",
-          "keys": ["@{register}", "@@"],
-          "status": "causally-enhanced",
-          "targetSlices": [23],
-          "targetParity": "Replay macros through the production command path.",
-          "currentJedit": "Macro replay is not implemented.",
-          "currentProof": [],
-          "proofGap": "Planned replay must stop at first obstruction and report applied count.",
-          "causalOpportunity": "Macro replay can emit a receipt-bearing causal script report.",
-          "echoBoundary": "Echo admits each resulting operation through normal ports."
-        }
-      ]
-    },
-    {
-      "id": "marksJumps",
-      "title": "Marks And Jumps",
-      "items": [
-        {
-          "id": "marks.local-global",
-          "keys": ["m{mark}"],
-          "status": "causally-enhanced",
-          "targetSlices": [24],
-          "targetParity": "Set local and global marks.",
-          "currentJedit": "Marks are not parity-complete.",
-          "currentProof": [],
-          "proofGap": "Planned marks need transformable anchor storage.",
-          "causalOpportunity": "Marks can move through edit receipts with anchor bias.",
-          "echoBoundary": "Echo stores receipts; jedit owns mark anchors."
-        },
-        {
-          "id": "marks.jump",
-          "keys": ["`{mark}", "'{mark}", "''"],
-          "status": "unsupported",
-          "targetSlices": [24, 25],
-          "targetParity": "Jump to exact mark, mark line, or previous jump.",
-          "currentJedit": "Mark jumps are not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs exact/line jump facts and stale mark posture.",
-          "causalOpportunity": "Jump facts can explain transformed or degraded marks.",
-          "echoBoundary": "Echo is not cursor authority."
-        },
-        {
-          "id": "jumps.list",
-          "keys": ["Ctrl-o", "Ctrl-i"],
-          "status": "unsupported",
-          "targetSlices": [25],
-          "targetParity": "Traverse the jump list backward and forward.",
-          "currentJedit": "Jump list traversal is not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs navigation receipt facts and stack policy.",
-          "causalOpportunity": "Navigation history can be inspectable without text mutation.",
-          "echoBoundary": "Echo receives no edit admission."
-        },
-        {
-          "id": "jumps.change-list",
-          "keys": ["g;", "g,"],
-          "status": "unsupported",
-          "targetSlices": [25],
-          "targetParity": "Traverse changes where feasible.",
-          "currentJedit": "Change-list traversal is not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs mapping from edit receipts to cursor-return anchors.",
-          "causalOpportunity": "Change list can be derived from causal edit receipts.",
-          "echoBoundary": "Echo facts are generic receipts; jedit projects editor navigation."
-        }
-      ]
-    },
-    {
-      "id": "searchSubstitute",
-      "title": "Search And Substitute",
-      "items": [
-        {
-          "id": "search.pattern-history",
-          "keys": ["/", "?"],
-          "status": "unsupported",
-          "targetSlices": [26],
-          "targetParity": "Record forward and backward search history.",
-          "currentJedit": "Vim search history is not complete.",
-          "currentProof": [],
-          "proofGap": "Needs pattern parsing, history storage, and match witness facts.",
-          "causalOpportunity": "Search history can cite reading basis and match ids.",
-          "echoBoundary": "Echo does not parse search patterns."
-        },
-        {
-          "id": "search.repeat-word",
-          "keys": ["n", "N", "*", "#", "g*", "g#"],
-          "status": "unsupported",
-          "targetSlices": [26],
-          "targetParity": "Repeat searches and search for word under cursor.",
-          "currentJedit": "Repeat and word-under-cursor search are not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs direction, token, and match identity rules.",
-          "causalOpportunity": "Search matches can feed later range commands.",
-          "echoBoundary": "Echo remains generic."
-        },
-        {
-          "id": "substitute.single-range",
-          "keys": [":s"],
-          "status": "unsupported",
-          "targetSlices": [27],
-          "targetParity": "Substitute within the current or specified range.",
-          "currentJedit": "Substitute command parity is not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs pattern/replacement parsing, flags, and escaping.",
-          "causalOpportunity": "Substitution can emit deterministic range-set facts.",
-          "echoBoundary": "Echo admits final replacement operations only."
-        },
-        {
-          "id": "substitute.file-confirm",
-          "keys": [":%s", "c"],
-          "status": "causally-enhanced",
-          "targetSlices": [27, 29],
-          "targetParity": "Run file-scope substitute with confirmation flow.",
-          "currentJedit": "File-scope confirmed substitute is not implemented.",
-          "currentProof": [],
-          "proofGap": "Planned as strand preview with selected admission.",
-          "causalOpportunity": "Each accepted replacement can be a strand slice.",
-          "echoBoundary": "Echo receives only admitted replacements."
-        },
-        {
-          "id": "global.vglobal",
-          "keys": [":g", ":v"],
-          "status": "causally-enhanced",
-          "targetSlices": [28, 29],
-          "targetParity": "Run commands over matching or non-matching line sets.",
-          "currentJedit": "Global and vglobal are not implemented.",
-          "currentProof": [],
-          "proofGap": "Planned range-set execution with unsupported nested-command obstruction.",
-          "causalOpportunity": "Global commands can preview a braid of affected ranges.",
-          "echoBoundary": "Echo does not evaluate ex syntax."
-        }
-      ]
-    },
-    {
-      "id": "exCommands",
-      "title": "Ex Commands",
-      "items": [
-        {
-          "id": "ex.edit",
-          "keys": [":edit", ":e"],
-          "status": "supported",
-          "targetSlices": [2],
-          "targetParity": "Open a path through command-line completion and dispatch.",
-          "currentJedit": "Command-line edit dispatch and file completion exist.",
-          "currentProof": [
-            "docs/design/0102-vim-command-line-completion-surface.md",
-            "spec/workspace-command-line.spec.mjs",
-            "spec/workspace-command-completion.spec.mjs"
-          ],
-          "proofGap": "",
-          "causalOpportunity": "Open can seed later workflow witnesses with basis facts.",
-          "echoBoundary": "Echo remains text authority after file material is opened."
-        },
-        {
-          "id": "ex.write-quit",
-          "keys": [":write", ":w", ":quit", ":q", ":wq", ":x"],
-          "status": "supported",
-          "targetSlices": [2],
-          "targetParity": "Save, quit, and save-then-quit from the Vim command line.",
-          "currentJedit": "Write, quit, wq, and aliases dispatch through existing workspace flows.",
-          "currentProof": [
-            "docs/design/0102-vim-command-line-completion-surface.md",
-            "spec/workspace-command-line.spec.mjs"
-          ],
-          "proofGap": "",
-          "causalOpportunity": "Save witnesses can cite final materialized text digest.",
-          "echoBoundary": "Filesystem save remains app/adapter policy, not Echo semantics."
-        },
-        {
-          "id": "ex.ranges",
-          "keys": [":1,10", ":%", ":.", ":'<,'>"],
-          "status": "unsupported",
-          "targetSlices": [28],
-          "targetParity": "Resolve ex ranges for later commands.",
-          "currentJedit": "General ex range grammar is not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs range parser and resolver over reading basis.",
-          "causalOpportunity": "Range resolution can feed strands and range-set witnesses.",
-          "echoBoundary": "Echo receives only admitted text operations."
-        },
-        {
-          "id": "ex.substitute-global",
-          "keys": [":s", ":%s", ":g", ":v"],
-          "status": "unsupported",
-          "targetSlices": [27, 28],
-          "targetParity": "Support substitute, global, and vglobal commands.",
-          "currentJedit": "These ex commands are not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs command parser, range-set executor, confirmation, and obstruction posture.",
-          "causalOpportunity": "Broad edits can be previewed and admitted as causal strands.",
-          "echoBoundary": "Echo does not parse ex commands."
-        },
-        {
-          "id": "ex.help-feedback",
-          "keys": [":help", "unknown-command"],
-          "status": "partial",
-          "targetSlices": [30],
-          "targetParity": "Expose command help and visible invalid-command feedback.",
-          "currentJedit": "Unknown command feedback exists; full help parity remains open.",
-          "currentProof": ["docs/design/0105-vim-power-moves-causal-parity.md#current-truth"],
-          "proofGap": "Needs complete help surface after commands stabilize.",
-          "causalOpportunity": "Help can expose proof status from this matrix.",
-          "echoBoundary": "Echo is not involved."
-        },
-        {
-          "id": "ex.shell-sort-filter",
-          "keys": [":!", ":r !", ":sort"],
-          "status": "unsupported",
-          "targetSlices": [28, 30],
-          "targetParity": "Handle shell, read-filter, and sort posture honestly.",
-          "currentJedit": "Shell/filter/sort ex commands are not implemented.",
-          "currentProof": [],
-          "proofGap": "Needs host-boundary policy and deterministic lower modes.",
-          "causalOpportunity": "Host effects should be isolated and reviewable before admission.",
-          "echoBoundary": "Echo never executes shell commands."
-        }
-      ]
-    }
-  ]
-}
diff --git a/docs/design/0105-vim-power-target-usability-fixtures.json b/docs/design/0105-vim-power-target-usability-fixtures.json
deleted file mode 100644
index 739de9f5..00000000
--- a/docs/design/0105-vim-power-target-usability-fixtures.json
+++ /dev/null
@@ -1,384 +0,0 @@
-{
-  "schemaVersion": 1,
-  "id": "wf-0105-vim-power-target-usability-fixtures",
-  "designDoc": "docs/design/0105-vim-power-moves-causal-parity.md",
-  "parityMatrix": "docs/design/0105-vim-power-moves-parity-matrix.json",
-  "owner": "jedit",
-  "futureCommandName": "jim",
-  "currentExecutionPosture": "target-fixtures-not-runtime-proof",
-  "fixtureSemantics": {
-    "humanTask": "Plain-language workflow the user should eventually be able to perform.",
-    "witness": "Structured target for a future deterministic agent-facing JSON witness.",
-    "matrixRows": "Parity matrix row ids exercised by the workflow.",
-    "expectedCurrentOutcome": "Honest current result before implementation catches up."
-  },
-  "workflows": [
-    {
-      "id": "open-edit-save-reopen",
-      "title": "Open, Edit, Save, Reopen",
-      "actor": "developer",
-      "humanTask": "Open jedit in a project, select a file through Vim command UX, edit text, save, quit, and verify the file on disk.",
-      "matrixRows": [
-        "ex.edit",
-        "ex.write-quit",
-        "motion.character",
-        "motion.line-boundary",
-        "motion.file-boundary"
-      ],
-      "expectedCurrentOutcome": "partially-supported",
-      "witness": {
-        "command": "node scripts/jedit-vim-power-witness.mjs --json --workflow open-edit-save-reopen",
-        "workspace": {
-          "cwd": "/tmp/jedit-vim-power/open-edit-save-reopen",
-          "files": [
-            {
-              "path": "main.txt",
-              "contents": "alpha\nbeta\n"
-            }
-          ]
-        },
-        "steps": [
-          {
-            "id": "launch",
-            "input": "jedit",
-            "expect": "title screen opens in the current working directory"
-          },
-          {
-            "id": "open-file",
-            "input": ":edit main.txt",
-            "expect": "main.txt opens and command completion can explain the selected path"
-          },
-          {
-            "id": "insert-text",
-            "input": "G0iabcdefghijklmnopqrstuvwxyz12343567890!@#$%^&*()_+-=[]'/\\\\.,",
-            "expect": "all inserted ASCII punctuation and numbers appear in the file buffer"
-          },
-          {
-            "id": "save-and-quit",
-            "input": ":wq",
-            "expect": "jedit saves the production text session to disk and exits cleanly"
-          },
-          {
-            "id": "verify-disk",
-            "input": "cat main.txt",
-            "expect": "the file contains the inserted text and original trailing content"
-          }
-        ],
-        "requiredFacts": [
-          "workflowId",
-          "openedPath",
-          "insertedTextDigest",
-          "saveReceiptId",
-          "finalDiskDigest"
-        ]
-      }
-    },
-    {
-      "id": "text-object-surgery",
-      "title": "Text Object Surgery",
-      "actor": "developer",
-      "humanTask": "Use familiar text-object edits like ci\", da(, gqap, >ip, yif, and p against source-shaped text.",
-      "matrixRows": [
-        "operator.delete-change-yank",
-        "operator.put",
-        "operator.indent-format",
-        "transaction.read-resolve-write",
-        "transaction.register-atomicity",
-        "text-object.quotes",
-        "text-object.brackets",
-        "text-object.sentence-paragraph",
-        "text-object.function-class"
-      ],
-      "expectedCurrentOutcome": "not-yet-supported",
-      "witness": {
-        "command": "node scripts/jedit-vim-power-witness.mjs --json --workflow text-object-surgery",
-        "workspace": {
-          "cwd": "/tmp/jedit-vim-power/text-object-surgery",
-          "files": [
-            {
-              "path": "sample.ts",
-              "contents": "function demo() {\n  const value = \"old\";\n  call(alpha, beta);\n}\n"
-            }
-          ]
-        },
-        "steps": [
-          {
-            "id": "change-quoted-string",
-            "input": "/oldci\"new",
-            "expect": "inside-quote range resolves and only the quoted payload changes"
-          },
-          {
-            "id": "delete-paren-call",
-            "input": "/callda(",
-            "expect": "around-parentheses range resolves with delimiters"
-          },
-          {
-            "id": "format-paragraph",
-            "input": "gqap",
-            "expect": "paragraph format either applies through provider proof or obstructs honestly"
-          },
-          {
-            "id": "indent-block",
-            "input": ">ip",
-            "expect": "paragraph or indentation range resolves as a linewise target"
-          },
-          {
-            "id": "yank-function-put",
-            "input": "yifGp",
-            "expect": "function object yanks with provenance and put inserts register material"
-          }
-        ],
-        "requiredFacts": [
-          "textObjectId",
-          "basisId",
-          "resolvedRange",
-          "operatorId",
-          "registerDigest",
-          "receiptIdOrObstruction"
-        ]
-      }
-    },
-    {
-      "id": "search-substitute-confirm",
-      "title": "Search, Substitute, Confirm",
-      "actor": "developer",
-      "humanTask": "Search through a file, repeat matches, and run a confirmed file-wide substitute that records accepted and rejected replacements.",
-      "matrixRows": [
-        "motion.search",
-        "search.pattern-history",
-        "search.repeat-word",
-        "substitute.single-range",
-        "substitute.file-confirm",
-        "ex.substitute-global"
-      ],
-      "expectedCurrentOutcome": "not-yet-supported",
-      "witness": {
-        "command": "node scripts/jedit-vim-power-witness.mjs --json --workflow search-substitute-confirm",
-        "workspace": {
-          "cwd": "/tmp/jedit-vim-power/search-substitute-confirm",
-          "files": [
-            {
-              "path": "story.txt",
-              "contents": "old one\nkeep old two\nold three\n"
-            }
-          ]
-        },
-        "steps": [
-          {
-            "id": "forward-search",
-            "input": "/old",
-            "expect": "first match gains a stable match id"
-          },
-          {
-            "id": "repeat-search",
-            "input": "nN",
-            "expect": "forward and backward repeats preserve search direction facts"
-          },
-          {
-            "id": "word-search",
-            "input": "*#",
-            "expect": "word-under-cursor search records token basis"
-          },
-          {
-            "id": "confirmed-substitute",
-            "input": ":%s/old/new/gcyny",
-            "expect": "accepted and rejected replacements are recorded deterministically"
-          }
-        ],
-        "requiredFacts": [
-          "searchPattern",
-          "matchIds",
-          "rangeSet",
-          "acceptedReplacementIds",
-          "rejectedReplacementIds",
-          "finalReadingId"
-        ]
-      }
-    },
-    {
-      "id": "macro-repeat-transform",
-      "title": "Macro And Dot Repeat Transform",
-      "actor": "developer",
-      "humanTask": "Record a macro, replay it on similar text, then use dot repeat as transformed semantic intent rather than raw key timing.",
-      "matrixRows": [
-        "macro.record",
-        "macro.replay",
-        "repeat.identity",
-        "repeat.transformed-replay",
-        "transaction.macro-script",
-        "transaction.read-resolve-write",
-        "operator.delete-change-yank",
-        "text-object.quotes"
-      ],
-      "expectedCurrentOutcome": "not-yet-supported",
-      "witness": {
-        "command": "node scripts/jedit-vim-power-witness.mjs --json --workflow macro-repeat-transform",
-        "workspace": {
-          "cwd": "/tmp/jedit-vim-power/macro-repeat-transform",
-          "files": [
-            {
-              "path": "config.txt",
-              "contents": "name = \"alpha\"\nname = \"beta\"\nname = \"gamma\"\n"
-            }
-          ]
-        },
-        "steps": [
-          {
-            "id": "record-macro",
-            "input": "qa/nameci\"deltaq",
-            "expect": "macro register a records parsed search and change intents"
-          },
-          {
-            "id": "replay-macro",
-            "input": "@a",
-            "expect": "macro replay applies through the production command path"
-          },
-          {
-            "id": "dot-repeat",
-            "input": "j.",
-            "expect": "dot repeat resolves the same inside-quote edit on a new basis"
-          },
-          {
-            "id": "obstruction-check",
-            "input": "j.",
-            "expect": "if no compatible target exists, replay stops with typed obstruction"
-          }
-        ],
-        "requiredFacts": [
-          "macroId",
-          "macroEntries",
-          "repeatIdentity",
-          "basisTransform",
-          "receiptIds",
-          "obstructedEntry"
-        ]
-      }
-    },
-    {
-      "id": "marks-jumps-causal-anchors",
-      "title": "Marks, Jumps, Causal Anchors",
-      "actor": "developer",
-      "humanTask": "Set marks, edit around them, jump back through marks and jump history, and inspect whether anchors moved or degraded honestly.",
-      "matrixRows": [
-        "marks.local-global",
-        "marks.jump",
-        "jumps.list",
-        "jumps.change-list",
-        "transaction.undo-redo",
-        "motion.file-boundary",
-        "operator.delete-change-yank"
-      ],
-      "expectedCurrentOutcome": "not-yet-supported",
-      "witness": {
-        "command": "node scripts/jedit-vim-power-witness.mjs --json --workflow marks-jumps-causal-anchors",
-        "workspace": {
-          "cwd": "/tmp/jedit-vim-power/marks-jumps-causal-anchors",
-          "files": [
-            {
-              "path": "anchors.txt",
-              "contents": "first\nanchor\nmiddle\nlast\n"
-            }
-          ]
-        },
-        "steps": [
-          {
-            "id": "set-mark",
-            "input": "/anchorma",
-            "expect": "mark a stores a transformable anchor at the match"
-          },
-          {
-            "id": "edit-before-mark",
-            "input": "ggOinserted",
-            "expect": "insert before the mark produces an edit receipt"
-          },
-          {
-            "id": "exact-jump",
-            "input": "`a",
-            "expect": "jump resolves to the transformed exact anchor"
-          },
-          {
-            "id": "jump-list",
-            "input": "GCtrl-oCtrl-i",
-            "expect": "jump list traversal exposes navigation facts"
-          },
-          {
-            "id": "change-list",
-            "input": "g;g,",
-            "expect": "change traversal uses edit receipt anchors or reports unavailable"
-          }
-        ],
-        "requiredFacts": [
-          "markId",
-          "anchorBias",
-          "sourceReceiptId",
-          "transformedCoordinate",
-          "jumpListState",
-          "degradedReason"
-        ]
-      }
-    },
-    {
-      "id": "causal-strand-preview",
-      "title": "Causal Strand Preview",
-      "actor": "developer",
-      "humanTask": "Preview a broad edit as a causal strand, compare alternatives as a braid, admit selected slices, and verify the final reading.",
-      "matrixRows": [
-        "operator.indent-format",
-        "operator.filter-range-command",
-        "substitute.file-confirm",
-        "global.vglobal",
-        "ex.ranges",
-        "ex.substitute-global"
-      ],
-      "expectedCurrentOutcome": "not-yet-supported",
-      "witness": {
-        "command": "node scripts/jedit-vim-power-witness.mjs --json --workflow causal-strand-preview",
-        "workspace": {
-          "cwd": "/tmp/jedit-vim-power/causal-strand-preview",
-          "files": [
-            {
-              "path": "preview.txt",
-              "contents": "alpha old\nbeta old\ngamma old\n"
-            }
-          ]
-        },
-        "steps": [
-          {
-            "id": "build-range-set",
-            "input": ":%s/old/new/gc",
-            "expect": "candidate replacements become a preview range set"
-          },
-          {
-            "id": "show-strand",
-            "input": "",
-            "expect": "preview reports strand id, basis id, and proposed head digest"
-          },
-          {
-            "id": "compare-braid",
-            "input": "",
-            "expect": "alternate proposal appears as a braid fact, not as applied text"
-          },
-          {
-            "id": "admit-slices",
-            "input": "",
-            "expect": "selected slices admit through the production text session"
-          },
-          {
-            "id": "verify-final-reading",
-            "input": "",
-            "expect": "final reading contains only admitted replacements"
-          }
-        ],
-        "requiredFacts": [
-          "strandId",
-          "braidId",
-          "basisId",
-          "candidateRangeSet",
-          "admittedSliceIds",
-          "receiptIds",
-          "finalReadingDigest"
-        ]
-      }
-    }
-  ]
-}
diff --git a/docs/design/0105-vim-target-usability-tests.md b/docs/design/0105-vim-target-usability-tests.md
deleted file mode 100644
index c4a26f86..00000000
--- a/docs/design/0105-vim-target-usability-tests.md
+++ /dev/null
@@ -1,606 +0,0 @@
----
-title: "WF-0105 - Vim Target Usability Tests"
-legend: "WF"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/107"
-status: "target"
-owners:
-  - "@flyingrobots"
-created: "2026-06-08"
-updated: "2026-06-09"
----
-
-# WF-0105 - Vim Target Usability Tests
-
-## Purpose
-
-This document defines target usability tests for common Vim workflows in
-Jedit. These are user-facing end-to-end contracts, not claims that every
-workflow is already automated or passing.
-
-The target is intentionally stricter than component tests. A workflow passes
-only when a user can drive the real Jedit interaction surface and the repo can
-prove the result through inspectable facts such as screen state, mode state,
-Echo-hosted production text evidence, filesystem contents, or process exit
-status.
-
-The workflows extend the Vim command-line completion surface in
-[`0102-vim-command-line-completion-surface.md`](0102-vim-command-line-completion-surface.md)
-and should become part of the "powered by Echo" release-candidate bar when the
-automation harness can drive the production TUI reliably.
-
-## Test Authority
-
-Target usability tests use this authority order:
-
-1. User-visible Jedit behavior.
-2. Echo-hosted production text session facts.
-3. Filesystem facts observed outside Jedit.
-4. Mode, command-line, completion, and error state facts.
-5. Component or fixture specs.
-
-Component specs can prove a renderer, parser, or provider in isolation. They
-cannot by themselves prove a target usability workflow.
-
-## Harness Contract
-
-Every automated target test should:
-
-- Start in a real temporary workspace directory.
-- Invoke the production Jedit entrypoint from that directory.
-- Drive the same keyboard interactions a user would use.
-- Use the production Vim command-line surface for Vim command workflows.
-- Use the production Echo-hosted text runtime, not a direct local text fallback.
-- Verify saved file bytes from outside Jedit with ordinary filesystem reads.
-- Record the active mode, command input, focused completion, opened file path,
-  dirty state, save result, and any Echo obstruction posture.
-- Fail closed when a workflow is unsupported instead of passing through a fake
-  helper.
-
-The harness may inspect structured model facts when available. Pixel or glyph
-matching is acceptable only as supporting evidence for screen layout; it should
-not be the only proof of text authority, save behavior, or command dispatch.
-
-## Current Lower-Level Anchors
-
-The target workflows are expected to compose existing proof surfaces rather
-than replace them:
-
-- `spec/workspace-command-line.spec.mjs`
-- `spec/workspace-command-completion.spec.mjs`
-- `spec/inline-completion-popup.spec.mjs`
-- `spec/workspace-text-cutover.spec.mjs`
-- `spec/production-text-session-witness.spec.mjs`
-- `scripts/jedit-production-text-session.mjs`
-- `scripts/jedit-echo-release-gate.mjs`
-
-Those anchors prove important slices of the product. The missing bar is a
-human-shaped, full-session witness that starts from `jedit`, performs a common
-Vim workflow, exits, and verifies disk output.
-
-## Workflow I - Open, Edit, Save, Quit
-
-User:
-
-A developer working on source code.
-
-Setup:
-
-```sh
-workspace="$(mktemp -d)"
-printf 'before\n' > "$workspace/example.txt"
-cd "$workspace"
-```
-
-Task:
-
-1. Run `jedit`.
-2. Arrive at the Jedit title screen for the current working directory.
-3. Press `:` and see the Vim command-line completion UX appear.
-4. Type `edit`.
-5. Press Enter or Tab to accept the highlighted `edit` command completion.
-6. Observe that command mode remains active with `:edit` followed by a space in
-   the command line and file completions visible.
-7. Type `exam`.
-8. Observe the file-completion list narrow to `example.txt`.
-9. Press Tab to accept the highlighted `example.txt` completion, leaving
-   `:edit example.txt` in the command line.
-10. Press Enter to dispatch `:edit example.txt`.
-11. Observe that Jedit opens the file and displays its contents.
-12. Use Normal-mode Vim navigation commands such as `G`, `gg`, and `0`, ending
-    with the cursor on the first byte of the file.
-13. Press `i` to enter Insert mode at the first byte.
-14. Type the payload below and see every character appear in the document:
-
-    ```text
-    abcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()_+-=[]'/\.,
-    ```
-
-15. Press Escape to return to Normal mode.
-16. Press `:` to open the Vim command-line surface again.
-17. Type `wq` and press Enter.
-18. Observe that Jedit saves the file and exits cleanly.
-19. Run `cat example.txt`.
-
-Expected result:
-
-- The title screen accepts `:` even when no file is open.
-- The completion popup stays anchored to the original command-line cursor
-  position while the user types.
-- Accepting the `edit` command completion inserts `edit`, appends one command
-  separator space, and switches the provider phase to file completions without
-  leaving command mode.
-- Enter and Tab can accept the highlighted completion.
-- `:edit example.txt` opens the file through the production text path.
-- Insert mode accepts the full punctuation-heavy payload.
-- Escape leaves Insert mode without losing the typed payload.
-- `:wq` saves through the production save path and exits.
-- `cat example.txt` exactly matches:
-
-  ```text
-  abcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()_+-=[]'/\.,before
-  ```
-
-  The final byte is the newline from the original file.
-
-Required proof:
-
-- TUI session transcript or structured event witness for the command sequence.
-- Mode transition evidence: title, command line, Normal, Insert, Normal,
-  command line, exited.
-- Echo-hosted production text evidence for open, insert, read, save, and
-  checkpoint or explicit obstruction when checkpoint evidence is not yet
-  available.
-- Filesystem read after exit showing byte-for-byte equality with the expected
-  final file.
-
-Current status:
-
-Target. Lower-level command-line, completion, and production text witnesses
-exist, but this exact full-session workflow should become an automated
-usability witness.
-
-## Workflow II - Open By Path, Navigate, Quit Without Save
-
-User:
-
-A developer inspecting a file without intending to edit it.
-
-Setup:
-
-```sh
-workspace="$(mktemp -d)"
-mkdir -p "$workspace/src"
-printf 'one\ntwo\nthree\n' > "$workspace/src/readme.txt"
-cd "$workspace"
-```
-
-Task:
-
-1. Run `jedit src/readme.txt`.
-2. Observe that Jedit opens the file instead of stopping at a file picker.
-3. Use Normal-mode movement commands such as `j`, `k`, `h`, `l`, `gg`, and
-   `G`.
-4. Press `:` and type `q`.
-5. Press Enter.
-
-Expected result:
-
-- The file argument resolves relative to the launch directory.
-- Jedit displays the file in Normal mode.
-- Movement commands update cursor or viewport facts without mutating text.
-- `:q` exits cleanly when the buffer is not dirty.
-- The file bytes are unchanged after exit.
-
-Required proof:
-
-- Process invocation record with the file argument.
-- Opened-file evidence for `src/readme.txt`.
-- Cursor or viewport movement facts.
-- Filesystem read after exit matching the original file exactly.
-
-Current status:
-
-Target. If direct path launch is not currently implemented, the test should
-fail as unsupported and feed the path-open backlog.
-
-## Workflow III - Save Without Quitting
-
-User:
-
-A developer incrementally saving while continuing to edit.
-
-Setup:
-
-```sh
-workspace="$(mktemp -d)"
-printf 'alpha\n' > "$workspace/notes.txt"
-cd "$workspace"
-```
-
-Task:
-
-1. Run `jedit`.
-2. Use `:edit notes.txt` to open the file.
-3. Enter Insert mode with `i`.
-4. Type one leading space followed by `beta`.
-5. Press Escape.
-6. Press `:` and type `write`.
-7. Press Enter.
-8. Continue editing in the still-open Jedit session.
-9. Inspect `notes.txt` from outside the process if the harness supports a
-   concurrent filesystem read, or exit with `:q` and then read the file.
-
-Expected result:
-
-- `:write` and `:w` both save the active file.
-- The command leaves Jedit open.
-- Dirty state clears after a successful save.
-- The active buffer remains focused in Normal mode.
-- The saved file includes a leading space followed by `beta`.
-
-Required proof:
-
-- Command dispatch evidence for canonical `write` or alias `w`.
-- Dirty-state transition from dirty to clean.
-- Filesystem read showing the saved material.
-- Evidence that Jedit remained running immediately after save.
-
-Current status:
-
-Partially covered by lower-level command dispatch and production save tests.
-The full user workflow remains a target witness.
-
-## Workflow IV - Insert, Delete, Change, Save
-
-User:
-
-A developer making ordinary line and word edits.
-
-Setup:
-
-```sh
-workspace="$(mktemp -d)"
-printf 'first line\nsecond word\nthird line\n' > "$workspace/edit.txt"
-cd "$workspace"
-```
-
-Task:
-
-1. Run `jedit`.
-2. Open `edit.txt` with `:edit`.
-3. Use Normal-mode navigation to reach `second word`.
-4. Use a Vim-shaped edit command to change text, such as `cwreplacement`.
-5. Press Escape to leave Insert mode after the replacement.
-6. Navigate to a different line with Normal-mode movement.
-7. Use a line edit command such as `dd`.
-8. Save with `:w`.
-9. Quit with `:q`.
-
-Expected result:
-
-- Vim-shaped text commands mutate production text through Jedit's command
-  planner and Echo-hosted session.
-- The mode sequence is Normal, pending/change command, Insert, Normal, line
-  delete, command line.
-- Cursor, selection, and pending command state remain Jedit-owned UI policy.
-- Save materializes the edited state to disk.
-- Deleted or changed text is absent from the final file.
-
-Required proof:
-
-- Normal-mode command transcript.
-- Echo-hosted production text receipts or equivalent app-safe evidence for the
-  mutations.
-- Final filesystem contents matching the expected edited text.
-
-Current status:
-
-Target. This workflow should stay blocked until the relevant Normal-mode Vim
-operators are production-grade; it must not pass through direct fixture edits.
-
-## Workflow V - Command Completion File Search
-
-User:
-
-A developer opening files by fuzzy searching from the Vim command surface.
-
-Setup:
-
-```sh
-workspace="$(mktemp -d)"
-mkdir -p "$workspace/src/app" "$workspace/docs"
-printf 'component\n' > "$workspace/src/app/component.ts"
-printf 'guide\n' > "$workspace/docs/guide.md"
-cd "$workspace"
-```
-
-Task:
-
-1. Run `jedit`.
-2. Press `:`.
-3. Type `edit`.
-4. Accept the command completion.
-5. Type the path prefix `src/app/comp`.
-6. Observe the file-completion list narrow to `src/app/component.ts`.
-7. Press Tab to accept the highlighted `src/app/component.ts` completion.
-8. Observe that the command line contains `:edit src/app/component.ts`.
-9. Press Enter to dispatch `:edit src/app/component.ts`.
-10. Observe that Jedit opens `src/app/component.ts`.
-
-Expected result:
-
-- The same popup handles command completions and file completions.
-- Accepting `edit` leaves command mode active and inserts `edit` followed by
-  one space.
-- File completions repopulate after the command is accepted.
-- Enter and Tab both accept the highlighted completion.
-- Accepting a file completion completes command input; the following Enter
-  dispatches `:edit src/app/component.ts`.
-- The suggestion list remains pinned to the original command-line anchor while
-  the user types.
-- The startup file picker or drawer does not consume Tab or Enter while command
-  mode is active.
-
-Required proof:
-
-- Completion provider facts for command and file provider phases.
-- Anchor coordinate evidence before and after typing.
-- Accepted completion evidence for command and file items.
-- Command-dispatch evidence after file-completion acceptance.
-- Opened-file evidence for `src/app/component.ts`.
-
-Current status:
-
-Partially covered by command-completion specs. Full end-to-end title-screen
-file search remains a target witness.
-
-## Workflow VI - Invalid Command Feedback And Recovery
-
-User:
-
-A developer who mistypes a command and needs actionable feedback.
-
-Setup:
-
-```sh
-workspace="$(mktemp -d)"
-printf 'content\n' > "$workspace/file.txt"
-cd "$workspace"
-```
-
-Task:
-
-1. Run `jedit`.
-2. Press `:`.
-3. Type `exi`.
-4. Observe inline invalid-command feedback.
-5. Correct the command to `edit file.txt`, or press Escape and start over.
-6. Open the file successfully.
-
-Expected result:
-
-- Unknown command fragments use the theme error or warning token.
-- The command surface shows a readable hint such as
-  `Command not recognized; type :help for help`.
-- Invalid feedback is visible on the title screen and in an open editor.
-- The invalid state does not trap the user.
-- Correcting or cancelling the command restores normal completion behavior.
-
-Required proof:
-
-- Command parse state with invalid-command posture.
-- Render or model evidence for error styling and help text.
-- Follow-up successful `:edit` evidence in the same session.
-
-Current status:
-
-Partially covered by lower-level invalid-command specs. The title-screen
-visibility regression should be covered by an end-to-end target witness.
-
-## Workflow VII - Dirty Quit Obstruction
-
-User:
-
-A developer who tries to quit after making unsaved changes.
-
-Setup:
-
-```sh
-workspace="$(mktemp -d)"
-printf 'draft\n' > "$workspace/draft.txt"
-cd "$workspace"
-```
-
-Task:
-
-1. Run `jedit`.
-2. Open `draft.txt` with `:edit`.
-3. Enter Insert mode and type one leading space followed by `unsaved`.
-4. Press Escape.
-5. Run `:q`.
-6. Observe a clear dirty-buffer obstruction.
-7. Run `:wq`.
-
-Expected result:
-
-- `:q` refuses to exit when the active file is dirty.
-- The obstruction names the dirty file or active buffer.
-- The user can recover by saving, cancelling, or using an explicit future
-  force-quit command if one is intentionally supported.
-- `:wq` saves and exits.
-- Final disk contents include a leading space followed by `unsaved`.
-
-Required proof:
-
-- Dirty-state evidence before `:q`.
-- Obstruction evidence for failed quit.
-- Successful save and exit evidence for `:wq`.
-- Filesystem read after exit.
-
-Current status:
-
-Target.
-
-## Workflow VIII - Unsupported File Is Honest
-
-User:
-
-A developer accidentally opening a binary or unsupported file.
-
-Setup:
-
-```sh
-workspace="$(mktemp -d)"
-printf '\000\001\002' > "$workspace/blob.bin"
-cd "$workspace"
-```
-
-Task:
-
-1. Run `jedit`.
-2. Use `:edit blob.bin`.
-3. Observe an honest unsupported or read-only posture.
-4. Press `i` to attempt Insert mode.
-5. Type `abc`.
-6. Observe that Jedit refuses mutation through a read-only or unsupported-file
-   obstruction.
-7. Press Escape if the command surface requires an explicit return to Normal
-   mode.
-8. Quit.
-9. Read `blob.bin` from disk.
-
-Expected result:
-
-- Jedit does not pretend binary bytes are safely editable text.
-- Unsupported text materialization is surfaced as an obstruction.
-- The explicit Insert-mode typing attempt cannot corrupt the file.
-- The original bytes remain unchanged after quit.
-
-Required proof:
-
-- File-open obstruction or read-only posture.
-- Input transcript for the `iabc` typing attempt and the resulting obstruction.
-- No production text mutation receipts for the unsupported file.
-- Byte-for-byte filesystem comparison after exit.
-
-Current status:
-
-Target.
-
-## Workflow IX - Restart Recovery
-
-User:
-
-A developer expecting recent Echo-backed editing history to survive process
-restart.
-
-Setup:
-
-```sh
-workspace="$(mktemp -d)"
-printf 'seed\n' > "$workspace/recover.txt"
-cd "$workspace"
-```
-
-Task:
-
-1. Run `jedit`.
-2. Open `recover.txt`.
-3. Insert one leading space followed by `durable`.
-4. Save or checkpoint according to the current product rule.
-5. Exit or terminate the process at a documented recovery point.
-6. Run `jedit` again in the same workspace.
-7. Observe recovered Echo-backed history or a typed obstruction that explains
-   why recovery is unavailable.
-
-Expected result:
-
-- Recovered state comes from Echo/WSC history posture, not stale process memory.
-- Jedit does not silently invent a recovered buffer.
-- The user can materialize and save/export the recovered state when recovery
-  evidence is complete.
-- Missing or incomplete Echo evidence is visible and auditable.
-
-Required proof:
-
-- WSC or Echo-history evidence for the original edit.
-- Restart witness from a fresh process.
-- Recovery posture facts.
-- Final export or obstruction evidence.
-
-Current status:
-
-Target. This workflow should compose the powered-by-Echo WSC durability and
-replay slices.
-
-## Workflow X - Multi-File Edit Session
-
-User:
-
-A developer editing related files without restarting Jedit.
-
-Setup:
-
-```sh
-workspace="$(mktemp -d)"
-printf 'left\n' > "$workspace/a.txt"
-printf 'right\n' > "$workspace/b.txt"
-cd "$workspace"
-```
-
-Task:
-
-1. Run `jedit`.
-2. Open `a.txt` with `:edit`.
-3. Insert one leading space followed by `A` and save.
-4. Open `b.txt` with `:edit`.
-5. Insert one leading space followed by `B` and save.
-6. Return to `a.txt` through the intended buffer or file workflow.
-7. Quit.
-8. Read both files from disk.
-
-Expected result:
-
-- Each open file has distinct production text authority.
-- Saving one file does not materialize the other file accidentally.
-- Dirty state is tracked per active buffer or explicitly documented as a
-  single-buffer limitation.
-- Final filesystem contents show the correct edit in each file.
-
-Required proof:
-
-- Multi-buffer authority map or explicit single-buffer obstruction.
-- Distinct file-path save evidence for each file.
-- Filesystem reads for both files.
-
-Current status:
-
-Target. If Jedit is still intentionally single-buffer, this workflow should
-fail with an honest obstruction rather than pretending multi-file authority
-exists.
-
-## Release-Candidate Interpretation
-
-These target usability tests are not all required for the next small PR, but
-they define the shape of "Jedit feels like a real Vim-shaped editor powered by
-Echo." The release-candidate gate should include at least:
-
-- Workflow I for the happy path.
-- Workflow VI for invalid command recovery.
-- Workflow VII for dirty quit behavior.
-- One Echo/WSC restart or export workflow when durability is in scope.
-
-The remaining workflows can graduate into the release gate as their underlying
-features become product commitments.
-
-## Non-Negotiables
-
-- Do not satisfy these workflows with direct model mutation helpers.
-- Do not bypass the production Vim command-line surface for command workflows.
-- Do not bypass the production Echo-hosted text session for text authority.
-- Do not claim save success without a filesystem read outside Jedit.
-- Do not treat screenshots as the only proof of command dispatch, save, or
-  recovery.
-- Do not hide unsupported behavior behind a passing fixture. A typed
-  obstruction is better than fake success.
diff --git a/docs/design/0106-emacs-ideas-to-steal-causally.md b/docs/design/0106-emacs-ideas-to-steal-causally.md
deleted file mode 100644
index 12bf9b28..00000000
--- a/docs/design/0106-emacs-ideas-to-steal-causally.md
+++ /dev/null
@@ -1,364 +0,0 @@
----
-title: "WF-0106 - Emacs Ideas To Steal Causally"
-legend: "WF"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/192"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-06-09"
-updated: "2026-06-29"
----
-
-# WF-0106 - Emacs Ideas To Steal Causally
-
-## Linked Issue
-
-- [#192 WF-0106: Emacs ideas to steal causally](https://github.com/flyingrobots/jedit/issues/192)
-- Milestone: [WF-0106 - Emacs Ideas To Steal Causally](https://github.com/flyingrobots/jedit/milestone/3)
-
-## Decision Summary
-
-Jim should keep Vim as the editing grammar, but steal selected Emacs ideas as
-causal affordances around that grammar: command discovery, self-documentation,
-buffer and mode surfaces, kill-ring-like register history, programmable command
-composition, macros, and project tools. Each borrowed idea must become
-strand-aware, braid-aware, and evidence-bearing instead of becoming hidden
-mutable editor state.
-
-## Sponsored Human
-
-A modal editor user wants the discoverability and programmable workspace power
-associated with Emacs so that Jim can grow beyond raw Vim key parity, without
-losing Vim's compact command language or Echo's causal truth.
-
-## Sponsored Agent
-
-An agent needs command, buffer, mode, register, macro, and strand facts so it can
-inspect and exercise advanced editor behavior through stable JSON and witness
-surfaces, without scraping visual-only menus or guessing hidden editor state.
-
-## Hill
-
-By the end of this exploration, Jim has a prioritized idea map for Emacs-like
-features, and every accepted idea states its causal representation, proof
-surface, failure posture, and relationship to the WF-0105 Vim grammar.
-
-## Current Truth
-
-WF-0105 is the active power-moves plan:
-
-- [0105 Vim Power Moves Causal Parity](0105-vim-power-moves-causal-parity.md)
-- [0105 Vim Power Moves Parity Matrix](0105-vim-power-moves-parity-matrix.json)
-- [0105 Vim Power Target Usability Fixtures](0105-vim-power-target-usability-fixtures.json)
-
-That plan intentionally centers Vim's modal command grammar. It also names
-causal enhancements such as strand preview, braid comparison, receipt-bearing
-macros, causal registers, causal marks, and transformed repeat. This document
-does not replace that plan. It gives Jim a way to borrow the useful Emacs
-surface area without turning Echo into an editor-specific runtime.
-
-## Problem
-
-Vim gives Jim a powerful editing language, but Vim alone does not solve every
-editor workflow:
-
-- users need discoverability before grammar fluency forms;
-- agents need command metadata rather than terminal-only clues;
-- large projects need buffer, mode, diagnostics, and task surfaces;
-- repeated transformations need macro and script inspection;
-- causal strands need a product surface that is not Git, not worktrees, and not
-  a hidden local undo stack.
-
-Emacs is strong in these areas, but classic Emacs also carries a lot of hidden
-mutable process state. Jim should steal the product shape, not the mutability
-model.
-
-## Scope
-
-This exploration includes:
-
-- Emacs-style command discovery and self-documentation.
-- Buffer and mode concepts as jedit-owned app state.
-- Kill-ring lessons for causal registers.
-- Keyboard macro and command-script lessons.
-- Project and diagnostic surfaces inspired by Emacs packages.
-- Debugging surfaces inspired by GUD, Edebug, and compilation buffers.
-- Causal strand and braid opportunities attached to each idea.
-
-## Non-Goals
-
-This exploration does not include:
-
-- Implementing Emacs keybindings.
-- Embedding Emacs Lisp.
-- Replacing Vim grammar with Emacs command chords.
-- Teaching Echo about editors, Vim, Emacs, buffers, or projects.
-- Designing a full plugin runtime.
-- Claiming runtime support before witnesses exist.
-- Claiming deterministic time-travel debugging for arbitrary non-Echo programs.
-
-## Causal Borrowing Rule
-
-An Emacs idea is eligible only if it can answer:
-
-1. What is the user-facing capability?
-2. What is the jedit-owned semantic model?
-3. What Echo evidence, receipt, retained material, or basis supports it?
-4. How does it preview, fork, braid, admit, obstruct, or replay?
-5. What JSON or CLI witness can prove the behavior?
-
-If the answer is "local mutable editor state," the idea is not ready.
-
-## Priority Set
-
-The first serious candidates are ordered by how much command truth they unlock:
-
-| Priority | Feature | Tracking issue | Why first |
-| --- | --- | --- | --- |
-| 1 | Command catalog and describe surfaces | [#183](https://github.com/flyingrobots/jedit/issues/183) | Enables discovery, docs, prefix help, agents, and later mode tooling. |
-| 2 | Prefix help and describe-key | [#184](https://github.com/flyingrobots/jedit/issues/184) | Makes Vim grammar legible without diluting modal editing. |
-| 3 | Register history / causal kill ring | [#185](https://github.com/flyingrobots/jedit/issues/185) | Bridges Vim registers and Emacs kill-ring behavior through provenance. |
-| 4 | Semantic macros | [#187](https://github.com/flyingrobots/jedit/issues/187) | Turns replay into accountable causal scripts instead of raw key ghosts. |
-| 5 | Buffer and mode reports | [#186](https://github.com/flyingrobots/jedit/issues/186) | Gives workspace power without hidden mutable state. |
-| 6 | Compilation / diagnostics buffer | [#188](https://github.com/flyingrobots/jedit/issues/188) | Adds practical build/test workflow with anchors and replay posture. |
-| 7 | Debug trace buffer | [#189](https://github.com/flyingrobots/jedit/issues/189) | Becomes a differentiator after transcript honesty exists. |
-| 8 | Dired-style host operations | [#190](https://github.com/flyingrobots/jedit/issues/190) | Useful host surface, but lower priority than local command truth. |
-
-The command catalog schema and register provenance schema should land early
-because they force honesty across describe surfaces, prefix help, `:why`,
-macros, diagnostics, and agent witnesses.
-
-## Ideas To Steal
-
-- `M-x` command execution: steal discoverable named commands. In Jim, command
-  palette execution emits typed `JimCommandIntent` facts with effect class,
-  basis needs, preview policy, and replay posture. First proof: JSON command
-  catalog lists effect class and supported lower mode.
-- `describe-key`: steal key explanation. In Jim, a chord inspector parses the
-  active key prefix and reports possible Vim grammar continuations plus causal
-  consequences. First proof: `di"` reports operator, text object, register,
-  basis, and obstruction policy.
-- `describe-function`: steal command contract docs. In Jim, command docs are
-  generated from command metadata, including Echo boundary and proof commands.
-  First proof: static spec checks every public command has metadata.
-- Which-key-like prefix help: steal legal-next-key guidance. In Jim, prefix help
-  reads the same grammar table as execution and never invents UI-only shortcuts.
-  First proof: `d` prefix lists motions/text objects without mutating text.
-- Buffers: steal multiple work surfaces. In Jim, buffer identity is jedit state
-  over Echo-backed text heads, readings, and export targets. First proof: agent
-  lists buffers with basis, dirty posture, and retained reading refs.
-- Major modes: steal file/domain behavior. In Jim, modes are app-owned command,
-  filter, and highlight packs over readings, not Echo behavior. First proof:
-  mode report says which commands are enabled and why.
-- Minor modes: steal optional behavior toggles. In Jim, minor modes are explicit
-  capability toggles with command metadata deltas and receipt-visible effects
-  when they mutate. First proof: toggle witness records mode transition and
-  affected command catalog rows.
-- Kill ring: steal killed/yanked text history. In Jim, registers gain ring
-  posture: each entry carries shape, source basis, range set, digest, retained
-  material ref, and producing receipt. First proof: register witness cycles
-  entries and proves provenance.
-- Keyboard macros: steal record and replay culture. In Jim, macros are causal
-  scripts of parsed semantic commands plus bounded raw insert spans, and replay
-  stops on typed obstruction. First proof: replay witness reports applied count,
-  receipts, and obstruction entry.
-- Undo tree: steal edit alternative navigation. In Jim, undo/redo are explicit
-  inverse causal inputs; alternate edits are strands, not hidden snapshots.
-  First proof: witness previews two heads and braids selected intent.
-- Dired: steal file operations as an editor surface. In Jim, file browser
-  commands emit explicit filesystem intents with preview, confirmation, and
-  host-bound proof. First proof: dry-run file command witness shows planned host
-  operations.
-- Magit: steal structured VCS control. In Jim, future VCS UI should be a causal
-  strand/braid dashboard, not a shell wrapper. First proof is deferred until Jim
-  has local strand views.
-- Org mode: steal structured documents and tasks. In Jim, Graft-backed
-  structural text objects expose headings, blocks, TODO states, and ranges as
-  causal anchors. First proof: structural text-object witness resolves heading
-  range on a reading basis.
-- Compilation buffer: steal navigable build/test diagnostics. In Jim, command
-  output becomes a diagnostic buffer with links to command, workspace basis, and
-  file anchors. First proof: witness stores diagnostics and jumps by anchor.
-- GUD and Edebug: steal debugger-in-editor ergonomics. In Jim, debugger events
-  become causal trace entries with source anchors, process facts, breakpoints,
-  and command receipts. First proof: debug trace witness can step through a
-  recorded session and jump to source anchors.
-- REPL integration: steal interactive process transcripts. In Jim, REPL
-  sessions are external process facts with input/output transcripts, not Echo
-  execution authority. First proof: transcript witness records command, output,
-  and linked buffer basis.
-
-## Product Shape
-
-Jim should feel like:
-
-```text
-Vim for editing grammar.
-Emacs for discoverability and programmable workspace surfaces.
-Echo for strands, braids, receipts, and durable causality.
-```
-
-The user does not need to think in Git branches or worktrees. Broad edits,
-macros, search replacements, and agent suggestions become previewable strands.
-The user can compare alternatives as braids and admit the useful slices into the
-current worldline.
-
-## Debugging DX
-
-Jim can become a strong debugging surface because Echo already makes causality a
-first-class product concept. The near-term goal is a small warp-time-travel-like
-debugger for Echo-backed behavior: browse submissions, readings, receipts,
-obstructions, retained evidence, and basis changes from inside the editor.
-
-The broader opportunity is debugging non-Echo systems with causal recording.
-That must be honest about replay levels:
-
-| Level | Name | Contract |
-| --- | --- | --- |
-| 0 | Trace inspection | Jim records events, output, logs, anchors, and commands for navigation only. |
-| 1 | Deterministic rerun | Jim reruns a command under a recorded environment and compares outputs. |
-| 2 | Adapter replay | Jim replays recorded IO through explicit mocks or adapters. |
-| 3 | Runtime TTD | Jim controls checkpoints, stepping, and reversal only when the runtime supports it. |
-
-For non-Echo programs, Jim should start at levels 0 and 1. Transcript replay is
-not the same as deterministic time travel. A non-Echo debug trace should carry:
-
-- command line and working directory;
-- environment digest and selected materialized environment fields;
-- input stream chunks and output stream chunks;
-- process exit facts;
-- source anchors for diagnostics, stack frames, and breakpoints;
-- wall-clock timing as diagnostic metadata only;
-- content hashes for artifacts read or produced during the run;
-- a replay posture: inspect-only, rerunnable, adapter-replayable, or TTD.
-
-The editor payoff is high: a user can jump from a failing test to source, inspect
-the causal trace that produced the failure, run a patch as a strand, compare the
-new trace as a braid, and admit only the useful edit slices. For Echo-backed
-systems, Jim can go deeper by showing actual Echo receipts and bases. For
-non-Echo systems, Jim still provides an honest causal wrapper around what was
-observed and what can be replayed.
-
-## Runtime / API Contract Sketch
-
-```text
-JimCommandCatalog = {
-  commands: JimCommandDescriptor[]
-}
-
-JimCommandDescriptor = {
-  id: string,
-  names: string[],
-  keyForms: string[],
-  effect: "readOnly" | "navigation" | "textMutation" | "appState" | "hostEffect",
-  vimGrammar?: VimGrammarShape,
-  modeScope: string[],
-  basisPolicy: "none" | "readingRequired" | "transactionRequired",
-  previewPolicy: "none" | "available" | "required",
-  replayPolicy: "notReplayable" | "semanticReplay" | "rawSpanReplay",
-  proof: string[]
-}
-```
-
-Command discovery and prefix help must consume this catalog. Runtime execution
-must still go through the WF-0105 Vim grammar and jedit-owned command ports.
-
-## Strand And Braid Opportunities
-
-| Workflow | Strand opportunity | Braid opportunity |
-| --- | --- | --- |
-| `:%s/foo/bar/g` | Preview all replacements before admission. | Admit only selected replacement rows. |
-| Macro replay | Run replay as a provisional strand. | Compare replay over old basis and transformed basis. |
-| Register paste | Paste retained material as a causal insertion intent. | Compare multiple register entries before admission. |
-| Project rename | Model rename as broad preview strand. | Braid accepted file/range slices into current work. |
-| Agent suggestion | Treat suggestion as external strand with evidence. | Compare human and agent edits without checkout. |
-| Format buffer | Preview formatter output as one strand. | Admit chunks rather than the whole formatter result. |
-| Build fix loop | Diagnostics become causal anchors. | Braid fixes that satisfy diagnostics into current head. |
-| Debug trace | Record observed execution as a causal trace. | Compare failing and fixed traces as a braid. |
-
-## Tracked Slices
-
-| Issue | Slice | First proof |
-| --- | --- | --- |
-| [#182](https://github.com/flyingrobots/jedit/issues/182) | Lock WF-0106 feature packet and issue links | This doc names priorities, tracking issues, and execution order. |
-| [#183](https://github.com/flyingrobots/jedit/issues/183) | Add Jim command catalog schema and witness | `jedit-command-catalog-witness` emits stable JSON metadata. |
-| [#184](https://github.com/flyingrobots/jedit/issues/184) | Add describe command, describe-key, and prefix help | Prefix help consumes the execution grammar, not a shadow table. |
-| [#185](https://github.com/flyingrobots/jedit/issues/185) | Add causal register history and kill-ring posture | Register entries retain source basis, range, digest, and command refs. |
-| [#186](https://github.com/flyingrobots/jedit/issues/186) | Add buffer and mode reports | Reports expose basis, dirty posture, mode packs, and command deltas. |
-| [#187](https://github.com/flyingrobots/jedit/issues/187) | Add semantic macro scripts and replay reports | Replay reports applied count, receipts, and first obstruction. |
-| [#188](https://github.com/flyingrobots/jedit/issues/188) | Add compilation diagnostics buffer with anchors | Diagnostics jump by file/line/column anchor and cite command facts. |
-| [#189](https://github.com/flyingrobots/jedit/issues/189) | Add debug trace buffer with honest replay levels | Trace entries distinguish inspection, rerun, adapter replay, and TTD. |
-| [#190](https://github.com/flyingrobots/jedit/issues/190) | Add Dired-style host operation previews | File operations produce previewable host-effect plans and receipts. |
-| [#191](https://github.com/flyingrobots/jedit/issues/191) | Add WF-0106 combined walkthrough witness | One workflow ties command help, `:why`, registers, macros, and strands. |
-
-## Implementation Slices
-
-### Slice 1: Command Discovery And Self-Documentation
-
-- Define the command catalog shape.
-- Map Vim grammar entries and command-line commands into descriptors.
-- Add `:describe`, `:describe-key`, and prefix-help witness examples.
-- Keep execution unchanged.
-
-### Slice 2: Buffers, Modes, And Register History
-
-- Define buffer and mode facts as jedit-owned app state over Echo-backed text
-  evidence.
-- Extend register doctrine with kill-ring-style history without replacing Vim
-  register names.
-- Add target fixtures for register cycling and mode report output.
-
-### Slice 3: Causal Scripts, Diagnostics, And Strand Workflows
-
-- Define macros as semantic causal scripts.
-- Define diagnostic buffers as external command transcripts with anchors.
-- Define debug traces with honest replay levels for Echo and non-Echo systems.
-- Add target fixtures for macro replay, substitution preview, and project-wide
-  braid admission.
-
-## Combined Walkthrough Target
-
-The target product proof for this packet is a single honest Jim workflow:
-
-1. The user types `d` and receives prefix help explaining legal next forms,
-   destructive posture, register writes, and basis requirements.
-2. The user runs `di"` on a string.
-3. Jim records command provenance and writes deleted text into causal register
-   history with source basis and range posture.
-4. `:why` explains what changed and what evidence posture supports it.
-5. `:describe-register "` shows where the deleted fragment came from.
-6. The user records a macro for the same cleanup pattern.
-7. Jim stores the macro as semantic commands plus bounded raw insert spans.
-8. Replay is previewed as a strand across several matches.
-9. One site obstructs because the expected delimiter structure is missing.
-10. Jim admits only valid applications and records receipts for the admitted
-    edits.
-
-That workflow should feel like Jim, not Vim-plus or Emacs-lite: Vim grammar,
-Emacs-style discoverability, Echo-backed evidence, typed obstructions, and
-strand admission.
-
-## Acceptance Criteria
-
-- Emacs-inspired features do not alter the WF-0105 commitment to Vim grammar.
-- Every accepted idea has a causal representation and first proof surface.
-- Echo remains generic and receives no editor-specific nouns.
-- Ideas that require host effects, plugins, or external processes are explicitly
-  lower-priority until local command catalog and register/macro proof exists.
-
-## Validation Plan
-
-```bash
-npx --yes markdownlint-cli2 \
-  docs/design/0106-emacs-ideas-to-steal-causally.md \
-  docs/design/0105-vim-power-moves-causal-parity.md \
-  docs/design/0108a-why-observation-evidence-roadmap.md
-node --test --test-concurrency=1 spec/design-cycle-policy.spec.mjs
-npm run --silent quality
-git diff --check
-```
-
-## Retrospective
-
-To fill when this design lands or is superseded.
diff --git a/docs/design/0107-geordi-raytraced-title-render-pipeline.md b/docs/design/0107-geordi-raytraced-title-render-pipeline.md
deleted file mode 100644
index 511b145e..00000000
--- a/docs/design/0107-geordi-raytraced-title-render-pipeline.md
+++ /dev/null
@@ -1,883 +0,0 @@
----
-title: "WF-0107 - Geordi Ray-Traced Title Render Pipeline"
-legend: "WF"
-lane: "design"
-issue: "TBD"
-status: "draft"
-owners:
-  - "@flyingrobots"
-created: "2026-06-10"
-updated: "2026-06-10"
----
-
-# WF-0107 - Geordi Ray-Traced Title Render Pipeline
-
-## Linked Issue
-
-- TBD. This jedit-owned design should become the coordination seed for later
-  jedit, Geordi, Bunny, and Bijou issues.
-
-## Decision Summary
-
-Jedit should move the title-scene ray tracer toward a Geordi-owned renderer
-contract with Bunny-owned math/geometry and Bijou-owned terminal presentation.
-
-The target is not merely "put Geordi in the path." The target is a compiled,
-buffered renderer pipeline that can produce either pre-Braille image frames for
-debug/export or terminal-native packed Braille cells for the live jedit title
-screen.
-
-Jedit owns this design because jedit currently drives the user-visible problem:
-the title screen needs smooth terminal rendering, performance evidence,
-pre-Braille visual debugging, and eventual image/video capture without turning
-the editor into a graphics-engine dumping ground.
-
-## Sponsored Human
-
-A jedit developer wants to inspect the ray-traced title scene before Braille
-collapse so that material, geometry, lighting, camera, and acceleration bugs can
-be debugged as images or videos, without reverse-engineering them from terminal
-cells.
-
-## Sponsored Agent
-
-An agent needs a deterministic render contract with explicit frame buffers,
-render targets, and renderer facts so it can compare CPU, WASM, and GPU
-backends, without inferring performance or image truth from terminal screenshots.
-
-## Hill
-
-By the end of this arc, jedit can ask a Geordi-RayTracer-compatible renderer for
-a frame, receive either a pre-Braille RGBA image or a packed Bijou cell buffer,
-and prove through fixtures that frame scheduling, buffer reuse, visual witnesses,
-and terminal output all describe the same scene.
-
-## Current Truth
-
-This document defines a target architecture. It does not claim the final
-Geordi-RayTracer, Bunny geometry kernel, GPU backend, or Bijou packed-cell image
-bridge already exists.
-
-The current jedit title renderer has useful pieces that should inform the
-target:
-
-- jedit has a title-scene object model, mesh path, primitive objects, lighting,
-  camera state, day/night environment, and ray-hit helpers.
-- jedit renders the title scene into a Bijou `Surface`.
-- jedit has a Braille sampling stage that collapses shader samples into 2x4
-  Unicode Braille cells.
-- jedit has performance and allocation pressure around the ray/Braille hot path.
-- jedit has title recording and visual witness needs that are currently
-  terminal-cell-shaped.
-
-The target should preserve those product facts while moving reusable rendering
-machinery into the right homes.
-
-## Problem
-
-The title scene is currently difficult to reason about at the right abstraction
-level.
-
-Terminal Braille output is the product surface, but it is a poor debug surface
-for ray-traced geometry and lighting. A strange mesh edge, shadow artifact,
-material color, or camera issue may be visible only after it has already been
-quantized into terminal cells. That makes graphics debugging harder than it
-needs to be.
-
-At the same time, a naive "render image then sample it" rewrite can make
-performance worse if every frame allocates new objects, synchronously waits on a
-GPU readback, or copies full image buffers through unnecessary layers.
-
-The renderer needs a better boundary:
-
-- compile scene data once;
-- reuse frame buffers;
-- render into explicit targets;
-- avoid per-frame IR parsing and object graph construction;
-- let image/video witnesses inspect pre-Braille frames;
-- let the live jedit path consume terminal-native cell buffers.
-
-## Scope
-
-This arc includes:
-
-- Defining the jedit-to-Geordi title render boundary.
-- Recording GraphQL as the preferred authoring contract for reusable UI and
-  Scene3D profiles.
-- Defining a Geordi-RayTracer frame slot and render target model.
-- Treating pre-Braille RGBA output as a first-class debug/export target.
-- Treating packed Bijou cells as the preferred live jedit target.
-- Requiring double-buffered or ring-buffered frame ownership.
-- Planning CPU, WASM, and GPU backend compatibility without making GPU the first
-  required implementation.
-- Recording ownership boundaries between jedit, Geordi, Bunny, and Bijou.
-- Defining proof requirements for visual witnesses, frame captures, performance
-  facts, and terminal output.
-
-## Non-Goals
-
-This arc does not include:
-
-- Making jedit own a general-purpose graphics engine.
-- Making Bijou understand rays, meshes, materials, or Geordi IR.
-- Making Bunny own scene files, renderer scheduling, terminal cells, or jedit UI.
-- Replacing the editor's Echo-backed text authority.
-- Requiring a GPU backend before the CPU pipeline has a deterministic contract.
-- Treating screenshots as the primary proof artifact.
-- Parsing Geordi IR, JSON, GraphQL, or scene files inside the frame loop.
-
-## User Experience / Product Shape
-
-The live user still sees a terminal title scene. The internal renderer gains a
-second inspectable surface: pre-Braille image frames.
-
-The expected developer flow is:
-
-```bash
-npm run title:render-image -- --scene title.jedit-scene --frame 120 --output frame.png
-npm run title:render-video -- --scene title.jedit-scene --frames 180 --output title.mp4
-npm run title:preview -- --scene title.jedit-scene --render braille
-```
-
-The exact commands may change, but the product shape should remain:
-
-- image output shows ray-traced color before Braille quantization;
-- video output captures the same pre-Braille render target over time;
-- terminal preview shows the packed Bijou-cell target;
-- JSON facts connect all outputs to the same scene id, camera, time, renderer
-  profile, and frame slot policy.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[Developer changes title scene] --> RenderImage[Render pre-Braille image]
-  RenderImage --> Inspect[Inspect geometry lighting and material artifacts]
-  Inspect --> RenderCells[Render packed Bijou cells]
-  RenderCells --> Terminal[Preview terminal title scene]
-  Terminal --> Facts[Compare render facts and visual witnesses]
-  Facts --> Ship[Accept renderer change]
-  Inspect --> Fix[Fix scene renderer or material bug]
-  Fix --> RenderImage
-```
-
-### Wide UI Mockup
-
-Not applicable. This arc changes renderer contracts and evidence surfaces. It
-does not add a visible application panel.
-
-### Narrow UI Mockup
-
-Not applicable. Small terminal behavior remains owned by the existing workspace
-and title rendering surfaces.
-
-### Accessibility Considerations
-
-The title scene is decorative. Any information needed for review or debugging
-must also exist as machine-readable facts, textual summaries, or artifacts. Image
-and video exports are evidence surfaces, not the only source of truth.
-
-## Runtime / API Contract
-
-Contract: `GeordiRayTracedTitleFrame`.
-
-The renderer contract should separate scene compilation from frame rendering:
-
-```text
-Geordi:
-compile(sceneArtifact, assets, rendererProfile) -> CompiledSceneReceipt
-acquireFrameSlot(compiledSceneReceipt, targetSpec, uniforms) -> FrameLease
-renderFrame(frameLease) -> RenderResult
-resolveTarget(renderResult, targetSpec) -> Rgba8Frame | PackedBijouCells
-exportWitness(resolvedTarget, witnessPolicy) -> ArtifactReceipt
-
-Bijou/jedit:
-presentCells(packedCells) -> BijouSurface
-```
-
-Geordi should not own presentation. Geordi compiles, renders, resolves, exports,
-and proves. Bijou and jedit present.
-
-### Scene Boundary
-
-The scene boundary should describe:
-
-- stable scene id;
-- asset identities and hashes;
-- camera defaults;
-- time-varying transforms;
-- primitive and mesh objects;
-- materials;
-- environment and lighting;
-- supported renderer profile;
-- required Bunny math/geometry profile;
-- supported render targets.
-
-The first jedit source format may remain `*.jedit-scene`, but the durable
-authoring direction should be GraphQL. Authored Scene3D authority belongs to
-Geordi, not Bunny. Bunny supplies imported primitive graphics contracts.
-
-The compiled runtime form should be Geordi-owned. If Geordi later owns a
-reusable `geordi-scene3d.graphql` profile, it can import or reference
-Bunny-owned primitive schemas without changing jedit's live rendering boundary.
-
-### GraphQL Authoring Profiles
-
-GraphQL should describe reusable contracts and authoring surfaces. It should not
-be parsed or lowered inside the title-frame loop.
-
-Two profiles should be planned:
-
-```text
-bijou-ui.graphql
-geordi-scene3d.graphql
-```
-
-`bijou-ui.graphql` should describe terminal UI blocks and components:
-
-- layout blocks;
-- panes, drawers, overlays, menus, command surfaces, and status rows;
-- text, borders, spacing, focus rings, and accessibility labels;
-- theme token references;
-- event/action ids;
-- component-level facts needed by agents and tests.
-
-The expected path is:
-
-```text
-GraphQL UI contract
-  -> Wesley-generated DTOs and validators
-  -> Geordi UI IR
-  -> Geordi-Bijou renderer
-  -> Bijou Surface or packed cell buffer
-```
-
-`geordi-scene3d.graphql` should describe reusable 3D scene content:
-
-- vectors, transforms, cameras, and projection settings;
-- primitive shapes and meshes;
-- materials, lights, environment, and animation tracks;
-- asset identities and hashes;
-- renderer feature requirements;
-- deterministic numeric and geometry profiles.
-
-It may import or reference Bunny primitive schemas such as:
-
-```text
-schemas/bunny/v0/graphics.graphql
-schemas/bunny/v0/optics.graphql
-```
-
-Those Bunny schemas should define renderer-neutral primitives such as `Vector3`,
-`Quaternion`, `Matrix4x4`, `Aabb3`, `Ray3`, `Sphere3`, `RayHit3`, camera math
-helpers, projection parameters, and color/vector helper types. Bunny should not
-own scene objects, materials, lights, animation tracks, renderer feature
-requirements, render targets, Geordi receipts, or jedit title-screen behavior.
-
-The expected path is:
-
-```text
-GraphQL Scene3D contract
-  -> Wesley-generated DTOs and validators
-  -> Geordi Scene3D IR or compiled scene artifact
-  -> Geordi-RayTracer backend
-  -> rgba8-image or bijou-braille-cells
-```
-
-The split matters:
-
-- GraphQL is the authoring and schema authority.
-- Wesley provides generated source and drift checks.
-- Geordi owns lowered IR, renderer profiles, receipts, and render targets.
-- Bunny owns reusable numeric, geometry, collision, and optics primitives used by
-  the scene profile.
-- Bijou owns the terminal component and cell semantics used by the UI profile.
-- jedit owns app-specific screens, title-scene product behavior, and wiring.
-
-The rest of jedit's UI can eventually become "Geordi -> Bijou-ized" through the
-UI profile. That should be a Bijou/Geordi feature, not a pile of jedit-only
-layout conventions.
-
-### Render Targets
-
-The renderer should support at least two targets:
-
-```text
-rgba8-image
-bijou-braille-cells
-```
-
-`rgba8-image` exists for:
-
-- PNG frame export;
-- raw RGBA frame hashes;
-- later GIF/video capture;
-- visual debugging before Braille;
-- renderer cross-checks;
-- pixel-level witness probes.
-
-`bijou-braille-cells` exists for:
-
-- live jedit title rendering;
-- terminal preview;
-- terminal recording;
-- Bijou diff/presentation.
-
-The live jedit path should prefer `bijou-braille-cells`. Rendering an RGBA image,
-reading it back, then CPU-sampling it into Braille is acceptable as an early
-proof, but it should not be the final hot path.
-
-The live-path rule is:
-
-```text
-Do not render pixels unless the user asked for pixels.
-The terminal asked for cells.
-```
-
-The GPU version of the live path should therefore be:
-
-```text
-Geordi-RayTracer
-  -> WebGPU or native GPU backend
-  -> packed Bijou cell buffer
-  -> Bijou Surface adapter
-  -> terminal
-```
-
-The GPU should compute rays, shading, and Braille resolve, then write
-terminal-native packed cells. The CPU should read back cells, not a full RGBA
-frame, for the live title path.
-
-### Packed Cell Target
-
-Contract: `PackedBijouCellTarget`.
-
-```text
-PackedBijouCellTarget = {
-  widthCells: PositiveInteger,
-  heightCells: PositiveInteger,
-  cellFormatId: string,
-  sampleGrid: "2x4",
-  sampleGridHash: string,
-  colorPolicyId: string,
-  brailleResolvePolicyId: string,
-  cells: PackedBijouCell[]
-}
-```
-
-The preferred GPU work distribution is one work item per terminal cell, or one
-small tile per workgroup:
-
-```text
-for each terminal cell:
-  cast or sample 2x4 rays
-  shade samples
-  compute Braille dot mask
-  choose foreground, background, and cell attributes
-  write one packed cell
-```
-
-The live readback target is:
-
-```text
-cellCount * packedCellSize
-```
-
-not:
-
-```text
-pixelWidth * pixelHeight * 4
-```
-
-### Target Equivalence
-
-Image and cell targets must prove they describe the same scene. The first proof
-should be small and explicit:
-
-```text
-sceneId: title-default
-frameIndex: 0
-timeSeconds: 0
-target A: rgba8-image
-target B: bijou-braille-cells
-proof:
-  rgba raw hash
-  reference rgba-to-braille hash
-  native packed-cell hash
-  facts hash
-```
-
-The reference path is:
-
-```text
-RGBA target at sample-grid resolution
-  -> reference Braille resolver
-  -> expected PackedBijouCells
-```
-
-A native packed-cell renderer then proves:
-
-```text
-native PackedBijouCells == reference PackedBijouCells
-```
-
-The equivalence policy must name thresholding, gamma, color-space conversion,
-dithering, background alpha, dot ordering, terminal cell dimensions, and sample
-grid layout. Without those fields, "same scene" is not an inspectable claim.
-
-### Frame Slot
-
-Frame slots should be reusable, mutable storage:
-
-```text
-FrameSlot = {
-  id: PositiveInteger,
-  generation: PositiveInteger,
-  leaseId: string,
-  state: "free" | "rendering" | "rendered" | "resolving" | "ready" | "presenting",
-  targetSpecHash: string,
-  bufferPolicy: "double-buffer" | "triple-buffer" | "ring-buffer",
-  rgbaTarget?: Rgba8Target,
-  cellTarget?: PackedBijouCellTarget,
-  facts: RenderFrameFacts
-}
-```
-
-The implementation must not allocate a new object graph for every rendered
-frame. Slots own reusable buffers, and frame rendering mutates those buffers.
-
-`slotId` alone is not enough to prevent stale-frame bugs. Any consumer holding a
-slot must also validate the slot generation and lease id.
-
-### Frame Facts
-
-Each frame should report:
-
-```text
-RenderFrameFacts = {
-  sceneId: string,
-  sceneHash: string,
-  compiledSceneHash: string,
-  assetBundleHash: string,
-  uniformsHash: string,
-  cameraHash: string,
-  rendererName: string,
-  rendererProfile: string,
-  geordiProfileHash: string,
-  bunnySchemaHash?: string,
-  rendererBuildHash: string,
-  shaderKernelDigest?: string,
-  precisionPolicyId?: string,
-  target: "rgba8-image" | "bijou-braille-cells",
-  targetSpecHash: string,
-  frameIndex: NonNegativeInteger,
-  timeSeconds: number,
-  width: PositiveInteger,
-  height: PositiveInteger,
-  slotId: PositiveInteger,
-  slotGeneration: PositiveInteger,
-  bufferPolicy: "double-buffer" | "triple-buffer" | "ring-buffer",
-  backend: "typescript-cpu" | "rust-wasm-cpu" | "webgpu" | "webgl" | "native-gpu",
-  accelerationPolicyId?: string,
-  accelerationStructureHash?: string,
-  brailleResolvePolicyId?: string,
-  sampleGridHash?: string,
-  colorSpace: string,
-  toneMapPolicyId?: string,
-  cellFormatId?: string,
-  rawBufferHash: string,
-  artifactHash?: string,
-  readbackByteCount?: NonNegativeInteger,
-  rayCount?: NonNegativeInteger,
-  intersectionCount?: NonNegativeInteger,
-  readbackWaitMs?: NonNegativeNumber,
-  renderMs?: NonNegativeNumber,
-  resolveMs?: NonNegativeNumber,
-  presentMs?: NonNegativeNumber
-}
-```
-
-## Buffering Model
-
-The renderer should use double buffering at minimum and should allow a
-three-slot ring when readback or terminal presentation can lag.
-
-Double buffering is enough only when render, resolve, and present are
-synchronous:
-
-```text
-front buffer: visible or being presented
-back buffer: renderer writes next frame
-```
-
-The preferred model is a small ring:
-
-```mermaid
-stateDiagram-v2
-  [*] --> Free
-  Free --> Rendering
-  Rendering --> Rendered
-  Rendered --> Resolving
-  Resolving --> Ready
-  Ready --> Presenting
-  Presenting --> Free
-```
-
-At runtime, the pipeline can overlap:
-
-```text
-slot A: Geordi renders next frame
-slot B: previous rendered frame resolves to image or cells
-slot C: previous ready cell frame presents through Bijou
-```
-
-If no completed slot is ready, jedit may reuse the last ready title frame rather
-than blocking input on a renderer readback.
-
-## CPU And GPU Posture
-
-The first implementation should be CPU-compatible. The design should not require
-GPU support before it proves the renderer contract and buffer ownership model.
-
-CPU path:
-
-- compile scene to flat arrays or typed arrays;
-- build acceleration structures once per scene or invalidation;
-- reuse per-frame ray scratch;
-- render into stable RGBA or packed-cell buffers;
-- expose allocation and frame-time facts.
-
-GPU path:
-
-- upload compiled scene and acceleration data to GPU resources;
-- render into a texture only for image targets;
-- render into packed cell storage for the live terminal target;
-- resolve Braille cells on GPU for `bijou-braille-cells`;
-- read back packed cells rather than full images for the live jedit path;
-- avoid mandatory per-frame CPU/GPU synchronization;
-- reuse the last ready frame when readback is late;
-- report backend identity, shader/kernel digest, precision policy, target hash,
-  and readback timing.
-
-The GPU can be much faster at ray/sample work, but synchronous readback can erase
-the win. The contract should make late readback observable and non-fatal.
-
-CPU reference remains truth. GPU is acceleration. GPU must emit facts. GPU must
-not silently define semantics.
-
-```text
-CPU reference:
-  proves Ray -> Sample -> BrailleCell semantics
-
-GPU backend:
-  proves it matches the reference under a named tolerance and precision policy
-
-Geordi receipt:
-  records backend, shader digest, target hash, readback timing, and policy ids
-
-Bijou:
-  presents cells and does not learn rays
-```
-
-The first GPU proof should be intentionally small:
-
-```text
-frameIndex: 0
-target: bijou-braille-cells
-backend: webgpu
-same sceneHash as CPU
-same uniformsHash as CPU
-same brailleResolvePolicyId
-same cellFormatId
-gpuCellBufferHash == cpuReferenceCellBufferHash
-```
-
-## Data / State Model
-
-| Category | Description |
-| --- | --- |
-| Source of truth | Scene artifact plus renderer profile and assets. |
-| Derived state | Compiled scene buffers, acceleration structures, frame slots, image targets, packed cell targets. |
-| Invalid states | Rendering from stale assets, presenting an incomplete slot, parsing scene IR inside the frame loop. |
-| Reset behavior | Scene, asset, renderer profile, target size, or backend changes invalidate compiled buffers and frame slots. |
-| Serialization | Scene artifacts, frame facts, raw RGBA hashes, PNG exports, terminal-cell recordings, visual witnesses, later video exports. |
-| Deterministic assumptions | Fixed scene, time, camera, target size, renderer profile, and asset hashes produce stable facts and bounded visual deltas. |
-
-```mermaid
-flowchart LR
-  JeditScene[Jedit scene authoring] --> GeordiCompile[Geordi scene compile]
-  GeordiCompile --> CompiledScene[Compiled scene buffers]
-  CompiledScene --> BunnyMath[Bunny math and geometry kernels]
-  BunnyMath --> Renderer[Geordi-RayTracer backend]
-  Renderer --> ImageTarget[RGBA image target]
-  Renderer --> CellTarget[Packed Bijou cell target]
-  ImageTarget --> DebugExport[Raw PNG and later video witnesses]
-  CellTarget --> Bijou[Bijou Surface or packed surface]
-  Bijou --> Terminal[Terminal presentation]
-```
-
-## Ownership Boundaries
-
-| Project | Owns | Does Not Own |
-| --- | --- | --- |
-| jedit | App-specific screens, title-screen product behavior, frame scheduling policy, CLI/debug commands, scene selection, terminal integration. | General graphics math, reusable renderer engine, terminal framework internals. |
-| Geordi | Scene/UI IR, Scene3D authoring profile, compiled render artifacts, renderer profiles, render targets, frame facts, backend dispatch, visual witnesses. | jedit editor behavior, Echo text authority, Bijou terminal output, Bunny primitive definitions. |
-| Bunny | Deterministic math, vectors, matrices, rays, shapes, intersections, bounds, acceleration primitives, optics math, reusable primitive graphics schemas. | Authored scenes, scene scheduling, renderer profiles, render receipts, title-screen UI, terminal cells. |
-| Bijou | Surface/cell model, packed cell presentation, frame diffing, terminal output, TUI composition, reusable terminal UI component schema primitives. | Rays, meshes, Scene3D IR, graphics acceleration. |
-
-## Accessibility Posture
-
-| Concern | Posture |
-| --- | --- |
-| Semantic labels or facts | Frame facts must describe renderer state, scene id, target, backend, and artifact paths. |
-| Focus order or ownership | No new focusable UI in this design. |
-| Hidden or visual-only information | Debug information must be available through JSON facts, not only image output. |
-| Keyboard behavior | Live jedit input must not block waiting for a renderer slot when a prior frame is reusable. |
-| Secret or redaction behavior | Title-scene artifacts should not include editor file contents unless a later explicit capture mode says so. |
-
-## Localization / Directionality Posture
-
-| Concern | Posture |
-| --- | --- |
-| User-visible strings | Export commands and facts should use existing CLI/help localization posture when they become product surfaces. |
-| Directionality | The title scene itself is decorative; terminal overlays remain responsible for left-to-right and right-to-left text. |
-| Image/video artifacts | Artifact metadata should record locale and text direction when overlays are included. |
-
-## Options Considered
-
-### Option A: Keep Everything In jedit
-
-jedit could continue to own the ray tracer, acceleration structures, image
-exports, and Braille collapse.
-
-Pros:
-
-- fastest short-term path;
-- fewer repository coordination steps;
-- easy to preserve current title behavior.
-
-Cons:
-
-- keeps reusable graphics code trapped in the editor;
-- makes GPU/WASM/native backends harder to share;
-- encourages jedit-specific math and scene contracts;
-- duplicates future Geordi/Bunny/Bijou capabilities.
-
-### Option B: Geordi Renders Only Images
-
-Geordi could render pre-Braille RGBA frames, and jedit could sample those frames
-into Bijou cells.
-
-Pros:
-
-- clean image/video debugging;
-- common shape for visual witnesses;
-- easier first GPU proof.
-
-Cons:
-
-- can add CPU readback and image sampling cost to the live path;
-- makes terminal rendering a second-class post-process;
-- risks losing jedit's terminal-cell facts and Braille-specific statistics.
-
-### Option C: Geordi Supports Image And Cell Targets
-
-Geordi renders either RGBA frames or packed Bijou cell frames from the same
-compiled scene.
-
-Pros:
-
-- supports pre-Braille debug output;
-- keeps live jedit rendering terminal-native;
-- allows GPU Braille resolve later;
-- makes renderer facts comparable across targets;
-- gives Bijou a clean cell boundary.
-
-Cons:
-
-- requires a sharper render target contract;
-- requires more coordination across repos;
-- needs careful proof that image and cell targets describe the same scene.
-
-## Decision
-
-Choose Option C.
-
-The Geordi-RayTracer direction should support both pre-Braille image targets and
-packed Bijou cell targets. Jedit should use image targets for debugging,
-fixtures, raw RGBA hashes, PNG capture, later video export, and visual witnesses.
-Jedit should use packed cell targets for live title rendering whenever the
-backend supports them.
-
-The first implementation may use CPU rendering and may internally resolve image
-samples into cells, but the public contract should not bake in "image first" as
-the only live path.
-
-## Implementation Plan
-
-### Goalpost 1: Jedit-Owned Contract And Witness Shape
-
-Define the jedit-facing renderer interface and evidence formats.
-
-- [ ] Slice 1: Land WF-0107 with ownership, lease, target, and witness
-      amendments.
-- [ ] Slice 2: Define TypeScript-only target specs, frame leases, frame slots,
-      and frame facts.
-- [ ] Slice 3: Add a deterministic frame-0 fixture with RGBA raw hash, reference
-      RGBA-to-Braille hash, native packed-cell hash, and facts hash.
-
-### Goalpost 2: CPU Frame Slots
-
-Make the current title renderer compatible with reusable frame slots.
-
-- [ ] Slice 4: Introduce reusable frame slot objects or typed buffers with
-      generation and lease ids.
-- [ ] Slice 5: Render title frames into a caller-owned or renderer-owned slot.
-- [ ] Slice 6: Prove no per-frame surface/sample object graph is required after
-      warmup.
-
-### Goalpost 3: Pre-Braille Image Export
-
-Expose image debug artifacts before Braille collapse.
-
-- [ ] Slice 7: Add an RGBA8 frame target for the current title scene.
-- [ ] Slice 8: Export deterministic raw RGBA hashes and PNG frames from the title
-      renderer.
-- [ ] Slice 9: Keep GIF/video export as a later convenience artifact, not the
-      first proof gate.
-
-### Goalpost 4: Geordi/Bunny Extraction
-
-Move reusable rendering substrate out of jedit.
-
-- [ ] Slice 10: Define the Geordi scene artifact or adapter profile for jedit
-      title scenes.
-- [ ] Slice 11: Move math/geometry/ray intersection kernels toward Bunny-owned
-      crates.
-- [ ] Slice 12: Add Geordi renderer facts and compiled scene receipts.
-
-### Goalpost 5: Packed Bijou Cell Target
-
-Make terminal cells a first-class render target.
-
-- [ ] Slice 13: Define packed Bijou cell buffer layout with `cellFormatId`,
-      `sampleGridHash`, and `brailleResolvePolicyId`.
-- [ ] Slice 14: Add adapter from packed cells to Bijou `Surface`.
-- [ ] Slice 15: Prove live title rendering can present from a completed cell
-      slot.
-
-### Goalpost 6: GPU-Ready Ring Buffer
-
-Prepare for asynchronous GPU rendering without making it mandatory.
-
-- [ ] Slice 16: Add double-buffer and ring-buffer scheduler tests.
-- [ ] Slice 17: Add late-readback behavior that reuses the last ready frame.
-- [ ] Slice 18: Add backend capability facts for CPU, WASM, and GPU renderers,
-      including shader/kernel digest and precision policy.
-- [ ] Slice 19: Add a future WebGPU packed-cell equivalence fixture plan that
-      compares GPU cell-buffer hash to CPU reference cell-buffer hash.
-
-## Follow-Up Design Arcs
-
-GraphQL authoring profiles are important, but they should not block WF-0107.
-They should move into separate design arcs:
-
-```text
-WF-0112 - Bijou UI GraphQL Profile
-WF-0113 - Geordi Scene3D Authoring Profile
-```
-
-WF-0112 should define `bijou-ui.graphql`, terminal component primitives,
-accessibility fields, and the Geordi-Bijou lowering bridge.
-
-WF-0113 should define `geordi-scene3d.graphql`, authored scene objects,
-materials, lights, animation tracks, renderer features, target capabilities, and
-imports from Bunny primitive graphics schemas.
-
-## Acceptance Criteria
-
-- [ ] jedit has a documented renderer boundary that does not make jedit the
-      permanent owner of reusable graphics machinery.
-- [ ] The design distinguishes pre-Braille image output from live terminal-cell
-      output.
-- [ ] The renderer contract supports reusable frame slots.
-- [ ] The live path can avoid blocking on an incomplete render slot.
-- [ ] Raw RGBA and PNG debug capture are planned before Braille collapse.
-- [ ] Packed Bijou cells are planned as the preferred live render target.
-- [ ] Bunny, Geordi, Bijou, and jedit ownership boundaries are explicit.
-- [ ] GraphQL authoring profiles are distinguished from compiled runtime render
-      artifacts.
-- [ ] The image target to packed-cell target equivalence policy is explicit.
-- [ ] GPU backends are specified as accelerators over CPU reference semantics.
-- [ ] The preferred GPU live path writes packed Bijou cells rather than forcing a
-      full RGBA image readback.
-
-## Validation Plan
-
-Design validation:
-
-```bash
-npx --yes markdownlint-cli docs/design/0107-geordi-raytraced-title-render-pipeline.md
-git diff --check
-```
-
-Future implementation validation should include:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test spec/title-scene-render.spec.mjs
-JEDIT_DIST_PREBUILT=1 node --test spec/title-scene-record-cli.spec.mjs
-JEDIT_DIST_PREBUILT=1 node --test spec/title-allocation-facts.spec.mjs
-npm run title:render-image -- --frame 0 --json
-npm run title:render-image -- --frame 0 --output frame.png
-```
-
-## Risks
-
-- A GPU backend can become slower than CPU if every frame blocks on readback.
-- A generic renderer contract can over-expand and delay practical title-scene
-  fixes.
-- Image witnesses can hide terminal-cell regressions if they replace, rather
-  than complement, packed-cell witnesses.
-- Moving math too early can destabilize jedit before Bunny has published stable
-  crates.
-- Packed-cell formats can accidentally duplicate Bijou internals unless Bijou
-  participates in the contract.
-- A GraphQL UI profile can turn into a second UI framework unless Bijou owns the
-  reusable component semantics.
-- A Scene3D schema can become misplaced graphics authority if scene objects,
-  materials, lights, animation, renderer features, or targets are smuggled into
-  Bunny.
-- A GPU backend can accidentally become the semantic source of truth unless
-  reference CPU equivalence remains mandatory.
-
-## Initial Answers And Remaining Questions
-
-- Scene3D profile ownership: not Bunny. If the schema includes authored scene
-  objects, materials, lights, animation, renderer features, or targets, it should
-  be `geordi-scene3d.graphql`. It may import Bunny primitive schemas.
-- Bunny schema ownership: Bunny owns primitive graphics contracts such as
-  `schemas/bunny/v0/graphics.graphql` and possibly
-  `schemas/bunny/v0/optics.graphql`.
-- Bijou UI profile ownership: Bijou should own terminal UI semantics. A
-  Geordi-Bijou bridge can own lowering and adapters.
-- Packed cell target ownership: cell layout semantics should be Bijou or
-  Geordi-Bijou. Geordi may support the render target, but should not silently
-  define Bijou internals.
-- GIF/video ownership: Geordi witness tooling should own canonical raw frame,
-  packed-cell, and frame-fact evidence. jedit CLI tooling may own convenient
-  product export commands. GIF/video files are convenience products, not first
-  proof artifacts.
-- First non-TypeScript backend: Rust/WASM CPU should precede WebGPU. GPU backend
-  work needs explicit precision, readback, and equivalence receipts.
-- First pixel format: RGBA8 with explicit `colorSpace` and `toneMapPolicyId`.
-  Linear float targets can come later if lighting debug work needs them.
-
-Remaining open question:
-
-- Which exact package owns the Geordi-Bijou bridge: Geordi, Bijou, or a separate
-  shared workspace package?
-
-## Retrospective
-
-Not yet implemented.
diff --git a/docs/design/0108-causal-command-provenance-surface.md b/docs/design/0108-causal-command-provenance-surface.md
deleted file mode 100644
index 47088090..00000000
--- a/docs/design/0108-causal-command-provenance-surface.md
+++ /dev/null
@@ -1,877 +0,0 @@
----
-title: "WF-0108 - Jim Command Provenance And :why"
-legend: "WF"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/131"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-06-13"
-updated: "2026-06-29"
----
-
-# WF-0108 - Jim Command Provenance And :why
-
-## Linked Issue
-
-- [#131 WF-0108: Jim Command Provenance And :why](https://github.com/flyingrobots/jedit/issues/131)
-- Follow-up roadmap: [#181 WF-0108A: Complete `:why` through observation evidence](https://github.com/flyingrobots/jedit/issues/181)
-
-## WF-0108A Roadmap Lock
-
-This document remains the historical base cycle for command provenance and the
-first `:why` implementation. The current completion plan is tracked in:
-
-- [WF-0108A - `:why` Observation Evidence Roadmap](0108a-why-observation-evidence-roadmap.md)
-
-Current source truth is sharper than the original checklist: `:why`
-command-line dispatch and the calm no-event case are already implemented. The
-remaining gap is not basic dispatch; it is full observation evidence for the
-golden commands, typed evidence obstruction posture, JSON witness parity, and
-Echo ReadingEnvelope identity.
-
-Jim owns the user-facing `:why` command. Echo owns generic runtime evidence.
-Continuum owns portable protocol/profile vocabulary only when the evidence must
-cross participant boundaries.
-
-## Decision Summary
-
-Jim's next product-defining surface is `:why`: selected Vim-powered edits must
-emit and expose durable facts that explain what command ran, what runtime target
-it resolved, what basis it used, what text/register state changed, and what
-evidence proves the result. This cycle starts with a small trust preflight, then
-makes command explanation visible to humans through `:why` and a compact
-lower-mode summary, and visible to agents through JSON witnesses.
-
-## Product Roadmap Lock
-
-The release is deliberately off the immediate radar. Jim should not ship as a
-public editor until it has one unmistakable product promise:
-
-```text
-Jim is a modal editor for people and agents who need edits to be explainable,
-recoverable, and reviewable.
-```
-
-That promise orders the next roadmap by one signature loop:
-
-```text
-explain -> preview -> admit -> recover
-```
-
-The first user-facing command grammar should be:
-
-| Command | Product role |
-| --- | --- |
-| `:why` | Explain the last meaningful action. |
-| `:preview` | Show a proposed, broad, or destructive edit before admission. |
-| `:admit` | Accept all or selected proposed ranges. |
-| `:history` | Inspect causal events and historical bases. |
-| `:yankfrom` | Pull retained historical material into the current head. |
-| `:explain` | Explain a range, character, diagnostic, or result. |
-
-Not all commands need to ship immediately or remain literal forever. They are
-the conceptual grammar for the product.
-
-The goalpost order is:
-
-1. **Editor Trust Gate**: prove open, edit, save, quit, search, dirty-state, and
-   disk-output behavior before leaning on causal UI.
-2. **Command Provenance And `:why`**: explain the last meaningful command and
-   expose equivalent facts to agents.
-3. **Historical Basis Preview**: preview a historical reading from the history
-   drawer while the current head remains unchanged.
-4. **Search Sets And Substitute Strand Preview**: create basis-bound search
-   result sets, preview `:%s` as a proposal strand, and admit selected rows.
-5. **Historical Yank And Register Provenance**: reuse retained historical
-   material without moving the current head.
-6. **Vim Power Core**: deepen visual mode, registers, semantic repeat, macros,
-   marks, structural text objects, and range commands through causal proofs.
-7. **Agent-Safe Editing**: require agent edits to arrive as accountable
-   proposal strands with basis, range, rationale, evidence, and admission paths.
-
-The next named cycle sequence is:
-
-| Cycle | Issue | Role |
-| --- | --- | --- |
-| WF-0108 | [#131](https://github.com/flyingrobots/jedit/issues/131) | Jim Command Provenance And `:why` |
-| WF-0109 | [#134](https://github.com/flyingrobots/jedit/issues/134) | Historical Basis Preview |
-| WF-0110 | [#132](https://github.com/flyingrobots/jedit/issues/132) | Search Sets And Substitute Strand Preview |
-| WF-0111 | [#133](https://github.com/flyingrobots/jedit/issues/133) | Historical Yank And Register Provenance |
-
-The internal version ladder remains advisory only:
-
-| Version | Public meaning | Must be true |
-| --- | --- | --- |
-| `v0.1.x` | Echo-hosted proof / internal release gate | Echo authority and witnesses are honest. |
-| `v0.2.0` | Dogfood editor trust release | Core editor lifecycle is reliable. |
-| `v0.3.0` | Causal alpha | Provenance, history drawer, checkpoints, and explanations exist. |
-| `v0.4.0` | Modal alpha | Visual mode, registers, substitute, repeat, and macros are serious. |
-| `v0.5.0` | Proposal alpha | Strand preview covers broad deterministic and agent-suggested edits. |
-| `v0.8.0` | Jim public preview | Installable `jim` alias, docs, demo path, and workflow witnesses exist. |
-| `v1.0.0` | Real product | Credible keyboard editor plus causal provenance, replay, recovery, and structure. |
-
-Do not rename the repo, contracts, WSC directories, or internal APIs in this
-cycle. The `jim` user-facing command alias is earned when the public product
-promise is demonstrable.
-
-## Sponsored Human
-
-A modal editor user wants to ask "what happened and why?" after a meaningful
-edit so they can trust powerful commands, repeat, and future preview/admission
-workflows, without reconstructing intent from raw buffer diffs or terminal
-pixels.
-
-## Sponsored Agent
-
-An agent needs structured command provenance facts so it can assert command
-syntax, resolved targets, affected ranges, receipt posture, and obstruction
-reasons through stable JSON, without scraping the rendered terminal or guessing
-private editor state.
-
-## Hill
-
-By the end of this cycle, Jim can explain the last meaningful Vim-powered edit
-through a human-facing `:why` surface and a JSON witness, without scraping
-terminal pixels or inventing facts not present in runtime behavior.
-
-## Current Truth
-
-Current implemented truth:
-
-- The production TUI has no supported non-Echo text runtime mode.
-- Interactive open, edit, read, render, save, export, and checkpoint flows route
-  through the Echo-hosted production text session.
-- PR #160 hardened the text projection and materialization boundary: bounded
-  Echo readings cannot replace whole editable editor text, save/export requires
-  full projection evidence, WSC recovery/materialization fails closed on window
-  readings, blocked materialization stays visibly blocked, and inactive buffer
-  records preserve local projection/authority across file switches.
-- WSC history listing, current export, and historical export exist as
-  agent-facing JSON surfaces.
-- `ctrl+h` opens an Echo History/worldline drawer that can show editor-shaped
-  Echo activity and optimistic/worldline posture, but it does not yet reproject
-  historical bases.
-- The Vim/Jim runtime has parser, normal/operator-pending state, basis-bound
-  core motions, core text objects, delete/change/yank/put execution, basic dot
-  repeat, transformed-repeat metadata, case operators, joins, local marks, and
-  partial register behavior.
-- Search repeat `n` and `N`, matching delimiter `%`, paragraph motions, and
-  unsupported section motions now expose explicit runtime facts in focused
-  specs.
-- `/` and `?` search entry and complete search-history mutation are not yet
-  product-complete.
-- Production undo/redo is still not the final causal undo model.
-- WF-0122 and WF-0123 were closed after PR #160; their remaining work is split
-  into focused recovery, external edit, braid reconciliation, native Echo
-  speculation, and watcher follow-up issues.
-
-Post-#160 anchors:
-
-- PR #160:
-  [Harden Echo text projection and file materialization semantics](https://github.com/flyingrobots/jedit/pull/160).
-- Restart recovery UI follow-up:
-  [#161](https://github.com/flyingrobots/jedit/issues/161).
-- External Edit intake follow-up:
-  [#162](https://github.com/flyingrobots/jedit/issues/162).
-- Braid/diff reconciliation follow-up:
-  [#163](https://github.com/flyingrobots/jedit/issues/163).
-- Native Echo speculative runtime follow-up:
-  [#164](https://github.com/flyingrobots/jedit/issues/164).
-- File watcher/external move follow-up:
-  [#165](https://github.com/flyingrobots/jedit/issues/165).
-
-Older WF-0108 evidence anchors from merge target
-`c511e2abc71c7c812ebc1eb79acb47480dad0ab5`:
-
-- Production text runtime is Echo-only and non-Echo profiles obstruct:
-  [spec/text-runtime-profile-session.spec.mjs#53:c511e2abc71c7c812ebc1eb79acb47480dad0ab5](https://github.com/flyingrobots/jedit/blob/c511e2abc71c7c812ebc1eb79acb47480dad0ab5/spec/text-runtime-profile-session.spec.mjs#L53).
-- BEARING records the same runtime profile, production undo/redo posture, WSC
-  surfaces, and Vim runtime baseline:
-  [docs/BEARING.md#14:c511e2abc71c7c812ebc1eb79acb47480dad0ab5](https://github.com/flyingrobots/jedit/blob/c511e2abc71c7c812ebc1eb79acb47480dad0ab5/docs/BEARING.md#L14).
-- Production text session opens, edits, reads, checkpoints, and exports through
-  app-owned text-session capabilities:
-  [spec/production-text-session.spec.mjs#20:c511e2abc71c7c812ebc1eb79acb47480dad0ab5](https://github.com/flyingrobots/jedit/blob/c511e2abc71c7c812ebc1eb79acb47480dad0ab5/spec/production-text-session.spec.mjs#L20).
-- Real workspace open/edit/save flows call production text authority and render
-  Echo readings:
-  [spec/workspace-app-echo-cutover.spec.mjs#5:c511e2abc71c7c812ebc1eb79acb47480dad0ab5](https://github.com/flyingrobots/jedit/blob/c511e2abc71c7c812ebc1eb79acb47480dad0ab5/spec/workspace-app-echo-cutover.spec.mjs#L5).
-- Viewer rendering treats Echo reading cache as production text projection,
-  not stale local line authority:
-  [spec/workspace-text-cutover.spec.mjs#128:c511e2abc71c7c812ebc1eb79acb47480dad0ab5](https://github.com/flyingrobots/jedit/blob/c511e2abc71c7c812ebc1eb79acb47480dad0ab5/spec/workspace-text-cutover.spec.mjs#L128).
-- Echo History drawer behavior and `ctrl+h` focus are covered by workspace
-  tests:
-  [spec/workspace-echo-history-drawer.spec.mjs#35:c511e2abc71c7c812ebc1eb79acb47480dad0ab5](https://github.com/flyingrobots/jedit/blob/c511e2abc71c7c812ebc1eb79acb47480dad0ab5/spec/workspace-echo-history-drawer.spec.mjs#L35).
-- WSC history listing exposes deterministic JSON records:
-  [spec/jedit-wsc-history-listing.spec.mjs#10:c511e2abc71c7c812ebc1eb79acb47480dad0ab5](https://github.com/flyingrobots/jedit/blob/c511e2abc71c7c812ebc1eb79acb47480dad0ab5/spec/jedit-wsc-history-listing.spec.mjs#L10).
-- Current and point-in-time WSC history export are covered by export specs:
-  [spec/jedit-wsc-current-history-export.spec.mjs#11:c511e2abc71c7c812ebc1eb79acb47480dad0ab5](https://github.com/flyingrobots/jedit/blob/c511e2abc71c7c812ebc1eb79acb47480dad0ab5/spec/jedit-wsc-current-history-export.spec.mjs#L11).
-- Historical basis selection is explicitly non-mutating:
-  [spec/jedit-wsc-history-basis.spec.mjs#30:c511e2abc71c7c812ebc1eb79acb47480dad0ab5](https://github.com/flyingrobots/jedit/blob/c511e2abc71c7c812ebc1eb79acb47480dad0ab5/spec/jedit-wsc-history-basis.spec.mjs#L30).
-- Vim motion resolver covers reading-basis motions, paragraph motions,
-  matching pairs, and repeat-search facts:
-  [spec/vim-power-motion-text-object.spec.mjs#9:c511e2abc71c7c812ebc1eb79acb47480dad0ab5](https://github.com/flyingrobots/jedit/blob/c511e2abc71c7c812ebc1eb79acb47480dad0ab5/spec/vim-power-motion-text-object.spec.mjs#L9).
-- Vim operators and registers cover delete/change/yank/put-style runtime
-  behavior with register provenance:
-  [spec/vim-power-operators-registers.spec.mjs#9:c511e2abc71c7c812ebc1eb79acb47480dad0ab5](https://github.com/flyingrobots/jedit/blob/c511e2abc71c7c812ebc1eb79acb47480dad0ab5/spec/vim-power-operators-registers.spec.mjs#L9).
-- Dot repeat and transformed repeat metadata are covered by normal-mode specs:
-  [spec/vim-power-normal-mode-integration.spec.mjs#9:c511e2abc71c7c812ebc1eb79acb47480dad0ab5](https://github.com/flyingrobots/jedit/blob/c511e2abc71c7c812ebc1eb79acb47480dad0ab5/spec/vim-power-normal-mode-integration.spec.mjs#L9).
-- Case operators, joins, and marks are covered by transform/mark specs:
-  [spec/vim-power-transforms-marks.spec.mjs#9:c511e2abc71c7c812ebc1eb79acb47480dad0ab5](https://github.com/flyingrobots/jedit/blob/c511e2abc71c7c812ebc1eb79acb47480dad0ab5/spec/vim-power-transforms-marks.spec.mjs#L9).
-
-Current design anchors:
-
-- [WF-0105 Vim Power Moves Causal Parity](0105-vim-power-moves-causal-parity.md)
-- [WF-0106 Emacs Ideas To Steal Causally](0106-emacs-ideas-to-steal-causally.md)
-- [Echo History Drawer](0034-echo-history-drawer.md)
-- [Causal Event Model](causal-event-model.md)
-- [Text Edit Algebra](text-edit-algebra.md)
-
-## Problem
-
-Jim has real causal substrate work and real Vim progress, but the product still
-does not show the user one unmistakable causal editing move. Receipts, readings,
-history exports, and basis facts are valuable, but they remain too
-infrastructure-shaped unless a user can ask a simple question after an edit:
-
-```text
-Why does the buffer look like this?
-```
-
-Without `:why`, Jim risks becoming "Vim-shaped editing with interesting
-internals." The product wedge is stronger: every meaningful edit should
-eventually be explainable, every broad edit should be previewable, every
-proposal should be selectively admissible, every retained history basis should
-be useful without moving the current head, and every stale projection should
-tell the truth.
-
-## Scope
-
-This cycle includes:
-
-- An Editor Trust Gate preflight that audits open/edit/save/quit, dirty-state,
-  search entry, and disk verification gaps before implementation starts.
-- A `JeditCommandEvent` model for selected command provenance.
-- Provenance for representative Vim edits. Slice 1 scope, tests, and acceptance
-  gates use the same initial command set: `dw`, `ciw`, `dd`, and `gUap`. Later
-  slices can add `d%`, `n`/`N`, and broader range commands when their product
-  surfaces are ready.
-- A compact lower-mode summary after meaningful edits.
-- `:why` command-line dispatch for the last meaningful command.
-- Optional richer detail rendering behind the `:why` surface.
-- A JSON witness that reports command provenance without terminal scraping.
-- Typed obstruction posture for unsupported, unavailable, or stale-basis cases.
-
-## Slice 1 `:why` MVP
-
-Do not start by explaining every possible edit. The first product slice should
-prove one thin path:
-
-```text
-last meaningful Vim edit
--> command event record
--> :why explanation
--> lower-mode text
--> JSON witness
--> Echo History drawer row
-```
-
-Initial command coverage should use existing proven operations:
-
-| Command | Why it belongs in Slice 1 |
-| --- | --- |
-| `dw` | Small destructive motion command with familiar Vim semantics. |
-| `ciw` | Text-object change proves target/range and mode transition facts. |
-| `dd` | Linewise edit proves command event and range summary without search. |
-| `gUap` | Operator plus text object proves transformed range provenance. |
-
-## Slice 1 Runtime Status
-
-Slice 1 now has a narrow runtime spine:
-
-- `createJeditCommandEvent(input)` is the supported construction surface for
-  command provenance events and returns either a validated Vim event or a typed
-  rejection.
-- Vim repeat state records the resolved target basis, byte range, and
-  charwise/linewise shape for mutating commands, so non-register transforms such
-  as `gUap` can still be explained honestly.
-- `:why` explains the last meaningful Vim edit using the validated event.
-- The normal-mode footer can show a compact last-command summary.
-- Echo History applied-edit rows include the command summary when an Echo edit
-  receipt settles.
-- The JSON witness is available after build:
-
-```bash
-node scripts/jedit-command-provenance-witness.mjs --json
-node scripts/jedit-command-provenance-witness.mjs --json --command gUap
-```
-
-The first witness-backed command set is `dw`, `ciw`, `dd`, and `gUap`. Native
-WSC linkage for command events, historical preview, range explanation, search
-sets, and substitute proposal strands remain future cycles.
-
-Hold `n`/`N` until `/` and `?` search entry is product-complete. Hold `:%s`
-until Search Sets And Substitute Strand Preview becomes the active preview
-cycle.
-
-## Slice 0 Editor Trust Gate Preflight
-
-Slice 0 is now recorded by an executable JSON report. The witness requires the
-explicit `--json` flag so callers cannot confuse it with a human display mode:
-
-```bash
-npm run build
-node scripts/jedit-editor-trust-preflight.mjs --json
-```
-
-Current passed gates:
-
-- Open, edit, save, and disk output route through production text authority.
-- Plain quit requires confirmation, and forced quit remains explicit.
-
-Current scoped posture:
-
-- The product is currently single-buffer. Multi-buffer behavior is not claimed
-  in this cycle.
-
-Current blockers before Slice 1:
-
-- Dirty quit uses the generic quit confirmation instead of a dirty-specific
-  guardrail.
-- Dirty file switches can start a replacement open before unsaved changes are
-  resolved.
-- `/` and `?` search entry is not product-complete, although repeat-search
-  facts exist for `n` and `N`.
-
-## Non-Goals
-
-This cycle does not include:
-
-- Public release work or version tagging.
-- Adding the `jim` binary alias.
-- Full Vim parity.
-- Full visual mode.
-- Full macro replay.
-- Full causal undo.
-- Durable replay completion.
-- Full timeline scrubbing.
-- AI chat or agent autonomous editing.
-- Plugin architecture.
-- Broad Git workbench behavior.
-- Title-rendering roadmap work.
-
-## User Experience / Product Shape
-
-The signature flow should be small:
-
-1. Open a file.
-2. Place the cursor inside a word.
-3. Run `ciw`.
-4. Type replacement text and return to Normal mode.
-5. Run `:why`.
-6. Jim shows command, target, range, receipt/result posture, and short
-   explanation.
-
-The lower-mode summary should stay quiet by default. It should name causal facts
-only when they explain command state, obstruction, or recent meaningful edits.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[User runs Vim command] --> Parse[Vim syntax parsed]
-  Parse --> Resolve[Target resolves against reading basis]
-  Resolve --> Apply[Command applies or obstructs]
-  Apply --> Evidence[Receipt and result reading recorded when available]
-  Evidence --> Summary[Footer/lower-mode summary names what happened]
-  Summary --> Why[User runs :why]
-  Why --> Detail[Jim shows structured command provenance]
-  Detail --> Agent[JSON witness exposes the same facts]
-```
-
-### Wide UI Mockup
-
-Terminal: 100 columns, dark theme, active editor surface.
-
-```text
-+--------------------------------------------------------------------------------------------------+
-| src/example.ts                                                                                   |
-|                                                                                                  |
-| const accountName = customerName                                                                 |
-|                                                                                                  |
-| NORMAL  last: ciw -> inner word "customerName"  range 3:21-33  receipt tick:77                   |
-| :why explains syntax, basis, register effect, receipt, and result reading                        |
-+--------------------------------------------------------------------------------------------------+
-```
-
-Detail command:
-
-```text
-:why
-
-ciw  change inner word
-basis: reading:R42
-target: word "customerName"
-range: line 3, cols 21-33
-register: unnamed <- "customerName"
-receipt: tick:T77
-result: reading:R43
-explanation: changed the word under the cursor and entered Insert mode
-```
-
-### Narrow UI Mockup
-
-Terminal: 44 columns, dark theme.
-
-```text
-+------------------------------------------+
-| const accountName = customerName         |
-|                                          |
-| NORMAL ciw range 3:21-33 receipt T77     |
-+------------------------------------------+
-```
-
-Optional causal detail collapses before mode, command, obstruction, and recovery
-posture. The detail command remains keyboard-accessible.
-
-### Accessibility Considerations
-
-Every surfaced command explanation must have model facts independent of color,
-layout, and terminal geometry. The lower-mode summary is a projection over the
-same event that JSON witnesses expose. No command explanation may require
-visual-only range highlighting.
-
-## Runtime / API Contract
-
-Contract: `JeditCommandEvent`.
-
-Initial event shape:
-
-```text
-JeditCommandEvent = {
-  eventId,
-  keys,
-  command,
-  mode,
-  operator,
-  motionOrTextObject,
-  count,
-  register,
-  basisReadingId,
-  targetKind,
-  rangeSet,
-  registerEffect,
-  receiptId,
-  resultReadingId,
-  obstruction,
-  summary
-}
-```
-
-The event distinguishes three phases:
-
-```text
-Raw keys
-  -> parsed Vim syntax
-    -> resolved target over a reading basis
-      -> mutation, non-mutating command, or obstruction
-```
-
-Echo remains generic. Echo does not learn Vim keys, commands, text objects,
-registers, panes, or editor terms. Jim/jedit owns the command event as a
-product-shaped projection over Echo receipts, readings, retained evidence, and
-app-owned editor state.
-
-## Lower Modes
-
-Lower modes required:
-
-- JSON command provenance witness.
-- No-color terminal summary.
-- Narrow terminal summary.
-- Honest posture when Echo receipt or result reading evidence is unavailable.
-- Honest posture when a command is supported in the editor but not yet
-  evidence-backed.
-- Keyboard-only access through `:why`.
-
-The JSON witness must expose enough structure for an agent to assert command
-keys, parsed syntax, resolved target, range, register effect, receipt posture,
-result posture, and obstruction reason.
-
-## Data / State Model
-
-| Category | Description |
-| --- | --- |
-| Source of truth | Echo-backed text readings and receipts, plus jedit-owned command syntax/resolution state. |
-| Derived state | Lower-mode summaries and `:why` detail views. |
-| Invalid states | Command event claims a mutation without a receipt posture, or claims a range without a basis. |
-| Reset behavior | A new meaningful command supersedes the lower-mode summary. |
-| Serialization | JSON witness output for command events; future WSC linkage when retained evidence supports it. |
-| Deterministic assumptions | Command parsing and target resolution are deterministic over the supplied editor state and basis. |
-
-Invariant enforcement requirement:
-
-- Slice 1 must expose `createJeditCommandEvent(input)` as the only construction
-  surface for runtime command events.
-- The factory returns a validated event union such as `AppliedCommandEvent`,
-  `RangeResolvedCommandEvent`, `ObservedCommandEvent`, or a typed
-  `JeditCommandEventRejected` object. Callers must not serialize bare payloads.
-- `AppliedCommandEvent` requires explicit receipt posture for any mutation. A
-  missing receipt posture returns `JeditCommandEventRejected`.
-- `RangeResolvedCommandEvent` requires `basisReadingId` for every emitted range
-  or range set. A range without a basis returns `JeditCommandEventRejected`.
-- JSON witnesses, lower-mode summaries, and `:why` detail rendering consume only
-  the validated event union.
-- Slice 0 preflight must confirm the current runtime can distinguish mutation,
-  non-mutating command, range resolution, and obstruction facts before Slice 1
-  promises those constructors.
-
-```mermaid
-stateDiagram-v2
-  [*] --> Parsed
-  Parsed --> Resolved
-  Resolved --> Applied
-  Resolved --> Obstructed
-  Applied --> Summarized
-  Summarized --> Explained
-  Obstructed --> Summarized
-```
-
-## Accessibility Posture
-
-| Concern | Posture |
-| --- | --- |
-| Semantic labels or facts | Command events carry explicit command, target, range, receipt, and obstruction fields. |
-| Focus order or ownership | Detail view or drawer owns focus explicitly and returns to editor focus on close. |
-| Hidden or visual-only information | Range highlights are optional projections, never the only explanation. |
-| Keyboard behavior | Summary and detail command are keyboard-first. |
-| Secret or redaction behavior | Register and range material may need future redaction policy; first slice should avoid secrets-specific claims. |
-
-## Localization / Directionality Posture
-
-| Concern | Posture |
-| --- | --- |
-| User-visible strings | Lower-mode summary and explanation labels are user-visible. |
-| Catalog keys | Add keys with the implementation slice that first renders strings. |
-| Supported locales updated | Required with rendering implementation. |
-| Directionality assumptions | Facts remain ordered by command semantics; rendered labels use existing footer direction policy. |
-| Validation command | Run focused workspace render/i18n specs once strings land. |
-
-## Agent Inspectability / Explainability Posture
-
-Agent inspectability is mandatory. The witness should let an agent answer:
-
-- What command keys ran?
-- What syntax parsed?
-- What mode was active?
-- What basis or reading was used?
-- What target resolved?
-- What range or range set changed?
-- What register changed?
-- What receipt/result reading was available?
-- What obstruction occurred?
-- What short human explanation did Jim show?
-
-## Roadmap System Objects
-
-The next roadmap should be built as four stacked systems, not as disconnected
-feature ideas.
-
-### System A: Command Provenance
-
-Enables:
-
-- `:why`;
-- `:explain` range;
-- register provenance;
-- semantic dot-repeat explanation;
-- evidence lens;
-- agent edit explanation.
-
-Core object: `JeditCommandEvent`.
-
-### System B: Basis-Bound Views
-
-Enables:
-
-- historical basis preview;
-- time-travel yank;
-- stale diagnostics;
-- stale search results;
-- current-vs-checkpoint panes.
-
-Core object target:
-
-```text
-JeditBasisView = {
-  basisId,
-  currentHeadId,
-  viewPosture,
-  sourceEvidence,
-  readBudget,
-  returnCommand
-}
-```
-
-Product rule:
-
-```text
-Viewing a historical or proposal basis must never mutate current head unless an
-explicit admission command runs.
-```
-
-### System C: Result Sets And Proposal Strands
-
-Enables:
-
-- search result sets;
-- substitute preview;
-- global command preview;
-- formatter preview;
-- agent proposals;
-- admit selected;
-- macro dry-run.
-
-Core object targets:
-
-- `JeditResultSet`;
-- `JeditProposalStrand`;
-- `JeditAdmissionSelection`.
-
-### System D: Retained Material Provenance
-
-Enables:
-
-- time-travel yank;
-- register provenance;
-- causal undo fragments;
-- historical paste;
-- macro replay evidence.
-
-Core object target:
-
-```text
-JeditRetainedTextMaterial = {
-  materialRef,
-  digest,
-  sourceBasis,
-  sourceRange,
-  producingEvent,
-  retentionPosture
-}
-```
-
-Missing retention is an obstruction, not a fallback invitation.
-
-## Linked Invariants
-
-- Tests are executable spec.
-- Runtime truth beats compile-time theater.
-- Design should become repo truth.
-- Files and previews are projections.
-- Echo authority remains outside jedit product nouns.
-- Unsupported or rejected work is final for that attempt.
-- Retry is explicit new causal input.
-- Buffers, panes, panels, and lenses are different things.
-- The main editor surface stays quiet; richer context appears at the edges.
-
-## Design Alternatives Considered
-
-### Option A: Build a full timeline first
-
-Pros:
-
-- Visually impressive.
-- Could eventually unify history, replay, proposal, and agent workflows.
-
-Cons:
-
-- Too large for the next cycle.
-- Risks hiding missing event semantics behind UI spectacle.
-- Hard to keep honest before historical basis projection and durable replay are
-  complete.
-
-### Option B: Keep provenance JSON-only
-
-Pros:
-
-- Easier to test.
-- Useful for agents and CI quickly.
-
-Cons:
-
-- Does not create a user-facing product moment.
-- Leaves Jim's causal differentiator invisible during normal editing.
-
-### Option C: Command provenance and `:why` first
-
-Pros:
-
-- Narrow enough to land.
-- Turns existing Vim, Echo, receipt, and history work into product shape.
-- Gives users and agents the same facts through different projections.
-- Creates a foundation for history drawer, strand preview, macros, and agent
-  proposals.
-
-Cons:
-
-- Requires discipline to avoid dumping debug details into the editor surface.
-- Needs trust preflight so the first demo does not reveal lifecycle gaps.
-
-## Decision
-
-Choose Option C. `:why` is the next product-defining cycle. It starts with an
-Editor Trust Gate preflight, then proves a small set of commands through shared
-model facts, lower-mode summary, `:why`, JSON witness, and obstruction posture.
-
-## Implementation Slices
-
-- [x] Slice 0: Run Editor Trust Gate preflight and record blockers.
-- [x] Slice 1: Define `JeditCommandEvent` model and fixture shape.
-- [ ] Slice 2: Emit provenance for `dw`, `ciw`, `dd`, and `gUap`.
-- [ ] Slice 3: Render lower-mode command provenance summary.
-- [x] Slice 4: Add `:why` command-line dispatch.
-- [ ] Slice 5: Add JSON command provenance witness.
-- [ ] Slice 6: Add typed obstruction posture for unsupported, no-event, or
-      stale-basis cases.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [x] Trust preflight witness for open/edit/save/quit and disk verification.
-- [ ] Command event model test for stable event fields.
-- [ ] Runtime tests comparing command behavior with emitted provenance facts.
-- [ ] Render test for lower-mode summary at wide and narrow terminal widths.
-- [x] Command-line/detail test for `:why`.
-- [ ] JSON witness test for agent-readable command facts.
-- [ ] Obstruction test for unsupported or stale-basis command provenance.
-
-Required command assertions:
-
-- [ ] `dw` `:why` reports word motion target and deletion range.
-- [ ] `ciw` `:why` reports text object, range, register effect, and
-      receipt/result posture.
-- [ ] `dd` `:why` reports linewise deletion and affected line range.
-- [ ] `gUap` `:why` reports paragraph text object and transform operator.
-- [x] `:why` with no meaningful event reports calm obstruction.
-
-Documentation and process tests:
-
-- [ ] Roadmap/signpost docs link WF-0108 as the active next cycle.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [x] Editor Trust Gate preflight names any blockers before implementation
-      proceeds.
-- [ ] The Slice 1 command set (`dw`, `ciw`, `dd`, `gUap`) emits stable
-      provenance facts.
-- [ ] Lower-mode summary communicates the last meaningful command without
-      overwhelming normal editing.
-- [ ] `:why` exposes structured facts for the last meaningful command.
-- [ ] JSON witness exposes the same command event facts without terminal
-      scraping.
-- [ ] Unsupported, unavailable, or stale-basis cases return typed obstruction
-      facts.
-- [ ] CI and local validation are green.
-
-## Validation Plan
-
-Commands expected before PR:
-
-```bash
-npm run build
-node --test --test-concurrency=1 \
-  spec/editor-trust-preflight.spec.mjs \
-  spec/editor-trust-preflight-cli.spec.mjs \
-  spec/causal-roadmap-signpost.spec.mjs \
-  spec/design-cycle-policy.spec.mjs \
-  spec/vim-power-parity-matrix.spec.mjs \
-  spec/vim-power-target-usability-fixtures.spec.mjs
-npm run quality
-npx --yes markdownlint-cli2 docs/BEARING.md README.md VISION.md docs/design/0108-causal-command-provenance-surface.md
-git diff --check
-```
-
-Implementation PRs must add and run a concrete focused command-provenance spec
-path; do not leave template placeholders in shell command blocks.
-
-## Playback / Witness
-
-Target human playback once the `jim` alias is earned:
-
-```text
-jim demo.txt
-ciw
-
-
-:why
-```
-
-Current repo command while the alias is not earned:
-
-```text
-npm run dev -- demo.txt
-```
-
-Target witness playback:
-
-```bash
-node scripts/jedit-command-provenance-witness.mjs --json --command ciw
-```
-
-The script name is a target, not current runtime truth.
-
-## Risks
-
-Known risks:
-
-- Provenance could become noisy and violate the quiet-editor product invariant.
-- Event facts could overclaim Echo evidence when only app-owned state exists.
-- The first command set could skip editor trust gaps that users hit first.
-- Search and structural motion evidence may not yet cover `/` and `?`.
-
-Mitigations:
-
-- Keep lower-mode summaries compact and put full details behind an explicit
-  command.
-- Separate receipt/result posture from command syntax facts.
-- Run Slice 0 before implementation.
-- Move `/` and `?` search entry into the Editor Trust Gate if it blocks the
-  demo path.
-
-## Follow-On Debt
-
-Follow-on issues:
-
-- [WF-0109 Historical Basis Preview](https://github.com/flyingrobots/jedit/issues/134).
-- [WF-0110 Search Sets And Substitute Strand Preview](https://github.com/flyingrobots/jedit/issues/132).
-- [WF-0111 Historical Yank And Register Provenance](https://github.com/flyingrobots/jedit/issues/133).
-- [WF-0114 Macro Dry-Run With Obstruction Report](https://github.com/flyingrobots/jedit/issues/141).
-- [WF-0115 Causal Marks With Drift](https://github.com/flyingrobots/jedit/issues/137).
-- [WF-0116 Explain Range](https://github.com/flyingrobots/jedit/issues/140).
-- [WF-0117 Register Provenance Detail View](https://github.com/flyingrobots/jedit/issues/139).
-- [WF-0118 Semantic Dot-Repeat Explanation](https://github.com/flyingrobots/jedit/issues/136).
-- [WF-0119 Stale Diagnostics And Causal Quickfix](https://github.com/flyingrobots/jedit/issues/138).
-- [WF-0120 Agent Proposal Strands](https://github.com/flyingrobots/jedit/issues/142).
-
-## Retrospective
-
-Fill this in after implementation.
-
-What changed from the design:
-
-- ...
-
-What the tests proved:
-
-- ...
-
-What remains open:
-
-- ...
-
-PR:
-
-- https://github.com/flyingrobots/jedit/pull/
diff --git a/docs/design/0108a-why-observation-evidence-roadmap.md b/docs/design/0108a-why-observation-evidence-roadmap.md
deleted file mode 100644
index 6a482b69..00000000
--- a/docs/design/0108a-why-observation-evidence-roadmap.md
+++ /dev/null
@@ -1,439 +0,0 @@
----
-title: "WF-0108A - :why Observation Evidence Roadmap"
-legend: "WF"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/181"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-06-29"
-updated: "2026-06-30"
----
-
-# WF-0108A - :why Observation Evidence Roadmap
-
-## Linked Issue
-
-- [#181 WF-0108A: Complete `:why` through observation evidence](https://github.com/flyingrobots/jedit/issues/181)
-
-## Decision Summary
-
-`:why` is a Jim feature with two different questions that must not be
-collapsed.
-
-No-selection `:why` answers the command question: why did Jim treat the last
-command as meaningful? That can start from local command provenance, then grow
-receipt links as Echo evidence becomes available.
-
-Cursor, selection, or range `:why` answers the text question: why is this text
-here? That must come from the rope/worldline path: current reading coordinate,
-current rope head, reverse rope diff or rewrite walk, producing tick, and then
-receipt or BTR provenance when available.
-
-WF-0108 already landed the narrow command-dispatch and local command-provenance
-base. WF-0108A closes the remaining gap by making evidence posture honest,
-then moving range explanations toward retained rope history without moving Jim
-editor nouns into Echo or pretending that Jim/Echo integration goes through
-Continuum.
-
-## Sponsored Human
-
-A Jim user wants `:why` to explain the last meaningful modal edit in product
-terms so that recovery, review, and trust do not require reading raw debug
-state or guessing which basis the editor observed.
-
-## Sponsored Agent
-
-An agent needs stable `:why` JSON witness fields and typed obstruction posture
-so it can inspect command provenance without scraping terminal prose or
-inventing Echo evidence that Jim has not received.
-
-## Hill
-
-By the end of WF-0108A, a user or agent can run representative Jim commands,
-ask `:why`, and inspect the same command, target, range, register, lower-mode,
-and evidence-posture facts through human text and JSON witnesses.
-
-## Current Truth
-
-Current builds already contain the first `:why` proof:
-
-- command-line dispatch for `:why`;
-- a command event model for meaningful Vim-powered edits;
-- a calm no-event response when no meaningful command is available;
-- human-facing explanation surfaces;
-- agent-facing witness paths for the local command event.
-
-The remaining production gaps are observation evidence and range causality:
-
-- local reading caches must not be represented as Echo ReadingEnvelopes;
-- `:why` must name the local window posture, explicit Echo reading identity, or
-  obstruction posture it depended on;
-- unsupported, stale, missing, or translated evidence must be typed instead of
-  collapsed into prose;
-- range `:why` must walk retained rope diff history instead of consulting
-  ephemeral command memory;
-- the first golden commands must prove the same command facts through runtime
-  behavior, JSON, and human explanation;
-- cryptographic proof posture should have reserved fields, but fake proof
-  strength must not be claimed before Echo and Continuum can witness it.
-
-## Problem
-
-`:why` currently proves that Jim can explain a local meaningful command. It
-does not yet prove complete observation evidence for every target command
-family, and it does not yet explain a selected text range from retained rope
-history.
-
-Without explicit evidence posture, a local reading cache can sound like an Echo
-ReadingEnvelope. Without range-at-head lookup, a text explanation can degrade
-into string search or command-memory replay. Both are false authority.
-
-## Scope
-
-This roadmap-lock cycle includes:
-
-- the Jim/Echo/Continuum ownership boundary for `:why` evidence;
-- the jedit, Echo, and Continuum issue topology;
-- the execution order for completing observation evidence;
-- the proof posture for future cryptographic evidence without implementation
-  overclaiming.
-
-It does not implement the runtime slices. Those are tracked as the linked
-jedit, Echo, and Continuum issues below.
-
-## Product Boundary
-
-The ownership split is deliberately strict:
-
-| Layer | Owns | Does not own |
-| --- | --- | --- |
-| Jim / jedit | `:why` UX, command catalog, Vim command grammar, editor facts, JSON witness shape | Runtime admission or generic protocol doctrine |
-| Echo | Reading envelopes, receipts, retained evidence, runtime admission, replayable basis facts | Jim commands, Vim nouns, buffers, registers, macros |
-| Continuum | Portable profile vocabulary, evidence posture, participant discovery, conformance fixtures | Jim/Echo app integration, runtime implementation, editor app ontology |
-
-Jim is an Echo app. Jim does not talk to Echo through Continuum. Continuum
-becomes relevant only where Jim/Echo evidence needs to be portable to WARP TTD,
-Graft, WARP DRIVE, agents, or other Continuum participants.
-
-## User Experience / Product Shape
-
-The product shape stays the golden Jim loop:
-
-- explain;
-- preview;
-- admit;
-- recover.
-
-For WF-0108A, the visible user action is still:
-
-```vim
-:why
-```
-
-The output should explain the last meaningful command without requiring the
-user to understand Echo internals. When evidence is partial, unavailable,
-stale, unsupported, translated, redacted, or obstructed, the wording should say
-that plainly instead of silently falling back to a weaker claim.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Command[User runs Jim command] --> Why[User runs :why]
-  Why --> Evidence[Jim reports command facts and evidence posture]
-  Evidence --> Review[User reviews or recovers from the edit]
-  Evidence --> Obstruction[Jim reports typed missing evidence when needed]
-```
-
-### Wide UI Mockup
-
-Not applicable for this roadmap-lock PR. Runtime slices that change rendered
-`:why` output should include focused snapshots or witness text.
-
-### Narrow UI Mockup
-
-Not applicable for this roadmap-lock PR. The intended narrow behavior is
-plain-text wrapping with no visual-only facts.
-
-### Accessibility Considerations
-
-`:why` facts must be available as text and JSON, not only through layout,
-color, or terminal position.
-
-## Runtime / API Contract
-
-The planned contract is a Jim-owned `:why` explanation surface backed by a
-stable JSON witness. The contract should include:
-
-- command identity and parsed form;
-- target or typed obstruction;
-- affected range or transform;
-- register and lower-mode posture;
-- Echo reading basis or missing-evidence posture;
-- receipt or retained evidence refs when available;
-- future-proof posture fields that do not claim proof strength before evidence
-  exists.
-- Supported Outcome Settlement outcome vocabulary: completion, repairable
-  obstruction, authority block, underdetermined support, dispute, and invalid
-  proposal must remain distinct in JSON and human text.
-
-Echo supplies generic reading, receipt, obstruction, and replay evidence. Jim
-projects that evidence into editor language. Continuum names portable protocol
-vocabulary only when the facts cross participant boundaries.
-
-`JeditWhyObservation` is an honesty envelope, not a causal authority source.
-It may label local editor provenance, local text-window posture, receipt refs,
-explicit Echo ReadingEnvelope refs, translated evidence, native evidence,
-missing evidence, stale basis, and obstruction. It must not synthesize an Echo
-ReadingEnvelope from a local cache or reading id.
-
-The follow-on range contract is `JeditWhyRange`: given a current rope head and
-byte range, map the range backward through retained `RopeDiff` and
-`RopeRewrite` history, identify the producing tick or receipt when possible,
-and report typed unavailable or missing evidence when BTR or provenance payload
-is absent.
-
-## Lower Modes
-
-Required lower modes:
-
-- JSON witness output for agents and tests;
-- deterministic no-event output when no meaningful command exists;
-- typed obstruction output for missing, stale, unsupported, redacted,
-  translated, or unavailable evidence;
-- plain terminal text that does not require color or layout to understand.
-
-## Accessibility Posture
-
-| Concern | Posture |
-| --- | --- |
-| Semantic labels or facts | Command, target, range, register, and evidence posture must be textual and machine-readable. |
-| Focus order or ownership | `:why` remains a command-line action; future rendered panels must not steal input focus silently. |
-| Hidden or visual-only information | No evidence fact may be conveyed only by color, glyph, or placement. |
-| Keyboard behavior | The feature remains keyboard-first through Vim command-line dispatch. |
-| Secret or redaction behavior | Redacted evidence must be named as redacted rather than omitted as if complete. |
-
-## Localization / Directionality Posture
-
-| Concern | Posture |
-| --- | --- |
-| User-visible strings | Roadmap-lock PR only changes docs. Runtime slices must account for changed `:why` strings. |
-| Catalog keys | Future command catalog work should provide stable ids before broad string expansion. |
-| Supported locales updated | Not applicable for this roadmap-lock PR. |
-| Directionality assumptions | `:why` output should not encode meaning through left-to-right alignment. |
-| Validation command | Runtime slices should add focused tests for any changed user-visible output. |
-
-## Agent Inspectability / Explainability Posture
-
-Agents should inspect `:why` through stable witness fields:
-
-- command id and key form;
-- effect class;
-- resolved target or typed obstruction;
-- range, transform, and register posture;
-- reading identity or missing-evidence posture;
-- receipt refs when available;
-- proof posture slots that distinguish native, translated, fixture,
-  digest-only, claimed, and absent evidence.
-
-Agents must not need to parse the human `:why` paragraph to understand whether
-evidence is complete.
-
-## Goalpost
-
-The active jedit goalpost is:
-
-- [#181 WF-0108A: Complete `:why` through observation evidence](https://github.com/flyingrobots/jedit/issues/181)
-
-It is complete when a user can run a representative Vim command, ask `:why`,
-and receive an explanation that includes:
-
-- parsed command identity;
-- resolved target or typed obstruction;
-- affected range or transform;
-- register and lower-mode effects where relevant;
-- Echo reading basis or explicit missing-evidence posture;
-- receipt or retained evidence refs when available;
-- JSON witness fields matching the human-facing truth.
-
-For range `:why`, completion additionally requires a selected or cursor-derived
-range at the current rope head to resolve through retained rope history rather
-than through `editor.lastVimEdit` or text-content search.
-
-## Implementation Slices
-
-The first implementation slices are jedit-owned:
-
-| Issue | Slice | Proof |
-| --- | --- | --- |
-| [#173](https://github.com/flyingrobots/jedit/issues/173) | Lock WF-0108A roadmap and cross-repo issue links | Docs name ownership, order, and evidence boundaries |
-| [#174](https://github.com/flyingrobots/jedit/issues/174) | Add `JeditWhyObservation` coordinate model | Model test proves basis/window/authority fields and no fake Echo envelope |
-| [#175](https://github.com/flyingrobots/jedit/issues/175) | Upgrade text-window envelope evidence fields | Window evidence distinguishes full, partial, stale, and unavailable |
-| [#176](https://github.com/flyingrobots/jedit/issues/176) | Wire `:why` JSON to Echo ReadingEnvelope identity | JSON witness includes Echo reading identity or obstruction |
-| [#177](https://github.com/flyingrobots/jedit/issues/177) | Add typed `:why` evidence obstructions | Unsupported and stale cases return machine-readable posture |
-| [#178](https://github.com/flyingrobots/jedit/issues/178) | Golden `dw` witness through Echo evidence | Human and JSON `:why` agree for `dw` |
-| [#179](https://github.com/flyingrobots/jedit/issues/179) | Expand witness to `dd`, `ciw`, and `gUap` | Each command proves command, target, range, and evidence facts |
-| [#180](https://github.com/flyingrobots/jedit/issues/180) | Add proof posture slots for future crypto evidence | Schema reserves proof posture without overclaiming |
-| [#194](https://github.com/flyingrobots/jedit/issues/194) | Explain selected text from rope diff history | Range witness walks rope diffs by coordinate and survives cleared command memory |
-
-## Echo Dependencies
-
-Echo work is required where `:why` needs runtime evidence, not editor semantics:
-
-| Issue | Slice | Why Jim needs it |
-| --- | --- | --- |
-| [echo#628](https://github.com/flyingrobots/echo/issues/628) | Export ReadingEnvelope identity for app consumers | Lets Jim cite the reading it observed |
-| [echo#629](https://github.com/flyingrobots/echo/issues/629) | Stabilize contract obstruction taxonomy for Jim | Lets Jim report typed missing/stale evidence |
-| [echo#630](https://github.com/flyingrobots/echo/issues/630) | Return retained receipt and reading evidence refs | Lets `:why` cite real runtime evidence |
-| [echo#631](https://github.com/flyingrobots/echo/issues/631) | Preserve trusted-host scheduler split for jedit witness | Prevents app code from claiming runtime admission authority |
-| [echo#632](https://github.com/flyingrobots/echo/issues/632) | Add replay proof for Jim edit and bounded reading | Makes recovery/debug claims evidence-backed |
-| [echo#633](https://github.com/flyingrobots/echo/issues/633) | Define canonical digest domains for observation evidence | Stabilizes future-proof posture and comparison |
-
-Echo must not learn Jim, Vim, buffers, registers, macros, or `:why`. It should
-export generic runtime evidence that Jim can project into editor language.
-
-## Continuum Dependencies
-
-Continuum work is protocol work. It is not on the Jim-to-Echo call path.
-
-Relevant Continuum goalposts:
-
-- [continuum#59](https://github.com/flyingrobots/continuum/issues/59) tracks
-  observation evidence and capability proof protocol slices.
-- [continuum#58](https://github.com/flyingrobots/continuum/issues/58) tracks
-  the later Verkle, IPA, ZK, DID, and UCAN proof posture plan.
-
-Use Continuum vocabulary when Jim/Echo facts need to become portable:
-
-- participant descriptors;
-- observation profile fixtures;
-- multidimensional evidence posture;
-- contract index and `qw doctor` conformance reports;
-- WARP TTD discovery and generic attach behavior;
-- future capability and proof presentation posture.
-
-Do not put Jim-only `:why` tasks in Continuum unless the task defines portable
-protocol shape or conformance evidence for other participants.
-
-## WF-0106 Relationship
-
-WF-0106 is the supporting product surface plan:
-
-- [#192 WF-0106: Emacs ideas to steal causally](https://github.com/flyingrobots/jedit/issues/192)
-
-It should reinforce `:why` by adding command catalog, describe surfaces, prefix
-help, register provenance, macro replay reports, buffer/mode reports, and
-diagnostic/debug trace buffers. Those features consume the same command and
-evidence truth; they do not replace WF-0108A.
-
-## Execution Order
-
-1. Lock this roadmap and issue topology through [#173](https://github.com/flyingrobots/jedit/issues/173).
-2. Add the honesty-only `JeditWhyObservation` model through [#174](https://github.com/flyingrobots/jedit/issues/174).
-3. Add typed local evidence obstructions through [#177](https://github.com/flyingrobots/jedit/issues/177).
-4. Upgrade text-window evidence fields through [#175](https://github.com/flyingrobots/jedit/issues/175).
-5. Wire Echo reading identity when Echo exposes the needed refs through [#176](https://github.com/flyingrobots/jedit/issues/176).
-6. Start range-at-head reverse rope-diff explanation through [#194](https://github.com/flyingrobots/jedit/issues/194).
-7. Prove `dw` end to end through [#178](https://github.com/flyingrobots/jedit/issues/178).
-8. Expand the command set through [#179](https://github.com/flyingrobots/jedit/issues/179).
-9. Add future-proof posture slots through [#180](https://github.com/flyingrobots/jedit/issues/180).
-
-This order keeps Jim useful before the full protocol and crypto posture are
-available, while preventing fake evidence claims.
-
-## Non-Goals
-
-- Do not rename the repo, package, contracts, or WSC directories.
-- Do not move Jim editor nouns into Echo.
-- Do not route Jim/Echo integration through Continuum.
-- Do not implement Verkle, IPA, ZK, DID, or UCAN proof systems in jedit.
-- Do not claim native cryptographic proof strength before witnesses exist.
-- Do not let `:why` become a raw debug dump.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [x] `JeditWhyObservation` model test covering basis, window, authority, and
-      evidence posture.
-- [x] `JeditWhyObservation` regression proving a local reading cache does not
-      claim `EchoReadingEnvelope` evidence.
-- [ ] JSON witness test proving Echo reading identity or typed missing evidence
-      appears without terminal scraping.
-- [x] Range `:why` test proving explanation survives cleared or mutated
-      `editor.lastVimEdit`.
-- [x] Duplicate-text range `:why` test proving coordinate lookup, not string
-      search.
-- [ ] Golden command tests for `dw`, `dd`, `ciw`, and `gUap`.
-- [ ] Obstruction tests for stale, unavailable, unsupported, translated, and
-      redacted evidence posture.
-
-Documentation and process tests:
-
-- [x] Design-cycle policy test proving WF-0108A preserves required full-cycle
-      headings.
-
-## Acceptance Criteria
-
-- `:why` explains the last meaningful command in user-facing Jim terms.
-- JSON witness output contains the same core facts without terminal scraping.
-- Missing, stale, partial, unsupported, redacted, or translated evidence is
-  machine-readable.
-- Local text-window evidence is never mislabeled as an Echo ReadingEnvelope.
-- Range `:why` resolves from the current rope head and retained rewrite history
-  when available.
-- `dw`, `dd`, `ciw`, and `gUap` each have command assertions covering command
-  identity, target, range or transform, register posture where applicable, and
-  evidence posture.
-- Echo evidence is cited through generic reading/receipt refs, not Jim nouns.
-- Continuum protocol terms are used only where the evidence crosses participant
-  boundaries.
-
-## Validation Plan
-
-Roadmap-lock PRs should run:
-
-```bash
-npx --yes markdownlint-cli2 \
-  docs/BEARING.md \
-  docs/design/0106-emacs-ideas-to-steal-causally.md \
-  docs/design/0108-causal-command-provenance-surface.md \
-  docs/design/0108a-why-observation-evidence-roadmap.md
-node --test --test-concurrency=1 spec/design-cycle-policy.spec.mjs
-git diff --check
-```
-
-Implementation PRs must add focused runtime tests for the specific slice and
-run the relevant command-provenance, witness, and Echo-history specs.
-
-## Playback / Witness
-
-Roadmap playback for this PR is:
-
-- inspect this design document for ownership boundaries and slices;
-- inspect linked jedit, Echo, and Continuum issues for repo-specific work;
-- run `spec/design-cycle-policy.spec.mjs` for template/process enforcement;
-- run markdownlint and `git diff --check` for docs hygiene.
-
-Implementation playback will move into the slice PRs and must include focused
-runtime witnesses for command explanations, JSON output, and typed evidence
-obstructions.
-
-## Retrospective
-
-This roadmap-lock pass clarified that the remaining `:why` work is evidence
-completion, not basic command dispatch. The important outcome is the ownership
-boundary: Jim owns the user-facing explanation and editor facts, Echo owns
-generic runtime evidence, and Continuum owns portable protocol vocabulary only
-when facts cross participant boundaries.
-
-The main correction was moving vague cross-repo ambition into explicit slices:
-Jedit can start with local observation coordinates and typed obstructions before
-Echo exposes every ReadingEnvelope ref, but local cache evidence must remain
-local. The next product pivot is range `:why` through rope diffs and producing
-ticks, while the Verkle, IPA, ZK, DID, and UCAN posture remains
-protocol-facing and future-proofed rather than claimed.
-
-Implementation retrospectives still belong in the slice PRs that land the
-model, witnesses, Echo evidence wiring, and golden command assertions.
diff --git a/docs/design/0121-strand-braid-worldline-ux.md b/docs/design/0121-strand-braid-worldline-ux.md
index e44d2f7e..d1bce009 100644
--- a/docs/design/0121-strand-braid-worldline-ux.md
+++ b/docs/design/0121-strand-braid-worldline-ux.md
@@ -213,12 +213,6 @@ check before planning against it.
 
 ## Follow-On Design
 
-- [WF-0122 - Optimistic Strand Worldline Phases](0146-optimistic-strand-worldline-phases.md)
-  narrows the local typing case: rapid user input should render as an
-  optimistic strand braided with the canonical basis, with WAL, pending,
-  admitted, observed, settled, and conflicted phases surfaced in the
-  worldline view.
-
 Jim can prototype UI affordances before the full substrate lands, but it must
 label any missing Echo recovery posture honestly.
 
diff --git a/docs/design/0145-jedit-cli-version-identity.md b/docs/design/0145-jedit-cli-version-identity.md
deleted file mode 100644
index 5dca1b47..00000000
--- a/docs/design/0145-jedit-cli-version-identity.md
+++ /dev/null
@@ -1,212 +0,0 @@
----
-title: "WF-0145 - jedit CLI version identity"
-legend: "WF"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/145"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-06-25"
-updated: "2026-06-25"
----
-
-# WF-0145 - jedit CLI version identity
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/145
-
-## Decision Summary
-
-jedit will expose a lightweight startup identity surface before the TUI starts.
-`--version` and `-V` print the jedit package identity, and `--help` / `-h`
-print the same identity plus supported startup options. These paths exit before
-Bijou, terminal mouse handling, Echo-hosted text runtime, Graft, or title
-rendering initialization.
-
-## Sponsored Human
-
-A maintainer wants to verify the installed jedit identity from a terminal so
-that release and integration checks can prove the local toolchain, without
-starting the full editor.
-
-## Sponsored Agent
-
-An agent needs a stable command output contract so it can verify jedit in a
-cross-repo chain with Colorful and Graft, without inferring version state from
-private package files or interactive UI startup.
-
-## Hill
-
-By the end of this cycle, `node dist/main.js --version` and `node dist/main.js
---help` provide package identity from the command line, and the repo proves
-that those paths return before TUI initialization.
-
-## Current Truth
-
-- `package.json` names the package `jedit` and marks it private, but does not
-  declare a package `version`:
-  [package.json#L1:b01370ffe01cb5c8691f1e5c4774d0d386a4e4e2](https://github.com/flyingrobots/jedit/blob/b01370ffe01cb5c8691f1e5c4774d0d386a4e4e2/package.json#L1).
-- `src/main.ts` initializes the text runtime profile, Bijou context, workspace
-  app, terminal mouse handling, and TUI at module top level:
-  [src/main.ts#L27:b01370ffe01cb5c8691f1e5c4774d0d386a4e4e2](https://github.com/flyingrobots/jedit/blob/b01370ffe01cb5c8691f1e5c4774d0d386a4e4e2/src/main.ts#L27).
-- `npm start` runs `node dist/main.js`; no startup flag is documented or
-  handled before editor startup:
-  [package.json#L15:b01370ffe01cb5c8691f1e5c4774d0d386a4e4e2](https://github.com/flyingrobots/jedit/blob/b01370ffe01cb5c8691f1e5c4774d0d386a4e4e2/package.json#L15).
-- Existing release-gate material uses `0.1.0-release-gate` as the current
-  jedit/Echo proof identity, for example the final witness report.
-
-## Problem
-
-There is no cheap way to ask jedit what it is. A version check currently means
-reading repository files or starting the editor. That is wrong for release
-chains, install checks, and agent-run integration diagnostics.
-
-## Scope
-
-This cycle includes:
-
-- Add a private package version to `package.json`.
-- Add a small jedit package identity module.
-- Add startup flag handling for `--version`, `-V`, `--help`, and `-h`.
-- Ensure startup identity output exits before TUI initialization.
-- Add tests that pin the command output and keep the runtime identity aligned
-  with `package.json`.
-
-## Non-Goals
-
-This cycle does not include:
-
-- Publishing jedit to npm.
-- Renaming the executable from `jedit` to `jim`.
-- Adding a `bin` entry.
-- Changing release policy or tagging a release.
-- Starting or changing Graft, Colorful, Echo, or Wesley runtime behavior.
-
-## User Experience / Product Shape
-
-The user can run:
-
-```bash
-node dist/main.js --version
-```
-
-Expected output:
-
-```text
-jedit 0.1.0-release-gate
-```
-
-The user can also run:
-
-```bash
-node dist/main.js --help
-```
-
-Expected output begins with the same package identity and names the supported
-startup flags. The command exits immediately after printing.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[User runs startup identity flag] --> Guard[Startup CLI guard parses flag]
-  Guard --> Version[Print version or help]
-  Version --> Exit[Exit before TUI initialization]
-```
-
-### Wide UI Mockup
-
-Not applicable. This is command output, not rendered TUI layout.
-
-### Narrow UI Mockup
-
-Not applicable. The output is short single-column terminal text.
-
-### Accessibility Considerations
-
-The output is plain text, does not rely on color, and can be read by shell
-logs, screen readers, and agents.
-
-## Runtime / API Contract
-
-The startup identity contract is:
-
-- `--version` prints `jedit \n`.
-- `-V` prints the same output.
-- `--help` prints `jedit ` and supported startup options.
-- `-h` prints the same help output.
-- Any startup identity path returns before calling `initDefaultContext`,
-  `createWorkspaceApp`, or `run`.
-
-The package identity contract is:
-
-- `package.json.version` is `0.1.0-release-gate` until a later release cycle
-  changes it intentionally.
-- The runtime identity constant must match `package.json.version`.
-
-## Lower Modes
-
-The lower mode is the command itself. It is non-interactive, plain text, and
-does not require a terminal, Echo runtime, Graft, Colorful, or an opened
-workspace.
-
-## Data / State Model
-
-| Category | Description |
-| --- | --- |
-| Source of truth | `package.json.version` plus a runtime identity constant pinned by tests. |
-| Derived state | Version and help text. |
-| Invalid states | Runtime identity differs from `package.json.version`. |
-| Reset behavior | No persisted state is read or written. |
-| Serialization | Plain terminal text. |
-| Deterministic assumptions | Output depends only on committed package identity constants. |
-
-## Accessibility Posture
-
-| Concern | Posture |
-| --- | --- |
-| Semantic labels or facts | The tool name and version are text. |
-| Focus order or ownership | No TUI focus exists on identity paths. |
-| Hidden or visual-only information | None. |
-| Keyboard behavior | Shell command only. |
-| Secret or redaction behavior | No secrets are read or printed. |
-
-## Localization / Directionality Posture
-
-| Concern | Posture |
-| --- | --- |
-| User-visible strings | Startup help is English ASCII command text. |
-| Directionality | Single-column command text; no bidirectional layout behavior. |
-| Translation | Not localized in this cycle. |
-
-## Test Strategy
-
-- RED: add startup CLI unit tests for `--version`, `-V`, `--help`, `-h`, and
-  no-match behavior.
-- RED: add a package identity spec that compares runtime identity with
-  `package.json`.
-- GREEN: implement the startup guard and package identity.
-- VERIFY: run the focused specs, build, quality gate, and smoke-test built
-  `dist/main.js --version` and `--help`.
-
-## Retrospective
-
-Implemented as a narrow startup guard in `src/main.ts` backed by
-`src/app/jedit-startup-cli.ts` and `src/app/jedit-package-identity.ts`.
-`package.json` now declares the private jedit identity as
-`0.1.0-release-gate`, and the runtime constant is pinned to that manifest
-value by `spec/jedit-startup-cli.spec.mjs`.
-
-Evidence:
-
-- `node --test spec/jedit-startup-cli.spec.mjs`
-- `node node_modules/typescript/bin/tsc -p tsconfig.json`
-- `npm run --silent quality`
-- `npm run build`
-- `npm run test:all`
-- `git diff --check`
-
-The final spec includes both the pure startup parser contract and a spawned
-`node dist/main.js --version` / `--help` witness, so the command boundary proves
-the identity paths return before TUI initialization.
diff --git a/docs/design/0146-optimistic-strand-worldline-phases.md b/docs/design/0146-optimistic-strand-worldline-phases.md
deleted file mode 100644
index 73cdc7af..00000000
--- a/docs/design/0146-optimistic-strand-worldline-phases.md
+++ /dev/null
@@ -1,329 +0,0 @@
----
-title: "WF-0122 - Optimistic Strand Worldline Phases"
-legend: "WF"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/158"
-status: "superseded"
-owners:
-  - "@flyingrobots"
-created: "2026-06-26"
-updated: "2026-06-27"
----
-
-# WF-0122 - Optimistic Strand Worldline Phases
-
-## Linked Issue
-
-- [#158 WF-0122: Optimistic strand worldline phases](https://github.com/flyingrobots/jedit/issues/158) was closed and split after
-  [PR #160](https://github.com/flyingrobots/jedit/pull/160) landed the
-  JEDIT-side projection posture foundation.
-
-## Outcome
-
-PR #160 landed the JEDIT-side product and architecture slice:
-
-- rapid typing renders through local/session projection without waiting for a
-  bounded Echo observation to return;
-- bounded Echo readings carry coverage and cannot replace whole editor text;
-- local optimistic text remains visible on obstruction;
-- speculative edit posture is explicit enough for the UI/history surfaces;
-- dependent optimistic edits are blocked when an earlier dependency obstructs;
-- worldline/history UI can name canonical, session, speculative, braid, and
-  obstructed posture.
-
-The broader WF-0122 cycle is now superseded by focused follow-up issues instead
-of remaining open as one umbrella. The remaining native runtime work moved to
-[#164 Native Echo speculative intent runtime](https://github.com/flyingrobots/jedit/issues/164).
-WF-0108 `:why` will consume this posture when explaining optimistic or
-conflicted visible text.
-
-## Decision Summary
-
-Jim should treat fast local typing as an optimistic strand braided with the
-current canonical basis, not as dirty text waiting for a filesystem save and
-not as a projection that rolls back invisibly when Echo obstructs an intent.
-
-The visible buffer can be a braid:
-
-```text
-visible braid = canonical materialized basis + local optimistic intent strand
-```
-
-Echo intake, WAL durability, scheduler admission, materialized observation,
-retained settlement, and conflict are separate phases. The worldline/history
-view should show those phases directly so the user can answer:
-
-- Did Echo receive this intent?
-- Is it durable in the WAL?
-- Has it been admitted to the canonical causal worldline?
-- Has Jim observed/materialized the admitted basis?
-- Is replay/settlement evidence retained?
-- Am I viewing canonical mainline or an optimistic braid?
-
-## Problem
-
-Classic editor state words like `dirty`, `unsaved`, `failed`, and `rollback`
-hide Jim's actual model.
-
-Rapid typing should not wait for Echo scheduler admission, tick
-materialization, BTR, or a fresh observed reading before characters appear on
-screen. The local UI should draw immediately. Once Echo receives an intent,
-the user should be able to see that the local strand is durable even if it is
-not yet canonical.
-
-If admission later obstructs, Jim should not erase the local text. The local
-optimistic strand remains a causal object the user can inspect, resolve,
-braid, admit later, or rewind away explicitly.
-
-## Product Contract
-
-Jim has three different facts that must remain visible:
-
-| Fact | Question | Example |
-| --- | --- | --- |
-| Display projection | What text am I looking at now? | `braid canonical@104 + local@3` |
-| Durability phase | How far did this intent get? | `WAL receipt:r105` |
-| Admission phase | Is this canonical worldline data? | `pending`, `admitted`, `conflict` |
-
-The visible editor may show text that is not yet canonical. That is allowed
-when the UI names the current projection honestly.
-
-## Phase Vocabulary
-
-These phases should be distinct in lower-mode/statusline text, the history
-drawer, `:why`, and future agent surfaces.
-
-| Phase | Meaning | Evidence |
-| --- | --- | --- |
-| `local` | The UI has projected the edit locally. | Local editor sequence. |
-| `unconfirmed` | Submitted from Jim, no Echo receipt yet. | Local request id. |
-| `WAL` | Echo intake received and durably recorded intent. | Receipt id. |
-| `pending` | WAL-backed intent awaits admission or materialization. | Receipt id. |
-| `admitted` | Echo admitted the intent into causal history. | Tick/diff id. |
-| `observed` | Jim has read a materialized basis including it. | Reading id. |
-| `settled` | Retained witness/checkpoint/hologram exists. | WSC/checkpoint id. |
-| `conflicted` | Intent cannot collapse cleanly into canonical. | Obstruction issue. |
-
-`admitted` and `settled` are not synonyms.
-
-```text
-admitted = accepted into the causal worldline
-settled  = retained replay/materialization evidence exists
-```
-
-## Typing Flow
-
-The intended typing path is:
-
-```text
-keydown
--> local projection updates immediately
--> optimistic local strand gains an intent node
--> Echo receives the intent
--> intent phase becomes WAL
--> scheduler/admission advances the node
--> materialized observation catches up
--> settlement evidence is retained when available
-```
-
-The UI must not require the full path before showing the character.
-
-## Conflict Flow
-
-On obstruction, Jim keeps the local optimistic strand visible and marks the
-worldline as conflicted:
-
-```text
-canonical: A -- B -- C
-                    \
-local:               x -- y -- !z
-
-visible braid: C + x + y + z
-phase: conflicted at z
-```
-
-The user can then choose an explicit action:
-
-- inspect the conflict;
-- stay in the optimistic braid;
-- fork a named strand from the optimistic projection;
-- resolve the conflict into a braid proposal;
-- admit the resolved braid;
-- rewind the local strand.
-
-No invisible rollback is allowed for a WAL-backed local intent.
-
-## Worldline View
-
-The history drawer should evolve from a flat event list into a compact
-worldline rail.
-
-Example:
-
-```text
-Worldlines
-C  canonical     tick:104     settled      main@104
-L  local         intent:107   conflicted   receipt:r107
-B  visible       braid        active       canonical@104 + local@3
-
-Graph
-C | 101 settled      open notes.md
-C | 102 settled      insert "a"
-C | 103 settled      insert "b"
-C | 104 settled      insert "c"
-L \ 105 WAL          insert "X"
-L o 106 pending      insert "Y"
-L ! 107 conflicted   insert "Z"
-B = active braid     canonical@104 + local@105..107
-```
-
-The first implementation does not need a full graph renderer. A list with
-clear strand labels and phases is enough if it answers the durability and
-admission questions.
-
-## Statusline Contract
-
-Lower-mode/statusline text should reveal when the editor is not showing pure
-canonical mainline.
-
-Examples:
-
-```text
-worldline canonical@104
-worldline canonical@104 + local@2 | braid active | WAL:2
-worldline canonical@104 + local@3 | conflict intent:107
-```
-
-This should sit beside, not replace, filesystem materialization posture.
-
-## `:why` Contract
-
-When the visible text includes optimistic or conflicted local intent, `:why`
-should explain the braid rather than pretending the current buffer is pure
-canonical text.
-
-Example:
-
-```text
-:why
-visible buffer: braid canonical@104 + local optimistic strand@3
-last intent: insert "Z"
-durability: WAL receipt:r107
-admission: conflicted
-materialization: not observed
-next action: inspect, resolve, stay local, braid, admit, or rewind
-```
-
-## Small Implementation Slice
-
-The smallest typing-latency improvement should stay aligned with this model:
-
-1. Update local editor projection immediately for insert-mode production keys.
-2. Mark the visible projection as optimistic instead of dirty-only.
-3. Keep the existing Echo edit command path for receipt/materialization.
-4. Do not roll back local text on obstruction.
-5. Add history/statusline evidence that the projection is an optimistic braid.
-6. Add a regression proving rapid typing updates visible text before Echo
-   observe/materialization completes.
-
-This slice can be implemented before the full worldline graph exists.
-
-## Architecture Correction: Speculation Belongs To Echo
-
-Jim/JEDIT must not own a fake pre-Echo predictive strand as durable truth.
-JEDIT may render keystrokes immediately, but the causal runtime underneath that
-projection must be Echo-owned speculative intent state. The UI should render
-projection/status facts; it should not invent an app-local worldline that can
-silently diverge from Echo.
-
-The future Echo client runtime should expose speculative causal intents with
-receipt/status evidence. Useful intent statuses include:
-
-- `predicted`;
-- `submitted`;
-- `admitted`;
-- `rebased`;
-- `blocked`;
-- `obstructed`;
-- `superseded`;
-- `abandoned`.
-
-Useful projection labels include:
-
-- `canonical`;
-- `session`;
-- `speculative`;
-- `braid`;
-- `obstructed`.
-
-If one predicted intent obstructs, dependent later intents become blocked,
-rebased, superseded, or abandoned through explicit causal records. They must
-not disappear through silent rollback. JEDIT can still draw the visible text
-quickly, but each rendered speculative edge should have an Echo receipt,
-request id, or obstruction status once the runtime can supply it.
-
-Example:
-
-```text
-user types: abcdef
-a -> admitted as receipt:a
-b -> obstructed by footprint check
-cdef -> blocked-by-b, rebased, superseded, or abandoned by explicit status
-visible text -> remains a named speculative/braid projection until resolved
-```
-
-The important rule is that `cdef` cannot later be reported as admitted through
-the same dependency chain while `b` remains obstructed. A future Echo
-speculative runtime should own the dependency graph and transform/rebase rules.
-Until then, JEDIT guardrails must preserve the local projection and mark
-dependent local work as blocked rather than silently rolling it back or
-claiming it was admitted.
-
-This document records the doctrine and the landed JEDIT-side guardrails. PR #160
-does not implement full Echo predictive runtime, full braid resolution, watcher
-intake, or conflict UI. It prevents JEDIT from cementing the wrong abstraction
-while the projection and save/materialization paths are made safe.
-
-## Non-Goals
-
-- Do not make Git branches or worktrees the live isolation model.
-- Do not make filesystem save state the source of truth for local intent.
-- Do not hide obstruction by reverting the local projection.
-- Do not require every design phase to exist in Echo core before Jim can label
-  the UI honestly.
-
-## Relationship To WF-0121
-
-WF-0121 defines the broad strand/braid worldline UX. This document narrows one
-critical subproblem: fast local typing and its durability/admission phases.
-
-The design should feed back into:
-
-- the history/worldline drawer;
-- lower-mode/statusline posture;
-- `:why` provenance;
-- agent strand contracts;
-- the immediate production typing-latency fix.
-
-## Acceptance Checklist
-
-Closed by PR #160:
-
-- [x] Define typed phase labels for local, unconfirmed, WAL, pending,
-      admitted, observed, settled, and conflicted.
-- [x] Preserve local visible text on Echo obstruction.
-- [x] Surface obstruction as blocked/obstructed projection posture, not silent
-      rollback.
-- [x] Add rapid typing regression coverage for local projection before bounded
-      Echo observations can replace editor text.
-- [x] Show canonical, session, speculative, braid, and obstructed posture in
-      history/worldline-adjacent surfaces.
-
-Moved to focused follow-ups:
-
-- [ ] Native Echo speculative intent runtime:
-      [#164](https://github.com/flyingrobots/jedit/issues/164).
-- [ ] Full braid/diff reconciliation UI:
-      [#163](https://github.com/flyingrobots/jedit/issues/163).
-- [ ] `:why` explanation for optimistic/conflicted visible text:
-      [WF-0108 / #131](https://github.com/flyingrobots/jedit/issues/131).
diff --git a/docs/design/0147-unmaterialized-file-frontier.md b/docs/design/0147-unmaterialized-file-frontier.md
deleted file mode 100644
index 56fdbecb..00000000
--- a/docs/design/0147-unmaterialized-file-frontier.md
+++ /dev/null
@@ -1,510 +0,0 @@
----
-title: "WF-0123 - Unmaterialized File Buffers And External Edit Frontier"
-legend: "WF"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/159"
-status: "landed"
-owners:
-  - "@flyingrobots"
-created: "2026-06-26"
-updated: "2026-06-27"
----
-
-# WF-0123 - Unmaterialized File Buffers And External Edit Frontier
-
-## Linked Issue
-
-- [#159 WF-0123: Unmaterialized file buffers and external edit frontier](https://github.com/flyingrobots/jedit/issues/159) landed its
-  safety foundation through [PR #160](https://github.com/flyingrobots/jedit/pull/160).
-
-## Outcome
-
-PR #160 landed the safe foundation:
-
-- missing-path `:edit foo.txt` opens an unmaterialized Echo-backed buffer;
-- opening a missing path does not write to disk;
-- save/export preflights host fingerprints for missing and existing paths;
-- externally changed, deleted, obstructed, or path-kind-conflicted host paths
-  block materialization instead of being overwritten;
-- blocked materialization never marks the buffer clean/materialized;
-- blocked `:wq` does not quit;
-- WSC recovery/export refuses bounded readings as materializable text;
-- inactive and unmaterialized buffers survive file switching.
-
-Remaining work is split into focused follow-up issues:
-
-- [#161 Restart recovery UI](https://github.com/flyingrobots/jedit/issues/161)
-- [#162 External Edit intake](https://github.com/flyingrobots/jedit/issues/162)
-- [#163 Braid and diff reconciliation UX](https://github.com/flyingrobots/jedit/issues/163)
-- [#165 File watcher and external move detection](https://github.com/flyingrobots/jedit/issues/165)
-
-## Decision Summary
-
-Jim should let `:edit foo.txt` create a causal buffer and local strand even
-when `foo.txt` does not exist on disk. The path binding begins
-unmaterialized, the user can edit immediately, and the file is only written to
-the host filesystem by an explicit save/export materialization. If another
-process creates or changes that path, Jim records the host fact as an
-`External Edit` intent on the canonical worldline and offers a braid flow
-instead of overwriting either frontier silently.
-
-## Sponsored Human
-
-A writer wants to start drafting `foo.txt` by naming it in `:edit`, without
-having to pre-create a placeholder file or choose between losing local work
-and overwriting disk changes made by another tool.
-
-## Sponsored Agent
-
-An agent needs an inspectable path-binding and frontier contract so it can
-open, edit, save, and reconcile files through Echo-backed causal history
-without inferring truth from filesystem existence or hidden editor dirtiness.
-
-## Hill
-
-By the end of this design arc, a user can create, edit, recover, save, and
-reconcile a not-yet-materialized file through `:edit`, `:write`, the history
-drawer, and braid prompts. The repo proves the behavior with command-line,
-workspace text, restart/recovery, and worldline UI witnesses.
-
-## Current Truth
-
-At commit `d0e4424b462795bfd814edebc698446ac5dfac20`, `:edit` can name a
-file that is not already in the current directory listing. The command
-dispatcher resolves the path and forwards a synthetic file entry to the normal
-file-open path:
-
-- [`src/app/workspace/command-line-dispatch.ts#L78`](https://github.com/flyingrobots/jedit/blob/d0e4424b462795bfd814edebc698446ac5dfac20/src/app/workspace/command-line-dispatch.ts#L78)
-- [`src/app/workspace/command-line-dispatch.ts#L144`](https://github.com/flyingrobots/jedit/blob/d0e4424b462795bfd814edebc698446ac5dfac20/src/app/workspace/command-line-dispatch.ts#L144)
-
-The bug is lower in the text-open command. `openWorkspaceText` calls
-`editorFile.loadEditorFile(request.filePath)` before opening the Echo-backed
-buffer. If the host path is missing, the catch block converts that exception
-into an open obstruction before any causal buffer or local strand can exist:
-
-- [`src/app/workspace/workspace-text-commands.ts#L200`](https://github.com/flyingrobots/jedit/blob/d0e4424b462795bfd814edebc698446ac5dfac20/src/app/workspace/workspace-text-commands.ts#L200)
-- [`src/app/workspace/workspace-text-commands.ts#L229`](https://github.com/flyingrobots/jedit/blob/d0e4424b462795bfd814edebc698446ac5dfac20/src/app/workspace/workspace-text-commands.ts#L229)
-
-The file adapter also exposes only `loadEditorFile` and `saveEditorFile`.
-There is no app-visible distinction between "missing path", "existing path",
-"external path was created after my basis", and "read failed":
-
-- [`src/ports/editor-file.ts#L1`](https://github.com/flyingrobots/jedit/blob/d0e4424b462795bfd814edebc698446ac5dfac20/src/ports/editor-file.ts#L1)
-
-The optimistic typing design already says local projection can be a strand
-braided with canonical truth. This design extends that doctrine from typed
-characters to path materialization and host filesystem frontiers:
-
-- [`docs/design/0146-optimistic-strand-worldline-phases.md`](0146-optimistic-strand-worldline-phases.md)
-
-## Problem
-
-Filesystem existence is currently treated as an open precondition. That makes
-the host filesystem the gatekeeper for causal buffer creation, even though Jim
-and Echo want causal history to be the source of truth and filesystem writes
-to be materializations.
-
-The broken user story is:
-
-```text
-:edit foo.txt
--> error: cannot open foo.txt because it does not exist
-```
-
-The intended story is:
-
-```text
-:edit foo.txt
--> creates buffer worldline for /cwd/foo.txt
--> path binding is unmaterialized
--> user edits a local strand
--> :write materializes /cwd/foo.txt if the host frontier is compatible
-```
-
-The harder case is when the host frontier changes while Jim has a local
-unmaterialized or dirty strand:
-
-```text
-Jim:       /repo/foo.txt missing at basis H0
-User:      drafts local strand L1
-External:  creates /repo/foo.txt with content E1
-Jim:       records External Edit on canonical mainline
-Jim UI:    "frontier advanced; braid external mainline with local strand?"
-```
-
-Jim must not pretend the external file is the same thing as the local strand,
-and must not silently save over it.
-
-## Scope
-
-This design arc includes:
-
-- missing-path `:edit` opening a causal buffer;
-- an unmaterialized path-binding state visible in footer/history surfaces;
-- save/export materialization from a chosen causal basis;
-- collision detection when disk changed or appeared since the buffer basis;
-- an `External Edit` causal event for host-originated file content;
-- worldline/history UI for canonical, local, external, and braid frontiers;
-- restart/recovery behavior for unmaterialized buffers.
-
-## Non-Goals
-
-This design arc does not include:
-
-- making Git the live reconciliation mechanism;
-- writing placeholder files on open;
-- auto-admitting external edits into the user's local strand;
-- silently overwriting host files whose frontier changed;
-- full filesystem watching as a required first slice;
-- multi-file transaction UX for project-wide external changes.
-
-Filesystem watchers can become an optimization later. The contract must still
-work when external changes are detected only during save, focus, refresh, or
-explicit read.
-
-## Product Contract
-
-Jim separates four facts that classic editors usually collapse:
-
-| Fact | Question | Example |
-| --- | --- | --- |
-| Buffer worldline | What causal document am I editing? | `buffer:/repo/foo.txt` |
-| Path binding | Is a host path associated with it? | `/repo/foo.txt` |
-| Materialization | Does that path currently exist on disk? | `unmaterialized` |
-| Frontier | Which basis does disk represent? | `external@e7`, `main@t4` |
-
-Opening a missing file creates the first two facts but not the third:
-
-```text
-buffer worldline: /repo/foo.txt
-path binding:     /repo/foo.txt
-materialization:  unmaterialized
-projection:       canonical empty + local strand
-```
-
-The buffer is real even before disk exists.
-
-## Scenario Matrix
-
-| Scenario | Current behavior | Intended behavior |
-| --- | --- | --- |
-| `:edit foo.txt` and path is missing | Open obstruction. | Open empty unmaterialized buffer on a local strand. |
-| Type then quit without save | Classic dirty prompt semantics. | Local causal history remains recoverable; no disk file appears. |
-| Type then `:write` and path still missing | Save writes file after edit. | Materialize chosen basis, record checkpoint/export evidence. |
-| Type then external process creates path | Save can overwrite by accident. | Record `External Edit`; prompt braid/reconcile before materializing. |
-| Existing file opens cleanly | Host contents seed Echo buffer. | Same, but basis records host frontier evidence. |
-| Existing file changes externally before local edits | Hidden until reopen/save. | Canonical frontier advances; user can observe or braid. |
-| Existing file changes externally after local edits | Collision risk. | Local strand remains; external edit is canonical; braid preview offered. |
-| Existing file is deleted externally | Future read/save may fail. | Record external delete as frontier event; local strand can rematerialize or abandon. |
-| Parent directory is missing | Generic open error. | Obstruct materialization/open with a path-binding issue, not a buffer-history loss. |
-| Host path is read-only | Save error. | Open can still create/view causal buffer; materialization obstructs with permission fact. |
-
-## User Experience
-
-### Missing-Path Open
-
-```text
-:edit foo.txt
-```
-
-The editor opens immediately with an empty buffer. The footer names the state:
-
-```text
-/repo/foo.txt [clean | main | fs:unmaterialized | target:main]
-```
-
-After typing:
-
-```text
-/repo/foo.txt [dirty | main+local | fs:unmaterialized | target:main]
-```
-
-The history/worldline drawer shows:
-
-```text
-Worldlines
-projection: canonical@t0 + local optimistic | braid active | phase:unconfirmed
-s phase       r name           basis          head  delta     evidence           note
-> settled     C main           main           0     +0/-0     canonical@t0       clear
-  unconfirmed L local          canonical@t0   -     +local/-0 request:3          optimistic
-  unconfirmed B visible braid  main+local     -     +local/-0 canonical@t0       active
-```
-
-### First Save
-
-If the host path is still absent, `:write` materializes the selected basis:
-
-```text
-:write
-saved /repo/foo.txt from braid main+local
-```
-
-The save creates causal checkpoint/export evidence and changes filesystem
-materialization posture from `unmaterialized` to `materialized`.
-
-### External Creation Before Save
-
-If another process creates `/repo/foo.txt` while Jim has local draft text,
-Jim should not write over it on save. The save path detects the host frontier
-and records the external content as a canonical event:
-
-```text
-External Edit: /repo/foo.txt materialized outside Jim
-frontier advanced: main@t0 -> main@t1
-local strand: local@3
-```
-
-The user sees a prompt or notification:
-
-```text
-foo.txt changed outside Jim.
-Canonical frontier advanced by External Edit.
-Open braid preview with your local strand?
-```
-
-The default action should be inspection, not overwrite.
-
-### External Change While Open
-
-Detection can happen by watcher, directory refresh, focus regain, explicit
-read, or save preflight. The same facts are emitted regardless of detection
-mechanism:
-
-```text
-host content observed
--> External Edit intent
--> canonical admission attempt
--> local view remains on local strand or visible braid
--> user chooses braid/admit/rewind/materialize
-```
-
-## Data / State Model
-
-| Category | Description |
-| --- | --- |
-| Source of truth | Echo causal history and retained WSC evidence. |
-| Host materialization | A projection of a causal basis to a filesystem path. |
-| Path binding | A durable association between a buffer worldline and desired path. |
-| Local strand | User's active edits, even when path is not materialized. |
-| Canonical frontier | Main worldline basis, including admitted external edits. |
-| Derived state | Footer labels, history rows, command prompts, file tree badges. |
-| Invalid states | Path exists with unknown frontier and save overwrites without prompt. |
-| Reset behavior | Rewind/abandon changes moves observer; it does not delete causal history. |
-| Serialization | WSC records must retain enough path-binding and materialization evidence to recover unmaterialized buffers. |
-
-Suggested path-binding states:
-
-| State | Meaning |
-| --- | --- |
-| `unbound` | Buffer has no desired host path. |
-| `unmaterialized` | Buffer has a desired path but no host artifact at the observed basis. |
-| `materialized` | Host path matches a known causal basis/export. |
-| `external-frontier` | Host path differs from the last known materialized basis. |
-| `materialization-obstructed` | Jim cannot read/write the host path due to permission, missing parent, type mismatch, or adapter error. |
-
-State sketch:
-
-```mermaid
-stateDiagram-v2
-  [*] --> MissingPathEdit
-  MissingPathEdit --> UnmaterializedBuffer: create buffer worldline
-  UnmaterializedBuffer --> LocalStrand: user edits
-  UnmaterializedBuffer --> Materialized: write and path absent
-  LocalStrand --> Materialized: write and path compatible
-  LocalStrand --> ExternalFrontier: host path appears/changes
-  ExternalFrontier --> BraidPreview: user inspects
-  BraidPreview --> Materialized: resolved braid admitted and exported
-  BraidPreview --> LocalStrand: stay local
-  ExternalFrontier --> LocalStrand: defer reconciliation
-```
-
-## Runtime / API Contract
-
-The current `EditorFilePort` is too coarse for this feature. The next contract
-should distinguish observation from materialization:
-
-```ts
-type HostPathObservation =
-  | { kind: 'missing'; filePath: string; observedAtMs: number }
-  | { kind: 'file'; filePath: string; lines: readonly string[]; readOnly: boolean; digest: string; observedAtMs: number }
-  | { kind: 'directory'; filePath: string; observedAtMs: number }
-  | { kind: 'obstructed'; filePath: string; issue: RuntimeIssue };
-```
-
-Open should accept both host-backed and missing observations:
-
-```ts
-type WorkspaceTextOpenBasis =
-  | { kind: 'host-file'; observation: HostPathObservation & { kind: 'file' } }
-  | { kind: 'missing-path'; filePath: string; initialText: '' };
-```
-
-Save/export should include the observed host frontier it believes it is
-materializing over:
-
-```ts
-interface WorkspaceTextMaterializeRequest {
-  readonly filePath: string;
-  readonly bufferId: string;
-  readonly basisReceiptId?: string;
-  readonly expectedHostDigest?: string;
-}
-```
-
-If the current host digest does not match `expectedHostDigest`, materialization
-does not overwrite. It emits an external frontier result and offers a braid
-path.
-
-## External Edit Intent
-
-An external filesystem change is not "just disk". It is a causal input into
-Jim's canonical worldline.
-
-Minimal fact shape:
-
-```ts
-interface ExternalEditIntent {
-  readonly kind: 'external-edit';
-  readonly filePath: string;
-  readonly previousHostDigest?: string;
-  readonly nextHostDigest: string;
-  readonly observedAtMs: number;
-  readonly source: 'save-preflight' | 'watcher' | 'focus-refresh' | 'manual-refresh';
-}
-```
-
-Admission semantics:
-
-- If the user has no local divergence, Jim may fast-forward the canonical
-  observer after the external intent settles.
-- If the user has local divergence, Jim keeps the local strand visible and
-  offers braid preview.
-- If external content cannot be read, Jim records an obstruction fact rather
-  than inventing text.
-
-## Cycle Plan
-
-### Cycle 1 - Missing-Path Open
-
-Hill: `:edit foo.txt` opens a recoverable unmaterialized buffer when the path
-is missing.
-
-Deliverables:
-
-- split host path observation from file load;
-- open missing paths with empty initial text;
-- footer/history label `fs:unmaterialized`;
-- command-line regression for `:edit missing.txt`;
-- no host file write before save.
-
-### Cycle 2 - First Save And Collision Preflight
-
-Hill: `:write` materializes an unmaterialized buffer only when the host
-frontier is compatible.
-
-Deliverables:
-
-- save preflight observes host digest/existence;
-- absent path writes materialized file and records checkpoint/export evidence;
-- appeared/changed path returns an external-frontier result instead of
-  overwriting;
-- command-line and workspace text tests cover absent, compatible, and changed
-  host paths.
-
-### Cycle 3 - External Edit Intake
-
-Hill: host-created or host-edited content becomes an `External Edit` causal
-event on canonical mainline.
-
-Deliverables:
-
-- external edit intent type and history entry;
-- admission/settlement evidence retained in WSC;
-- restart recovers external frontier facts;
-- manual refresh/save preflight can detect external changes even without a
-  watcher.
-
-### Cycle 4 - Frontier Braid UX
-
-Hill: when canonical frontier advances while the user has local strand edits,
-Jim shows the local, canonical, external, and visible braid paths and lets the
-user choose reconciliation.
-
-Deliverables:
-
-- notification/prompt for frontier advancement;
-- history/worldline drawer rows for external edit and braid preview;
-- `:why` explains external frontier plus local strand;
-- braid preview/admit/defer actions;
-- accessibility-friendly lower-mode text for no-color terminals.
-
-## Lower Modes
-
-Lower modes must expose the same facts without relying on color:
-
-- footer text uses explicit `fs:unmaterialized`, `external-frontier`, and
-  `braid active` labels;
-- history drawer rows include `External Edit` as text, not just color;
-- `:why` states whether the visible buffer is canonical, local, external, or
-  a braid;
-- JSON witnesses use stable enum-like strings for path-binding state and
-  frontier state.
-
-## Accessibility Posture
-
-| Concern | Posture |
-| --- | --- |
-| Semantic labels | Path materialization and frontier state appear as text. |
-| Focus order | Existing command line, editor, history drawer order remains. |
-| Hidden information | No conflict state is color-only. |
-| Keyboard behavior | All reconcile actions have command-line equivalents. |
-| Agent inspectability | External edit, materialization, and braid state use structured facts. |
-
-## Localization / Directionality Posture
-
-The first slice can reuse existing terse English status tokens, but any prompt
-or notification must enter the i18n catalog. Directionality-sensitive surfaces
-must keep path and receipt ids as literal spans and localize the surrounding
-message.
-
-## Test Plan
-
-Add focused tests before implementation expands:
-
-- `:edit missing.txt` opens an empty unmaterialized buffer and queues no host
-  write.
-- Rapid typing into an unmaterialized buffer follows the optimistic strand
-  projection rules from WF-0122.
-- `:write` creates the host file only when the path is still missing.
-- `:write` detects that the host path appeared and emits external-frontier
-  state.
-- External edit with no local divergence advances the canonical observer.
-- External edit with local divergence keeps the local strand visible and opens
-  braid prompt/view state.
-- Restart recovers an unmaterialized buffer and its path binding.
-- `:why` explains missing-path buffer, external frontier, and braid states.
-
-## Open Questions
-
-- Should `:edit foo.txt` create a canonical empty head immediately, or should
-  the empty basis live as an unadmitted local path-binding intent until the
-  first edit or save?
-- Is external delete its own `External Delete` intent, or an `External Edit`
-  with a tombstone body?
-- Should Jim ever auto-braid external changes when local edits are only
-  additive and non-overlapping, or should braid/admit remain explicit?
-- What retention tier is required so an unmaterialized buffer survives a long
-  period without host materialization?
-
-## Acceptance Checklist
-
-- [ ] Missing-path `:edit` opens a causal buffer instead of obstructing.
-- [ ] Missing-path open does not create a host file.
-- [ ] Footer/history distinguish unmaterialized path binding from dirty text.
-- [ ] Save materializes only after host frontier compatibility check.
-- [ ] Host-created/changed path is recorded as `External Edit`.
-- [ ] Save collision never overwrites external content silently.
-- [ ] Local strand remains visible after external frontier advancement.
-- [ ] Braid UX lets the user inspect, admit, defer, or rewind.
-- [ ] Restart/recovery preserves unmaterialized path bindings.
-- [ ] `:why` explains the current path/frontier/braid state.
diff --git a/docs/design/0148-workspace-buffer-registry.md b/docs/design/0148-workspace-buffer-registry.md
index 28cdf3a5..85029efc 100644
--- a/docs/design/0148-workspace-buffer-registry.md
+++ b/docs/design/0148-workspace-buffer-registry.md
@@ -2,7 +2,7 @@
 title: "WF-0124 - Workspace Buffer Registry"
 legend: "WF"
 lane: "design"
-status: "draft"
+status: "landed"
 owners:
   - "@flyingrobots"
 created: "2026-06-27"
@@ -43,7 +43,7 @@ interface WorkspaceBufferRecord {
   pathBinding: string;
   textAuthority: WorkspaceTextAuthorityOpened;
   editorProjection: EditorState;
-  materializationState: WorkspaceWorldlineMaterializationKind;
+  materializationState: WorkspaceMaterializationKind;
   sourceHighlight?: SourceHighlightReading;
   graftInfo?: GraftInfo;
   graftSelectedIndex: number;
@@ -106,16 +106,8 @@ requests claim an active buffer after a switch.
 
 ## Future Slices
 
-The registry is not yet complete. Future cycles should add:
-
-- restart recovery UI for inactive unmaterialized buffers;
-- explicit path-binding records separate from `pathBinding: string`;
-- per-buffer source-highlight and Graft request identity;
-- inactive-buffer history drawer filters;
-- conflict and external-frontier posture per buffer;
-- multi-pane lenses over the same buffer registry;
-- agent proposal strands as isolated buffer records;
-- buffer close/abandon UI.
+Remaining registry work is tracked in
+[#364](https://github.com/flyingrobots/jedit/issues/364).
 
 ## Non-Goals
 
diff --git a/docs/design/0149-graph-backed-rope-runtime-discovery.md b/docs/design/0149-graph-backed-rope-runtime-discovery.md
deleted file mode 100644
index 5dd459d8..00000000
--- a/docs/design/0149-graph-backed-rope-runtime-discovery.md
+++ /dev/null
@@ -1,1252 +0,0 @@
----
-title: "HT-0149 - Graph-Backed Rope Runtime Discovery"
-legend: "HT"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/206"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-07-04"
-updated: "2026-07-04"
----
-
-# HT-0149 - Graph-Backed Rope Runtime Discovery
-
-> **Scope correction:** This active discovery document records how the current
-> Wesley/Rust compatibility corridor acquired real graph-rope authority. Its
-> direct TypeScript operation port is not the final Jim/Echo protocol. The
-> target sends canonical events to `jim.core`; application-owned `jedit.text`
-> lawpacks own text operations, optics, and private rope mechanics;
-> `jim.core` composes them into editor commands; Echo interprets only
-> compiler-produced generic programs. Do not implement the sentence "replace
-> this port with a generated Edict client" as frontend
-> command-to-`ReplaceRange` orchestration. See
-> [../../ARCHITECTURE.md](../../ARCHITECTURE.md) and
-> [../BEARING.md](../BEARING.md).
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/206
-
-## Decision Summary
-
-jedit's production text authority must move from retained full-text snapshots to
-a graph-backed rope runtime whose heads, nodes, blobs, rewrites, diffs,
-checkpoints, and receipts are admitted as inspectable causal facts. Until a real
-graph-backed create/read/replace/checkpoint path exists, new UI causal-honesty
-work must not claim storage truth that the runtime cannot prove.
-
-## Sponsored Human
-
-A Jim daily driver wants edits, saves, history, and `:why` explanations to remain
-fast and causally trustworthy on real files, without depending on retained
-full-buffer snapshots that make the editor slower and less honest as files grow.
-
-## Sponsored Agent
-
-An agent needs stable graph facts, basis IDs, byte ranges, receipts, and witness
-APIs so it can inspect text authority and explain changes without scraping
-rendered projections or inferring private runtime state.
-
-## Hill
-
-By the end of this cycle, jedit can create a graph-backed buffer, read a bounded
-text window, replace a narrow byte range, checkpoint the resulting head, and prove
-through witnesses that unchanged rope structure and authoritative bytes were not
-duplicated as full snapshots.
-
-## Current Truth
-
-An external audit called out a real architectural drift in jedit's current text
-runtime. The blunt version is correct: the code currently named around
-`RopeHead`, `BufferRoot`, `replaceRangeAsTick`, and `HotTextBufferState` does not
-implement a graph-backed rope runtime.
-
-The current hot text runtime still uses full-text snapshots:
-
-- [`src/domain/text-edit-contract.ts`](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/src/domain/text-edit-contract.ts#L84)
-  encodes the entire buffer into UTF-8 bytes, splices the requested range,
-  decodes a new full string, and wraps that string in a new `BufferRoot`.
-- [`src/ports/hot-text-runtime.ts`](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/src/ports/hot-text-runtime.ts#L6)
-  defines `HotTextBufferState.roots` as an array of retained roots.
-- [`src/adapters/in-memory-hot-text-runtime.ts`](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/src/adapters/in-memory-hot-text-runtime.ts#L76)
-  appends the new full root to that retained array after an admitted edit.
-- [`src/adapters/installed-jedit-contract-echo-transport.ts`](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/src/adapters/installed-jedit-contract-echo-transport.ts#L159)
-  still defaults the installed jedit contract transport to that in-memory
-  runtime.
-
-That means the current implementation has O(N) edit cost and O(N) retained text
-per edit for buffer size N. For repeated small edits on a large file, retained
-memory grows with file size times edit count. That is not the intended jedit
-architecture.
-
-## What Was Intended
-
-The original design intent is stronger than "a text runtime behind an Echo-shaped
-API." The rope should be modeled with Echo graph primitives through the jedit
-contract layer. Echo intents should evolve that graph by rewriting rope facts and
-producing a new rope model in the Echo-hosted causal history.
-
-In that model:
-
-- `BufferWorldline` is the logical editable object.
-- `RopeHead` identifies one graph-backed text state.
-- `RopeBranch`, `RopeLeaf`, and `TextBlob` are graph facts, not names for a full
-  JavaScript string.
-- `replaceRangeAsTick` is the compatibility name for a `jedit.text` intent
-  composed by `jim.core` and admitted by Echo. Its law reads a base head,
-  range-closes over touched rope nodes,
-  creates new local rope facts, emits rewrite and diff evidence, and advances
-  the worldline head. It is not an Echo runtime primitive.
-- `RopeRewrite`, `RopeDiff`, application tick evidence, checkpoint declarations,
-  and anchor associations are retained jedit evidence; Echo owns causal-anchor
-  and admission evidence.
-- Materialized strings are readings or projections. They are allowed for UI
-  rendering, export, save, tests, and caches, but they are not the source of
-  editor truth.
-
-Echo still remains generic. `jedit.text` owns the public text contracts and
-private rope law; `jim.core` owns their editor-specific interpretation and
-composition; the Jedit body owns transport and presentation. Echo hosts generic
-admission, scheduling, receipts, retention, and causal storage. The important
-correction is that the `jedit.text` contract vocabulary must be real
-graph-backed state, not labels over full string snapshots.
-
-## Why This Matters
-
-This is not a minor performance issue.
-
-The current runtime breaks the product's intended causal posture in several
-ways:
-
-- It makes the authoritative retained state a list of full materialized strings
-  rather than compact causal graph evidence.
-- It makes the rope vocabulary misleading because no rope graph is actually
-  being evolved.
-- It makes `:why`, historical basis preview, strands, braids, gutter evidence,
-  and retention policy harder to make honest because they must recover history
-  from full roots instead of reading graph facts.
-- It can make dogfooding painful on larger files because every edit copies and
-  retains the whole buffer.
-- It risks making UI language more causally honest than the storage model below
-  it.
-
-The existing docs already point in the right direction. In particular:
-
-- [`0003-echo-backed-rope-worldline-contract.md`](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/docs/design/0003-echo-backed-rope-worldline-contract/echo-backed-rope-worldline-contract.md#L28)
-  says witnessed causal history is canonical and materialized projections are
-  not editor truth.
-- [`jedit-echo-graph-model.md`](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/docs/design/jedit-echo-graph-model.md#L31)
-  describes the desired `BufferWorldline -> RopeHead -> Rope DAG` shape and
-  states that `ReplaceRangeAsTick` should reuse untouched subtrees.
-- [`0027-echo-hosted-production-cutover.md`](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/docs/design/0027-echo-hosted-production-cutover.md#L35)
-  says the local in-memory text model is no longer a production authority target.
-- [`structural-history-graphql-authority.md`](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/docs/design/structural-history-graphql-authority.md#L11)
-  says the TypeScript model is transitional evidence, not durable authority.
-
-The problem is that implementation reality has not caught up to those design
-claims.
-
-## Problem
-
-The installed jedit text authority still admits edits by copying and retaining
-whole materialized strings. That contradicts the graph-backed rope architecture,
-turns rope/worldline names into misleading labels, makes byte-range provenance
-harder to prove, and allows future UI work to present causal claims that the
-storage layer cannot support.
-
-## Scope
-
-This cycle includes:
-
-- documenting the current full-snapshot runtime as fixture-only;
-- defining the production guard that prevents implicit snapshot authority;
-- defining authoritative UTF-8 byte coordinates and projection coordinates;
-- defining concrete graph-backed rope fact shapes and validation boundaries;
-- defining byte authority for `TextBlob` facts;
-- defining no-op admission semantics without minting text ticks;
-- defining retention, subtree identity, materialization, checkpoint, and `:why`
-  witnesses;
-- linking the active repo bearing to this hard gate.
-
-## Non-Goals
-
-This cycle does not include:
-
-- implementing the final production graph-backed runtime;
-- optimizing the full-snapshot runtime;
-- changing rendered editor UI, gutter UI, footer UI, or settings UI;
-- solving compaction, braids, collaborative merges, search indexes, syntax
-  caches, or structural highlighting;
-- moving jedit text semantics into Echo core.
-
-## User Experience / Product Shape
-
-This design does not add a new rendered surface. The user-facing impact is a
-hard execution gate: Jim should avoid additional causal-honesty UI claims until
-runtime truth can back those claims with graph facts.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[User edits a buffer] --> Admit[Runtime admits text intent]
-  Admit --> Facts[Graph-backed rope facts evolve]
-  Facts --> Read[UI reads bounded projection from a basis head]
-  Read --> Explain[:why cites head, leaf, blob, rewrite, diff, and tick]
-  Admit --> NoOp[No-op admission]
-  NoOp --> Receipt[Receipt without new text head or tick]
-```
-
-### Wide UI Mockup
-
-Not applicable. This cycle changes runtime authority design and process
-signposting, not rendered TUI layout.
-
-### Narrow UI Mockup
-
-Not applicable. This cycle changes runtime authority design and process
-signposting, not rendered TUI layout.
-
-### Accessibility Considerations
-
-No rendered accessibility behavior changes in this cycle. Future UI work that
-uses this runtime must expose the same causal facts through keyboard-accessible
-commands and machine-readable witnesses, not color-only or pixel-only cues.
-
-## Runtime / API Contract
-
-We should not patch this by making full-string replacement faster. That would
-preserve the wrong architecture. The response needs to be a graph-backed runtime
-cutover.
-
-The hard gate is:
-
-```text
-Do not begin more UI causal-honesty work until the text runtime has at least one
-real graph-backed path for create, read, replace, and checkpoint.
-```
-
-Until then, UI labels such as `basis`, `head`, `tick`, `checkpoint`, and
-`worldline` must either be backed by graph facts or explicitly marked as
-transitional projection posture.
-
-### 1. Rename And Fence The Fixture
-
-The current in-memory full-snapshot runtime must be renamed so accidental
-production use is visibly wrong. Acceptable names include:
-
-- `FullSnapshotHotTextRuntimeFixture`
-- `InMemoryFullSnapshotTextRuntime`
-- `TransitionalSnapshotTextRuntime`
-
-Unacceptable names include:
-
-- `InMemoryHotTextRuntime`
-- `HotTextRuntime`
-- `DefaultHotTextRuntime`
-- `ProductionHotTextRuntime`
-
-The name should make the wrong wiring ugly.
-
-Planned guardrails:
-
-- rename or document the runtime as full-snapshot/transitional;
-- add a production guard against implicit default use;
-- keep focused tests able to inject it deliberately;
-- make release and preflight checks fail if product code starts treating it as
-  durable text authority again.
-
-The installed/default transport must not silently instantiate the full-snapshot
-runtime. If a temporary escape hatch is required, it should be explicit:
-
-```typescript
-if (process.env.JEDIT_ALLOW_FULL_SNAPSHOT_TEXT_AUTHORITY !== "1") {
-  throw new Error(
-    "FullSnapshotHotTextRuntimeFixture cannot be used as production text authority.",
-  );
-}
-```
-
-Tests may opt in deliberately. Product startup should not.
-
-### 2. Define Coordinates Before Facts
-
-The graph-backed rope design must define its coordinate system before it defines
-facts. The current code uses UTF-8 byte ranges, JavaScript strings are UTF-16,
-and editor UI needs line/column positions. Those must not blur together.
-
-Authoritative mutation coordinates should be UTF-8 byte offsets. UI coordinates
-should be adapters over that storage coordinate.
-
-The design should introduce branded coordinate types:
-
-```typescript
-type ByteOffset = number & { readonly __brand: "utf8-byte-offset" };
-type Utf16Offset = number & { readonly __brand: "utf16-code-unit-offset" };
-
-interface LineColumn {
-  readonly line: number & { readonly __brand: "zero-based-line-index" };
-  readonly columnUtf16: Utf16Offset;
-}
-```
-
-Rules:
-
-- rope mutation ranges are half-open UTF-8 byte ranges;
-- text blobs store UTF-8 bytes;
-- `LineColumn.line` is a zero-based logical line index;
-- `LineColumn.columnUtf16` is a zero-based UTF-16 code-unit offset from the start
-  of that logical line;
-- line/column and UTF-16 offsets are UI or protocol projections, not storage
-  authority;
-- line projection treats CRLF as one logical line break and treats bare CR and
-  bare LF as one logical line break each;
-- newline projection never mutates stored blob bytes or save/export bytes;
-- grapheme-aware movement is a command-planning concern over readings, not the
-  authoritative storage coordinate;
-- every conversion must cite the basis head or reading it was computed from.
-
-### 3. Define Real Typed Graph Facts
-
-Create a full graph-backed rope runtime design that specifies concrete fact
-shapes. The exact names may evolve, but the design must be precise enough for
-witnesses to target.
-
-Example fact skeleton:
-
-```typescript
-type WorldlineId = string & { readonly __brand: "WorldlineId" };
-type RopeHeadId = string & { readonly __brand: "RopeHeadId" };
-type RopeNodeId = string & { readonly __brand: "RopeNodeId" };
-type TextBlobId = string & { readonly __brand: "TextBlobId" };
-type EchoReceiptId = string & { readonly __brand: "EchoReceiptId" };
-type RopeRewriteId = string & { readonly __brand: "RopeRewriteId" };
-type RopeDiffId = string & { readonly __brand: "RopeDiffId" };
-type RopeStructuralMaintenanceId =
-  string & { readonly __brand: "RopeStructuralMaintenanceId" };
-type Hash = string & { readonly __brand: "Hash" };
-
-interface TextByteRange {
-  readonly startByte: ByteOffset;
-  readonly endByte: ByteOffset;
-}
-
-interface BufferWorldlineFact {
-  readonly kind: "jedit.text.BufferWorldline";
-  readonly schemaVersion: 1;
-  readonly worldlineId: WorldlineId;
-  readonly createdByEchoReceiptId: EchoReceiptId;
-  readonly initialHeadId: RopeHeadId;
-}
-
-interface RopeHeadFact {
-  readonly kind: "jedit.text.RopeHead";
-  readonly schemaVersion: 1;
-  readonly headId: RopeHeadId;
-  readonly worldlineId: WorldlineId;
-  readonly rootNodeId: RopeNodeId;
-  readonly basisHeadId?: RopeHeadId;
-  readonly createdByEchoReceiptId: EchoReceiptId;
-  readonly byteLength: number;
-  readonly lineCount: number;
-  readonly contentHash: Hash;
-}
-
-interface RopeBranchFact {
-  readonly kind: "jedit.text.RopeBranch";
-  readonly schemaVersion: 1;
-  readonly nodeId: RopeNodeId;
-  readonly left: RopeNodeId;
-  readonly right: RopeNodeId;
-  readonly byteLength: number;
-  readonly lineCount: number;
-  readonly height: number;
-  readonly contentHash: Hash;
-}
-
-interface RopeLeafFact {
-  readonly kind: "jedit.text.RopeLeaf";
-  readonly schemaVersion: 1;
-  readonly nodeId: RopeNodeId;
-  readonly blobId: TextBlobId;
-  readonly byteStart: ByteOffset;
-  readonly byteLength: number;
-  readonly lineCount: number;
-  readonly contentHash: Hash;
-}
-
-interface InlineTextBlobStorage {
-  readonly kind: "inline-utf8-bytes";
-  readonly bytes: Uint8Array;
-}
-
-interface StoredTextBlobStorage {
-  readonly kind: "content-addressed-blob-store";
-  readonly storeId: "jedit.text.blob-store.v1";
-  readonly contentRef: string;
-}
-
-type TextBlobStorage = InlineTextBlobStorage | StoredTextBlobStorage;
-
-interface TextBlobFact {
-  readonly kind: "jedit.text.TextBlob";
-  readonly schemaVersion: 1;
-  readonly blobId: TextBlobId;
-  readonly encoding: "utf8";
-  readonly byteLength: number;
-  readonly contentHash: Hash;
-  readonly storage: TextBlobStorage;
-}
-
-interface RopeRewriteFact {
-  readonly kind: "jedit.text.RopeRewrite";
-  readonly schemaVersion: 1;
-  readonly rewriteId: RopeRewriteId;
-  readonly worldlineId: WorldlineId;
-  readonly basisHeadId: RopeHeadId;
-  readonly nextHeadId: RopeHeadId;
-  readonly admittedByEchoReceiptId: EchoReceiptId;
-  readonly range: TextByteRange;
-  readonly replacementBlobId: TextBlobId;
-  readonly diffId: RopeDiffId;
-  readonly contentHash: Hash;
-}
-
-interface RopeEqualDiffSpan {
-  readonly kind: "equal";
-  readonly basisRange: TextByteRange;
-  readonly nextRange: TextByteRange;
-  readonly contentHash: Hash;
-}
-
-interface RopeDeleteDiffSpan {
-  readonly kind: "delete";
-  readonly basisRange: TextByteRange;
-  readonly contentHash: Hash;
-}
-
-interface RopeInsertDiffSpan {
-  readonly kind: "insert";
-  readonly nextRange: TextByteRange;
-  readonly blobId: TextBlobId;
-  readonly contentHash: Hash;
-}
-
-type RopeDiffSpan = RopeEqualDiffSpan | RopeDeleteDiffSpan | RopeInsertDiffSpan;
-
-interface RopeDiffFact {
-  readonly kind: "jedit.text.RopeDiff";
-  readonly schemaVersion: 1;
-  readonly diffId: RopeDiffId;
-  readonly rewriteId: RopeRewriteId;
-  readonly basisHeadId: RopeHeadId;
-  readonly nextHeadId: RopeHeadId;
-  readonly spans: readonly RopeDiffSpan[];
-  readonly contentHash: Hash;
-}
-
-type RopeStructuralMaintenanceOperation =
-  | "split-leaf"
-  | "merge-leaves"
-  | "rotate-left"
-  | "rotate-right"
-  | "rebalance-branch";
-
-interface RopeStructuralMaintenanceFact {
-  readonly kind: "jedit.text.RopeStructuralMaintenance";
-  readonly schemaVersion: 1;
-  readonly maintenanceId: RopeStructuralMaintenanceId;
-  readonly worldlineId: WorldlineId;
-  readonly rewriteId: RopeRewriteId;
-  readonly basisHeadId: RopeHeadId;
-  readonly nextHeadId: RopeHeadId;
-  readonly operation: RopeStructuralMaintenanceOperation;
-  readonly affectedRange: TextByteRange;
-  readonly replacedNodeIds: readonly RopeNodeId[];
-  readonly replacementNodeIds: readonly RopeNodeId[];
-  readonly contentHash: Hash;
-}
-```
-
-The full design must also define jedit facts for:
-
-- associations between rope checkpoints and opaque Echo anchor evidence;
-- strands, braids, and admissions when their implementation slice begins.
-
-Echo remains generic and owns causal-anchor admission. `jedit.text` owns rope
-facts, domain associations, and text-specific witnesses; its rope
-representation remains private to the text capability.
-
-Runtime construction and validation are part of the contract. The branded types
-above are compile-time helpers only; decoded runtime payloads must pass through
-jedit-owned constructors or validators before becoming facts.
-
-Required constructor and validator path:
-
-```typescript
-type FactValidationErrorCode =
-  | "invalid-kind"
-  | "invalid-schema-version"
-  | "invalid-id"
-  | "invalid-reference"
-  | "invalid-metric"
-  | "invalid-hash"
-  | "hash-mismatch";
-
-type FactValidationResult =
-  | { readonly ok: true; readonly fact: TFact }
-  | { readonly ok: false; readonly code: FactValidationErrorCode };
-
-type RopeAdmittedFact =
-  | BufferWorldlineFact
-  | RopeHeadFact
-  | RopeBranchFact
-  | RopeLeafFact
-  | TextBlobFact
-  | RopeRewriteFact
-  | RopeDiffFact
-  | RopeStructuralMaintenanceFact
-  | RopeCheckpointFact
-  | RopeCheckpointAnchoredFact;
-
-interface RopeFactReadModel {
-  getFact(id: string): RopeAdmittedFact | null;
-}
-
-interface TextBlobStorePort {
-  readBlobBytes(storage: StoredTextBlobStorage): Uint8Array | null;
-}
-
-interface TextBlobHashPort {
-  sha256Hex(value: string): string;
-}
-
-interface MakeTextBlobFactInput {
-  readonly bytes: Uint8Array;
-  readonly hash: TextBlobHashPort;
-}
-
-interface RopeFactValidationContext {
-  readonly writeSet: readonly RopeAdmittedFact[];
-  readonly admittedBasis: RopeFactReadModel;
-  readonly blobStore: TextBlobStorePort;
-  readonly hash: TextBlobHashPort;
-}
-
-declare function makeTextBlobFact(
-  input: MakeTextBlobFactInput,
-): FactValidationResult;
-declare function validateRopeFact(
-  payload: RopeAdmittedFact,
-  context: RopeFactValidationContext,
-): FactValidationResult;
-```
-
-Validation rules:
-
-- `kind` and `schemaVersion` are mandatory runtime tags;
-- IDs must be non-empty canonical IDs in the expected namespace;
-- numeric metrics must be non-negative integers;
-- branch children, head roots, leaf blobs, rewrites, diffs, receipts, and
-  checkpoints must reference facts available in the same write set or an already
-  admitted basis;
-- reference validation must retrieve typed facts from the current write set or
-  `admittedBasis.getFact(...)` before checking kind, metrics, content hash, and
-  worldline linkage; ID existence alone is not a valid reference proof;
-- the validator receives those scopes through `RopeFactValidationContext` and
-  must not consult ambient process state;
-- `TextBlobFact.blobId` and `contentHash` must be derived from
-  `encoding + bytes`, not trusted from caller input;
-- inline blob facts must compute hash and length from their `Uint8Array` bytes;
-- blob-store-backed facts must name the store adapter and content reference, and
-  admission must fetch bytes through `context.blobStore`, verify length, and
-  recompute the hash before the fact can become authority;
-- a `textWindow` read over a missing or hash-mismatched blob is an obstruction,
-  not a fallback to stale projection text;
-- branch, leaf, and head hashes must be recomputed from child/blob references and
-  metrics before admission;
-- rewrite, diff, tick receipt, and checkpoint hashes and sequence numbers must
-  be recomputed or range-checked against the admitted basis before admission;
-- diff spans are kind-specific: equal spans must carry basis and next ranges,
-  delete spans must carry only the removed basis range, insert spans must carry
-  the next range and inserted blob, and validators must reject missing or extra
-  coordinate fields for each span kind;
-- structural maintenance facts must reference the semantic rewrite, basis head,
-  next head, affected range, operation, and exact replaced and replacement node
-  IDs before an untouched subtree identity exception is accepted;
-- invalid facts are rejected before Echo admission and never become retained
-  authority.
-
-### 4. Separate Text Authority From Observations
-
-No-op behavior needs causal precision. A no-op replacement should not mint a new
-text head or rewrite evidence claiming text changed. The system may still record
-an admitted no-op intent, rejected edit, idempotent command, observation, or
-receipt.
-
-The design should distinguish:
-
-- `ReplaceRangeIntent`;
-- `TextChangeAdmission`;
-- `NoOpAdmissionReceipt`;
-- `RejectedIntentReceipt`;
-- `RopeRewrite | null`;
-- `RopeDiff | null`;
-- `WorldlineAdvance | null`;
-- `TickReceipt | null`.
-
-Rules:
-
-- no text change means no new `RopeHead`;
-- no changed range means no `RopeRewrite`;
-- no text change means no new text tick, no tick sequence advance, and no reuse
-  of a prior `TickId`;
-- `TickReceipt` exists only for a text-changing admission that advances the
-  worldline;
-- `NoOpAdmissionReceipt` records request ID, basis head, range, replacement hash,
-  and reason such as `unchanged-bytes`, but it is not a text tick;
-- rejected intents use `RejectedIntentReceipt` and also do not mint text ticks;
-- no-op evidence must not pollute the rope graph as if bytes changed.
-
-### 5. Make Untouched Subtree Identity A Contract
-
-Untouched subtree identity is the central rope property. If a narrow replacement
-rebuilds the whole tree, it is not the intended runtime.
-
-Witness shape:
-
-```typescript
-const before = await runtime.debugRopeShape(headA);
-const result = await runtime.replaceRangeAsTick({
-  worldlineId,
-  basisHeadId: headA,
-  range,
-  replacement,
-});
-const after = await runtime.debugRopeShape(result.nextHeadId);
-
-const preserved = compareUntouchedStructure({
-  before,
-  after,
-  changedRange: range,
-});
-
-expect(preserved.rebuiltUntouchedSpans).toEqual([]);
-expect(preserved.preservedSubtreeIds).toEqual(
-  preserved.expectedUntouchedSubtreeIds,
-);
-```
-
-This should be part of the contract, not an incidental optimization.
-
-The witness must be recursive. `debugRopeShape` should expose each node's byte
-span within the head, node ID, child IDs, hash, and structural-maintenance
-evidence if a rebalance touched otherwise unchanged text. The comparison should
-walk the before and after shapes, classify spans outside the edited range as
-untouched, and require every unaffected subtree identity to survive unless a
-retained structural-maintenance fact explicitly explains the replacement.
-
-### 6. Make Retention Measurable
-
-Do not rely on qualitative claims. Add an explicit witness around retained
-authoritative bytes.
-
-Example target:
-
-```text
-largeBufferSize = 10_000_000 bytes
-edits = 1_000 single-byte edits
-```
-
-The full-snapshot runtime retains roughly 10 GB of authoritative text snapshots.
-The graph-backed runtime should retain approximately:
-
-- initial text blobs;
-- changed leaves;
-- path-copied branch nodes;
-- rewrite and diff facts;
-- receipts;
-- indexes and checkpoints.
-
-The exact byte count may vary, but the witness must assert retained
-authoritative text is not O(buffer_size * edit_count).
-
-### 7. Define Materialization Boundaries
-
-Materialized strings are allowed only as readings or projections. Every
-materialized string must answer:
-
-- which `RopeHead` was read;
-- which UTF-8 byte range was read;
-- whether the materialization came from cache;
-- how the cache was validated against the head.
-
-Good:
-
-```typescript
-const text = await runtime.textWindow({
-  basisHeadId,
-  byteRange,
-});
-```
-
-Bad:
-
-```typescript
-const text = state.roots[state.roots.length - 1].text;
-```
-
-This boundary is what makes `:why`, historical preview, save/export, and UI
-evidence trustworthy.
-
-### 8. Write Witnesses Before Most Implementation
-
-The better implementation order is:
-
-1. minimal design skeleton;
-2. failing witnesses;
-3. tiny graph-backed runtime;
-4. refined design;
-5. more witnesses;
-6. production cutover.
-
-The witnesses are architectural teeth, not after-the-fact documentation.
-
-Required first witnesses:
-
-- snapshot fixture cannot be constructed as default production authority;
-- repeated edits do not retain one full-text snapshot per edit;
-- untouched subtree identity survives a narrow replacement;
-- no-op intent can produce admission evidence without a new head or rewrite;
-- text-window reads cite a basis head and byte range;
-- save/export reads from a causal basis without mutating text authority;
-- `:why` can cite rewrite, diff, tick, head, leaf, and blob evidence for a byte
-  range.
-
-### 9. Build The Smallest Real Runtime First
-
-Do not start by solving compaction, braids, collaborative merge, source
-highlighting, and `:why` all at once. The first implementation win should be:
-
-```text
-create buffer
--> read window
--> replace small range
--> read window
--> prove untouched identity survived
--> checkpoint
-```
-
-Initial scope:
-
-- immutable rope nodes;
-- content-addressed blobs;
-- binary branch tree;
-- append-only graph fact store;
-- single-range replacement;
-- text-window read;
-- checkpoint fact;
-- debug-only shape inspection.
-
-### 10. Mark Evidence Versus Indexes
-
-The design must distinguish durable semantic facts from rebuildable acceleration
-indexes.
-
-Durable truth:
-
-- `RopeHead`;
-- `RopeBranch`;
-- `RopeLeaf`;
-- `TextBlob`;
-- `RopeRewrite`;
-- `RopeDiff`;
-- `TickReceipt`;
-- `RopeStructuralMaintenance`;
-- `echo.causal.Anchor`;
-- `RopeCheckpoint`.
-
-Rebuildable indexes and caches:
-
-- line offset index;
-- syntax highlighting cache;
-- materialized window cache;
-- source map cache;
-- render layout cache;
-- search index.
-
-Rule:
-
-```text
-If deleting it changes history, it is evidence.
-If deleting it only makes reads slower, it is an index.
-```
-
-### 11. Define Balance And Checkpoint Policy
-
-A rope that path-copies forever without balance policy eventually becomes a
-linked list with better names. The design must define:
-
-- target leaf size;
-- maximum and minimum leaf size;
-- branch weight rules;
-- balance invariant;
-- when replacement triggers rebalance;
-- whether rebalance creates causal facts;
-- whether rebalance is visible to `:why`.
-
-Recommended posture:
-
-- edits create semantic rewrite evidence;
-- rebalancing creates structural maintenance evidence;
-- both can be retained;
-- normal UI hides structural maintenance unless debugging.
-
-Initial balance invariant for the tiny graph-backed runtime:
-
-- target leaf byte length is 4096 bytes;
-- minimum non-edge leaf byte length is 1024 bytes;
-- edge leaves may be smaller than the minimum when the buffer itself is smaller
-  or when the edge range has no merge candidate;
-- maximum leaf byte length is 8192 bytes before a replacement must split or
-  rebalance;
-- branches store exact `byteLength`, `lineCount`, `height`, and `contentHash`
-  aggregates from children;
-- branch height difference must be no greater than 1 after maintenance, except
-  while one admitted rewrite is still emitting its structural-maintenance facts;
-- replacement triggers rebalance when a touched leaf exceeds 8192 bytes, a
-  non-edge leaf falls below 1024 bytes and has a merge candidate, or a copied
-  path would create a branch height difference greater than 1;
-- rebalancing emits structural-maintenance evidence linked to the semantic
-  rewrite that made maintenance necessary.
-
-Checkpoint semantics also need precision. A checkpoint is not new text truth.
-It is a jedit declaration that a named rope head matters for a domain reason.
-That declaration does not necessarily request special Echo retention. Echo owns
-generic causal-anchor admission, while jedit may separately associate an
-admitted Echo anchor with a checkpoint for durable recovery, retention, save,
-or export policy.
-
-```typescript
-type CheckpointId = string & { readonly __brand: "CheckpointId" };
-type CausalAnchorId = string & { readonly __brand: "CausalAnchorId" };
-type CausalAnchorFactId = string & { readonly __brand: "CausalAnchorFactId" };
-type CausalAnchorReceiptId = string & { readonly __brand: "CausalAnchorReceiptId" };
-
-interface RopeCheckpointFact {
-  readonly kind: "jedit.text.RopeCheckpoint";
-  readonly schemaVersion: 1;
-  readonly checkpointId: CheckpointId;
-  readonly worldlineId: WorldlineId;
-  readonly headId: RopeHeadId;
-  readonly reason:
-    | "manual-save"
-    | "autosave"
-    | "retention-boundary"
-    | "export"
-    | "import"
-    | "test-fixture";
-}
-
-interface RopeCheckpointAnchoredFact {
-  readonly kind: "jedit.text.RopeCheckpointAnchored";
-  readonly schemaVersion: 1;
-  readonly associationId: string;
-  readonly checkpointId: CheckpointId;
-  readonly causalAnchorId: CausalAnchorId;
-  readonly causalAnchorFactId: CausalAnchorFactId;
-  readonly causalAnchorReceiptId: CausalAnchorReceiptId;
-}
-```
-
-Echo receipts are kernel-owned evidence and remain opaque to jedit. Jedit facts
-may retain an Echo receipt identity to state which admitted operation created a
-head or rewrite, but jedit must not define an application-local receipt fact,
-derive Echo receipt or admission identities, or validate Echo-owned receipt
-internals. Echo validates that evidence at the installed-operation boundary.
-
-Save/export should read from a head or checkpoint. It should not mutate text
-authority unless the product explicitly records a checkpoint. Declaring a
-checkpoint creates only `RopeCheckpointFact`. A separate, explicitly injected
-Echo capability may admit a causal anchor and return opaque anchor, fact, and
-receipt identities; jedit then records `RopeCheckpointAnchoredFact`. Neither
-operation creates a `RopeHead`, `RopeRewrite`, `RopeDiff`, replacement blob, or
-text mutation receipt.
-
-The transitional TypeScript port must not derive Echo basis frontiers, IDs,
-digests, receipts, WAL evidence, or retention policy. It validates jedit-owned
-checkpoint and materialization semantics before invocation, fails closed when
-no Echo capability is available, and treats all returned Echo identities as
-opaque references. Echo's witnessed causal history remains authoritative after
-restart; registries and lookup maps are disposable projections over that
-history. Replace this port with canonical event delivery to the installed
-`jim.core` observer, authored from `Jim.edict`, once Edict and Echo can build,
-verify, and run the required generic programs. A direct generated-client
-operation runner may exist only as test-only conformance scaffolding. The port
-is a short-lived seam for this one capability, not a Jim/Echo protocol: do not
-add new handwritten operations or give it long-term compatibility guarantees.
-
-### 12. Make `:why` An Acceptance Target
-
-Do not let `:why` become a bolt-on archaeology tool. For a byte range, the
-runtime should be able to answer:
-
-- this range is present in head H;
-- it descends from leaf L and blob B;
-- it was introduced or last touched by rewrite R;
-- rewrite R was admitted by tick T;
-- tick T had basis head H0;
-- here is the diff evidence;
-- here are related checkpoints.
-
-This is the runtime acceptance demo.
-
-### 13. Implement The Cutover In Slices
-
-The likely implementation sequence is:
-
-1. rename the snapshot runtime and add the production guard;
-2. add the fixture quarantine witness;
-3. define coordinate and fact skeletons;
-4. add retention, subtree identity, materialization, no-op, and `:why` witnesses;
-5. implement graph-backed `createBufferWorldline`;
-6. implement graph-backed `textWindow` over a `RopeHead`;
-7. implement graph-backed single-range `replaceRangeAsTick`;
-8. implement graph-backed `createCheckpoint`;
-9. cut the production session over to the graph-backed runtime;
-10. quarantine or delete full-root production authority paths;
-11. update `:why`, gutter evidence, worldline drawers, and save/export posture to
-    consume graph facts directly;
-12. define compaction and cold-retention rules.
-
-### 14. Useful Later Ideas
-
-These are not first-slice requirements, but they should stay visible:
-
-- content-addressed `TextBlob` storage where `blobId = hash(encoding + bytes)`;
-- internal-only `debugRopeShape` for witnesses and developer tools;
-- transitional `textAuthorityKind` such as `full-snapshot-fixture` or
-  `graph-backed-rope`;
-- explicit import from old snapshot roots into one graph-backed import
-  checkpoint;
-- queryable retention policy that explains why evidence, blobs, projections, or
-  indexes were retained or compacted;
-- a rope fact inspector drawer;
-- a causal heatmap over edit ancestry;
-- a retention budget dashboard;
-- basis-pinned save/export receipts.
-
-### 15. Things Not To Do
-
-- Avoid optimizing the full-snapshot runtime as a substitute for graph-backed
-  authority.
-- Keep names behind facts. A `RopeHead` must point to an actual rope.
-- Keep UI claims no more authoritative than storage truth.
-- Separate cache invalidation from authority mutation.
-- Preserve explainability when compaction policy deletes or cold-stores evidence.
-
-### 16. Treat UI Work As Dependent On Runtime Honesty
-
-UI posture work, including the causal footer and gutter evidence work, should be
-checked against the runtime truth. If the UI says "basis", "head", "tick",
-"checkpoint", or "worldline", the source underneath should be graph-backed
-causal evidence or explicitly marked as a transitional projection.
-
-## Lower Modes
-
-The runtime contract must remain inspectable without a full TUI session:
-
-- tests can inject the full-snapshot fixture only through an explicit
-  fixture-allowing path;
-- debug and witness APIs can emit deterministic JSON for rope shape, retained
-  bytes, materialization basis, no-op receipts, and checkpoints;
-- missing Echo, Graft, filesystem, or blob-store evidence produces typed
-  obstructions instead of silently falling back to projection text;
-- terminal size, color, and localization do not affect graph fact authority.
-
-## Data / State Model
-
-| Category | Description |
-| --- | --- |
-| Source of truth | Echo-admitted jedit rope facts: worldlines, heads, nodes, blobs, rewrites, diffs, checkpoints, and receipts. |
-| Derived state | Materialized text windows, line offset indexes, syntax spans, render layout, search indexes, and UI caches. |
-| Invalid states | A head without a root node, a leaf without verified blob bytes, a branch with mismatched metrics or hash, a no-op that advances a text tick, and product startup that silently uses the snapshot fixture. |
-| Reset behavior | Rebuild derived indexes from a named head or checkpoint. Do not rebuild authority from rendered lines or cached projections. |
-| Serialization | Graph facts and blob-store entries serialize with runtime `kind`, `schemaVersion`, IDs, byte metrics, references, and hashes. |
-| Deterministic assumptions | UTF-8 bytes are storage authority; line/column and UTF-16 positions are basis-bound projections; hash and metric validation is deterministic. |
-
-```mermaid
-stateDiagram-v2
-  [*] --> SnapshotFixtureQuarantined
-  SnapshotFixtureQuarantined --> GraphFactsDefined
-  GraphFactsDefined --> WitnessesFailing
-  WitnessesFailing --> TinyGraphRuntime
-  TinyGraphRuntime --> ProductionCutover
-```
-
-## Accessibility Posture
-
-| Concern | Posture |
-| --- | --- |
-| Semantic labels or facts | Runtime truth is exposed as graph facts and deterministic witness output. |
-| Focus order or ownership | Not changed by this design cycle. |
-| Hidden or visual-only information | Causal state must not be available only through color, gutter marks, or footer prose. |
-| Keyboard behavior | Not changed by this design cycle. |
-| Secret or redaction behavior | Blob witnesses should support redacted byte previews while retaining hashes and byte ranges. |
-
-## Localization / Directionality Posture
-
-| Concern | Posture |
-| --- | --- |
-| User-visible strings | No new runtime strings beyond guard and obstruction messages. |
-| Catalog keys | Not required for this design-only cycle. |
-| Supported locales updated | Not required. |
-| Directionality assumptions | Text storage uses UTF-8 byte order; UI directionality is a projection concern. |
-| Validation command | `npx markdownlint-cli2 docs/design/0149-graph-backed-rope-runtime-discovery.md` |
-
-## Agent Inspectability / Explainability Posture
-
-Agents must be able to inspect the result through stable IDs and witness APIs:
-
-- `debugRopeShape(headId)` exposes head ID, root ID, spans, node IDs, child IDs,
-  hashes, depth, retained blob bytes, and materialized projection bytes;
-- `textWindow({ basisHeadId, byteRange })` returns text with basis head, byte
-  range, cache status, and validation evidence;
-- no-op admissions emit non-ticking receipt objects;
-- `:why` acceptance cites head, leaf, blob, rewrite, diff, tick, checkpoint, and
-  basis evidence for a byte range.
-
-## Linked Invariants
-
-- Runtime truth beats type theater.
-- Materialization is a reading, not reality.
-- A rope runtime is defined by what survives an edit.
-- Echo remains generic and does not learn jedit text semantics.
-- UI causal claims must not outrun storage authority.
-- Tests and witnesses are executable spec.
-
-## Design Alternatives Considered
-
-### Option A: Optimize The Snapshot Runtime
-
-Pros:
-
-- Smaller immediate code change.
-- Could reduce short-term latency for small files.
-
-Cons:
-
-- Preserves the wrong authority model.
-- Keeps full-buffer retention as production truth.
-- Lets misleading rope/worldline names continue to outrun facts.
-
-### Option B: Move Directly To A Complete Rope Runtime
-
-Pros:
-
-- Reaches the intended architecture in one broad effort.
-- Avoids intermediate fixture quarantine work.
-
-Cons:
-
-- Too large to review or witness safely.
-- Risks mixing compaction, braids, UI, syntax, and retention before the minimal
-  create/read/replace/checkpoint path is proven.
-
-### Option C: Fence The Fixture And Build The Smallest Real Path
-
-Pros:
-
-- Makes the unsafe authority explicit immediately.
-- Lets witnesses fail before implementation.
-- Proves graph-backed create/read/replace/checkpoint before UI posture depends on
-  it.
-
-Cons:
-
-- Leaves some current dogfood discomfort in place while the real runtime lands.
-- Requires transitional compatibility until production cutover finishes.
-
-## Decision
-
-Do not treat the current full-snapshot hot text runtime as an acceptable
-production implementation. It can remain only as a bounded fixture while the
-graph-backed runtime is designed and cut over.
-
-The next work item is not implementation of the final runtime. It is:
-
-1. rename and fence the snapshot fixture;
-2. add the production guard;
-3. define concrete coordinate and graph fact shapes;
-4. write failing witnesses for retention, subtree identity, no-op admission,
-   materialization basis, save/export basis, and `:why` evidence;
-5. implement the smallest real graph-backed create/read/replace/checkpoint path.
-
-The core principle is:
-
-```text
-A rope runtime is defined by what survives an edit.
-Materialization is a reading, not reality.
-Causal honesty is an end-to-end property.
-```
-
-## Implementation Slices
-
-- [x] Slice 1: Rename the snapshot runtime as a full-snapshot fixture and add the
-      production guard.
-- [x] Slice 2: Add a quarantine witness proving default product construction
-      cannot silently use the fixture.
-- [x] Slice 3: Land coordinate, fact, byte-authority, and validation contracts.
-- [x] Slice 4: Add failing retention, subtree identity, materialization, no-op,
-      save/export, and `:why` witnesses.
-- [x] Slice 5: Implement graph-backed `createBufferWorldline` and `textWindow`.
-- [x] Slice 6: Implement graph-backed single-range `replaceRangeAsTick`.
-- [ ] Slice 7: Implement graph-backed `createCheckpoint` and cut product
-      construction over to graph-backed authority.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [x] Product construction rejects implicit `FullSnapshotHotTextRuntimeFixture`.
-- [x] Graph rope contracts separate UTF-8 storage coordinates from UI
-      projections, derive text blob identity from bytes, and reject hash or
-      reference mismatches.
-- [x] RED witness declared: repeated small edits on a large buffer do not retain
-      O(buffer size * edit count) authoritative bytes.
-- [x] RED witness declared: narrow replacement preserves untouched subtree
-      identity recursively.
-- [x] Graph-backed no-op replacement emits no new head, rewrite, diff, or text
-      tick.
-- [x] Graph-backed `textWindow` returns basis head, UTF-8 byte range, cache
-      status, and hash validation evidence for the initial single-leaf runtime.
-- [x] Graph-backed `replaceRangeAsTick` admits rewrite, diff, receipt, and next
-      head facts without retaining a full replacement snapshot.
-- [x] RED witness declared: save/export reads from a named head or checkpoint
-      without mutating text authority.
-- [x] RED witness declared: `:why` can cite head, leaf, blob, rewrite, diff,
-      tick, checkpoint, and basis evidence for a byte range.
-
-Documentation and process tests:
-
-- [ ] Design-cycle policy continues to recognize the required template headings.
-- [ ] BEARING links this runtime gate while it blocks UI causal-honesty work.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [x] The full-snapshot runtime cannot be installed as default production text
-      authority without an explicit fixture escape hatch.
-- [x] A graph-backed runtime can create and read one single-leaf buffer.
-- [x] A graph-backed runtime can create, read, and replace one buffer.
-- [x] A graph-backed runtime can checkpoint one buffer.
-- [ ] Retention stress, recursive subtree identity, save/export, and `:why`
-      witnesses pass against graph-backed authority.
-- [ ] UI surfaces that mention basis, head, tick, checkpoint, or worldline cite
-      graph facts or explicitly mark transitional projection posture.
-- [ ] Issue #206 and PR #205 are linked correctly.
-- [ ] CI and local validation are green.
-
-## Validation Plan
-
-Commands expected before implementation PRs:
-
-```bash
-git diff --check
-npx markdownlint-cli2 docs/BEARING.md docs/design/0149-graph-backed-rope-runtime-discovery.md
-node --test --test-concurrency=1 spec/design-cycle-policy.spec.mjs
-node --test --test-concurrency=1 spec/graph-rope-contract.spec.mjs
-node --test --test-concurrency=1 spec/graph-rope-runtime.spec.mjs
-node --test --test-concurrency=1 spec/graph-rope-runtime-red-matrix.spec.mjs
-npm run quality
-```
-
-Runtime implementation slices should also run focused behavior witnesses and the
-full `npm run check` before merge.
-
-## Playback / Witness
-
-Reviewers can inspect:
-
-```bash
-sed -n '1,260p' docs/design/0149-graph-backed-rope-runtime-discovery.md
-sed -n '1,220p' docs/BEARING.md
-node --test --test-concurrency=1 spec/design-cycle-policy.spec.mjs
-node --test --test-concurrency=1 spec/graph-rope-contract.spec.mjs
-node --test --test-concurrency=1 spec/graph-rope-runtime.spec.mjs
-node --test --test-concurrency=1 spec/graph-rope-runtime-red-matrix.spec.mjs
-```
-
-Future runtime PRs should add machine-readable witness output for retained bytes,
-debug rope shape, text-window basis, checkpoint basis, and `:why` byte-range
-evidence.
-
-## Risks
-
-Known risks:
-
-- The snapshot fixture could remain wired into product code too long.
-- A graph-backed runtime could materialize full strings internally and still pass
-  superficial read tests.
-- Blob-store-backed facts could become unverifiable if byte retrieval and hash
-  checks are optional.
-- UI work could resume causal language before runtime authority is ready.
-
-Mitigations:
-
-- Keep the fixture name and guard intentionally loud.
-- Make retention and untouched subtree witnesses required implementation proof.
-- Treat missing or mismatched blob bytes as obstructions.
-- Keep BEARING pointed at this gate until create/read/replace/checkpoint lands.
-
-## Follow-On Debt
-
-- [#206](https://github.com/flyingrobots/jedit/issues/206) tracks the runtime
-  gate and implementation slices.
-- [#207](https://github.com/flyingrobots/jedit/issues/207) tracks graph-backed
-  rope compaction policy.
-- [#208](https://github.com/flyingrobots/jedit/issues/208) tracks graph-backed
-  rope rebalancing evidence.
-- [#209](https://github.com/flyingrobots/jedit/issues/209) tracks the rope fact
-  inspector and range `:why` UI.
-- [#210](https://github.com/flyingrobots/jedit/issues/210) tracks the retention
-  budget dashboard.
-- [#211](https://github.com/flyingrobots/jedit/issues/211) tracks snapshot
-  fixture import migration.
-
-## Retrospective
-
-What changed from the design:
-
-- The snapshot runtime is quarantined as a fixture.
-- The first executable graph rope contract slice now defines coordinate values,
-  typed fact shapes, byte-derived text blob identity, blob-store validation, and
-  typed admission context. It does not yet implement graph-backed authority.
-
-What the tests proved:
-
-- Product construction rejects implicit full-snapshot text authority.
-- Graph rope contract witnesses prove coordinate separation, byte-derived blob
-  identity, stored blob hash validation, and typed reference validation.
-- The first graph-backed runtime path can create a single-leaf worldline, read a
-  named head window, report retained blob bytes through debug shape, and obstruct
-  missing heads or invalid UTF-8 byte boundaries.
-- The graph-backed runtime can admit a single-range replacement as rewrite, diff,
-  receipt, and next-head facts; logical no-op replacements do not mint text
-  authority facts.
-- The graph-backed runtime RED matrix declares retention, subtree identity,
-  save/export, and `:why` acceptance witnesses.
-- Markdown structure, design-cycle policy, ASCII hygiene, and the repo quality
-  gate pass for the design packet.
-
-What remains open:
-
-- Graph-backed checkpoint authority remains open.
-- Retention stress and recursive subtree identity still need stronger witnesses
-  before product cutover.
-
-PR:
-
-- https://github.com/flyingrobots/jedit/pull/205
diff --git a/docs/design/0150-obstruction-receipt-display.md b/docs/design/0150-obstruction-receipt-display.md
deleted file mode 100644
index 75669d04..00000000
--- a/docs/design/0150-obstruction-receipt-display.md
+++ /dev/null
@@ -1,200 +0,0 @@
----
-title: "WF-0150 - Obstruction Receipt Display"
-legend: "WF"
-lane: "implementation"
-issue: "https://github.com/flyingrobots/jedit/issues/212"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-07-05"
-updated: "2026-07-05"
----
-
-# WF-0150 - Obstruction Receipt Display
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/212
-
-## Decision Summary
-
-jedit will render an optional opaque obstruction receipt projection lane in the
-Graft drawer when upstream Graft/Edict metadata supplies one. The drawer shows
-carried facts such as outcome kind, Target IR digest, reason kind, and reason
-payload, but it does not execute Echo, admit Jim artifacts, compute receipt
-digests, or interpret domain-specific obstruction meaning.
-
-## Sponsored Human
-
-A Jim user wants to inspect why an Edict/Echo projection ran into an obstruction
-so that they can see the receipt facts beside existing Graft projection context,
-without mistaking that display for jedit runtime admission or execution.
-
-## Sponsored Agent
-
-An agent needs a stable display-side slot for obstruction receipt facts so it
-can verify that jedit preserves upstream receipt evidence, without scraping
-strings from Echo, Edict, or Graft internals.
-
-## Hill
-
-By the end of this cycle, the Graft drawer can display an opaque obstruction
-receipt projection supplied through `GraftInfo`, and a focused spec proves the
-drawer preserves the carried facts without rendering a receipt digest or
-reclassifying the receipt as hard rejection or scheduler counterfactual.
-
-## Current Truth
-
-On `origin/main` at
-`daf07936b4a4ee1047fac0224e20a5bd2d4c0e5e`, `GraftInfo` carries path,
-projection source/posture, outline rows, change lines, notice, and error, but no
-receipt lane:
-[`src/ports/graft-session.ts#L20:daf07936b4a4ee1047fac0224e20a5bd2d4c0e5e`](https://github.com/flyingrobots/jedit/blob/daf07936b4a4ee1047fac0224e20a5bd2d4c0e5e/src/ports/graft-session.ts#L20).
-
-The Graft drawer currently renders `graft`, path, projection source, projection
-posture, loading/notice, error, and outline sections:
-[`src/ui/graft-drawer.ts#L64:daf07936b4a4ee1047fac0224e20a5bd2d4c0e5e`](https://github.com/flyingrobots/jedit/blob/daf07936b4a4ee1047fac0224e20a5bd2d4c0e5e/src/ui/graft-drawer.ts#L64).
-
-The active bearing warns that graph-backed rope runtime authority is a hard gate
-for new jedit causal-storage UI claims:
-[`docs/BEARING.md#L35:daf07936b4a4ee1047fac0224e20a5bd2d4c0e5e`](https://github.com/flyingrobots/jedit/blob/daf07936b4a4ee1047fac0224e20a5bd2d4c0e5e/docs/BEARING.md#L35).
-This slice stays outside that gate by displaying external projection evidence
-only; it does not claim jedit text-runtime authority.
-
-## Problem
-
-After the Edict, Echo, and Graft obstruction-strand slices, jedit has no display
-surface for an upstream Echo obstruction receipt projection. Without a narrow
-display lane, future UX would either hide receipt evidence or be tempted to map
-it into existing error, rejection, or counterfactual labels. That would collapse
-separate meanings.
-
-## Scope
-
-This cycle includes:
-
-- adding a typed optional obstruction receipt projection to `GraftInfo`;
-- rendering receipt, outcome, target, reason, and reason payload rows in the
-  Graft drawer;
-- preserving the receipt as upstream evidence, not jedit-owned semantics;
-- proving the drawer does not render a receipt digest before canonical receipt
-  bytes exist;
-- keeping existing Graft saved-file drawer behavior unchanged.
-
-## Non-Goals
-
-This cycle does not include:
-
-- Echo execution;
-- Jim admission;
-- Graft dependency upgrades;
-- canonical Echo receipt bytes;
-- receipt digests;
-- scheduler counterfactual exploration;
-- jedit text-runtime causal authority claims.
-
-## User Experience / Product Shape
-
-The receipt lane appears inside the Graft drawer above the outline section when
-`GraftInfo.obstructionReceipt` is present.
-
-### Wide UI Mockup
-
-```text
-graft
-demo.edict
-source: live-buffer
-posture: current
-
-
-receipt
-outcome: obstructed_strand
-target: echo.span-ir/v1 sha256:333333...
-reason: jim.EditObstruction.StaleBase
-payload: inputBasisDigest=sha256:111111...
-payload: observedBasisDigest=sha256:444444...
-outline
-structural outline unavailable
-```
-
-### Narrow UI Mockup
-
-The drawer keeps the same line-fitting behavior as existing Graft rows. Long
-digests and payload entries are truncated by drawer width rather than wrapping
-into adjacent UI.
-
-### Accessibility Considerations
-
-The lane uses plain text labels and does not rely on color. The receipt facts
-are visible through the same drawer text representation used by tests and
-terminal rendering.
-
-## Runtime / API Contract
-
-`GraftInfo` gains:
-
-```ts
-type GraftObstructionReceiptProjection = {
-  outcomeKind: string;
-  targetIrDigest: string;
-  targetIrDomain?: string;
-  reasonKind?: string;
-  reasonPayload?: GraftJsonObject;
-  receipt?: GraftJsonObject;
-};
-```
-
-`receipt` is the opaque Graft/Edict receipt review object. jedit may carry it
-but does not interpret it.
-
-The drawer renders:
-
-- `receipt`
-- `outcome: `
-- `target:  ` when domain is present
-- `target: ` otherwise
-- `reason: ` when present
-- one deterministic `payload: =` row per payload key
-
-The drawer must not render a receipt digest. A future cycle can add that only
-after Echo or Edict freezes canonical receipt bytes.
-
-## Lower Modes
-
-The lower mode is the existing text drawer output. Tests assert the rendered
-lines directly.
-
-## Data / State Model
-
-| Category | Description |
-| --- | --- |
-| Source of truth | Upstream Graft/Edict/Echo projection metadata. |
-| Derived state | Drawer text rows. |
-| Invalid states | jedit interpreting receipt semantics or rendering a digest without canonical bytes. |
-| Reset behavior | Receipt disappears when `graftInfo` is absent or replaced. |
-| Serialization | No new persistence. |
-| Deterministic assumptions | Payload keys render in sorted order. |
-
-## Retrospective
-
-The cycle stayed display-only. `GraftInfo` now carries an optional opaque
-obstruction receipt projection, and the Graft drawer renders the receipt
-outcome, Target IR binding, reason kind, and sorted reason payload rows without
-claiming Echo execution or Jim admission authority.
-
-The RED spec first failed because the drawer rendered no receipt lane. The
-GREEN implementation added the typed receipt shape, receipt rows, deterministic
-payload ordering, and drawer pagination that counts receipt payload rows rather
-than using a fixed estimate.
-
-Validation:
-
-- `npm run build && JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-drawer.spec.mjs`
-- `npm run --silent quality`
-- `npx markdownlint-cli2 CHANGELOG.md docs/design/0150-obstruction-receipt-display.md`
-- `git diff --check`
-- `npm run check`
-
-Follow-up work remains in the upstream stack: this PR does not bump the Graft
-package dependency, create canonical receipt bytes, or add jedit-side runtime
-authority over Echo obstruction semantics.
diff --git a/docs/design/0151-causal-rope-text-authority-inventory.md b/docs/design/0151-causal-rope-text-authority-inventory.md
deleted file mode 100644
index c32d800a..00000000
--- a/docs/design/0151-causal-rope-text-authority-inventory.md
+++ /dev/null
@@ -1,122 +0,0 @@
-# Causal Rope Text Authority Inventory
-
-Status: active CR-00 inventory for
-[#216](https://github.com/flyingrobots/jedit/issues/216).
-
-> **Active-observer correction:** This inventory predates the decision that the
-> final application package is `jim.core`, authored from `Jim.edict`, not
-> TypeScript orchestration plus generated operation clients. Entries below
-> remain useful for locating compatibility
-> code, but command interpretation, operation choice, range derivation,
-> cursor/mode advancement, and outcome handling must migrate to `jim.core`,
-> authored from `Jim.edict`; text operations and optics migrate to `jedit.text`.
-> Jedit/Bijou/native code retains canonical event decoding, raw transport and
-> bootstrap, file I/O adapters, and disposable rendering. Echo remains generic
-> and has no rope or editor vocabulary.
-
-This document names every current product path that can create, read, mutate,
-save, export, or explain buffer text while Jim is cutting over to causal rope.
-It separates authority from projection so the full-snapshot fixture cannot hide
-behind app-facing ports.
-
-## Authority Rule
-
-The current compatibility authority path is:
-
-```text
-workspace command
--> ProductionTextSession
--> TextBufferSessionPort
--> TextBufferOptic
--> installed jedit contract transport
--> graph-backed causal rope authority
-```
-
-The target application path is canonical event delivery to `jim.core`,
-application-owned `jedit.text` bounded optics and operation lawpacks,
-compiler-produced generic Echo programs, and returned outcome/read projection
-rendering.
-
-Full materialized strings are allowed only as import inputs, export outputs,
-render windows, tests, or caches. They are forbidden as product text authority.
-
-## Classifications
-
-- **causal rope authority**: authoritative graph-backed rope facts or the
-  product seam that must become graph-backed.
-- **materialized projection**: text read from a named basis for display,
-  export, highlighting, or temporary cache use.
-- **fixture**: test-only full-snapshot authority.
-- **compatibility authority**: active transitional command interpretation,
-  operation choice, range derivation, or coordinate policy that production
-  still executes and the final `jim.core`/`jedit.text` cutover must remove.
-- **migration/import**: code that converts host bytes into initial authority
-  or adapts old evidence during cutover.
-- **forbidden**: a product path that would make full materialized text the
-  authority again.
-
-## Inventory
-
-| Area | Path | Current classification | CR target | Follow-up |
-| --- | --- | --- | --- | --- |
-| Installed transport | `src/adapters/installed-jedit-contract-echo-transport.ts` | migration/import | Construct graph-backed causal rope authority by default; reject fixture authority. | [#218](https://github.com/flyingrobots/jedit/issues/218), [#222](https://github.com/flyingrobots/jedit/issues/222) |
-| Runtime profile | `src/adapters/text-runtime-profile-session.ts` | migration/import | Keep `echoHosted` as the product runtime profile and remove the fixture escape hatch after graph rope installs. | [#218](https://github.com/flyingrobots/jedit/issues/218), [#250](https://github.com/flyingrobots/jedit/issues/250) |
-| Product session | `src/app/workspace/production-text-session.ts` | materialized projection | Create, edit, read, save, export, and explain through `TextBufferSessionPort`; export remains a projection. | [#224](https://github.com/flyingrobots/jedit/issues/224), [#225](https://github.com/flyingrobots/jedit/issues/225), [#226](https://github.com/flyingrobots/jedit/issues/226) |
-| Open/import | `src/app/workspace/workspace-text-open-basis.ts` | migration/import | Treat host file bytes as import material for `BufferWorldline` and initial `RopeHead`. | [#223](https://github.com/flyingrobots/jedit/issues/223) |
-| Workspace authority state | `src/app/workspace/workspace-text-authority.ts` | causal rope authority | Track buffer id, dirty posture, receipts, checkpoints, and projections without storing authority text. | [#231](https://github.com/flyingrobots/jedit/issues/231), [#232](https://github.com/flyingrobots/jedit/issues/232) |
-| Command handlers | `src/app/workspace/workspace-text-commands.ts` and `src/app/workspace/workspace-text-edit-planner.ts` | compatibility authority | Preserve compatibility behavior, then replace command-to-operation mapping with canonical event delivery to `jim.core`. | [#224](https://github.com/flyingrobots/jedit/issues/224), [#295](https://github.com/flyingrobots/jedit/issues/295) |
-| Operation sequencing | `src/app/workspace/workspace-text-operation-sequencer.ts` | causal rope authority | Preserve admission order for edit, checkpoint, and export operations. | [#231](https://github.com/flyingrobots/jedit/issues/231) |
-| Save/export | `src/app/workspace/workspace-save-key.ts` and `src/app/workspace/workspace-text-commands.ts` | materialized projection | Save/export from the current `RopeHead`, then record anchor/checkpoint evidence without mutating text authority. | [#226](https://github.com/flyingrobots/jedit/issues/226), [#233](https://github.com/flyingrobots/jedit/issues/233) |
-| Source rendering | `src/app/workspace/viewer-content.ts` and `src/ui/source-viewer.ts` | materialized projection | Render only from basis-tagged text windows and cached projections. | [#225](https://github.com/flyingrobots/jedit/issues/225), [#228](https://github.com/flyingrobots/jedit/issues/228) |
-| Reading cache | `src/app/workspace/workspace-text-reading-cache.ts` | materialized projection | Cache projected windows with explicit coverage and basis; never make cache entries authority. | [#230](https://github.com/flyingrobots/jedit/issues/230) |
-| Cursor and coordinates | `src/app/workspace/workspace-text-position.ts` | compatibility authority | Convert coordinates for compatibility rendering; final cursor and range policy belongs to `jim.core` over public `jedit.text` coordinate contracts. | [#227](https://github.com/flyingrobots/jedit/issues/227), [#295](https://github.com/flyingrobots/jedit/issues/295) |
-| Why command | `src/app/workspace/workspace-why-range.ts` and `src/app/jedit-why-range.ts` | materialized projection | Explain ranges from rope head, leaf, blob, rewrite, diff, tick, checkpoint, and anchor evidence. | [#209](https://github.com/flyingrobots/jedit/issues/209), [#239](https://github.com/flyingrobots/jedit/issues/239) |
-| Gutter markers | `src/ui/source-viewer.ts` | materialized projection | Compute modified and deleted markers from rope rewrite/diff ancestry. | [#84](https://github.com/flyingrobots/jedit/issues/84), [#235](https://github.com/flyingrobots/jedit/issues/235), [#236](https://github.com/flyingrobots/jedit/issues/236) |
-| Footer posture | `src/app/workspace/workspace-footer-posture.ts` | materialized projection | Display durability ladder facts derived from pending intents, admitted heads, save anchors, and Git state. | [#233](https://github.com/flyingrobots/jedit/issues/233), [#234](https://github.com/flyingrobots/jedit/issues/234) |
-| Contract runtime | `src/app/jedit-contract-runtime.ts` | migration/import | Replace `HotTextRuntimePort` full-root semantics with graph rope create/read/replace/checkpoint authority. | [#206](https://github.com/flyingrobots/jedit/issues/206), [#222](https://github.com/flyingrobots/jedit/issues/222) |
-| Contract observers | `src/app/jedit-contract-query-observers.ts` and `src/app/jedit-observer-runtime.ts` | materialized projection | Query `textWindow` and `worldlineSnapshot` from causal rope basis evidence. | [#225](https://github.com/flyingrobots/jedit/issues/225), [#228](https://github.com/flyingrobots/jedit/issues/228) |
-| Graph rope runtime | `src/domain/graph-rope-runtime.ts` and `src/domain/graph-rope-*` | causal rope authority | Become the only installed text authority. | [#222](https://github.com/flyingrobots/jedit/issues/222) |
-| Full-snapshot fixture | `src/adapters/full-snapshot-hot-text-runtime-fixture.ts` | fixture | Stay test-only, then move under an explicit test fixture namespace. | [#217](https://github.com/flyingrobots/jedit/issues/217), [#248](https://github.com/flyingrobots/jedit/issues/248) |
-| Fake transport | `src/adapters/fake-echo-jedit-optic-transport.ts` | fixture | Remain non-production or accept an explicit fixture injection only. | [#217](https://github.com/flyingrobots/jedit/issues/217), [#247](https://github.com/flyingrobots/jedit/issues/247) |
-| Hot buffer helpers | `src/app/hot-buffer-session.ts` and `src/ports/hot-text-runtime.ts` | fixture | Remove from product authority paths after graph rope installation. | [#247](https://github.com/flyingrobots/jedit/issues/247), [#249](https://github.com/flyingrobots/jedit/issues/249) |
-| Tests and witnesses | `spec/**` and `tests/**` | fixture | May use the fixture explicitly, but must not mask product imports or clean-build failures. | [#217](https://github.com/flyingrobots/jedit/issues/217), [#249](https://github.com/flyingrobots/jedit/issues/249) |
-
-## Forbidden Product Patterns
-
-These patterns are forbidden in installed product code and enforced by
-`scripts/jedit-production-cutover-guard.mjs`:
-
-- constructing `FullSnapshotHotTextRuntimeFixture`;
-- importing `full-snapshot-hot-text-runtime-fixture`;
-- importing stale `in-memory-hot-text-runtime` aliases;
-- importing `fake-echo-jedit-optic-transport`;
-- importing `hot-buffer-session`;
-- reading current buffer text from `HotTextBufferState.roots`;
-- treating `materializeHotBuffer(...)` or a full text window cache as authority;
-- saving from an editor line array instead of a causal basis export;
-- computing modified lines from Git diff.
-- mapping terminal commands directly to `ReplaceRange` in final production;
-- advancing cursor, mode, register, or pending-operator state outside
-  `Jim.edict` in final production;
-- adding Jim/Jedit nouns, verbs, or rope intrinsics to Echo production code.
-
-## Open Blockers
-
-- [#217](https://github.com/flyingrobots/jedit/issues/217): add the
-  automated product fixture import ban.
-- [#218](https://github.com/flyingrobots/jedit/issues/218): make installed
-  construction fail unless graph rope authority is supplied.
-- [#222](https://github.com/flyingrobots/jedit/issues/222): install graph
-  rope runtime as Jim default text authority.
-- [#247](https://github.com/flyingrobots/jedit/issues/247): delete or
-  quarantine full-root authority.
-- [#249](https://github.com/flyingrobots/jedit/issues/249): remove stale
-  in-memory runtime aliases and generated import paths.
-
-## Exit Criteria For CR-00
-
-- This inventory covers open/import, workspace state, command handlers,
-  save/export, source rendering, `:why`, installed transports, and tests.
-- The full-snapshot fixture is explicitly classified as fixture-only.
-- Product code has an automated import ban for fixture authority.
-- Installed construction fails when no graph-backed authority is supplied.
diff --git a/docs/design/0151-edict-projection-lens.md b/docs/design/0151-edict-projection-lens.md
deleted file mode 100644
index ae9f78a5..00000000
--- a/docs/design/0151-edict-projection-lens.md
+++ /dev/null
@@ -1,398 +0,0 @@
----
-title: "WF-0151 - Edict Projection Lens"
-legend: "WF"
-lane: "implementation"
-issue: "https://github.com/flyingrobots/jedit/issues/256"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-07-05"
-updated: "2026-07-05"
----
-
-# WF-0151 - Edict Projection Lens
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/256
-
-## Decision Summary
-
-jedit will consume Graft 0.11.1 and use the Graft/Edict projection provider for
-dirty `.edict` editor buffers. The Graft drawer will render bounded Edict Core
-and Echo Target IR projection lanes, including projection state and digest
-facts, while preserving jedit's boundary as a display surface rather than an
-Edict compiler, Echo runtime, or Jim admission authority.
-
-## Sponsored Human
-
-A Jim user wants to edit Edict source and inspect the compiler's Core and Echo
-Target IR projections beside the editor so that the source-to-artifact path is
-visible before any runtime or admission flow exists, without saving the file
-just to refresh the projection.
-
-## Sponsored Agent
-
-An agent needs a typed jedit surface for upstream Edict projection facts so it
-can verify source, Core, Target IR, and receipt lanes through stable fields,
-without scraping pixels or inferring private Graft or Edict internals.
-
-## Hill
-
-By the end of this cycle, dirty `.edict` buffers can be projected through Graft
-0.11.1, the drawer can show Edict Core and Echo Target IR lanes, and focused
-adapter plus drawer specs prove the carried facts are decoded and rendered
-without jedit interpreting Edict, Echo, or receipt semantics.
-
-## Current Truth
-
-On `origin/main` at
-`bf6a98bbf26fdee3571af62ac2bbc82ee764bea4`, `GraftFileRequest`
-contains workspace root, file path, and dirty state, but no editor buffer
-content:
-[`src/ports/graft-session.ts#L50:bf6a98bbf26fdee3571af62ac2bbc82ee764bea4`](https://github.com/flyingrobots/jedit/blob/bf6a98bbf26fdee3571af62ac2bbc82ee764bea4/src/ports/graft-session.ts#L50).
-
-The Graft API adapter currently loads saved-file outlines and labels dirty
-files as stale saved-file projections:
-[`src/adapters/graft-api-session.ts#L124:bf6a98bbf26fdee3571af62ac2bbc82ee764bea4`](https://github.com/flyingrobots/jedit/blob/bf6a98bbf26fdee3571af62ac2bbc82ee764bea4/src/adapters/graft-api-session.ts#L124).
-
-The Graft drawer already renders an opaque obstruction receipt lane when
-upstream metadata supplies one:
-[`src/ui/graft-drawer.ts#L105:bf6a98bbf26fdee3571af62ac2bbc82ee764bea4`](https://github.com/flyingrobots/jedit/blob/bf6a98bbf26fdee3571af62ac2bbc82ee764bea4/src/ui/graft-drawer.ts#L105).
-
-The current package dependency is `@flyingrobots/graft` 0.10.1, which predates
-the published Edict projection bridge:
-[`package.json#L38:bf6a98bbf26fdee3571af62ac2bbc82ee764bea4`](https://github.com/flyingrobots/jedit/blob/bf6a98bbf26fdee3571af62ac2bbc82ee764bea4/package.json#L38).
-
-## Problem
-
-jedit can already show Graft outline and receipt facts, but it still treats
-dirty editor buffers as stale saved-file projections. That blocks the intended
-Edict authoring loop: write Edict, inspect Core, inspect Echo Target IR, then
-later inspect any upstream receipt facts. If jedit keeps using saved-file-only
-projection for `.edict`, the editor surface lies about the projection basis.
-
-## Scope
-
-This cycle includes:
-
-- bumping `@flyingrobots/graft` from 0.10.1 to 0.11.1;
-- passing dirty `.edict` editor text to the Graft/Edict projection provider;
-- adding typed optional Edict Core and Echo Target IR projection lanes to
-  `GraftInfo`;
-- rendering bounded Core and Target IR rows in the Graft drawer;
-- preserving existing outline, diff, Colorful, and obstruction receipt behavior;
-- documenting the display-only authority boundary.
-
-## Non-Goals
-
-This cycle does not include:
-
-- Echo execution from jedit;
-- Jim admission;
-- canonical Echo receipt bytes or receipt digests;
-- jedit-side Edict parsing, Core construction, or Target IR lowering;
-- jedit interpretation of Edict, Echo, Jim, or obstruction semantics;
-- Graft schema freezing beyond consuming the published package API.
-
-## User Experience / Product Shape
-
-The user opens or edits a `.edict` file. When the Graft drawer refreshes, jedit
-uses the live buffer text as projection input. If Graft/Edict returns Core or
-Target IR facts, the drawer shows compact lanes before the receipt and outline
-sections.
-
-### Wide UI Mockup
-
-```text
-graft
-demo.edict
-source: live-buffer
-posture: current
-
-edict core
-state: available
-digest: sha256:1111111111111111111111111111111111111111111111111111111111111111
-
-echo target ir
-state: available
-domain: echo.span-ir/v1
-digest: sha256:2222222222222222222222222222222222222222222222222222222222222222
-
-outline
-structural outline unavailable
-```
-
-### Narrow UI Mockup
-
-Long digests and review summaries are truncated with the same line-fitting rule
-used by the existing drawer. The drawer does not wrap Core, Target IR, or
-receipt facts into adjacent panes.
-
-### Accessibility Considerations
-
-The projection lanes use plain text labels and values. The same rows are
-available to tests and terminal output, so agents and screen readers can inspect
-the facts without color or layout-only cues.
-
-## Runtime / API Contract
-
-`GraftFileRequest` gains optional live source content. The adapter only uses it
-for `.edict` projection requests.
-
-`GraftInfo` gains typed optional lanes:
-
-```ts
-interface GraftEdictProjectionLane {
-  readonly state: string;
-  readonly digest?: string;
-  readonly summaryLines: readonly string[];
-}
-
-interface GraftEchoTargetIrProjectionLane extends GraftEdictProjectionLane {
-  readonly domain?: string;
-}
-```
-
-jedit treats these lanes as display facts from Graft. It does not derive them,
-validate their Edict semantics, execute Echo, or admit artifacts.
-
-jedit may pass the published Graft target selection shape for the Echo lens:
-target coordinate, target profile digest, and Target IR domain. It must not
-own compiler context, operation profile mappings, budgets, effect lowerings, or
-obstruction coordinates for Edict projection.
-
-## Lower Modes
-
-The lower mode is the existing text drawer output. Focused specs assert the
-rendered lines directly and the adapter specs assert the decoded `GraftInfo`
-shape.
-
-When Graft 0.11.1 or the Edict provider is unavailable, jedit should keep the
-existing outline/diff error handling: the drawer shows an error or unavailable
-state rather than crashing.
-
-## Data / State Model
-
-| Category | Description |
-| --- | --- |
-| Source of truth | The current editor buffer for `.edict` projection input; upstream Graft/Edict output for projection facts. |
-| Derived state | `GraftInfo` lanes and drawer text rows. |
-| Invalid states | jedit computing Core/Target IR itself, carrying Edict compiler or Echo lowering semantics, treating saved-file projection as current for dirty `.edict`, or interpreting receipt semantics. |
-| Reset behavior | Projection lanes disappear when new `GraftInfo` lacks them or the active file changes. |
-| Serialization | No new persistence. |
-| Deterministic assumptions | Drawer row ordering is fixed and bounded; payload keys remain sorted where existing receipt logic applies. |
-
-## Accessibility Posture
-
-| Concern | Posture |
-| --- | --- |
-| Semantic labels or facts | Core and Target IR rows have text labels. |
-| Focus order or ownership | Drawer navigation remains unchanged. |
-| Hidden or visual-only information | Projection state and digests are textual. |
-| Keyboard behavior | Existing Graft drawer refresh and navigation keys remain unchanged. |
-| Secret or redaction behavior | No new secret material is introduced. |
-
-## Localization / Directionality Posture
-
-| Concern | Posture |
-| --- | --- |
-| User-visible strings | New drawer labels are English-only like adjacent Graft drawer rows. |
-| Catalog keys | No catalog update in this cycle. |
-| Supported locales updated | Not applicable; existing drawer is not catalog-backed. |
-| Directionality assumptions | Rows remain left-to-right diagnostic facts. |
-| Validation command | Focused drawer specs assert text rows. |
-
-## Agent Inspectability / Explainability Posture
-
-Agents can inspect `GraftInfo.edictCoreProjection` and
-`GraftInfo.echoTargetIrProjection` directly through the port type, or inspect
-the rendered drawer rows in focused specs. The lanes expose carried digest and
-domain facts without requiring agents to parse opaque receipt JSON.
-
-## Linked Invariants
-
-- Tests are executable spec.
-- Runtime truth beats compile-time theater.
-- Encoding and decoding happen at the adapter boundary.
-- Graft routes projection authority; jedit displays projection facts.
-- Echo authority remains outside jedit product nouns.
-- No `any`, no `unknown`, no TypeScript file over 500 LOC.
-
-## Design Alternatives Considered
-
-### Option A: Keep Saved-File Projection Only
-
-Pros:
-
-- Minimal jedit code change.
-- Existing outline/diff behavior stays untouched.
-
-Cons:
-
-- Dirty `.edict` buffers still project stale saved-file content.
-- The editor cannot support the source-to-Core-to-Target-IR authoring loop.
-
-### Option B: Let jedit Interpret Edict JSONL Directly
-
-Pros:
-
-- Avoids another Graft adapter call.
-
-Cons:
-
-- Violates the Graft projection-broker boundary.
-- Makes jedit depend on Edict internals instead of the Graft projection facade.
-
-### Option C: Consume Graft 0.11.1 Projection Lanes
-
-Pros:
-
-- Keeps Graft as projection broker and Edict as compiler authority.
-- Lets dirty editor text remain source of truth.
-- Preserves jedit as display/composition layer.
-
-Cons:
-
-- Requires package upgrade and adapter decoding work.
-
-## Decision
-
-Choose Option C. jedit will consume the published Graft 0.11.1 package and
-decode only the projection facts needed for display. The decision expires when
-a future jedit cycle introduces a richer generic projection-lane panel; this
-cycle should not build that larger UI.
-
-## Implementation Slices
-
-- [x] Slice 1: Add design packet and issue linkage.
-- [x] Slice 2: Bump Graft dependency to 0.11.1 and add adapter RED tests for
-      dirty `.edict` projection input and decoded Core/Target IR lanes.
-- [x] Slice 3: Implement adapter decoding and live buffer request plumbing.
-- [x] Slice 4: Add drawer RED tests for Core/Target IR rows.
-- [x] Slice 5: Implement bounded drawer rendering and row accounting.
-- [x] Slice 6: Update docs/changelog, fill retrospective, validate, and open PR.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [x] `spec/graft-api-session.spec.mjs` proves dirty `.edict` content is passed
-      to the Graft/Edict projection surface.
-- [x] `spec/graft-api-session.spec.mjs` proves Core and Target IR lanes decode
-      into `GraftInfo`.
-- [x] `spec/workspace-graft-refresh.spec.mjs` proves live editor lines are
-      passed into Graft requests.
-- [x] `spec/graft-drawer.spec.mjs` proves Core and Target IR rows render.
-- [x] `spec/graft-drawer.spec.mjs` proves rows stay bounded and receipt display
-      remains opaque.
-
-Documentation and process tests:
-
-- [x] Existing quality and design-cycle checks remain green.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [x] jedit depends on `@flyingrobots/graft` 0.11.1.
-- [x] Dirty `.edict` buffers use live editor content for projection requests.
-- [x] Core projection state and digest render in the drawer when available.
-- [x] Echo Target IR state, domain, and digest render in the drawer when
-      available.
-- [x] Existing obstruction receipt rows still render without receipt digests.
-- [x] Existing non-Edict outline/diff behavior remains unchanged.
-- [x] Issue #256 and the PR are linked correctly.
-- [x] Local validation is green.
-
-## Validation Plan
-
-Commands expected before PR:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-api-session.spec.mjs spec/workspace-graft-refresh.spec.mjs spec/graft-drawer.spec.mjs
-npm run quality
-npm run check
-```
-
-## Playback / Witness
-
-Reviewers can inspect the focused specs and run:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-api-session.spec.mjs spec/workspace-graft-refresh.spec.mjs spec/graft-drawer.spec.mjs
-```
-
-The drawer rows provide the witness surface.
-
-## Risks
-
-Known risks:
-
-- Graft 0.11.1 projection bundle shape may be broader than this display slice
-  needs.
-- Rendering full review JSON could flood the drawer.
-- Dirty buffer projection could regress existing saved-file outline behavior.
-
-Mitigations:
-
-- Decode only bounded state, digest, domain, and summary facts.
-- Keep review JSON opaque and off the drawer in this cycle.
-- Preserve existing saved-file outline/diff tests and route only `.edict` live
-  buffer requests to the Edict projection path.
-
-## Follow-On Debt
-
-Known deferrals in this cycle:
-
-- generic projection-lane panel:
-  https://github.com/flyingrobots/jedit/issues/258
-- full Core/Target IR review JSON viewer:
-  https://github.com/flyingrobots/jedit/issues/259
-- Echo run button from jedit:
-  https://github.com/flyingrobots/jedit/issues/257
-- canonical Echo receipt digest display:
-  https://github.com/flyingrobots/jedit/issues/260
-
-## Retrospective
-
-What changed from the design:
-
-- The implementation kept the display-only scope but intentionally did not map
-  Graft/Edict `echoReceipt` slots through the live `.edict` projection helper.
-  Existing obstruction receipt display remains on the already validated
-  `file_outline` adapter path until jedit owns a JSON decoder for that slot
-  shape without accepting `unknown` payloads.
-- The adapter uses a local process-runner boundary because Graft exports the
-  Edict provider factory but not its Node process runner.
-- The adapter now passes only the published target selection facts to Graft:
-  target coordinate, target profile digest, and Target IR domain. It does not
-  carry Edict compiler context, operation profile mappings, budgets, effect
-  lowerings, or obstruction coordinates.
-
-What the tests proved:
-
-- `spec/workspace-graft-refresh.spec.mjs` proves refresh commands pass current
-  editor lines as `sourceText`.
-- `spec/graft-api-session.spec.mjs` proves dirty `.edict` source text reaches
-  the Graft/Edict projection surface and Core/Target IR slots normalize into
-  `GraftInfo`. It also proves jedit does not pass compiler context or Echo
-  lowering semantics into the provider.
-- `spec/graft-drawer.spec.mjs` proves the drawer renders Core and Echo Target
-  IR rows, keeps receipt display opaque, and does not claim execution or
-  admission.
-
-What remains open:
-
-- Generic projection-lane panel: https://github.com/flyingrobots/jedit/issues/258
-- Full Core/Target IR review JSON viewer:
-  https://github.com/flyingrobots/jedit/issues/259
-- jedit Echo run button: https://github.com/flyingrobots/jedit/issues/257
-- Canonical Echo receipt digest display:
-  https://github.com/flyingrobots/jedit/issues/260
-
-PR:
-
-- https://github.com/flyingrobots/jedit/pull/262
diff --git a/docs/design/0152-generic-projection-lane-panel.md b/docs/design/0152-generic-projection-lane-panel.md
deleted file mode 100644
index aa06d3b5..00000000
--- a/docs/design/0152-generic-projection-lane-panel.md
+++ /dev/null
@@ -1,465 +0,0 @@
----
-title: "WF-0152 - Generic Projection-Lane Panel"
-legend: "WF"
-lane: "implementation"
-issue: "https://github.com/flyingrobots/jedit/issues/258"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-07-06"
-updated: "2026-07-06"
----
-
-# WF-0152 - Generic Projection-Lane Panel
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/258
-
-## Decision Summary
-
-jedit will add a jedit-owned generic `projectionLanes` display field and route
-the existing Edict Core and Echo Target IR facts through it. The cycle keeps the
-current Edict-specific fields for compatibility, but makes the display shell
-provider-neutral enough for future Graft-backed language lanes without making
-jedit an Edict debugger, REPL, Echo runner, or semantic authority.
-
-## Sponsored Human
-
-A Jim user wants compiler and projection facts to appear in a consistent drawer
-shape so that Core, Target IR, and future language projections can be compared
-without learning a different mini-UI for every provider.
-
-## Sponsored Agent
-
-An agent needs a stable projection-lane display contract so it can inspect
-state, digest, metadata, and bounded summary rows without scraping
-provider-specific prose or inferring Edict, Echo, Wesley, or Colorful semantics.
-
-## Hill
-
-By the end of this cycle, the Graft drawer renders Edict Core and Echo Target IR
-through a generic projection-lane panel helper, focused specs prove the rendered
-rows and row accounting are unchanged for the current Edict surface, and the
-implementation carries no execution, debugger, REPL, or host-eligibility claim.
-
-## Current Truth
-
-On `origin/main` at
-`3a2d576020542f07ba903b2694cf587df521595d`, `GraftInfo` carries two
-projection-specific fields, `edictCoreProjection` and
-`echoTargetIrProjection`:
-[`src/ports/graft-session.ts#L36:3a2d576020542f07ba903b2694cf587df521595d`](https://github.com/flyingrobots/jedit/blob/3a2d576020542f07ba903b2694cf587df521595d/src/ports/graft-session.ts#L36).
-
-The drawer surface renders those fields through dedicated Edict Core and Echo
-Target IR helpers:
-[`src/ui/graft-drawer.ts#L121:3a2d576020542f07ba903b2694cf587df521595d`](https://github.com/flyingrobots/jedit/blob/3a2d576020542f07ba903b2694cf587df521595d/src/ui/graft-drawer.ts#L121).
-
-The workspace drawer row accounting duplicates that provider-specific split:
-[`src/app/workspace/graft-drawer.ts#L115:3a2d576020542f07ba903b2694cf587df521595d`](https://github.com/flyingrobots/jedit/blob/3a2d576020542f07ba903b2694cf587df521595d/src/app/workspace/graft-drawer.ts#L115).
-
-WF-0151 explicitly deferred the generic projection-lane panel to issue #258:
-[`docs/design/0151-edict-projection-lens.md#L350:3a2d576020542f07ba903b2694cf587df521595d`](https://github.com/flyingrobots/jedit/blob/3a2d576020542f07ba903b2694cf587df521595d/docs/design/0151-edict-projection-lens.md#L350).
-
-Focused drawer specs already prove the current Edict rows and non-execution
-claims:
-[`spec/graft-drawer.spec.mjs#L106:3a2d576020542f07ba903b2694cf587df521595d`](https://github.com/flyingrobots/jedit/blob/3a2d576020542f07ba903b2694cf587df521595d/spec/graft-drawer.spec.mjs#L106).
-
-## Problem
-
-The drawer currently has a provider-specific row helper for Edict Core and
-another for Echo Target IR. That works for the first Edict slice, but it makes
-the next provider harder to add because every projection lane needs bespoke
-rendering and row-count code before the UI can show state, digests, metadata,
-and summaries. The duplication also keeps the display abstraction too close to
-Edict even though jedit only owns projection display.
-
-## Scope
-
-This cycle includes:
-
-- adding a generic projection-lane display model to jedit's Graft session
-  boundary;
-- rendering Edict Core and Echo Target IR by adapting their existing facts into
-  that display model;
-- replacing duplicated row-count helpers with generic projection-lane row
-  accounting;
-- preserving current drawer row order, bounded summaries, receipt display,
-  outline navigation, and dirty-buffer posture;
-- documenting that this is projection inspection only.
-
-## Non-Goals
-
-This cycle does not include:
-
-- Edict execution from jedit;
-- an Edict debugger view;
-- an Edict REPL;
-- Echo execution, admission, or runtime host selection;
-- host compatibility or eligibility checks;
-- generic Target IR execution;
-- Wesley, Colorful, or other new provider integration;
-- full Core or Target IR review JSON viewing;
-- canonical Echo receipt bytes or receipt digests;
-- jedit-side Edict, Echo, Wesley, or Colorful semantic interpretation.
-
-## User Experience / Product Shape
-
-The visible drawer stays familiar. A `.edict` buffer still shows `edict core`
-and `echo target ir`, but those sections are produced through one projection
-lane renderer. Future providers can reuse the same section shape without
-copying Edict-specific row code.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[User opens Graft drawer] --> Projection[Drawer reads projection lanes]
-  Projection --> Rows[Drawer renders state, digest, metadata, summaries]
-  Rows --> Outline[Outline and changes remain below projection facts]
-  Projection --> Missing[Missing lanes are omitted]
-  Missing --> Outline
-```
-
-### Wide UI Mockup
-
-Terminal: 120 columns, default theme.
-
-```text
-graft
-demo.edict
-source: live-buffer
-posture: current
-
-edict core
-state: available
-core digest: sha256:2222222222222222222222222222222222222222222222222222222222222222
-review: apiVersion
-
-echo target ir
-state: available
-domain: echo.span-ir/v1
-target: echo.dpo@1
-target profile: sha256:1111111111111111111111111111111111111111111111111111111111111111
-target ir digest: sha256:3333333333333333333333333333333333333333333333333333333333333333
-review: intents
-
-outline
-structural outline unavailable
-```
-
-### Narrow UI Mockup
-
-Terminal: 50 columns, default theme.
-
-```text
-graft
-demo.edict
-source: live-buffer
-posture: current
-
-edict core
-state: available
-core digest: sha256:222222222222222222222222...
-review: apiVersion
-```
-
-Long values continue to fit through the existing drawer line-fitting path.
-
-### Accessibility Considerations
-
-Projection lanes remain plain text. State, digest, metadata keys, and summary
-rows do not rely on color, layout-only icons, or hidden UI state.
-
-## Runtime / API Contract
-
-This cycle adds a jedit-owned display contract to `GraftInfo`, not a new
-runtime API:
-
-```ts
-interface GraftProjectionPanelLane {
-  readonly title: string;
-  readonly state: GraftProjectionSlotState;
-  readonly digest?: {
-    readonly label: string;
-    readonly value: string;
-  };
-  readonly metadata: readonly {
-    readonly label: string;
-    readonly value: string;
-  }[];
-  readonly summaryLines: readonly string[];
-}
-```
-
-The existing `GraftInfo.edictCoreProjection` and
-`GraftInfo.echoTargetIrProjection` fields remain the source facts for this
-cycle. `projectionLanes` carries their display shape:
-
-```ts
-interface GraftInfo {
-  readonly projectionLanes?: readonly GraftProjectionPanelLane[];
-}
-```
-
-The adapter derives `projectionLanes` from already decoded provider facts. It
-does not compute projection facts, validate language semantics, execute Echo, or
-admit artifacts.
-
-## Lower Modes
-
-The lower mode is the existing text drawer output. Focused specs assert rendered
-lines directly. No JSON, CLI, or pipe output changes in this cycle.
-
-If projection lanes are unavailable, the drawer continues to omit them and show
-outline/change sections as it does now.
-
-## Data / State Model
-
-| Category | Description |
-| --- | --- |
-| Source of truth | Existing `GraftInfo` projection lane fields from the Graft session port. |
-| Derived state | `GraftInfo.projectionLanes` rows for rendering and row accounting. |
-| Invalid states | jedit deriving projection facts, interpreting provider semantics, showing execution/debugger/REPL controls, or treating projection availability as runtime availability. |
-| Reset behavior | Same as WF-0151: lanes disappear when new `GraftInfo` lacks them or the active file changes. |
-| Serialization | No persistence or wire format. |
-| Deterministic assumptions | Lane ordering is fixed; metadata row order is adapter-defined; summary rows preserve provider order and remain bounded by existing drawer fitting. |
-
-## Accessibility Posture
-
-| Concern | Posture |
-| --- | --- |
-| Semantic labels or facts | Lane title, state, digest, metadata labels, and summaries are visible text. |
-| Focus order or ownership | Existing Graft drawer navigation remains unchanged. |
-| Hidden or visual-only information | None; no new icon-only controls or color-only states. |
-| Keyboard behavior | Existing refresh and outline navigation keys remain unchanged. |
-| Secret or redaction behavior | No new secret material is introduced. |
-
-## Localization / Directionality Posture
-
-| Concern | Posture |
-| --- | --- |
-| User-visible strings | Existing English drawer labels remain English-only like adjacent Graft rows. |
-| Catalog keys | No catalog update in this cycle. |
-| Supported locales updated | Not applicable. |
-| Directionality assumptions | Rows remain left-to-right diagnostic facts. |
-| Validation command | Focused drawer specs assert text rows. |
-
-## Agent Inspectability / Explainability Posture
-
-Agents can inspect the existing `GraftInfo` fields or focused drawer specs. The
-new helper gives maintainers one stable row-shape contract for projection
-inspection without requiring agents to distinguish Edict-specific rendering
-helpers.
-
-## Linked Invariants
-
-- Tests are executable spec.
-- Runtime truth beats compile-time theater.
-- Graft routes projection authority; jedit displays projection facts.
-- Echo authority remains outside jedit product nouns.
-- Projection availability is not execution availability.
-- Editors are mirrors, not judges.
-- No `any`, no `unknown`, no TypeScript file over 500 LOC.
-
-## Design Alternatives Considered
-
-### Option A: Keep Edict-Specific Rendering
-
-Pros:
-
-- No new abstraction.
-- Current tests already pass.
-
-Cons:
-
-- Next provider repeats rendering and row-count logic.
-- The drawer remains shaped around Edict instead of projection display.
-
-### Option B: Convert `GraftInfo` To Arbitrary Provider Payloads
-
-Pros:
-
-- Moves closer to a fully generic projection model.
-
-Cons:
-
-- Too large for this slice.
-- Risks changing the Graft session port before a second provider proves the
-  shape.
-- Could weaken the already tested Edict projection contract.
-
-### Option C: Add A Generic Drawer Panel Adapter
-
-Pros:
-
-- Removes display duplication while preserving the current port contract.
-- Keeps the slice local to drawer rendering and row accounting.
-- Builds the seam needed by future providers without claiming provider
-  semantics.
-
-Cons:
-
-- Still requires explicit adapters from current `GraftInfo` fields.
-- Does not solve full review JSON browsing.
-
-## Decision
-
-Choose Option C. jedit will introduce a generic drawer-panel display model and
-adapt the existing Edict Core and Echo Target IR fields into it. The decision
-expires when Graft and jedit land a broader multi-provider projection payload
-contract.
-
-## Implementation Slices
-
-- [x] Slice 1: Add design packet and issue linkage.
-- [x] Slice 2: Add RED drawer spec proving Edict Core and Echo Target IR render
-      through a generic projection-lane fixture with current non-execution
-      assertions intact.
-- [x] Slice 3: Implement generic projection-lane rendering in
-      `src/ui/graft-drawer.ts`.
-- [x] Slice 4: Add focused workspace row-accounting coverage for generic lane metadata
-      and summary rows.
-- [x] Slice 5: Implement generic row accounting in
-      `src/app/workspace/graft-drawer.ts`.
-- [x] Slice 6: Update docs/changelog, fill retrospective, validate, and open
-      PR.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [x] `spec/graft-drawer.spec.mjs` proves projection lanes keep the current
-      visible Edict Core and Echo Target IR rows.
-- [x] `spec/graft-drawer.spec.mjs` proves projection lane display still avoids
-      execution, admission, debugger, and REPL wording.
-- [x] `spec/graft-drawer.spec.mjs` proves generic lane metadata remains bounded
-      and ordered.
-- [x] `spec/graft-drawer.spec.mjs` proves
-      page movement accounts for generic projection-lane rows.
-
-Documentation and process tests:
-
-- [x] Existing design-cycle checks remain green.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [x] `GraftInfo.projectionLanes` can render a provider-neutral projection
-      section.
-- [x] Edict Core and Echo Target IR rows are rendered through generic
-      projection lanes.
-- [x] Workspace row accounting uses the same generic lane model.
-- [x] Existing obstruction receipt, outline, changes, and dirty projection
-      behavior remain unchanged.
-- [x] Drawer output contains no execution, admission, debugger, or REPL claim.
-- [x] Issue #258 and the PR are linked correctly.
-- [x] Local validation is green.
-
-## Validation Plan
-
-Commands expected before PR:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-drawer.spec.mjs
-npm run quality
-npx markdownlint-cli2 CHANGELOG.md docs/BEARING.md docs/design/0152-generic-projection-lane-panel.md
-node --test --test-concurrency=1 spec/design-cycle-policy.spec.mjs
-git diff --check
-npm run check
-```
-
-## Playback / Witness
-
-Reviewers can inspect the focused drawer specs and run:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-drawer.spec.mjs
-```
-
-The witness is the rendered Graft drawer text rows.
-
-## Risks
-
-Known risks:
-
-- A generic helper could hide important provider-specific labels.
-- Row-count logic could drift from rendered rows and break page movement.
-- The wording could imply runtime capability if "Run", "Debug", or "REPL"
-  language appears near projection facts.
-
-Mitigations:
-
-- Keep provider adapters responsible for labels.
-- Add focused row-accounting coverage.
-- Assert forbidden runtime/debugger words are absent from projection drawer
-  output.
-
-## Follow-On Debt
-
-Known deferrals in this cycle:
-
-- full Core/Target IR review JSON viewer:
-  https://github.com/flyingrobots/jedit/issues/259
-- Echo run button from jedit:
-  https://github.com/flyingrobots/jedit/issues/257
-- canonical Echo receipt digest display:
-  https://github.com/flyingrobots/jedit/issues/260
-
-No new follow-on issue is required for debugger or REPL work in this cycle
-because this cycle explicitly rejects that scope rather than deferring part of
-its implementation.
-
-## Retrospective
-
-What changed from the design:
-
-- The implementation added `GraftInfo.projectionLanes` as the generic display
-  shape and retained `edictCoreProjection` plus `echoTargetIrProjection` as
-  compatibility/source facts for the current Edict projection adapter.
-- The row-accounting coverage landed as a compact extension to the existing
-  PageDown drawer spec after the generic renderer RED/GREEN, rather than as a
-  separate test file, to keep the touched specs under the 500-line ratchet.
-
-What the tests proved:
-
-- `spec/graft-drawer.spec.mjs` first failed because `projectionLanes` were
-  ignored, then passed after the generic renderer showed provider-neutral
-  title, state, digest, metadata, and summary rows.
-- `spec/graft-api-session.spec.mjs` proves the live Edict adapter now carries
-  generic `projectionLanes` alongside the existing Edict-specific fields.
-- `spec/graft-drawer.spec.mjs` proves PageDown accounting includes generic lane
-  metadata and summary rows.
-- The drawer output still excludes runtime, debugger, REPL, execution, and
-  admission wording for projection lanes.
-
-Validation completed:
-
-- RED:
-  `npm run build && JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-drawer.spec.mjs`
-  failed because the drawer ignored generic `projectionLanes`.
-- GREEN:
-  `npm run build && JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-api-session.spec.mjs spec/graft-drawer.spec.mjs`
-- GREEN: `npm run quality`
-- GREEN:
-  `npx markdownlint-cli2 CHANGELOG.md docs/BEARING.md docs/design/0152-generic-projection-lane-panel.md`
-- GREEN: `node --test --test-concurrency=1 spec/design-cycle-policy.spec.mjs`
-- GREEN: `git diff --check`
-- GREEN: `npm run check`
-
-What remains open:
-
-- Full Core/Target IR review JSON viewer:
-  https://github.com/flyingrobots/jedit/issues/259
-- Any Echo execution UX belongs in a separate explicitly scoped design, not
-  this projection panel:
-  https://github.com/flyingrobots/jedit/issues/257
-- Canonical Echo receipt digest display:
-  https://github.com/flyingrobots/jedit/issues/260
-
-PR:
-
-- https://github.com/flyingrobots/jedit/pull/263
diff --git a/docs/design/0153-generic-projection-review-payload-viewer.md b/docs/design/0153-generic-projection-review-payload-viewer.md
deleted file mode 100644
index 0615f7a7..00000000
--- a/docs/design/0153-generic-projection-review-payload-viewer.md
+++ /dev/null
@@ -1,458 +0,0 @@
----
-title: "WF-0153 - Generic Projection Review Payload Viewer"
-legend: "WF"
-lane: "implementation"
-issue: "https://github.com/flyingrobots/jedit/issues/259"
-status: "active"
-owners:
-  - "@flyingrobots"
-created: "2026-07-06"
-updated: "2026-07-06"
----
-
-# WF-0153 - Generic Projection Review Payload Viewer
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/259
-
-## Decision Summary
-
-jedit will let generic Graft projection lanes carry provider-owned review
-payloads and render those payloads through an expandable, bounded, display-only
-viewer in the Graft drawer. Edict Core and Echo Target IR review payloads are
-the first concrete payloads, but the viewer is provider-neutral.
-
-## Sponsored Human
-
-A Jim user wants to inspect the details behind compact projection lanes so that
-they can see the Core or Target IR review payload produced upstream, without
-leaving jedit or pretending jedit understands provider semantics.
-
-## Sponsored Agent
-
-An agent needs a bounded structured payload display surface so it can inspect
-projection evidence and row accounting, without scraping provider-specific prose
-or inferring Edict, Echo, Wesley, or Colorful meaning.
-
-## Hill
-
-By the end of this cycle, a projection lane can expose an optional review
-payload, the Graft drawer can expand that payload as bounded structured text,
-and focused specs prove row accounting, truncation, and non-execution wording.
-
-## Current Truth
-
-On `origin/main` at
-`6363afeb20854811f4617d029fdfbf41564458da`, `GraftProjectionPanelLane`
-contains title, state, digest, metadata, and summary rows, but no review payload:
-[`src/ports/graft-session.ts#L67:6363afeb20854811f4617d029fdfbf41564458da`](https://github.com/flyingrobots/jedit/blob/6363afeb20854811f4617d029fdfbf41564458da/src/ports/graft-session.ts#L67).
-
-The generic lane adapter can synthesize Edict Core and Echo Target IR projection
-lanes, but it only forwards compact row data:
-[`src/ports/graft-projection-lanes.ts#L26:6363afeb20854811f4617d029fdfbf41564458da`](https://github.com/flyingrobots/jedit/blob/6363afeb20854811f4617d029fdfbf41564458da/src/ports/graft-projection-lanes.ts#L26).
-
-The drawer renders each projection lane as title, state, digest, metadata, and
-summary lines:
-[`src/ui/graft-drawer.ts#L128:6363afeb20854811f4617d029fdfbf41564458da`](https://github.com/flyingrobots/jedit/blob/6363afeb20854811f4617d029fdfbf41564458da/src/ui/graft-drawer.ts#L128).
-
-Issue #259 now tracks the generic projection review payload viewer:
-https://github.com/flyingrobots/jedit/issues/259
-
-## Problem
-
-Projection lanes currently prove that upstream projection artifacts exist, but
-they only show compact summaries such as `review: apiVersion`. A user cannot
-inspect the provider-owned review payload from inside jedit. Adding an Edict-
-specific JSON panel would solve the first example but would repeat the exact
-provider-shaped drawer problem WF-0152 removed.
-
-## Scope
-
-This cycle includes:
-
-- adding an optional provider-neutral review payload field to projection lanes;
-- carrying Edict Core and Echo Target IR review payloads into that field;
-- rendering review payloads as bounded structured text in the Graft drawer;
-- exposing collapsed and expanded lane states through jedit-owned UI state;
-- updating drawer row accounting for expanded review payloads;
-- documenting that this is projection inspection only.
-
-## Non-Goals
-
-This cycle does not include:
-
-- Edict execution;
-- Echo execution;
-- an Edict debugger;
-- an Edict REPL;
-- Core validation in jedit;
-- Target IR lowering in jedit;
-- receipt digest computation;
-- runtime host selection;
-- runtime compatibility checks;
-- provider-specific schema-aware formatting;
-- jedit-owned interpretation of Core, Target IR, Wesley, Colorful, or Echo
-  payload semantics.
-
-## User Experience / Product Shape
-
-The Graft drawer keeps compact projection lanes by default. Pressing `Space`
-while the Graft drawer is focused cycles through projection lanes that expose a
-provider-owned review payload, and pressing `Space` after the last payload lane
-collapses the expanded payload. The expanded rows are plain text, capped, and
-explicitly truncated when the payload is too large for the viewer budget.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Start[User opens Graft drawer] --> Compact[Projection lanes render compact rows]
-  Compact --> Expand[User presses Space to expand next payload lane]
-  Expand --> Payload[Drawer shows bounded review payload]
-  Payload --> Collapse[User presses Space past the last payload lane]
-  Collapse --> Compact
-```
-
-### Wide UI Mockup
-
-Terminal: 120 columns, default theme.
-
-```text
-graft
-demo.edict
-source: live-buffer
-posture: current
-
-edict core
-state: available
-core digest: sha256:2222222222222222222222222222222222222222222222222222222222222222
-review: apiVersion
-review payload:
-  {
-    "apiVersion": "edict.core/v1",
-    "module": {
-      "name": "demo.echo"
-    },
-    "intents": [
-      {
-        "name": "replaceThing"
-      }
-    ]
-  }
-
-outline
-structural outline unavailable
-```
-
-### Narrow UI Mockup
-
-Terminal: 50 columns, default theme.
-
-```text
-edict core
-state: available
-core digest: sha256:222222222222222222222222...
-review: apiVersion
-review payload:
-  {
-    "apiVersion": "edict.core/v1",
-    "module": {
-      "name": "demo.echo"
-```
-
-Long rows continue through the drawer line-fitting path.
-
-### Accessibility Considerations
-
-The expanded payload is visible text. The presence of a payload, truncation
-state, and scalar values do not rely on color, hidden controls, or icon-only
-state.
-
-## Runtime / API Contract
-
-This cycle adds a display field to the existing jedit projection lane contract:
-
-```ts
-interface GraftProjectionPanelLane {
-  readonly reviewPayload?: GraftJsonObject;
-}
-```
-
-Expansion is jedit-owned drawer state. Providers supply payload data; jedit
-decides which lane is currently expanded in the drawer. The rendering contract
-is intentionally generic:
-
-- JSON object keys render deterministically.
-- arrays render in order.
-- strings are JSON-escaped and length-capped.
-- arrays, objects, depth, row count, and object-key scan work are bounded.
-- truncation is explicit.
-
-jedit displays provider-owned review payloads. jedit does not interpret,
-validate, lower, execute, canonicalize, or assign semantic meaning to those
-payloads.
-
-## Lower Modes
-
-Focused specs assert rendered text rows directly. No CLI, JSON pipe, or external
-protocol changes are introduced in this cycle.
-
-When a payload is absent, compact projection lane rendering stays unchanged.
-When a payload is present but collapsed, the compact lane still shows only the
-existing title, state, digest, metadata, and summary rows.
-
-## Data / State Model
-
-| Category | Description |
-| --- | --- |
-| Source of truth | Provider-owned review payloads already decoded by the Graft projection adapter. |
-| Derived state | Bounded drawer rows generated from `reviewPayload`. |
-| Invalid states | jedit validating provider semantics, computing digests, executing artifacts, or treating expansion as runtime availability. |
-| Reset behavior | Expanded lane state is jedit-owned UI state and resets when the file changes or refreshed projection lanes no longer have a payload at the expanded index. |
-| Serialization | No persistence or wire format. |
-| Deterministic assumptions | Object key rendering uses a bounded key scan and sorts the visible bounded key set; arrays preserve provider order; truncation is stable. |
-
-## Accessibility Posture
-
-| Concern | Posture |
-| --- | --- |
-| Semantic labels or facts | Lane title, digest labels, metadata, summaries, payload rows, and truncation notices are visible text. |
-| Focus order or ownership | Existing Graft drawer focus remains unchanged. |
-| Hidden or visual-only information | None; no new icon-only controls. |
-| Keyboard behavior | Existing drawer navigation remains; space cycles expanded review payload lanes. |
-| Secret or redaction behavior | No new secret material is introduced. Payloads are upstream projection facts. |
-
-## Localization / Directionality Posture
-
-| Concern | Posture |
-| --- | --- |
-| User-visible strings | New English diagnostic labels match adjacent drawer rows. |
-| Catalog keys | No catalog update in this cycle. |
-| Supported locales updated | Not applicable. |
-| Directionality assumptions | Payload inspection rows remain left-to-right structured facts. |
-| Validation command | Focused drawer specs assert the visible rows. |
-
-## Agent Inspectability / Explainability Posture
-
-Agents can inspect `GraftInfo.projectionLanes[].reviewPayload` and focused
-drawer specs. The viewer produces stable text rows rather than provider-specific
-UI state.
-
-## Linked Invariants
-
-- Tests are executable spec.
-- Runtime truth beats compile-time theater.
-- Graft routes projection authority; jedit displays projection facts.
-- jedit displays provider-owned review payloads without interpreting them.
-- Projection availability is not execution availability.
-- Editors are mirrors, not judges.
-- No `any`, no `unknown`, no TypeScript file over 500 LOC.
-
-## Design Alternatives Considered
-
-### Option A: Edict-Specific Core And Target IR JSON Panels
-
-Pros:
-
-- Fast path for the first payloads.
-
-Cons:
-
-- Reintroduces provider-specific drawer paths.
-- Delays Wesley or Colorful reuse.
-- Makes the panel look like jedit understands Edict/Echo semantics.
-
-### Option B: Generic Structured Payload Viewer
-
-Pros:
-
-- Reuses the projection-lane model.
-- Fits future providers.
-- Keeps semantics provider-owned.
-
-Cons:
-
-- Cannot provide schema-specific formatting.
-- Requires bounded rendering and row accounting.
-
-## Decision
-
-Choose Option B. The first implementation will render provider-owned JSON-like
-payloads generically and use Edict Core plus Echo Target IR as fixtures.
-
-## Implementation Slices
-
-- [x] Slice 1: Reframe issue #259 and add this design packet.
-- [x] Slice 2: Add RED drawer/API tests for collapsed and expanded review
-      payloads.
-- [x] Slice 3: Add generic review payload fields and carry Edict/Echo review
-      payloads through the projection lane adapter.
-- [x] Slice 4: Add bounded payload rendering and row accounting.
-- [x] Slice 5: Update docs/changelog, fill retrospective, validate, and open
-      PR.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [x] `spec/graft-review-payload-viewer.spec.mjs` proves collapsed lanes do not show review
-      payload rows.
-- [x] `spec/graft-review-payload-viewer.spec.mjs` proves an expanded generic lane renders a
-      structured review payload.
-- [x] `spec/graft-review-payload-viewer.spec.mjs` proves large payloads truncate explicitly.
-- [x] `spec/graft-review-payload-viewer.spec.mjs` proves collection entries are capped explicitly.
-- [x] `spec/graft-review-payload-viewer.spec.mjs` proves nested object payload
-      depth is capped explicitly.
-- [x] `spec/graft-review-payload-viewer.spec.mjs` proves object-key scan work is
-      bounded.
-- [x] `spec/graft-review-payload-viewer.spec.mjs` proves stale expanded lane
-      state toggles like collapsed state.
-- [x] `spec/workspace-graft-refresh.spec.mjs` proves file and lane refreshes
-      clear stale expanded lane state.
-- [x] `spec/graft-review-payload-viewer.spec.mjs` proves PageDown accounting includes expanded
-      payload rows.
-- [x] `spec/graft-review-payload-api-session.spec.mjs` proves Edict Core and Echo Target IR
-      lanes carry review payloads from upstream projection results.
-- [x] `spec/graft-review-payload-api-session.spec.mjs` proves jedit does not
-      JSON-clone provider review payloads.
-- [x] `spec/graft-review-payload-viewer.spec.mjs` proves runtime, admission, debugger, and REPL
-      wording stays absent.
-
-Documentation and process tests:
-
-- [x] Existing design-cycle checks remain green.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [x] Projection lanes may expose an optional review payload.
-- [x] jedit can render collapsed compact lanes without payload rows.
-- [x] jedit can render expanded generic review payload rows.
-- [x] Payload rendering is bounded by depth, row count, array/object entries,
-      object-key scan work, and scalar length.
-- [x] Truncation is explicit.
-- [x] Row accounting remains correct for expanded payloads.
-- [x] Expanded payload state clears when a file changes or refreshed lanes no
-      longer support the current expanded index.
-- [x] Edict Core review payloads display through the generic viewer.
-- [x] Echo Target IR review payloads display through the generic viewer.
-- [x] Drawer output contains no execution, admission, debugger, or REPL claim.
-- [x] Issue #259 and the PR are linked correctly.
-- [x] Local validation is green.
-
-## Validation Plan
-
-Commands expected before PR:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-api-session.spec.mjs spec/graft-drawer.spec.mjs
-npm run quality
-npx markdownlint-cli2 CHANGELOG.md docs/BEARING.md docs/design/0153-generic-projection-review-payload-viewer.md
-node --test --test-concurrency=1 spec/design-cycle-policy.spec.mjs
-git diff --check
-npm run check
-```
-
-## Playback / Witness
-
-Reviewers can inspect the focused drawer specs and run:
-
-```bash
-npm run build
-JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-drawer.spec.mjs
-```
-
-The witness is the rendered Graft drawer text rows.
-
-## Risks
-
-Known risks:
-
-- Pretty-printing could become schema interpretation.
-- Large payloads could crowd out outline navigation.
-- Row-count logic could drift from rendered rows.
-
-Mitigations:
-
-- Keep the renderer generic.
-- Cap row count, depth, entries, and scalar length.
-- Assert row accounting in focused tests.
-
-## Follow-On Debt
-
-Known deferrals in this cycle:
-
-- profile-aware Wesley SDL projection belongs in Graft first:
-  https://github.com/flyingrobots/graft/issues/226
-- jedit Wesley projection consumption follows the Graft provider work:
-  https://github.com/flyingrobots/jedit/issues/266
-- canonical Echo receipt digest display waits for Echo-side canonical receipt
-  bytes and digests:
-  https://github.com/flyingrobots/jedit/issues/260
-
-## Retrospective
-
-What changed from the design:
-
-- The implementation kept the viewer generic by adding `reviewPayload` to
-  projection panel lanes rather than adding Edict- or Echo-specific drawer
-  branches.
-- Edict Core and Echo Target IR review objects are carried through as
-  provider-owned `GraftJsonObject` payloads instead of JSON-cloning the full
-  provider tree.
-- Expanded payload state is jedit-owned drawer state; providers only supply the
-  payload.
-- The renderer caps total rows, depth, collection entries, object-key scan work,
-  and scalar length.
-- Self-review tightened the interaction path so the Graft drawer `space` key
-  cycles expanded review payload lanes, and root object entries now use the same
-  entry cap as nested objects.
-- Follow-up review tightened stale expansion reset, nested object depth caps,
-  bounded object-key scanning, provider payload pass-through, and issue-backed
-  follow-on debt.
-
-What the tests proved:
-
-- RED:
-  `npm run build && JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-review-payload-api-session.spec.mjs spec/graft-review-payload-viewer.spec.mjs`
-  failed because lanes did not carry review payloads and the drawer ignored
-  expanded payload state.
-- GREEN:
-  `npm run build && JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-review-payload-api-session.spec.mjs spec/graft-review-payload-viewer.spec.mjs spec/graft-api-session.spec.mjs spec/graft-drawer.spec.mjs`
-- GREEN: `npm run quality`
-- GREEN: `npm run check`
-  passed with 1170 passing, 13 skipped, and quality regressions none.
-- GREEN: `git diff --check`
-- REVIEW RED:
-  `npm run build && JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-review-payload-viewer.spec.mjs`
-  failed because root object entries were not capped and no key path toggled
-  review payload visibility.
-- REVIEW RED:
-  `npm run build && JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-review-payload-viewer.spec.mjs spec/workspace-graft-refresh.spec.mjs`
-  failed because nested object depth, object-key scan work, stale expansion
-  toggle state, and cross-file expansion reset were not yet enforced.
-- REVIEW GREEN:
-  `npm run build && JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-review-payload-viewer.spec.mjs`
-- REVIEW GREEN:
-  `JEDIT_DIST_PREBUILT=1 node --test --test-concurrency=1 spec/graft-api-session.spec.mjs spec/graft-drawer.spec.mjs spec/graft-review-payload-api-session.spec.mjs spec/graft-review-payload-viewer.spec.mjs spec/design-cycle-policy.spec.mjs`
-- REVIEW GREEN: `npm run quality`
-- REVIEW GREEN:
-  `npx markdownlint-cli2 docs/design/0153-generic-projection-review-payload-viewer.md CHANGELOG.md docs/BEARING.md`
-- REVIEW GREEN: `git diff --check`
-
-What remains open:
-
-- Profile-aware Wesley SDL projection belongs in Graft first:
-  https://github.com/flyingrobots/graft/issues/226
-- jedit Wesley projection consumption follows the Graft provider work:
-  https://github.com/flyingrobots/jedit/issues/266
-- Canonical Echo receipt digest display waits for Echo-side canonical receipt
-  bytes and digests:
-  https://github.com/flyingrobots/jedit/issues/260
-
-PR:
-
-- https://github.com/flyingrobots/jedit/pull/264
diff --git a/docs/design/0154-e-brake-absurdity-fixes.md b/docs/design/0154-e-brake-absurdity-fixes.md
deleted file mode 100644
index fda2386c..00000000
--- a/docs/design/0154-e-brake-absurdity-fixes.md
+++ /dev/null
@@ -1,474 +0,0 @@
----
-title: "WF-0154 - E-Brake: Observed Absurdity Fixes"
-legend: "WF"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/267"
-status: "landed"
-owners:
-  - "@flyingrobots"
-created: "2026-07-12"
-updated: "2026-07-13"
----
-
-# WF-0154 - E-Brake: Observed Absurdity Fixes
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/267
-- https://github.com/flyingrobots/jedit/issues/269
-- https://github.com/flyingrobots/jedit/pull/268
-- https://github.com/flyingrobots/jedit/pull/272
-
-## Decision Summary
-
-One short emergency-brake goalpost fixes four absurdities surfaced by the
-2026-07-12 forensic audit and its review: (1) production undo/redo works and
-submits Echo replacement edits, but `docs/BEARING.md` still declares it
-unsupported and provenance records undo as an anonymous replacement — retire
-the stale claim and name undo/redo in provenance so `:why` can explain a
-reversal; (2) the title scene is the highest-churn surface in the repo —
-freeze it behind a leash entry and a CI changed-paths guard; (3) root identity
-depends on a process-global counter — replace it with chain-threaded
-allocation state; (4) top-level guides cite files and flows that no longer
-exist — add an executable doc-path governance witness and rewrite
-`ADVANCED_GUIDE.md`. The Echo WASM lane and the causal-undo family are
-explicitly out of scope.
-
-## Sponsored Human
-
-A daily-driver Jim user wants `:why` to explain an undo as the reversal it is
-so that recovered mistakes are as accountable as the edits that caused them,
-without having to reconstruct intent from an anonymous replacement event.
-
-## Sponsored Agent
-
-An agent needs deterministic root/head identities and truthful guide paths so
-it can correlate replayed evidence across runs and navigate the codebase from
-documentation, without inferring identity from process-global creation order or
-discovering that documented files do not exist.
-
-## Hill
-
-By the end of this cycle, undo/redo settlements are named as reversals that
-`:why` and the history surfaces can explain, and the stale unsupported claim is
-retired; the title scene is frozen by CI policy; two independently constructed
-runtimes replaying the same script mint identical root identities; and a
-doc-path witness proves every `src/**` and `scripts/**` reference in the
-top-level guides resolves — with the repo proving all four through RED-first
-specs.
-
-## Current Truth
-
-Citations at merge target
-[`a42e1d5d8d8ee851a556fd714df3584b0fce1ea8`](https://github.com/flyingrobots/jedit/commit/a42e1d5d8d8ee851a556fd714df3584b0fce1ea8).
-
-- Production undo/redo **works**: `u`/`ctrl+r` are mapped at
-  [src/app/workspace/editor-editing.ts#95:a42e1d5d8d8ee851a556fd714df3584b0fce1ea8](https://github.com/flyingrobots/jedit/blob/a42e1d5d8d8ee851a556fd714df3584b0fce1ea8/src/app/workspace/editor-editing.ts#L95),
-  and `viewer-key.ts` routes the history transition through
-  `planWorkspaceTextReplaceTransition` into the production text session
-  (landed in `f7a96fce`, PR #66). Witnessed green by
-  `spec/workspace-text-boundaries.spec.mjs` ("production undo and redo submit
-  Echo replacement edits", "production insert-mode edits can be undone through
-  Echo").
-- Two truth defects remain. `docs/BEARING.md` still states "Production
-  undo/redo remains intentionally unsupported until modeled as explicit causal
-  input" — contradicted by the spec above. And no `undo`/`redo` command kind
-  exists in `src/app/workspace/command-provenance.ts` or the settlement
-  envelopes (persisted settlements carry kinds like `insert`), so an undo is
-  indistinguishable from an ordinary replacement in `:why`, history listing,
-  and WSC evidence.
-- The initial audit claim that undo was unwired was wrong; review
-  falsification corrected it, and this document records the verified truth.
-- `src/ui/title-screen.ts` is the most-modified file in the repository
-  (55 commits, 18 fix-prefixed, per `git log --name-only`), including
-  `506df18c` "chore: keep merged title screen under quality cap". Title-scene
-  code spans `src/ui/title-*` (28 files), `src/app/title-*` (5),
-  `src/app/workspace/title-*` (5), `src/adapters/title-*` and
-  `src/adapters/raytracer-profiler.ts` (7), `scripts/title-*` (4), and the
-  `src/ui/*.obj` mesh assets.
-- A module-global counter mints root identity:
-  [src/domain/text-edit-contract.ts#49:a42e1d5d8d8ee851a556fd714df3584b0fce1ea8](https://github.com/flyingrobots/jedit/blob/a42e1d5d8d8ee851a556fd714df3584b0fce1ea8/src/domain/text-edit-contract.ts#L49)
-  (`let nextRootId = 1;`), consumed by `createBufferRoot` and flowing into
-  `HeadId`/`RootNodeId` via `src/app/jedit-contract-runtime-id.ts`. Known debt:
-  `docs/method/backlog/bad-code/global-next-root-id-counter.md`.
-- `ADVANCED_GUIDE.md` locates the editor core in `src/main.ts`
-  ([ADVANCED_GUIDE.md#14:a42e1d5d8d8ee851a556fd714df3584b0fce1ea8](https://github.com/flyingrobots/jedit/blob/a42e1d5d8d8ee851a556fd714df3584b0fce1ea8/ADVANCED_GUIDE.md#L14))
-  — a 13-line dispatcher — and cites the deleted
-  `src/adapters/in-memory-hot-text-runtime.ts`
-  ([ADVANCED_GUIDE.md#91:a42e1d5d8d8ee851a556fd714df3584b0fce1ea8](https://github.com/flyingrobots/jedit/blob/a42e1d5d8d8ee851a556fd714df3584b0fce1ea8/ADVANCED_GUIDE.md#L91)),
-  the latter appearing inside a fenced flow block rather than as a backtick
-  or link reference. `GUIDE.md` misstates the `check` script composition.
-  Seventeen existing doc-governance specs run in the `docs-release` shard;
-  none assert path existence.
-- Audit provenance: full forensic audit delivered 2026-07-12 in-session;
-  findings ledger reproduced in issue #267, corrected by PR #268 review.
-
-## Problem
-
-Four independently observed defects share one shape: the repo's visible claims
-(BEARING, provenance vocabulary, guides, identity semantics, effort
-allocation) have drifted from its runtime truth. The bearing document denies a
-capability the spec suite proves; recovered mistakes are unexplainable as
-reversals; agents cannot trust identity across runs; readers cannot trust the
-advanced guide; and revision effort concentrates on a decorative surface.
-
-## Scope
-
-This cycle includes:
-
-- Naming undo/redo in command provenance and settlement metadata so `:why`
-  and history surfaces can explain a reversal, and retiring the stale
-  `docs/BEARING.md` unsupported claim.
-- A leash entry and changed-shards guard freezing `src/ui/title-*`,
-  `src/app/title-*`, `src/app/workspace/title-*`, `src/adapters/title-*`,
-  `src/adapters/raytracer-profiler.ts`, `scripts/title-*`, and `src/ui/*.obj`
-  absent a `title-unfreeze` PR label.
-- Replacing the module-global root-id counter with chain-threaded allocation
-  state (`nextRootId` as value state on `TickAdmissionState` and
-  `HotTextBufferState`); resolving the bad-code journal entry.
-- A doc-path governance spec (RED today) asserting every `src/**` and
-  `scripts/**` path-like reference in `README.md`, `GUIDE.md`,
-  `ADVANCED_GUIDE.md`, `ARCHITECTURE.md`, and `docs/BEARING.md` resolves,
-  including references inside fenced code blocks and plain prose; rewriting
-  `ADVANCED_GUIDE.md` around the real boot/edit path; correcting `GUIDE.md`'s
-  `check` description; naming the in-process contract posture where README
-  says "Echo-hosted".
-
-## Non-Goals
-
-This cycle does not include:
-
-- Real Echo WASM in-tree, transport parity, or the agent proposal demo
-  (separate lane; depends on Slice 3 landing here).
-- The causal-undo family (`docs/method/backlog/cool-ideas/causal-undo-family.md`).
-- Any new title-scene work, Vim surface growth, or visual-mode features.
-- Content-addressed root identity (identity-doctrine decision deferred; this
-  cycle only removes order dependence).
-- Reworking the undo mechanism itself — the existing
-  projection-transition-to-replacement path stays as-is.
-
-## User Experience / Product Shape
-
-The user edits, makes a mistake, presses `u`; the text restores exactly as it
-does today. What changes: `:why` on the resulting state explains the last
-meaningful command as an undo that reverses a named prior transition, the
-history drawer lists it as an undo rather than an anonymous edit, and BEARING
-tells the truth about the capability. `u` on an empty stack remains a calm
-no-op. No new chrome; no new panes.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Edit[User edits text] --> Mistake[User notices mistake]
-  Mistake --> U[User presses u]
-  U --> Restored[Projection restored + Echo replacement submitted]
-  Restored --> Why[:why names the undo and the reversed transition]
-  Restored --> History[History drawer lists an undo entry]
-  U --> Empty[Empty stack: no-op]
-```
-
-### Wide UI Mockup
-
-Not applicable: no new rendered surface. Undo reuses existing buffer render,
-footer, `:why`, and history-drawer paths.
-
-### Narrow UI Mockup
-
-Not applicable: same as above.
-
-### Accessibility Considerations
-
-Undo/redo outcomes are announced through the existing notification facts and
-recorded as named history entries; agents and screen-reader flows read the
-same structured entries rather than visual diffing.
-
-## Runtime / API Contract
-
-- Undo/redo settlements carry a reversal-aware command kind (e.g.
-  `undo`/`redo`) in the settlement envelope and command-provenance event,
-  with a reference to the reversed transition, so `:why` output and history
-  listing name the reversal.
-- `docs/BEARING.md` Current Truth describes undo/redo as supported through
-  the production text session, citing the boundary spec.
-- `createBufferRoot(id, text)`, `createTextFragment(id, text)`,
-  `emptyFragment(id)`, and `replaceRange(base, range, fragment, nextRootId)`
-  take explicit ids; `TickAdmissionState` and `HotTextBufferState` thread
-  `nextRootId` as value state; `admitReplaceRangeTick(state, range, text)` is
-  the single allocation authority. Identical scripts on independent runtimes
-  mint identical ids.
-- `scripts/ci/changed-shards.mjs` gains a frozen-paths policy: plans fail with
-  an explicit reason when frozen title paths change and the PR lacks
-  `title-unfreeze`.
-- Doc-path witness contract: extract every `src/**` / `scripts/**` path-like
-  token from the five named guides — backtick spans, markdown links, fenced
-  code blocks, and plain prose — and assert existence, with an explicit
-  allowlist (empty to start) for documented-as-future paths.
-
-## Lower Modes
-
-- Undo works identically in keyboard-only operation (it is keyboard-only).
-- Doc-path witness and changed-shards guard run headless in CI and emit
-  standard `node:test` output; the guard also reports its reason in the plan
-  JSON/summary.
-- Provenance naming appears in the agent-facing history JSON surfaces, not
-  only in rendered UI.
-
-## Data / State Model
-
-| Category | Description |
-| --- | --- |
-| Source of truth | Causal history (facts + settlements) for text; `EditorState.undoStack`/`redoStack` remain projection-local planning state. |
-| Derived state | The restoring replacement delta derived from projection snapshots (existing behavior). |
-| Invalid states | Duplicate root ids across chains in one runtime; undo settlements without reversal metadata once this cycle lands. |
-| Reset behavior | Undo/redo stacks reset on buffer open as today; `nextRootId` resets per chain construction. |
-| Serialization | Settlement envelopes gain the reversal-aware command kind; `HotTextBufferState` serializes `nextRootId` across the optic seam (state is not persisted to disk). |
-| Deterministic assumptions | Same script + same runtime construction => identical root/head identities (witnessed). |
-
-## Accessibility Posture
-
-| Concern | Posture |
-| --- | --- |
-| Semantic labels or facts | Undo/redo history entries carry named kinds and reversal references. |
-| Focus order or ownership | Unchanged. |
-| Hidden or visual-only information | None added; provenance is queryable via `:why` and history JSON. |
-| Keyboard behavior | Unchanged (`u`/`ctrl+r` already live). |
-| Secret or redaction behavior | Not applicable. |
-
-## Localization / Directionality Posture
-
-| Concern | Posture |
-| --- | --- |
-| User-visible strings | `:why`/history wording for undo reversal entries. |
-| Catalog keys | Added via the existing bijou-i18n catalog path if new strings land. |
-| Supported locales updated | Yes, alongside string introduction. |
-| Directionality assumptions | None; existing surfaces. |
-| Validation command | Existing i18n generation + doc specs. |
-
-## Agent Inspectability / Explainability Posture
-
-- Undo/redo appear as named settlement kinds with reversal references in the
-  history listing JSON surfaces; `:why` resolves them.
-- Root ids become replay-stable, so agents can correlate evidence across runs.
-- The changed-shards guard emits its frozen-path verdict in machine-readable
-  plan output.
-- The doc-path witness output lists every unresolved path with file and line.
-
-## Linked Invariants
-
-- Tests are executable spec.
-- Runtime truth beats type theater.
-- Undo is authored counter-history, not deletion.
-- `EditorState.lines` is a projection cache and is never reconstructed from
-  bounded readings.
-- Echo authority remains outside jedit product nouns.
-- One file, one runtime truth; no file over 500 LOC.
-
-## Design Alternatives Considered
-
-### Option A: Leave undo provenance anonymous
-
-Pros:
-
-- Zero work; behavior already correct.
-
-Cons:
-
-- `:why` cannot answer the question the product promise names ("why did this
-  edit happen?") for the one command whose purpose is recovery; BEARING keeps
-  lying; the drift that misled the audit stays load-bearing.
-
-### Option B: Rework undo into first-class causal counter-history now
-
-Pros:
-
-- Doctrinally final; aligns with the causal-undo family direction.
-
-Cons:
-
-- Rebuilds a working, spec-proven mechanism inside an emergency-brake cycle;
-  belongs to the causal-undo design cycle instead.
-
-### Option C (chosen): Name the existing mechanism in provenance and fix doc truth
-
-Pros:
-
-- Small, honest, immediately explains reversals through existing `:why` and
-  history surfaces; leaves mechanism rework to the causal-undo cycle.
-
-Cons:
-
-- Reversal reference is metadata over a replacement settlement, not yet a
-  first-class causal reversal fact.
-
-## Decision
-
-Option C for undo truth; leash + CI guard for the freeze; chain-threaded
-allocation state for identity (content addressing deferred to the identity
-doctrine); executable doc-path witness before prose rewrite.
-
-## Implementation Slices
-
-- [x] Slice 1: Name undo/redo in provenance (issue #269; the stale BEARING
-      claim was retired in PR #268)
-      (`feat(provenance): name undo and redo settlements as reversals`).
-- [x] Slice 2: Title-scene freeze leash + changed-shards guard
-      (`chore(ci): freeze title scene behind title-unfreeze label`).
-- [x] Slice 3: RED identity witness + chain-threaded root-id allocation;
-      resolve bad-code entry
-      (`fix(domain): thread root id allocation through chain state`).
-- [x] Slice 4: RED doc-path witness + ADVANCED_GUIDE rewrite + GUIDE/README
-      corrections (`docs: make top-level guides pass the path witness`).
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [x] Provenance spec: after an edit and `u`, the settlement/provenance
-      surface names an undo with a reference to the reversed transition (the
-      reversed edit's settlement receipt id, carried as `reversedReceiptId`
-      on the event and the settlement payload), and `:why` output includes
-      the reversal explanation
-      (`spec/undo-provenance.spec.mjs`; failed RED before naming landed).
-- [x] Redo provenance spec: `ctrl+r` after undo is named as a redo
-      (`spec/undo-provenance.spec.mjs`; failed RED before naming landed).
-- [x] Identity spec: two independently constructed runtimes replaying an
-      identical script mint identical root/head identities; interleaved
-      buffers do not perturb ids (`spec/root-identity-determinism.spec.mjs`;
-      failed RED before the allocation change).
-- [x] Changed-shards guard spec: plan over a frozen title path without
-      `title-unfreeze` fails with the frozen-path reason; with the label it
-      passes (`spec/ci-frozen-paths.spec.mjs`; failed RED before the module
-      existed).
-
-Documentation and process tests, only if relevant:
-
-- [x] Doc-path witness: every `src/**`/`scripts/**` path-like reference in
-      README, GUIDE, ADVANCED_GUIDE, ARCHITECTURE, BEARING — including fenced
-      code blocks and plain prose — resolves
-      (`spec/guide-path-references.spec.mjs`; failed RED on ADVANCED_GUIDE's
-      fenced `in-memory-hot-text-runtime` flow before the guide fix).
-- [x] BEARING truth assertion: BEARING no longer claims undo/redo is
-      unsupported.
-
-Rule honored: the doc witnesses prove only doc claims; slices 1-3 are proven
-by behavior tests.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [x] Provenance/history surfaces name undo and redo settlements with
-      reversal references, proven by behavior spec.
-- [x] `:why` output explains an undo as a reversal (history command events
-      flow through the existing `lastCommandEvent` -> `:why` path).
-- [x] Identity witness proves replay-stable root ids.
-- [x] Changed-shards guard blocks unlabeled title changes in CI.
-- [x] Doc-path witness is green and ADVANCED_GUIDE describes the real paths.
-- [x] BEARING describes undo/redo truthfully, citing the boundary spec.
-- [x] `docs/method/backlog/bad-code/global-next-root-id-counter.md` resolved.
-- [x] CHANGELOG updated; issues #267/#269 and PRs #268/#272 linked.
-- [x] CI and local validation are green.
-
-## Validation Plan
-
-```bash
-npm run build
-node --test --test-concurrency=1 spec/root-identity-determinism.spec.mjs \
-  spec/workspace-text-boundaries.spec.mjs spec/tick-admission.contract.spec.mjs \
-  spec/replace-range.contract.spec.mjs
-npm run quality
-npm run check
-```
-
-## Playback / Witness
-
-```bash
-node --test --test-concurrency=1 spec/root-identity-determinism.spec.mjs
-node --test --test-concurrency=1 spec/workspace-text-boundaries.spec.mjs
-```
-
-TUI reproduction: open a file, `dw`, `u` (text restored), `:why` (reversal
-explanation names the reversed receipt), `ctrl+r` (re-applied). 120x30
-terminal, graphite theme, en locale.
-
-## Risks
-
-Known risks:
-
-- Renaming settlement kinds could affect consumers of persisted
-  `workspace_text_edit_settlement.v1` envelopes or history JSON readers.
-- Widening `HotTextBufferState` changes the optic-seam wire shape.
-- Doc-path witness may flag intentional future-tense references.
-
-Mitigations:
-
-- Additive metadata: keep existing kind vocabulary valid; new reversal fields
-  are additive, and the restart round-trip spec guards recovery.
-- State is transport-transient (never persisted); the schema change is
-  encode/decode symmetric within one process and covered by transport specs.
-- Witness supports an explicit allowlist for documented-as-future paths, with
-  zero entries to start.
-
-## Follow-On Debt
-
-- Native Echo speculative-intent undo metadata (existing BEARING third-lane
-  item).
-- Causal-undo family design cycle
-  (`docs/method/backlog/cool-ideas/causal-undo-family.md`).
-- Content-addressed root identity under the identity doctrine.
-- `docs/design/0001-replace-range-contract/replace-range-contract.md`
-  turned out to state only behavior-level laws (still true); a Later
-  Evolution note recording the WF-0154 identity-allocation change was added
-  instead of a rewrite.
-
-## Retrospective
-
-What changed from the design:
-
-- The original draft claimed undo/redo was implemented but unwired; review
-  falsification (PR #268) proved it wired and Echo-routed since `f7a96fce`,
-  and Slice 1 was rescoped from "wire undo" to "name undo in provenance and
-  fix doc truth". PR #268 corrected BEARING; issue #269 landed the provenance
-  naming and reversed-receipt linkage in closeout PR #272, with history-family
-  command handling split out of `command-provenance.ts`.
-- The doc was renumbered WF-0153 -> WF-0154 mid-cycle (0153 was already taken
-  on main) and the title-freeze globs were expanded from two path roots to
-  seven after inventorying the real title-scene file spread.
-- The root-id fix was implemented as chain-threaded value state
-  (`nextRootId` on `TickAdmissionState`/`HotTextBufferState`) rather than an
-  allocator object — stronger than the design's "per-runtime allocator":
-  serializable, replay-safe, and per-chain deterministic.
-- `admitReplaceRangeTick` now takes fragment text instead of a pre-built
-  fragment, making the domain the single allocation authority; the
-  `EXPECTED_RUNTIME_EXPORTS` pin in `tests/replace-range-cycle.spec.mjs`
-  gained `FIRST_ROOT_ID`.
-
-What the tests proved:
-
-- `spec/root-identity-determinism.spec.mjs` (RED against the global counter,
-  GREEN after): same-script buffers and independent runtimes mint identical
-  root/head identities; interleaved creation does not perturb per-buffer ids.
-- `spec/ci-frozen-paths.spec.mjs` (RED before the module existed): all seven
-  title path roots are frozen, non-title paths never are, and the
-  `title-unfreeze` label admits changes; the CLI exits 1 with the policy
-  reason on a real historical title-only diff.
-- `spec/guide-path-references.spec.mjs` (RED on ADVANCED_GUIDE.md:91): every
-  `src/**`/`scripts/**` reference in the five top-level guides resolves,
-  including fenced-code and plain-prose references.
-- `spec/undo-provenance.spec.mjs` proves undo/redo settlement naming, stable
-  history event identity, and reversed-receipt correlation across queued and
-  repeated history commands.
-- `npm run check` (full suite + quality gate) green over all slices.
-
-What remains open:
-
-- Nothing. Slice 1 (provenance naming, #269) landed in the closeout PR along
-  with the dist/source parity witness (#249), the retained full-root guard
-  (#247), the 0001 Later Evolution note, and the WF-0155/WF-0156 draft
-  designs. The goalpost is met.
-
-PR:
-
-- https://github.com/flyingrobots/jedit/pull/268
-- https://github.com/flyingrobots/jedit/pull/272
diff --git a/docs/design/0155-causal-undo-family.md b/docs/design/0155-causal-undo-family.md
deleted file mode 100644
index cb94e412..00000000
--- a/docs/design/0155-causal-undo-family.md
+++ /dev/null
@@ -1,300 +0,0 @@
----
-title: "WF-0155 - Causal Undo Family"
-legend: "WF"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/270"
-status: "draft"
-owners:
-  - "@flyingrobots"
-created: "2026-07-12"
-updated: "2026-07-12"
----
-
-# WF-0155 - Causal Undo Family
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/270
-
-## Decision Summary
-
-Undo becomes a family of causal operations layered on the signature loop
-rather than a stack pop: (1) regional time-rewind restores a cursor-scoped
-range to its state at a named time or checkpoint via materialize + diff;
-(2) surgical revert attributes a line to its originating fact, synthesizes the
-inverse, and commutes it to head via anchor transforms; (3) cascade revert
-computes downstream dependency closure from basis-bound edit evidence. Every
-variant is a forward counter-edit proposal strand behind preview -> admit —
-never history deletion. Plain `u`/`ctrl+r` stays untouched; the family lives
-near `:why` and `g?`.
-
-## Sponsored Human
-
-A Jim user wants to point at a line and undo the change that introduced it —
-or rewind a region to last Wednesday — so that recovery is targeted, without
-having to hand-reconstruct the past or globally rewind unrelated work.
-
-## Sponsored Agent
-
-An agent operator needs "revert everything this agent's edit caused
-downstream" as one reviewable proposal strand so that machine edits are
-recoverable at the same granularity they were made, without diff archaeology.
-
-## Hill
-
-By the end of this family's first cycle, a user can select a range and
-propose its restoration to a named historical basis, preview the resulting
-strand, and admit it — with the repo proving the proposal is a forward
-counter-edit whose evidence chain replays.
-
-## Current Truth
-
-- Plain undo/redo works and is provenance-named as of WF-0154
-  (`spec/workspace-text-boundaries.spec.mjs`, `spec/undo-provenance.spec.mjs`).
-- Anchor commutation primitives exist:
-  `src/domain/anchor-transform-contract.ts` (`transformPointAnchor`, bias,
-  receipts).
-- Attribution front end is specced but unbuilt:
-  `docs/method/backlog/cool-ideas/JEDIT_why-is-this-character-here-debugger.md`
-  (`g?`), blocked on Echo session/event attribution.
-- Historical Basis Preview (roadmap goalpost 3) and proposal strands /
-  `:admit` (goalpost 4) are unshipped; this family composes them.
-- Origin and blast-radius laws:
-  `docs/method/backlog/cool-ideas/causal-undo-family.md`.
-- Open substrate question: whether `RopeDiff` facts retain replaced bytes
-  (cheap local inversion) or ranges only (inversion materializes adjacent
-  states); pin before slicing surgical revert.
-
-## Problem
-
-Recovery today is all-or-nothing temporal: `u` walks the whole-buffer stack.
-Users and agent operators cannot undo a *specific* past change or a *region's*
-drift without manually reconstructing text, even though the substrate records
-everything needed to do it lawfully.
-
-## Scope
-
-This cycle includes (first slice only; later slices are follow-on cycles):
-
-- Regional time-rewind: select range + named basis (time/checkpoint) ->
-  materialized historical window -> diff -> `replaceRange` proposal strand ->
-  preview -> `:admit`.
-- The proposal strand carries source-basis evidence so `:why` explains the
-  restoration.
-
-## Non-Goals
-
-This cycle does not include:
-
-- Surgical revert and cascade (later slices; need attribution + commutation).
-- `g?` attribution UI (separate cool-idea, blocked on Echo).
-- Any change to plain `u`/`ctrl+r` semantics.
-- Collaboration or multi-worldline braiding.
-
-## User Experience / Product Shape
-
-Visual-select a range (or accept the current line), `:rewind `; a lens
-shows the proposed restoration as a diff against head with the source basis
-named; `:admit` applies it as an ordinary forward edit; escape abandons. The
-head never moves until admission.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Select[User selects range] --> Rewind[:rewind names a basis]
-  Rewind --> Preview[Lens previews restoring diff + basis evidence]
-  Preview --> Admit[:admit applies forward counter-edit]
-  Preview --> Abandon[Escape abandons; head untouched]
-  Admit --> Why[:why explains restoration + source basis]
-```
-
-### Wide UI Mockup
-
-Deferred to cycle activation; the preview reuses the existing lens/diff
-surfaces (no new chrome planned).
-
-### Narrow UI Mockup
-
-Deferred with the wide mockup; wrapping and footer behavior follow the
-existing preview-lens rules.
-
-### Accessibility Considerations
-
-The proposal is announced as a structured pending strand with named basis and
-range; admission/abandonment emit the standard notification facts.
-
-## Runtime / API Contract
-
-- `:rewind` resolves a named basis (checkpoint id or relative time) to a
-  bounded historical reading for the selected range.
-- The restoration is planned as a standard `replaceRange` intent whose
-  provenance names the operation `rewind` and references the source basis.
-- No new persistence: the proposal is a pending intent; admitted output is an
-  ordinary edit fact.
-
-## Lower Modes
-
-- Agent-facing JSON: the proposal strand, its basis reference, and the diff
-  are readable through the history/why JSON surfaces before admission.
-- When retention for the named basis is unavailable, the command returns a
-  typed obstruction naming the missing retention — never a silent fallback.
-
-## Data / State Model
-
-| Category | Description |
-| --- | --- |
-| Source of truth | Causal history; the proposal is a pending intent until admitted. |
-| Derived state | Materialized historical window and restoring diff. |
-| Invalid states | Admitted restoration without basis evidence; preview mutating head. |
-| Reset behavior | Abandoning the preview discards derived state only. |
-| Serialization | Provenance kind `rewind` + basis reference on the settlement (additive). |
-| Deterministic assumptions | Same basis + same range => identical proposal bytes. |
-
-## Accessibility Posture
-
-| Concern | Posture |
-| --- | --- |
-| Semantic labels or facts | Proposal strand carries named kind, basis, range. |
-| Focus order or ownership | Preview lens follows existing lens focus rules. |
-| Hidden or visual-only information | None; JSON surfaces mirror the lens. |
-| Keyboard behavior | `:rewind`, `:admit`, escape; no new chords. |
-| Secret or redaction behavior | Not applicable. |
-
-## Localization / Directionality Posture
-
-| Concern | Posture |
-| --- | --- |
-| User-visible strings | `:rewind` prompts, obstruction messages. |
-| Catalog keys | Via the bijou-i18n catalog path. |
-| Supported locales updated | With string introduction. |
-| Directionality assumptions | None; existing surfaces. |
-| Validation command | Existing i18n generation + doc specs. |
-
-## Agent Inspectability / Explainability Posture
-
-- Proposal strands, basis references, and admission receipts are readable
-  through history JSON before and after admission; `:why` explains admitted
-  restorations.
-
-## Linked Invariants
-
-- Undo is authored counter-history, not deletion.
-- Preview and structural inspection surfaces are projections over buffer
-  truth, not competing sources of truth.
-- Echo authority remains outside jedit product nouns.
-- Tests are executable spec.
-
-## Design Alternatives Considered
-
-### Option A: Ship surgical revert first
-
-Pros:
-
-- The most-asked-for gesture ("undo the change that introduced this line").
-
-Cons:
-
-- Requires attribution (`g?`, Echo-blocked) and inverse commutation; highest
-  theory load; wrong first slice.
-
-### Option B (chosen): Ship regional time-rewind first
-
-Pros:
-
-- No commutation: materialize + diff; exercises Historical Basis Preview and
-  proposal strands exactly as the roadmap intends; delivers the causal-undo
-  experience at a tenth of the machinery.
-
-Cons:
-
-- Defers the headline surgical gesture one cycle.
-
-## Decision
-
-Option B. Surgical revert and cascade follow as separate cycles once `g?`
-attribution and commutation land; cascade obeys the blast-radius containment
-laws (dependency = non-commutation; minimal honest bases; ring preview with
-budget; surgical escape valve).
-
-## Implementation Slices
-
-- [ ] Slice 1: Basis resolution + bounded historical window for a range
-      (RED: obstruction when retention is missing).
-- [ ] Slice 2: Restoring-diff proposal strand + preview lens.
-- [ ] Slice 3: `:admit` path with `rewind` provenance naming; `:why` proof.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [ ] Rewind proposal for a range reproduces the historical bytes exactly
-      (fails before materialization lands).
-- [ ] Admission applies a forward edit whose settlement names `rewind` and
-      the source basis.
-- [ ] Missing retention yields the typed obstruction, not a fallback.
-
-Documentation and process tests, only if relevant:
-
-- [ ] Design/roadmap linkage assertions per docs-release conventions.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [ ] A selected range can be previewed and admitted back to a named basis.
-- [ ] Head never changes before admission (spec-proven).
-- [ ] `:why` explains the restoration with its basis.
-- [ ] Docs/changelog updated; issue and PR linked; CI green.
-
-## Validation Plan
-
-```bash
-npm run build
-node --test --test-concurrency=1 spec/rewind-*.spec.mjs
-npm run quality
-```
-
-## Playback / Witness
-
-To be named at cycle activation (rewind witness spec + TUI reproduction
-sequence).
-
-## Risks
-
-Known risks:
-
-- Retention gaps make honest rewind impossible for old bases.
-- Basis vocabulary (time vs checkpoint) may outrun what Echo retains.
-
-Mitigations:
-
-- Typed obstructions for missing retention are first-class outcomes.
-- Start with checkpoint-named bases; add relative time only when retention
-  proves it.
-
-## Follow-On Debt
-
-- Surgical revert cycle (attribution + inverse + commutation).
-- Cascade cycle under the blast-radius containment laws.
-- `g?` attribution (existing cool-idea).
-
-## Retrospective
-
-Fill this in after implementation.
-
-What changed from the design:
-
-- ...
-
-What the tests proved:
-
-- ...
-
-What remains open:
-
-- ...
-
-PR:
-
-- https://github.com/flyingrobots/jedit/pull/
diff --git a/docs/design/0156-echo-wasm-in-tree.md b/docs/design/0156-echo-wasm-in-tree.md
deleted file mode 100644
index d5dcaffb..00000000
--- a/docs/design/0156-echo-wasm-in-tree.md
+++ /dev/null
@@ -1,339 +0,0 @@
----
-title: "WF-0156 - Real Echo WASM In-Tree And The Accountable-Edit Demo"
-legend: "WF"
-lane: "design"
-issue: "https://github.com/flyingrobots/jedit/issues/271"
-status: "draft"
-owners:
-  - "@flyingrobots"
-created: "2026-07-12"
-updated: "2026-07-12"
----
-
-# WF-0156 - Real Echo WASM In-Tree And The Accountable-Edit Demo
-
-## Linked Issue
-
-- https://github.com/flyingrobots/jedit/issues/271
-
-## Decision Summary
-
-The real Echo engine becomes an in-tree dependency behind the existing
-transport seam, validated by a differential parity witness against the
-installed TypeScript contract implementation, and proven by one end-to-end
-demo: an agent submits a proposal strand, a human inspects and admits it, and
-a replay witness re-derives identical evidence. Five phases: (A) publish a
-hash-pinned `@flyingrobots/echo-warp-wasm` package from the echo repo;
-(B) a real transport adapter promoting the loading/ABI logic from
-`scripts/jedit-echo-witness.mjs`; (C) an `echoWasm` member on
-`TextRuntimeProfile`; (D) the parity witness wired into the release gate,
-gating any default cutover; (E) the demo. The three-month TypeScript
-implementation stops being a placeholder and becomes the conformance oracle.
-
-## Sponsored Human
-
-A Jim maintainer wants the engine the product story names to actually run
-under the editor so that dogfooding hours harden Echo instead of a
-simulation, without a sibling-checkout ritual (`ECHO_WARP_WASM_DIR`).
-
-## Sponsored Agent
-
-An agent needs a durable, versioned Echo boundary and a proposal-submission
-tool so it can produce accountable edits with basis, range, rationale, and
-admission paths, without reaching around the product into runtime internals.
-
-## Hill
-
-By the end of this lane, `JEDIT_TEXT_RUNTIME=echoWasm` runs the real engine
-for open/edit/read/checkpoint, the parity witness proves it indistinguishable
-from the installed implementation on identical scripts, and the demo
-recording shows propose -> inspect -> admit -> replay with re-derived
-evidence.
-
-## Current Truth
-
-- Production text runs the in-process TypeScript Echo-contract implementation
-  (`src/adapters/installed-jedit-contract-echo-transport.ts`); zero `.wasm`
-  files exist in the repo.
-- Real Echo is exercised only by opt-in witnesses requiring a sibling
-  checkout (`scripts/run-real-echo-wasm-stack-witness.sh` requires
-  `ECHO_WARP_WASM_DIR`); the WASM stack spec skips in CI when
-  `JEDIT_ECHO_WASM_MODULE` is unset
-  (`spec/jedit-echo-wasm-stack-witness.spec.mjs`).
-- The wire layer is ready: `src/transport/eint.ts` mirrors `echo_wasm_abi`,
-  and `TextRuntimeProfile` is a single-member union with obstruction-typed
-  parsing built to receive a second member
-  (`src/app/text-runtime-profile.ts`).
-- Root identity is replay-stable as of WF-0154
-  (`spec/root-identity-determinism.spec.mjs`) — the precondition for
-  differential evidence comparison.
-- An MCP witness surface exists to extend for proposals
-  (`src/adapters/jedit-echo-witness-mcp-adapter.ts`).
-- VISION names `missing_retention` and `durable_replay_unavailable` as
-  release-gate blockers, not acceptable end states.
-- **Upstream dependency: Edict.** Echo's runtime execution semantics flow
-  through the Edict pipeline (intent -> Core IR -> Echo Target IR -> WASM
-  sandbox), and Edict `v0.11.0-alpha.1` states that participant admission,
-  runtime execution, canonical full-manifest bytes, and the WASM sandbox are
-  not implemented yet (Edict README, Current Status). The raw text-kernel
-  byte ABI (`rmg_wasm` create/replace/textWindow) exists today without
-  Edict, so Phases A-C are packaging/adapter work; Phase D's full gate
-  (scheduler-owned tick, retained evidence, durable replay) and Phase E's
-  admission step land behind Edict's runtime milestones.
-
-## Problem
-
-The gating strategy ("jedit is Echo's release gate") currently validates Echo
-through a narrow hand-run witness while all real editing pressure hardens the
-TypeScript stand-in. None of that evidence transfers to the Rust engine, and
-the product's moat claim rests on an engine that is not in the tree.
-
-## Scope
-
-This lane includes (phases; each activates as its own cycle):
-
-- Phase A (echo repo): versioned, hash-pinned `@flyingrobots/echo-warp-wasm`
-  npm package owning the byte ABI and package export boundary.
-- Phase B: `createEchoWasmJeditContractTransport` behind the same seam as the
-  installed transport, promoting witness-script loading into an adapter.
-- Phase C: `echoWasm` profile member; default remains `echoHosted`.
-- Phase D: differential parity witness — identical scripts through both
-  transports must yield identical readings, evidence, and obstruction
-  posture; wired into `release-gate:jedit-echo`; default cutover gated on
-  parity plus Echo clearing its retention/replay blockers.
-- Phase E: the demo — agent proposes via MCP, human inspects (`:why`,
-  history drawer), `:admit`, replay witness re-derives identical evidence;
-  scripted and recorded. One file, one proposal, one admit.
-
-## Non-Goals
-
-This lane does not include:
-
-- Collaboration, Continuum, or multi-worldline braiding.
-- Search Sets / `:%s` proposal preview (goalpost 4 owns that surface).
-- Deleting the installed TypeScript transport — it remains the conformance
-  oracle and the fallback profile.
-- Echo feature work beyond the package/retention/replay boundary the gate
-  already names.
-
-## User Experience / Product Shape
-
-No visible change until cutover: same editor, same commands. The demo adds an
-agent-facing MCP tool (`jedit_propose_edit`) and exercises existing surfaces
-(history drawer, `:why`, `:admit`). Post-cutover, the footer's authority
-posture names the engine profile.
-
-### User Journey
-
-```mermaid
-flowchart TD
-  Agent[Agent submits proposal via MCP] --> Strand[Proposal strand recorded]
-  Strand --> Inspect[Human inspects via history drawer + :why]
-  Inspect --> Admit[:admit applies the edit]
-  Inspect --> Reject[Abandon; head untouched]
-  Admit --> Replay[Replay witness re-derives identical evidence]
-```
-
-### Wide UI Mockup
-
-Not applicable: no new rendered surface; existing drawer/lens/footer paths.
-
-### Narrow UI Mockup
-
-Not applicable: same as above.
-
-### Accessibility Considerations
-
-The demo's every step is JSON-witnessable; nothing is screen-only.
-
-## Runtime / API Contract
-
-- `@flyingrobots/echo-warp-wasm` exports the versioned WASM module and byte
-  ABI; the adapter loads it without environment path lore.
-- `createEchoWasmJeditContractTransport` implements the same transport seam
-  as `createInstalledJeditContractEchoTransport`.
-- `parseTextRuntimeProfile` accepts `echoWasm`; unsupported values keep the
-  existing typed obstruction.
-- Parity witness contract: for a scripted session (create, edits, reads,
-  checkpoint, replay), both transports produce identical reading payloads,
-  evidence identifiers, and obstruction postures.
-- `jedit_propose_edit` MCP tool: basis, range, rationale, proposed text ->
-  proposal strand id + admission path.
-
-## Lower Modes
-
-- Parity witness and demo script run headless with JSON reports (CI and
-  agent consumption).
-- When the WASM package is absent or version-mismatched, profile selection
-  yields a typed obstruction naming the package requirement.
-
-## Data / State Model
-
-| Category | Description |
-| --- | --- |
-| Source of truth | Echo-owned causal substrate behind the transport seam. |
-| Derived state | Parity reports; demo recordings. |
-| Invalid states | Divergent evidence between transports for identical scripts (gate failure). |
-| Reset behavior | Profile selection is per-process; no migration of local histories in this lane. |
-| Serialization | Package version + module hash pinned in the lockfile and asserted by the adapter. |
-| Deterministic assumptions | WF-0154 root-id determinism; Echo scheduler determinism per its own gate. |
-
-## Accessibility Posture
-
-| Concern | Posture |
-| --- | --- |
-| Semantic labels or facts | Proposal strands and admissions are structured facts. |
-| Focus order or ownership | Unchanged. |
-| Hidden or visual-only information | None; JSON witnesses mirror the demo. |
-| Keyboard behavior | Unchanged. |
-| Secret or redaction behavior | Not applicable. |
-
-## Localization / Directionality Posture
-
-| Concern | Posture |
-| --- | --- |
-| User-visible strings | Obstruction messages for missing package/profile. |
-| Catalog keys | Via the bijou-i18n catalog path. |
-| Supported locales updated | With string introduction. |
-| Directionality assumptions | None. |
-| Validation command | Existing i18n generation + doc specs. |
-
-## Agent Inspectability / Explainability Posture
-
-- The MCP tool returns structured strand ids and admission paths; parity and
-  replay witnesses emit machine-readable reports; nothing requires scraping.
-
-## Linked Invariants
-
-- Echo authority remains outside jedit product nouns.
-- jedit is the consumer, not the substrate.
-- Witness reports stay honest about retention and replay obstructions.
-- Tests are executable spec.
-
-## Design Alternatives Considered
-
-### Option A: Vendor the .wasm binary into this repo
-
-Pros:
-
-- No publish pipeline; immediate availability.
-
-Cons:
-
-- Unversioned drift against the echo repo; binary blobs in git; violates the
-  "package is versioned, byte ABI is documented" boundary doctrine.
-
-### Option B (chosen): Versioned npm package from the echo repo
-
-Pros:
-
-- Matches the stack's distribution channel; lockfile pinning; the boundary
-  doctrine's "boring" Echo interface.
-
-Cons:
-
-- Requires echo-repo release work before jedit phases B-E can go green.
-
-## Decision
-
-Option B. Phase D is the hinge: no default cutover until the parity witness
-is green in the release gate and Echo's retention/replay blockers are
-cleared. The installed TypeScript transport is retained as oracle and
-fallback.
-
-## Implementation Slices
-
-- [ ] Phase A (echo repo): publish hash-pinned `@flyingrobots/echo-warp-wasm`.
-- [ ] Phase B: WASM transport adapter behind the installed seam.
-- [ ] Phase C: `echoWasm` profile member + obstruction for missing package.
-- [ ] Phase D: differential parity witness in the release gate.
-- [ ] Phase E: `jedit_propose_edit` MCP tool + demo script + recording.
-
-## Tests To Write First
-
-Behavior tests required:
-
-- [ ] Profile spec: `echoWasm` selects the WASM transport; absence of the
-      package yields the typed obstruction (fails before phases B-C).
-- [ ] Parity spec: scripted session through both transports produces
-      identical readings/evidence/obstructions (fails before phase B).
-- [ ] Demo spec: proposal -> admit -> replay re-derives identical evidence
-      (fails before phase E).
-
-Documentation and process tests, only if relevant:
-
-- [ ] Release-gate report includes the parity verdict.
-
-## Acceptance Criteria
-
-The work is done when:
-
-- [ ] `JEDIT_TEXT_RUNTIME=echoWasm` runs open/edit/read/checkpoint on the
-      real engine.
-- [ ] Parity witness is green in the release gate.
-- [ ] The demo recording exists and its witness re-derives evidence.
-- [ ] Docs/changelog updated; issues and PRs linked; CI green.
-
-## Validation Plan
-
-```bash
-npm run build
-node --test --test-concurrency=1 spec/echo-wasm-*.spec.mjs
-npm run release-gate:jedit-echo
-npm run quality
-```
-
-## Playback / Witness
-
-To be named at cycle activation (parity witness + demo script + recording
-path).
-
-## Risks
-
-Known risks:
-
-- Edict readiness is the pacing dependency: runtime execution, participant
-  admission, and the WASM sandbox are unimplemented at `v0.11.0-alpha.1`,
-  and Phases D-E cannot go green until Echo hosts them.
-- Echo-repo readiness: retention and durable replay are admitted blockers.
-- ABI drift between the package and `src/transport/eint.ts`.
-- Parity divergence exposing semantic gaps the TS implementation papered
-  over.
-
-Mitigations:
-
-- Sequence around Edict: land Phases A-C (package, adapter, profile) against
-  the existing text-kernel byte ABI now, and scope an interim parity witness
-  to the create/replace/read/checkpoint script that ABI already serves;
-  widen the gate to scheduler/retention/replay as Edict milestones land.
-- Phase D treats divergence as the product working as designed: every
-  divergence becomes an Echo conformance bug with a jedit-authored witness.
-- EINT codec round-trip tests pin the ABI on both sides.
-- Cutover is gated, not scheduled; `echoHosted` remains the default until
-  the gate says otherwise.
-
-## Follow-On Debt
-
-- Retire the sibling-checkout witness scripts once the package path covers
-  them.
-- Native Echo speculative-intent undo metadata (BEARING third lane).
-
-## Retrospective
-
-Fill this in after implementation.
-
-What changed from the design:
-
-- ...
-
-What the tests proved:
-
-- ...
-
-What remains open:
-
-- ...
-
-PR:
-
-- https://github.com/flyingrobots/jedit/pull/
diff --git a/docs/design/0157-rope-fact-inspector-and-range-why.md b/docs/design/0157-rope-fact-inspector-and-range-why.md
index a2a5148f..131746b1 100644
--- a/docs/design/0157-rope-fact-inspector-and-range-why.md
+++ b/docs/design/0157-rope-fact-inspector-and-range-why.md
@@ -51,47 +51,25 @@ details consume the same evidence model.
 
 ## Current Truth
 
-The merge target is
-[`6c4a54cda6d47b297a90ceed580691a2bc2b1fb8`](https://github.com/flyingrobots/jedit/commit/6c4a54cda6d47b297a90ceed580691a2bc2b1fb8).
-
-- The public `JeditWhyRangeReport` names a worldline, current head, queried
-  range, reverse walk, and one produced-or-unavailable result, but it has no
-  leaf, blob, checkpoint, anchor, coverage, bound, or continuation model.
-  [`src/ports/jedit-why-range.ts#L21:6c4a54cda6d47b297a90ceed580691a2bc2b1fb8`](https://github.com/flyingrobots/jedit/blob/6c4a54cda6d47b297a90ceed580691a2bc2b1fb8/src/ports/jedit-why-range.ts#L21)
-- The current implementation reconstructs a pseudo-diff from retained local
-  `TickMetadata`, derives rewrite and diff identifiers through local conversion
-  helpers, and aliases tick to rewrite plus receipt to diff. Those aliases are
-  not proof that distinct runtime facts were observed.
-  [`src/app/jedit-why-range.ts#L98:6c4a54cda6d47b297a90ceed580691a2bc2b1fb8`](https://github.com/flyingrobots/jedit/blob/6c4a54cda6d47b297a90ceed580691a2bc2b1fb8/src/app/jedit-why-range.ts#L98)
-  [`src/app/jedit-why-range.ts#L143:6c4a54cda6d47b297a90ceed580691a2bc2b1fb8`](https://github.com/flyingrobots/jedit/blob/6c4a54cda6d47b297a90ceed580691a2bc2b1fb8/src/app/jedit-why-range.ts#L143)
-- The legacy range-why spec still constructs the production-unsafe full
-  snapshot fixture and asserts those identity aliases. It proves coordinate
-  walking behavior, not graph-backed provenance.
-  [`spec/jedit-why-range.spec.mjs#L7:6c4a54cda6d47b297a90ceed580691a2bc2b1fb8`](https://github.com/flyingrobots/jedit/blob/6c4a54cda6d47b297a90ceed580691a2bc2b1fb8/spec/jedit-why-range.spec.mjs#L7)
-  [`spec/jedit-why-range.spec.mjs#L43:6c4a54cda6d47b297a90ceed580691a2bc2b1fb8`](https://github.com/flyingrobots/jedit/blob/6c4a54cda6d47b297a90ceed580691a2bc2b1fb8/spec/jedit-why-range.spec.mjs#L43)
-- Graph-rope authority already defines distinct worldline, head, leaf, blob,
-  rewrite, diff, and text-tick receipt facts.
-  [`src/domain/graph-rope-types.ts#L89:6c4a54cda6d47b297a90ceed580691a2bc2b1fb8`](https://github.com/flyingrobots/jedit/blob/6c4a54cda6d47b297a90ceed580691a2bc2b1fb8/src/domain/graph-rope-types.ts#L89)
-  [`src/domain/graph-rope-types.ts#L156:6c4a54cda6d47b297a90ceed580691a2bc2b1fb8`](https://github.com/flyingrobots/jedit/blob/6c4a54cda6d47b297a90ceed580691a2bc2b1fb8/src/domain/graph-rope-types.ts#L156)
-- Checkpoint declarations and optional Echo anchor associations are already
-  separate application facts, so `:why` must not infer an anchor from a
-  checkpoint.
-  [`src/domain/graph-rope-types.ts#L261:6c4a54cda6d47b297a90ceed580691a2bc2b1fb8`](https://github.com/flyingrobots/jedit/blob/6c4a54cda6d47b297a90ceed580691a2bc2b1fb8/src/domain/graph-rope-types.ts#L261)
-  [`src/domain/graph-rope-types.ts#L302:6c4a54cda6d47b297a90ceed580691a2bc2b1fb8`](https://github.com/flyingrobots/jedit/blob/6c4a54cda6d47b297a90ceed580691a2bc2b1fb8/src/domain/graph-rope-types.ts#L302)
-- `GraphRopeRuntime` exposes basis-pinned text windows, causal line diffs, and a
-  debug rope shape, but not a bounded range-provenance observation.
-  [`src/domain/graph-rope-runtime.ts#L146:6c4a54cda6d47b297a90ceed580691a2bc2b1fb8`](https://github.com/flyingrobots/jedit/blob/6c4a54cda6d47b297a90ceed580691a2bc2b1fb8/src/domain/graph-rope-runtime.ts#L146)
-- Workspace inline panels already stay tied to a buffer and cursor anchor and
-  close on `Esc`, focus loss, buffer change, or cursor movement. Their payload
-  is currently only a title, message, and tone.
-  [`src/app/workspace/workspace-inline-panel.ts#L17:6c4a54cda6d47b297a90ceed580691a2bc2b1fb8`](https://github.com/flyingrobots/jedit/blob/6c4a54cda6d47b297a90ceed580691a2bc2b1fb8/src/app/workspace/workspace-inline-panel.ts#L17)
-  [`src/app/workspace/workspace-inline-panel.ts#L64:6c4a54cda6d47b297a90ceed580691a2bc2b1fb8`](https://github.com/flyingrobots/jedit/blob/6c4a54cda6d47b297a90ceed580691a2bc2b1fb8/src/app/workspace/workspace-inline-panel.ts#L64)
-- The architectural gate already requires range `:why` to cite head, leaf,
-  blob, rewrite, diff, tick, and checkpoint evidence.
-  [`docs/design/0149-graph-backed-rope-runtime-discovery.md#L880:6c4a54cda6d47b297a90ceed580691a2bc2b1fb8`](https://github.com/flyingrobots/jedit/blob/6c4a54cda6d47b297a90ceed580691a2bc2b1fb8/docs/design/0149-graph-backed-rope-runtime-discovery.md#L880)
-- [PR #205](https://github.com/flyingrobots/jedit/pull/205) established that
-  runtime-honesty gate. CR-00 through CR-05 subsequently landed the graph-rope,
-  coordinate, materialization, durability, and gutter prerequisites.
+- Production range `:why` returns a typed `WhyRange` obstruction:
+  `explainRange` in `src/adapters/workspace-production-text-session.ts` is an
+  unsupported operation on the Echo-hosted corridor.
+- The TypeScript range reader and graph-rope runtime this design first
+  targeted (`src/app/jedit-why-range.ts`, `src/domain/graph-rope-runtime.ts`,
+  and `spec/jedit-why-range.spec.mjs`) were removed in `a05cb427` with the rest
+  of the local text authority. Rope facts now live in the native Echo host under
+  the fact law in
+  [0158-replace-range-canonical-fact-law.md](0158-replace-range-canonical-fact-law.md).
+- The projection side survives: `src/ports/jedit-why-range.ts` defines the
+  report, and `src/app/workspace/workspace-why-range.ts` and
+  `workspace-why-range-details.ts` render it in the inline panel.
+- Checkpoint declarations and optional Echo anchor associations are separate
+  facts, so `:why` must not infer an anchor from a checkpoint.
+- [PR #205](https://github.com/flyingrobots/jedit/pull/205) established the
+  runtime-honesty gate this design implements: range `:why` must cite head,
+  leaf, blob, rewrite, diff, tick, and checkpoint evidence or say which is
+  missing. The evidence chain must come from a bounded Echo observation (a
+  future `jim.core`/`TextWindow` reading), not from a TypeScript reader.
 
 ## Problem
 
@@ -372,8 +350,9 @@ code. Human wording is localized outside the domain observation.
 - A checkpoint declaration does not imply an Echo anchor.
 - Echo owns admission, scheduling, causal control history, anchor facts, and
   Echo receipts.
-- The current graph-rope runtime may expose a transitional read seam, but the
-  observation contract must remain independent of its private map layout.
+- The range observation will come from the native host or a future
+  `jim.core`/`TextWindow` reading; the observation contract must remain
+  independent of any runtime's private fact layout.
 - Generated Edict operations will eventually own mutation invocation. This
   design adds no new handwritten mutation or inverse protocol.
 - Caches, line indexes, syntax readings, and rendered panels are disposable.
@@ -617,8 +596,6 @@ Commands expected before the CR-06 PR:
 
 ```bash
 npm run build
-node --test --test-concurrency=1 spec/rope-fact-inspector-design.spec.mjs
-node --test --test-concurrency=1 spec/jedit-why-range.spec.mjs
 node --test --test-concurrency=1 spec/workspace-command-line.spec.mjs
 npm run quality
 npm run check
@@ -684,7 +661,9 @@ Mitigations:
 What changed from the design:
 
 - The production range reader was added to the generated rope contract and
-  installed transport rather than exposed as a debug-only fact map.
+  installed transport rather than exposed as a debug-only fact map. That reader
+  was later removed with the local text authority in `a05cb427`; production
+  range `:why` is now a typed obstruction (see Current Truth).
 - The active inline panel retains the structured report as its application
   evidence payload. Gutter and footer projections consume that object instead
   of parsing the human message or copying provenance logic.
diff --git a/docs/design/0160-static-title-screen.md b/docs/design/0160-static-title-screen.md
index 53fbcf2b..b0e80b3e 100644
--- a/docs/design/0160-static-title-screen.md
+++ b/docs/design/0160-static-title-screen.md
@@ -136,7 +136,7 @@ reachable through the live workspace dependency graph.
 - Tests exercise runtime and rendered output, not design-document assertions.
 - Preserve editor behavior and the Echo authority boundary.
 - Use the existing `title-unfreeze` label under the
-  [freeze policy](../method/backlog/leash/title-scene-freeze.md). The human's
+  [freeze policy](../method/title-scene-freeze.md). The human's
   explicit removal request authorizes this narrow title integration change;
   engine/asset polish remains frozen.
 
diff --git a/docs/design/TEMPLATE.md b/docs/design/TEMPLATE.md
index 69e6ec78..4bf14658 100644
--- a/docs/design/TEMPLATE.md
+++ b/docs/design/TEMPLATE.md
@@ -3,7 +3,7 @@ title: "- - "
 legend: ""
 lane: "design"
 issue: "https://github.com/flyingrobots/jedit/issues/"
-status: "draft|active|landed|superseded"
+status: "draft|active|landed"
 owners:
   - "@flyingrobots"
 created: "YYYY-MM-DD"
@@ -196,7 +196,6 @@ stateDiagram-v2
   [*] --> Draft
   Draft --> Active
   Active --> Landed
-  Active --> Superseded
 ```
 
 ## Accessibility Posture
diff --git a/docs/design/echo-identity-doctrine.md b/docs/design/echo-identity-doctrine.md
index 65392039..709ea819 100644
--- a/docs/design/echo-identity-doctrine.md
+++ b/docs/design/echo-identity-doctrine.md
@@ -89,24 +89,12 @@ No export may claim full replay if it leaves dangling references.
    `(NamespaceId, AnchorId) -> LocalPath` or `(ImportInstanceId, AnchorId) -> LocalPath`.
 6. Rename and copy remain distinct even when snapshots are byte-identical.
 
-## Acceptance checkpoints for this doctrine
-
-- [ ] Same-content, different-path records keep `ContentRef` identical but preserve
-  declared worldline distinction.
-- [ ] Two empty buffers can coexist with shared genesis content but distinct
-  `WorldlineId`.
-- [ ] Rename preserves logical identity (`WorldlineId`) and changes only binding/path.
-- [ ] Copy mints a new `WorldlineId`, reuses current content snapshot, and
-  records `derived_from` to source lineage.
-- [ ] Imported WSC can be opened, forked, or adopted without changing transport
-  payload bytes.
-- [ ] Local anchor resolution is scoped by namespace/import instance, never `AnchorId -> LocalPath`.
-- [ ] WSC provenance completeness vs horizon-bounded partials are explicitly declared.
-- [ ] Replay remains deterministic under the same canonical bytes + declared IDs.
+## Acceptance
+
+Witnessing this doctrine is tracked in
+[#358](https://github.com/flyingrobots/jedit/issues/358).
 
 ## Reference
 
-Canonical source for implementation and policy follow-on:
-[ARCHITECTURE.md](../ARCHITECTURE.md),
-[docs/method/backlog/asap/echo-identity-doctrine.md](../method/backlog/asap/echo-identity-doctrine.md),
+Related: [ARCHITECTURE.md](../../ARCHITECTURE.md),
 [docs/echo-application-hosting-guide.md](../echo-application-hosting-guide.md).
diff --git a/docs/design/jedit-echo-graph-model.md b/docs/design/jedit-echo-graph-model.md
deleted file mode 100644
index b9740a21..00000000
--- a/docs/design/jedit-echo-graph-model.md
+++ /dev/null
@@ -1,977 +0,0 @@
-# Jedit Echo Reading Model
-
-Status: design sketch
-
-> **Ownership correction:** This sketch's phrase "jedit submits intent" is a
-> compatibility-era shorthand. Final production submits canonical events to
-> the `jim.core` package authored from `Jim.edict`; `jim.core` requests bounded
-> optics and derives operation intents from
-> its own state. Application reading and rewrite vocabulary lives in
-> `jedit.text`; `jim.core` consumes and composes those Edict lawpacks without
-> owning their private rope representation. Echo supplies generic admission,
-> interpretation, ticks, readings, receipts, and recovery without learning
-> editor or rope semantics.
-
-Purpose: describe the exact text reading shape and rewrite semantics `jedit`
-wants Echo-hosted contracts to support, without assuming handwritten Echo
-runtime edits.
-
-Terminology note: this file predates the stricter "there is no graph" doctrine.
-When it says "graph model," it means the graph-like reading vocabulary that the
-`jedit` contract can emit or rewrite lawfully over witnessed causal history.
-It does not mean Echo owns one canonical precomputed state object.
-
-This note is the detailed companion to:
-
-- [../../contracts/jedit/hot-text-runtime.graphql](../../contracts/jedit/hot-text-runtime.graphql)
-- [../../src/app/jedit-contract-runtime.ts](../../src/app/jedit-contract-runtime.ts)
-- [0005 - jedit-observer-spec](0005-jedit-observer-spec/jedit-observer-spec.md)
-- [0006 - optic-backed-file-model](0006-optic-backed-file-model/optic-backed-file-model.md)
-- [text-edit-algebra.md](text-edit-algebra.md)
-- [0004 - dynamic-footprint-binding-contract](0004-dynamic-footprint-binding-contract/dynamic-footprint-binding-contract.md)
-- [runtime-temperatures.md](runtime-temperatures.md)
-- [why-echo.md](why-echo.md)
-- [0003 - echo-backed-rope-worldline-contract](0003-echo-backed-rope-worldline-contract/echo-backed-rope-worldline-contract.md)
-
-## One Sentence
-
-`jedit` wants Echo to host canonical causal text history whose first useful
-reading shape centers on:
-
-`BufferWorldline -> RopeHead -> Rope DAG`
-
-with ticks as the canonical causal boundary, checkpoints as retained markers,
-anchors as first-class position carriers, and structural surfaces such as ASTs
-and diagnostics staying observer-relative rather than canonical.
-
-## Why This Exists
-
-I previously talked about "changing Echo," but the real ask is narrower and
-cleaner:
-
-- define the graph-like reading nouns that the editor kernel needs
-- define the lawful rewrites that may touch those nouns
-- make dishonest rewrites impossible or at least statically rejected
-- keep parser structure, UI state, and Git export layers out of canonical
-  text truth
-
-This document is therefore not a request for ad hoc runtime hacking. It is a
-request for a precise contract reading and rewrite model.
-
-The intended integration posture is optic-shaped:
-
-- Jedit submits a canonical event to the Echo-hosted `jim.core` observer
-- `jim.core` requests a `jedit.text` optic and derives any application intent
-- Echo admits generic substrate history and returns the deterministic result /
-  receipt envelope
-- `jim.core` handles the outcome and requests the resulting worldline reading
-- Jedit rendering code projects the returned reading into visible nouns such as
-  `BufferWorldline`, `RopeHead`, `TickReceipt`, and `WorldlineSnapshot`
-
-So Echo stays generic causal substrate truth. `jedit.text` owns the app-facing
-text contracts and private rope law; `jim.core` owns their editor-specific
-interpretation and composition. The Jedit body only transports and renders the
-resulting projections.
-
-The dynamic/static footprint split for these rewrites is defined in
-[0004 - dynamic-footprint-binding-contract](0004-dynamic-footprint-binding-contract/dynamic-footprint-binding-contract.md).
-The first authored GraphQL home for that boundary now lives in
-[../../contracts/jedit/hot-text-runtime.graphql](../../contracts/jedit/hot-text-runtime.graphql).
-That authored contract now also carries the first read-side surface:
-`worldlineSnapshot`, which is intentionally limited to canonical-head truth in
-v1 rather than pretending the runtime already supports arbitrary retained-head
-materialization.
-The first app-owned observer shape for that read-side boundary now lives in
-[0005 - jedit-observer-spec](0005-jedit-observer-spec/jedit-observer-spec.md),
-which intentionally starts with a memoryless canonical-head observer rather
-than pretending every read is already a full observer lifecycle.
-
-## What I Need Echo To Own
-
-Echo should own causal text history:
-
-- canonical editable text truth
-- head identity
-- tick admission
-- tick receipts
-- anchors and anchor transforms
-- checkpoints
-- later strands, braids, and admission
-
-Echo should not be required to own:
-
-- AST interpretation
-- diagnostics
-- preview rendering
-- file paths as canonical truth
-- editor panes, panels, or mode semantics
-- Git commit history as the source of causal text truth
-
-## What I Do Not Need As First-Class Text-History Nodes
-
-These are explicitly not required as causal text truth in v1:
-
-- one node per character
-- AST nodes as canonical text truth
-- one node per cursor movement
-- one node per viewport change
-- one node per keystroke forever-visible in user history
-- Git commits as the cadence of editor truth
-- file-on-disk as the canonical editable object
-
-The first text readings should stay text-native.
-
-## Minimal First-Class Node Kinds
-
-This is the node set I actually want to declare.
-
-### 1. `BufferWorldline`
-
-The canonical editable object.
-
-Responsibilities:
-
-- names the logical buffer identity
-- points to the current canonical head
-- owns the tick chain
-- owns checkpoint references
-- owns anchor membership
-- later owns strand membership
-
-Suggested fields:
-
-- `worldlineId`
-- `bufferKey`
-- `createdAtTick` or equivalent causal basis
-- optional app-facing metadata such as `projectionPath`
-
-Important note:
-
-- `projectionPath` is metadata, not truth
-- the worldline must remain lawful even when there is no file path or when the
-  path changes
-
-### 2. `RopeHead`
-
-The materialized causal head for one worldline state.
-
-Responsibilities:
-
-- names one specific rope state
-- points to the rope root node
-- carries aggregate text metrics for the whole head
-- serves as the basis for structural readings
-
-Suggested fields:
-
-- `headId`
-- `worldlineId`
-- `byteLength`
-- `lineCount`
-- `utf16Length`
-- `equivalenceDigest` or similar canonical digest
-
-Design note:
-
-- I do not strictly need both `RopeRoot` and `RopeHead` as separate node kinds
-- one `RopeHead` node that points at the root rope node is enough if that keeps
-  the schema simpler
-
-### 3. `RopeBranch`
-
-Interior rope node.
-
-Responsibilities:
-
-- ordered composition of child rope nodes
-- aggregate metrics for subtree navigation
-
-Suggested fields:
-
-- `branchId`
-- `byteLength`
-- `lineCount`
-- `utf16Length`
-- optional `height` or balancing metadata
-
-### 4. `RopeLeaf`
-
-Leaf rope node pointing at immutable text storage.
-
-Responsibilities:
-
-- represent one text slice in the rope
-- carry slice-local metrics
-- point at one blob plus a byte range
-
-Suggested fields:
-
-- `leafId`
-- `startByte`
-- `endByte`
-- `byteLength`
-- `lineCount`
-- `utf16Length`
-
-### 5. `TextBlob`
-
-Immutable storage unit for text bytes.
-
-Responsibilities:
-
-- hold immutable text payload
-- allow many leaves to reuse the same underlying bytes
-
-Suggested fields:
-
-- `blobId`
-- `encoding`
-- `byteLength`
-- `contentHash`
-
-Design note:
-
-- the payload may be externalized or stored in a content-addressed side store
-- I do not need the reading shape itself to inline arbitrarily large strings if Echo
-  prefers a blob store
-
-### 6. `Anchor`
-
-First-class logical position or interval.
-
-Responsibilities:
-
-- carry cursor, selection, bookmark, comment, diagnostic target, or AI target
-  identity
-- survive lawful text rewrites by deterministic transform
-
-Suggested fields:
-
-- `anchorId`
-- `kind`
-- `basisHeadId`
-- `startByte`
-- optional `endByte`
-- `startBias`
-- optional `endBias`
-- optional `stickiness`
-
-Design note:
-
-- anchors are not UI junk
-- they are required substrate truth because many later features depend on them
-
-### 7. `Tick`
-
-Canonical causal append boundary.
-
-Responsibilities:
-
-- record one admitted causal rewrite boundary
-- connect base head to next head
-- connect to its receipt
-- participate in the causal worldline chain
-
-Suggested fields:
-
-- `tickId`
-- `worldlineId`
-- `kind`
-- `sequenceNumber`
-- `author` or actor metadata if available
-
-### 8. `TickReceipt`
-
-Minimal witness for one tick.
-
-Responsibilities:
-
-- capture the lawful rewrite at a causal boundary
-- retain enough information to explain and replay the transition
-- drive anchor transforms
-
-Suggested fields:
-
-- `receiptId`
-- `tickId`
-- `baseHeadId`
-- `nextHeadId`
-- `rewriteKind`
-- `startByte`
-- `endByte`
-- `insertedByteLength`
-- `deletedByteLength`
-- optional `inverseFragmentDigest`
-- optional summary metadata
-
-Important note:
-
-- this is the transition witness
-- it should not be polluted by rope housekeeping details like split/merge/rotate
-
-### 9. `Checkpoint`
-
-Retained marker over the causal worldline.
-
-Responsibilities:
-
-- mark save points
-- mark explicit bookmarks or admissions later
-- allow durable history retention without freezing every primitive event forever
-
-Suggested fields:
-
-- `checkpointId`
-- `worldlineId`
-- `headId`
-- `kind`
-- `label`
-- `createdByEchoReceiptId`
-
-## Optional But Likely Later Node Kinds
-
-These are not required for the first useful cut, but I expect to want them.
-
-### `Strand`
-
-Alternate head lineage over shared ancestry.
-
-Used for:
-
-- draft alternatives
-- AI suggestions
-- speculative edits
-- later braid/admission semantics
-
-### `Braid`
-
-Explicit relation across multiple strands or heads.
-
-Used for:
-
-- compare/select/admit flows
-- structured alternative handling
-
-### `Admission`
-
-Explicit record that selected material from one strand or head was admitted into
-another.
-
-Used for:
-
-- partial acceptance
-- causal editorial history
-
-I do not need these in the first schema cut if they complicate initial progress,
-but the v1 reading model should not block them.
-
-## Edge Kinds I Actually Care About
-
-The edges matter as much as the node kinds.
-
-### Worldline ownership and current truth
-
-- `BufferWorldline -CANONICAL_HEAD-> RopeHead`
-- `BufferWorldline -HAS_TICK-> Tick`
-- `BufferWorldline -HAS_CHECKPOINT-> Checkpoint`
-- `BufferWorldline -HAS_ANCHOR-> Anchor`
-
-Later:
-
-- `BufferWorldline -HAS_STRAND-> Strand`
-
-### Tick chain and transition edges
-
-- `Tick -PREV_TICK-> Tick`
-- `Tick -BASE_HEAD-> RopeHead`
-- `Tick -NEXT_HEAD-> RopeHead`
-- `Tick -HAS_RECEIPT-> TickReceipt`
-
-This gives us:
-
-- causal history chain
-- explicit transition basis
-- explicit witness
-
-### Rope structure edges
-
-- `RopeHead -ROOT_NODE-> RopeBranch | RopeLeaf`
-- `RopeBranch -CHILD_AT[index]-> RopeBranch | RopeLeaf`
-- `RopeLeaf -SLICE_OF-> TextBlob`
-
-Important note:
-
-- child order is not optional
-- whether order lives as an edge property or child slot field is an
-  implementation detail, but it must be stable and deterministic
-
-### Checkpoint edges
-
-- `Checkpoint -AT_HEAD-> RopeHead`
-- optionally `Checkpoint -CAUSED_BY-> Tick`
-
-### Anchor edges
-
-I only need enough edge structure to keep anchors scoped and basis-bound.
-
-Minimal:
-
-- `BufferWorldline -HAS_ANCHOR-> Anchor`
-- `Anchor -BASIS_HEAD-> RopeHead`
-
-I do not need anchors to point directly into individual branch or leaf nodes if
-that makes transforms harder. Byte-range basis against a head is sufficient as
-long as transform law is strong.
-
-## Minimal Required Rewrite Families
-
-These are the rewrites I actually want to declare.
-
-## 1. `CreateBufferWorldline`
-
-Purpose:
-
-- create a new empty or seeded editable worldline
-
-Touches:
-
-- create `BufferWorldline`
-- create initial `RopeHead`
-- create initial rope node(s)
-- maybe create initial `TextBlob`
-- optionally create initial `Checkpoint`
-
-Semantics:
-
-- this is the seed event for a buffer truth
-- it may start empty or from a projected file snapshot
-
-Example conceptual input:
-
-```ts
-createBufferWorldline({
-  bufferKey: "src/main.ts",
-  initialText: "console.log('hello')\n"
-})
-```
-
-Expected outcome:
-
-- one worldline exists
-- one initial head exists
-- text materializes exactly to the provided initial text
-
-## 2. `ReplaceRangeAsTick`
-
-This is the most important rewrite.
-
-Purpose:
-
-- admit one lawful text rewrite into causal history
-
-Conceptually it combines:
-
-- `ReplaceRange`
-- tick admission
-- tick receipt emission
-
-Inputs I care about:
-
-- `worldlineId`
-- `baseHeadId`
-- `startByte`
-- `endByte`
-- inserted fragment or inserted text payload
-- optional actor metadata
-
-Reads:
-
-- current base head
-- touched rope path
-- touched blob slices
-
-Creates:
-
-- zero or more new `TextBlob`
-- zero or more new `RopeLeaf`
-- zero or more new `RopeBranch`
-- one new `RopeHead`
-- one new `Tick`
-- one new `TickReceipt`
-
-Updates logically:
-
-- `BufferWorldline.CANONICAL_HEAD`
-- tick chain membership
-
-Reuses:
-
-- every untouched subtree by identity
-
-Required laws:
-
-- no-op replace does not mint a tick
-- next head materializes exactly to the textual replacement result
-- unchanged subtrees are reused
-- tick receipt names base and next heads
-- anchor transform can be derived from the receipt
-
-Dynamic binding note:
-
-- the exact touched rope path and affected anchor set are runtime bindings
-- the lawful kinds of slots, closures, creates, and updates must still be
-  declared statically
-- see [0004 - dynamic-footprint-binding-contract](0004-dynamic-footprint-binding-contract/dynamic-footprint-binding-contract.md)
-
-Conceptual example:
-
-```ts
-replaceRangeAsTick({
-  worldlineId: "buf-1",
-  baseHeadId: "head-10",
-  startByte: 6,
-  endByte: 11,
-  insertText: "kind"
-})
-```
-
-If `head-10` materializes to:
-
-```text
-hello cruel world
-```
-
-then the next head must materialize to:
-
-```text
-hello kind world
-```
-
-and the rewrite should create:
-
-- a new blob for `"kind"` if needed
-- one or more new leaves/branches for the changed local path
-- a new head
-- a tick
-- a tick receipt
-
-It should not:
-
-- rebuild the whole rope
-- mutate old heads
-- require AST success
-
-## 3. `CreateCheckpoint`
-
-Purpose:
-
-- retain a meaningful marker over the current canonical causal head in v1
-
-Typical uses:
-
-- save
-- later admission marker once checkpoint scope widens explicitly
-
-Inputs:
-
-- `worldlineId`
-- `kind`
-- optional `label`
-
-Reads:
-
-- current worldline and its canonical head
-
-Creates:
-
-- one `Checkpoint`
-
-Must not do:
-
-- change the canonical head
-- clear tick history
-- rewrite text
-
-Conceptual example:
-
-```ts
-createCheckpoint({
-  worldlineId: "buf-1",
-  kind: "save",
-  label: "manual save"
-})
-```
-
-This should preserve:
-
-- existing canonical head
-- existing tick chain
-- existing edit-group policy in `jedit`
-
-## 4. `RegisterAnchor`
-
-Purpose:
-
-- create a durable logical point or interval over a head
-
-Inputs:
-
-- `worldlineId`
-- `basisHeadId`
-- start and optional end byte positions
-- bias/stickiness
-
-Creates:
-
-- one `Anchor`
-
-Design note:
-
-- this can be a small standalone rewrite or part of a broader app-level flow
-- I do not need it to be especially clever, but I do need it to be first-class
-
-## 5. `TransformAnchorAcrossTick`
-
-This can be implemented one of two ways:
-
-- as an explicit rewrite that updates persisted anchor basis and positions
-- or as a derived transform function over `TickReceipt`
-
-My preference:
-
-- make anchor transform derivable from the tick receipt
-- only persist anchor updates when the product truly needs persistence
-
-That means `ReplaceRangeAsTick` may read the affected anchor set to establish
-the lawful transform window, while still leaving persisted anchor movement out
-of the v1 rewrite itself.
-
-What I need semantically:
-
-- left-biased insertion stays before inserted text
-- right-biased insertion moves after inserted text
-- anchors after a replacement shift by the replacement delta
-- anchors inside deleted content collapse deterministically
-
-## Maintenance-Only Rewrite Families
-
-These are valid, but they must stay semantically separate from authorial text
-history.
-
-### `RebalanceHead`
-
-Purpose:
-
-- improve rope shape without changing materialized text
-
-Allowed effects:
-
-- create equivalent branch/leaf structure
-- maybe replace the internal root path of a head
-
-Must not change:
-
-- materialized text
-- logical byte positions
-- anchor behavior
-- author-facing tick semantics
-
-Important note:
-
-- if maintenance requires a new head identity, that identity must be typed as
-  maintenance and excluded from authorial history surfaces
-- better still, maintenance should remain below the level of canonical author
-  heads if Echo can model that honestly
-
-### `CompactBlobStore`
-
-Purpose:
-
-- deduplicate or compact blob storage
-
-Allowed effects:
-
-- rewrite physical storage representation
-- preserve logical blob content identity
-
-Must not change:
-
-- head materialization
-- logical receipt meaning
-- anchor transforms
-
-## Later Rewrite Families
-
-I do not need these in the first useful cut, but I do want the graph model to
-make them possible.
-
-### `ForkStrand`
-
-Purpose:
-
-- create an alternate editable future from an existing head
-
-### `AdmitStrandSlice`
-
-Purpose:
-
-- admit selected material from one strand or head into another
-
-### `CreateBraid`
-
-Purpose:
-
-- relate alternatives without flattening them into one branch/merge story
-
-## Focus Boundaries I Want Wesley To Enforce
-
-This is where the model gets especially important.
-
-I want the rewrite focus to be explicit enough that dishonest causal-history or
-reading mutation becomes a compile-time error.
-
-### `ReplaceRangeAsTick` should be allowed to touch
-
-- `BufferWorldline`
-- `RopeHead`
-- `RopeBranch`
-- `RopeLeaf`
-- `TextBlob`
-- `Tick`
-- `TickReceipt`
-- optionally `Anchor` if anchor persistence is part of the rewrite
-
-It should not be allowed to silently mutate:
-
-- unrelated worldlines
-- checkpoints
-- AST or diagnostics readings
-- Git export history
-- UI state
-
-### `CreateCheckpoint` should be allowed to touch
-
-- `BufferWorldline`
-- `Checkpoint`
-- `RopeHead`
-- optionally `Tick`
-
-It should not be allowed to mutate rope structure or text content.
-
-### `RegisterAnchor` should be allowed to touch
-
-- `BufferWorldline`
-- `Anchor`
-- `RopeHead`
-
-It should not be allowed to mint ticks or mutate rope content.
-
-### `RebalanceHead` should be allowed to touch
-
-- `RopeHead`
-- `RopeBranch`
-- `RopeLeaf`
-- `TextBlob` only if storage compaction genuinely needs it
-
-It should not be allowed to mutate:
-
-- checkpoints
-- other worldlines
-- structural reading state
-
-## Concrete Example: Typing Into An Empty Buffer
-
-Start state:
-
-- `BufferWorldline(buf-1)`
-- `RopeHead(head-0)` materializes to `""`
-- no ticks yet or one seed tick, depending on implementation
-
-Operation:
-
-```ts
-replaceRangeAsTick({
-  worldlineId: "buf-1",
-  baseHeadId: "head-0",
-  startByte: 0,
-  endByte: 0,
-  insertText: "hello"
-})
-```
-
-Expected result:
-
-- create `TextBlob(blob-1, "hello")`
-- create `RopeLeaf(leaf-1 -> blob-1[0..5])`
-- create `RopeHead(head-1 -> leaf-1)`
-- create `Tick(tick-1)`
-- create `TickReceipt(receipt-1)`
-- update `BufferWorldline(buf-1).CANONICAL_HEAD = head-1`
-
-Materialized text:
-
-```text
-hello
-```
-
-## Concrete Example: Replacing Interior Text
-
-Current text:
-
-```text
-hello cruel world
-```
-
-Possible existing leaves:
-
-```text
-leaf-a -> "hello "
-leaf-b -> "cruel"
-leaf-c -> " world"
-```
-
-Operation:
-
-```ts
-replaceRangeAsTick({
-  worldlineId: "buf-1",
-  baseHeadId: "head-10",
-  startByte: 6,
-  endByte: 11,
-  insertText: "kind"
-})
-```
-
-Expected result:
-
-- `leaf-a` reused
-- `leaf-c` reused
-- new blob and leaf for `"kind"`
-- new parent path
-- new head, tick, and receipt
-
-Materialized next text:
-
-```text
-hello kind world
-```
-
-The important part is local reuse. The rewrite should not clone `leaf-a` and
-`leaf-c` just because `leaf-b` changed.
-
-## Concrete Example: Save
-
-Current causal state:
-
-- worldline at `head-11`
-- ticks `tick-1 .. tick-9`
-
-Operation:
-
-```ts
-createCheckpoint({
-  worldlineId: "buf-1",
-  headId: "head-11",
-  kind: "save"
-})
-```
-
-Expected result:
-
-- one new checkpoint node
-- no new head
-- no text mutation
-- tick chain remains intact
-
-This is the exact reason save should not be modeled as "reset causal rope."
-
-## Concrete Example: Anchor Survives Edit
-
-Suppose there is a point anchor after `"hello"`:
-
-```ts
-registerAnchor({
-  worldlineId: "buf-1",
-  basisHeadId: "head-11",
-  startByte: 5,
-  bias: "right"
-})
-```
-
-Now we insert `" there"` at byte `5`.
-
-For a right-biased anchor, the transformed anchor should land after the
-inserted content, not before it.
-
-Conceptually:
-
-```ts
-const next = replaceRangeAsTick({
-  worldlineId: "buf-1",
-  baseHeadId: "head-11",
-  startByte: 5,
-  endByte: 5,
-  insertText: " there"
-})
-
-const moved = transformAnchorAcrossTick(anchor, next.receipt)
-```
-
-Expected logical result:
-
-- old text: `hello world`
-- new text: `hello there world`
-- old anchor at `5`
-- new right-biased anchor at `11`
-
-## Things I Expect To Stay Outside This Reading Model
-
-These should stay outside the Echo text reading model unless a later proof shows
-otherwise:
-
-- AST nodes
-- diagnostics
-- syntax spans
-- fold regions
-- file explorer state
-- active pane/focus state
-- preview mode state
-- Git branch metadata
-- workspace-level build output
-
-Those belong in observer readings, product state, or ecosystem projections.
-
-## Summary Of The Smallest Useful First Cut
-
-If I had to compress this to the smallest text reading and rewrite model that
-still feels honest, it would be:
-
-- `BufferWorldline`
-- `RopeHead`
-- `RopeBranch`
-- `RopeLeaf`
-- `TextBlob`
-- `Tick`
-- `TickReceipt`
-- `Checkpoint`
-- `Anchor`
-
-with these rewrites:
-
-- `CreateBufferWorldline`
-- `ReplaceRangeAsTick`
-- `CreateCheckpoint`
-- `RegisterAnchor`
-- derived or explicit `TransformAnchorAcrossTick`
-- maintenance-only `RebalanceHead`
-
-That is enough for:
-
-- canonical causal text truth
-- lawful local editing
-- save as checkpoint
-- anchor stability
-- structural reading basis for Graft
-
-without forcing ASTs, Git commits, or UI behavior into canonical causal text
-history.
diff --git a/docs/design/optic-session-bootstrap-contract.md b/docs/design/optic-session-bootstrap-contract.md
deleted file mode 100644
index 26db655d..00000000
--- a/docs/design/optic-session-bootstrap-contract.md
+++ /dev/null
@@ -1,104 +0,0 @@
-# Optic Session Bootstrap Contract
-
-## Status
-
-Draft contract slice for Stack Witness follow-up work.
-
-## Purpose
-
-jedit must request bounded readings through an opaque read-basis handle, not by
-carrying Echo substrate coordinates through app-facing code.
-
-This document defines the first anti-leak boundary only. It does not define the
-full optic protocol, Echo bootstrap API, Continuum schema, or publishing flow.
-
-## Contract shape
-
-```ts
-type ReadBasisHandle = {
-  readonly kind: 'read-basis-handle';
-  readonly id: string;
-};
-```
-
-The handle is opaque to jedit app-facing code. Its `id` is deterministic,
-diagnostic, and session-local, but it is not authority by itself. Authority is
-the registered handle object held below the adapter boundary; cloned objects
-with the same `id` must not resolve.
-
-The `id` is not a substrate coordinate, buffer key, file path, head id, or
-application semantic identifier.
-
-## App-facing flow
-
-```text
-client.openTextBuffer(...)
-  -> nextSession + ReadBasisHandle
-
-client.textWindow(nextSession, frontierRef, readBasisHandle, range)
-  -> TextWindowReading
-```
-
-`frontierRef` remains app-visible read identity and correlation material. It is
-not a license for app code to construct substrate coordinates.
-
-App-facing text-window input names editor range information only:
-
-```text
-cursorLine
-viewportLineCount
-beforeLines
-afterLines
-maxBytes
-```
-
-App-facing code must not construct read requests with:
-
-```text
-worldlineId
-basisRef
-headId
-tick
-root
-strand
-```
-
-Those coordinates belong below the optic/session adapter boundary.
-
-## Adapter responsibility
-
-The session or transport adapter owns the mapping:
-
-```text
-ReadBasisHandle -> runtime read coordinates
-```
-
-For the current jedit-only slice, the fake/session-local resolver maps the
-registered handle object back to the session worldline before encoding the
-existing fake Echo transport request. Handle IDs are deterministic process-local
-diagnostic tokens such as `read-basis:0`; they must not encode buffer keys,
-paths, worldlines, heads, ticks, roots, strands, or other meaningful
-coordinates.
-
-The current handle is a same-worldline read-target capability, not a
-head-pinned historical-basis proof. It may be reused after a local edit advances
-the same session worldline. Exact stale-basis obstruction belongs in a later
-head-pinned basis capability, not this first anti-leak contract slice.
-
-That preserves current behavior while proving the app-facing contract no longer
-needs raw substrate coordinates for `textWindow`.
-
-## Non-goals
-
-- No Echo change.
-- No Wesley change.
-- No Continuum change.
-- No production optic/session bootstrap protocol.
-- No publishing workflow.
-- No claim that the current local handle resolver is the durable runtime
-  implementation.
-
-## Acceptance
-
-jedit can request `textWindow` through an opaque `ReadBasisHandle`, while only
-the transport/session adapter knows how that handle maps to Echo coordinates.
diff --git a/docs/design/project-invariants.md b/docs/design/project-invariants.md
index d364fd0b..2345c329 100644
--- a/docs/design/project-invariants.md
+++ b/docs/design/project-invariants.md
@@ -200,8 +200,8 @@ Important decisions should land in inspectable docs, tests, and code, not live
 only in chat.
 
 Design docs define intent, but executable witnesses prove implementation.
-Design-doc assertions may support evidence ledgers, but they are not sufficient
-proof for product, runtime, UI, or tooling work.
+Tests never read documentation, so a design doc is never evidence that its
+contract holds.
 
 ### 19. Graceful degradation is mandatory
 
diff --git a/docs/design/runtime-temperatures.md b/docs/design/runtime-temperatures.md
index 59c7fda1..5afce0ea 100644
--- a/docs/design/runtime-temperatures.md
+++ b/docs/design/runtime-temperatures.md
@@ -26,8 +26,7 @@ Interpret them through the current doctrine:
 The old terms are compatibility labels. They are not ontology claims.
 
 The rationale for choosing Echo as native truth is written down in
-[why-echo.md](why-echo.md). The Optic-shaped file model is written down in
-[0006-optic-backed-file-model](0006-optic-backed-file-model/optic-backed-file-model.md).
+[why-echo.md](why-echo.md).
 
 ## Core Law
 
diff --git a/docs/design/structural-history-graphql-authority.md b/docs/design/structural-history-graphql-authority.md
deleted file mode 100644
index 073f610b..00000000
--- a/docs/design/structural-history-graphql-authority.md
+++ /dev/null
@@ -1,161 +0,0 @@
-# Structural History GraphQL Authority
-
-Status: schema-authority slice
-
-## Scope
-
-This slice extracts the current in-memory structural history model into a
-GraphQL contract without wiring runtime storage. The new authored SDL is
-[`contracts/jedit/structural-history.graphql`](../../contracts/jedit/structural-history.graphql).
-
-The TypeScript model was useful evidence. It is not the durable authority for
-buffer history, edit admission, edit grouping, checkpoints, or evidence-bearing
-readings.
-
-## Source Model Inspected
-
-- `src/adapters/full-snapshot-hot-text-runtime-fixture.ts`
-- `src/ports/hot-text-runtime.ts`
-- `src/domain/text-edit-contract.ts`
-- `src/domain/tick-admission-contract.ts`
-- `src/domain/edit-group-contract.ts`
-- `src/domain/save-checkpoint-contract.ts`
-- `src/app/text-buffer-session.ts`
-- `src/ports/jedit-optic-client.ts`
-
-The inspected behavior already separates the app-facing text buffer optic from
-the lower causal text runtime. This slice keeps that boundary: structural
-history is a product contract, not a storage backend.
-
-## Extraction Map
-
-Old TS concept -> GraphQL concept -> notes
-
-| Old TS concept | GraphQL concept | Notes |
-| :--- | :--- | :--- |
-| `HotTextBufferState.path` | `TextHistory.bufferKey`, `projectionPath` | A path-like key is metadata/projection context, not storage authority. |
-| `BufferRoot` | `TextRevision` | The schema names the meaning: one revision in a text history. It does not preserve the root implementation name. |
-| `TextRange` | `TextByteRange` | Half-open UTF-8 byte ranges stay explicit because existing behavior validates byte boundaries. |
-| `ReplaceReceipt` | `TextReplacement` plus `TextHistoryEvent.evidence` | Replacement shape and provenance are separate so evidence can evolve without mutating the event fact. |
-| `AdmittedTick` | `TextHistoryEvent` | The schema promotes the authorial event rather than the low-level tick name used by the placeholder model. |
-| `TickAdmissionReceipt` | `TextHistoryEvent.evidence` | A receipt remains first-class as evidence and can later bind to generated runtime artifacts. |
-| `EditGroup` / `OpenEditGroup` | `TextEditGroup.status` | Open and closed groups are one domain concept with explicit status. |
-| `SaveCheckpoint` | `TextCheckpoint` | Save is modeled as a revision marker over a projection path, not as a reset of editor truth. |
-| `Observed.evidence` | `TextHistoryEvidence` | Readings and command results carry citable evidence instead of anonymous wrapper fields. |
-| `TextWindowReading` | `TextHistorySnapshotReading.lines` | Bounded reads stay explicit and budgeted; full history materialization is not the default read. |
-
-## Canonical GraphQL
-
-`contracts/jedit/structural-history.graphql` is now the canonical contract for
-these app-owned facts:
-
-- `TextHistory`
-- `TextRevision`
-- `TextHistoryEvent`
-- `TextEditGroup`
-- `TextCheckpoint`
-- `TextHistoryProvenance`
-- `TextHistoryEvidence`
-- `TextHistorySnapshotReading`
-
-The contract also names command result status and validation error codes:
-
-- `TextHistoryCommandStatus`
-- `TextHistoryErrorCode`
-- `TextHistoryError`
-
-This prevents the old TypeScript result shapes from becoming invisible
-authority. Commands return explicit `APPLIED`, `NO_OP`, or `REJECTED` status
-with structured errors.
-
-## Transitional TypeScript
-
-Transitional TypeScript remains in place until generated replacements exist.
-The current in-memory adapter still preserves behavior for local tests and
-product development, but it should be read as an adapter/projection over the
-GraphQL contract direction.
-
-The following names are transitional evidence, not canonical schema names:
-
-- `HotTextBufferState`
-- `BufferRoot`
-- `TextFragment`
-- `AdmittedTick`
-- `OpenEditGroup`
-- `SaveCheckpointState`
-
-Future TypeScript should prefer generated contract names or thin adapter
-classes that translate to them. New app behavior should not add more
-hand-authored authority beside the SDL.
-
-## Wesley Generation
-
-Wesley generation should consume
-`contracts/jedit/structural-history.graphql` through the published
-`wesley-cli` 0.0.4 crate. The intended flow is:
-
-1. Author the domain contract in GraphQL.
-2. Generate TypeScript request, payload, and operation metadata from the SDL.
-3. Refactor the current adapter ports to accept generated inputs and return
-   generated payload shapes.
-4. Keep storage and substrate resolution behind ports.
-
-The first schema-authority slice deliberately did not add a package script
-because no generated artifact was consumed yet. The `replaceTextRange` metadata
-slice adds the local generation command below because a real adapter boundary
-now depends on generated operation identity.
-
-## First Metadata Consumer
-
-The first consumer is deliberately narrow:
-`src/app/structural-history-replace-text-range.ts` imports the build-generated
-`mutationReplaceTextRangeOperation` descriptor from
-`src/generated/jedit/structural-history-replace-text-range.wesley.generated.ts`.
-That descriptor carries the generated operation identity for
-`replaceTextRange`; the existing in-memory runtime still executes the edit via
-the old tick-admission model.
-
-The local generation command is:
-
-```sh
-npm run gen:contract:structural-history:wesley
-```
-
-It writes the full Wesley TypeScript output to
-`.wesley-cache/structural-history.wesley.generated.ts`, extracts the
-`mutationReplaceTextRangeOperation` descriptor, and writes the adapter-facing
-metadata file under `src/generated/jedit/`. That source file is ignored and is
-created by the build/test path rather than committed.
-
-The generator installs `wesley-cli` 0.0.4 into `.wesley-cache/cargo` when the
-expected binary is missing. This mirrors Echo's current direction: Echo's
-`echo-wesley-gen` consumes the published `wesley-core` 0.0.4 crate, while jedit
-uses the published CLI only to produce TypeScript operation metadata for this
-schema-authority slice.
-
-## Out Of Scope
-
-Runtime storage is out of scope. This slice does not:
-
-- implement a persistent store
-- migrate existing data
-- delete the current in-memory adapter
-- wire Echo, git-warp, SQLite, or file-cache internals into the schema
-- replace `hot-text-runtime.graphql`
-- change public editor behavior
-
-The next storage or runtime slice should start from generated contracts rather
-than treating the placeholder TypeScript structures as peer authority.
-
-## Validation Assumptions
-
-The current TypeScript code enforces these assumptions, and the schema names
-them as contract concepts rather than implementation quirks:
-
-- text replacement uses half-open UTF-8 byte ranges
-- no-op replacements produce no authorial event
-- admitted events have explicit sequence numbers
-- edit groups contain known admitted events only
-- checkpoints cite a revision and projection path
-- readings may be partial, stale, imported, fallback-translated, or native
-- command failures are structured status/error payloads, not thrown strings
diff --git a/docs/design/supported-outcome-settlement-and-why.md b/docs/design/supported-outcome-settlement-and-why.md
index ecde0ca4..ec5e23c1 100644
--- a/docs/design/supported-outcome-settlement-and-why.md
+++ b/docs/design/supported-outcome-settlement-and-why.md
@@ -1,6 +1,8 @@
 # Supported Outcome Settlement And `:why`
 
-Status: design note for WF-0108A.
+Status: accepted doctrine for how `:why` words runtime evidence. In production
+today, range `:why` returns a typed obstruction; this vocabulary governs it as
+explanation is implemented.
 
 Supported Outcome Settlement is the cross-repo doctrine that replaces the
 temporary ULTRAGOLD working name. For jedit, the doctrine matters because
@@ -23,6 +25,16 @@ Jim does not own:
 - XYPH Quest settlement;
 - proof-tier policy for a foreign authority.
 
+Jim is an Echo application. It does not talk to Echo through Continuum.
+Continuum matters only where Jim and Echo evidence must be portable to other
+Continuum participants (WARP TTD, Graft, WARP DRIVE, agents):
+
+| Layer | Owns | Does not own |
+| --- | --- | --- |
+| Jim / jedit | `:why` UX, command catalog, Vim command grammar, editor facts, JSON witness shape | Runtime admission or generic protocol doctrine |
+| Echo | Reading envelopes, receipts, retained evidence, runtime admission, replayable basis facts | Jim commands, Vim nouns, buffers, registers, macros |
+| Continuum | Portable profile vocabulary, evidence posture, participant discovery, conformance fixtures | Jim/Echo app integration, runtime implementation, editor app ontology |
+
 ## `:why` Outcome Vocabulary
 
 `:why` should distinguish:
diff --git a/docs/design/text-edit-algebra.md b/docs/design/text-edit-algebra.md
index 97c7ba77..a1bfbebe 100644
--- a/docs/design/text-edit-algebra.md
+++ b/docs/design/text-edit-algebra.md
@@ -15,10 +15,12 @@ work hardens the wrong abstractions.
 
 Event-class boundaries live in [causal-event-model.md](causal-event-model.md).
 The substrate choice is explained in [why-echo.md](why-echo.md).
-The detailed Echo-hosted text reading shape is described in
-[jedit-echo-graph-model.md](jedit-echo-graph-model.md).
-The static/dynamic rewrite-footprint split is described in
-[0004 - dynamic-footprint-binding-contract](0004-dynamic-footprint-binding-contract/dynamic-footprint-binding-contract.md).
+The native `ReplaceRange` fact law and its differential corpus are fixed in
+[0158-replace-range-canonical-fact-law.md](0158-replace-range-canonical-fact-law.md);
+the Edict-authored rope representation is drafted in
+[0159-edict-rope-representation.md](0159-edict-rope-representation.md).
+The static/dynamic rewrite-footprint split is
+[project invariant 14](project-invariants.md#14-footprint-schema-is-static-binding-is-dynamic).
 
 ## One Sentence
 
@@ -354,6 +356,22 @@ Anchor payload should support:
 
 Anchors transform through logical receipts, not through rope housekeeping.
 
+A point anchor transforms through one logical `ReplaceRange` delta (replace
+bytes `[startByte, endByte)` with `insertedByteLength` bytes) by these laws:
+
+1. An anchor before `startByte` is unchanged.
+2. At a pure insertion point, a left-biased anchor stays before the inserted
+   text and a right-biased anchor moves after it.
+3. An anchor at or after `endByte` shifts by the replacement's byte delta
+   (`insertedByteLength - (endByte - startByte)`).
+4. An anchor inside a replaced span collapses to `startByte`.
+
+`src/domain/anchor-transform-contract.ts` implements them, and
+`spec/anchor-transform.contract.spec.mjs` and
+`tests/anchor-transform-cycle.spec.mjs` pin them. Interval anchors,
+persistence, and editor integration are not specified yet
+([#359](https://github.com/flyingrobots/jedit/issues/359)).
+
 ## Suggested Runtime Shapes
 
 Illustrative only:
@@ -428,34 +446,17 @@ That gives the runtime:
 
 ## Persistence Direction
 
-The likely persistent shape is:
+The persistent shape is:
 
-- Echo-backed causal truth
-- `echo-text` schema for rope roots, blobs, anchors, and receipts
-- `.jedit/` for local persistence, refs, checkpoints, caches, and workspace
-  state
-- ordinary files as projections for interoperability
+- Echo-backed causal truth, recovered from the native host's Echo WAL
+  (`.jedit/echo-wal` by default)
+- `jedit.text` rope facts in Echo's graph, with the schema in
+  `contracts/jedit/lawpacks/replace-range-v1/text-schema-v1.json`
+- ordinary files as import sources and export projections
 
 Git is optional interop, not architecture.
 
-## Initial Build Order
-
-1. persistent piece-rope in memory
-2. `ReadRange`
-3. `ReplaceRange`
-4. anchor transforms
-5. undo groups
-6. strands
-7. strand-slice admission
-8. persistence to `.jedit/`
-9. Markdown and block-aware projections
-
-## Immediate Design Test
-
-The next useful test is simple:
-
-define the exact invariants, preconditions, and postconditions for
-`ReplaceRange`.
+## Build Order
 
-If that one operation feels elegant, the whole editor can stay clean.
-If it feels cursed, the architecture is just expensive poetry.
+The README's [Roadmap](../../README.md#roadmap) owns the order of work. The `ReplaceRange` law is fixed in
+0158, and the persistent rope is drafted in 0159.
diff --git a/docs/echo-application-hosting-guide.md b/docs/echo-application-hosting-guide.md
index ef3e922f..772ea4ff 100644
--- a/docs/echo-application-hosting-guide.md
+++ b/docs/echo-application-hosting-guide.md
@@ -11,8 +11,8 @@ Identity rules are governed by
 
 `Jim.edict` is the application and proposes work. Echo owns generic admission,
 scheduling, ticks, receipts, witnessed causal history, recovery, bounded
-program interpretation, and basis-pinned observation. Jim-owned Edict lawpacks
-own text semantics. Jedit/Bijou/native code owns terminal and process I/O plus
+program interpretation, and basis-pinned observation. `jedit.text` Edict
+lawpacks own text semantics, composed by `jim.core`. Jedit/Bijou/native code owns terminal and process I/O plus
 rendering. A TypeScript map, queue, runtime, or ledger may neither impersonate
 Echo authority nor interpret Jim commands and choose application operations.
 
@@ -38,9 +38,10 @@ The production workspace now performs this narrow path:
 8. Recover the graph and continue editing from Echo's runtime WAL after
    process restart.
 
-Create/open, single-range insert/replace/delete, and bounded text-window reads
-are implemented. Checkpoints, save/export, multi-range editing, undo/redo,
-causal gutter readings, and `:why` fail closed with typed obstructions.
+Create/open, single-range insert/replace/delete, checkpoint declaration, and
+bounded text-window reads are implemented. Save/export, multi-range editing,
+undo/redo, causal gutter readings, and range `:why` fail closed with typed
+obstructions.
 
 The prior raw WASM facade is deleted. It was not the product text path and no
 longer has a runnable side lane.
@@ -64,7 +65,7 @@ Echo owns:
 - canonical event interpretation, observation requests, operation intents,
   and outcome or obstruction handling.
 
-Jim-owned Edict lawpacks own:
+`jedit.text` Edict lawpacks own:
 
 - rope, buffer, checkpoint, range, and editor semantics;
 - application fact schemas, identities, results, and typed obstructions;
@@ -82,7 +83,7 @@ The Wesley compatibility package currently supplies:
 - canonical EINT codecs and operation ids generated from GraphQL;
 - package registry and artifact evidence;
 - generated mutation-rule and query-observer host helpers;
-- a typed Rust binding around the transitional Jim-owned operation law.
+- a typed Rust binding around the transitional operation law.
 
 Edict owns the generated semantic boundary:
 
@@ -256,7 +257,8 @@ parity by widening handwritten Rust operation APIs.
 
 The planned migration is:
 
-1. Author the exact Jim-owned `ReplaceRange.edict` source and closure.
+1. Author the persistent-rope `ReplaceRange.edict` in `jedit.text`; the
+   flat-text reference is already authored, built, and verified.
 2. Build it through Edict's public application-build boundary.
 3. Add only the generic Edict or Echo capabilities that the honest build proves
    missing; execute the exact verified package against the retained oracle.
@@ -265,7 +267,7 @@ The planned migration is:
 6. Make direct frontend operation orchestration and the bespoke Wesley/Rust
    replacement path unreachable, then delete them.
 7. Migrate buffer creation, checkpoint, save/export, undo/redo, and historical
-   explanation as Jim-owned lawpacks and bounded observations.
+   explanation as `jedit.text` lawpacks and bounded observations.
 8. Delete semantic JSONL operation glue once only the event/artifact membrane
    remains.
 
diff --git a/docs/jedit-echo-end-to-end.md b/docs/jedit-echo-end-to-end.md
index f1cc6b72..3f14a1cf 100644
--- a/docs/jedit-echo-end-to-end.md
+++ b/docs/jedit-echo-end-to-end.md
@@ -43,7 +43,8 @@ Jim has one production text-authority posture:
 2. The host initializes a real `WorldlineRuntime`, filesystem runtime WAL, and
    deterministic Echo engine.
 3. The host registers the checked generated package for buffer creation,
-   single-range replacement, and bounded text-window observation.
+   single-range replacement, checkpoint declaration, and bounded text-window
+   observation.
 4. Mutations enter through Echo's WAL-acknowledged app capability, receive
    Echo-owned installed-operation admission evidence, and execute only during a
    scheduler-owned tick.
@@ -58,7 +59,9 @@ builder, snapshot fallback, or optimistic settled-text mutation.
 
 The real corridor currently implements:
 
-- create or reopen a buffer;
+- create a buffer, or reopen one whose import anchor matches the file's current
+  bytes (otherwise the open is a typed obstruction; see
+  [How Jim sees source files](jim-component-ownership.md#how-jim-sees-source-files));
 - insert text through single-range replacement;
 - replace one UTF-8 byte range;
 - delete one UTF-8 byte range;
@@ -69,7 +72,7 @@ The real corridor currently implements:
 These operations remain typed obstructions:
 
 - multi-range edits;
-- checkpoint declaration and causal-anchor association;
+- causal-anchor association (checkpoint declaration itself is implemented);
 - save and export;
 - causal line-diff and gutter evidence;
 - `:why` range explanation;
@@ -97,8 +100,8 @@ features through a second authority.
 | Terminal loop and surfaces | Bijou |
 
 This table describes what is running, not what should remain. In the target,
-`Jim.edict` owns modal state and event interpretation; Jim-owned lawpacks own
-operations and optics; Jedit/Bijou/native adapters only decode events,
+`Jim.edict` owns modal state and event interpretation; `jedit.text` lawpacks own
+operations and optics, composed by `jim.core`; Jedit/Bijou/native adapters only decode events,
 transport artifacts, and render projections. Jim treats Echo-issued head, tick,
 commit, receipt, and reading identities as opaque.
 
@@ -285,9 +288,6 @@ JEDIT_DIST_PREBUILT=1 node --test spec/workspace-production-echo-wiring.spec.mjs
 node scripts/jedit-production-cutover-guard.mjs
 ```
 
-The older Echo WASM smoke witness proves a separate module-load boundary only.
-It is not the production text path and is not evidence that this package ran.
-
 ## Edict Migration
 
 The compatibility corridor exists to apply product pressure now, not to become
@@ -304,7 +304,7 @@ permanent protocol law. The convergence order is:
 6. Make the Wesley/Rust replacement path and frontend operation orchestration
    unreachable, then delete them.
 7. Migrate buffer create/open, checkpoint, save/export, and inverse operations
-   as Jim-owned Edict lawpacks and bounded readings.
+   as `jedit.text` Edict lawpacks and bounded readings.
 8. Delete the compatibility package and semantic process protocol.
 
 No migration step may restore local text authority to make the editor appear
diff --git a/docs/jim-component-ownership.md b/docs/jim-component-ownership.md
index c4e32f74..e235bf1d 100644
--- a/docs/jim-component-ownership.md
+++ b/docs/jim-component-ownership.md
@@ -4,14 +4,13 @@ date: 2026-08-22
 author: James Ross
 description: "A guided map of Jim's editor mind, text capability, causal settlement, runtime, UI body, compiler, structural intelligence, compatibility layers, and external-effect boundaries."
 tags: [jim, jedit, edict, echo, architecture, ownership, causal-rope]
-draft: true
-status: review
+draft: false
+status: accepted
 project: jedit
 related:
   - ../ARCHITECTURE.md
-  - BEARING.md
+  - ../README.md
   - jedit-echo-end-to-end.md
-  - stack-map.md
 ---
 
 # Jim: Components, Responsibilities, and Ownership
@@ -445,7 +444,7 @@ positive responsibility and the forbidden expansion for each participant.
 | Bijou | Terminal UI substrate | Terminal event decoding support, surface lifecycle, focus, layout, paint | Modes, motions, rope law, causal truth | Exists and remains part of the target body |
 | Native adapters | Process bootstrap and raw host capabilities | Echo process lifecycle, filesystem import/export, declared materialization guarantees, package transport, raw I/O | Native Jim planner callbacks or exaggerated filesystem authority in the final composition | Exists; the current Rust host still contains compatibility rope law |
 | `jim.core` / `Jim.edict` | Active observer and editor mind | Persistent editor state, event interpretation, observation requests, operation choice, command settlement composition, result handling | Rope representation, scheduling, WAL, receipt identity, terminal or filesystem mechanics | Target only; source not yet checked in |
-| `jedit.text` Edict capability | Reusable application-owned text model, operations, and optics | Buffer and head contracts, `ReplaceRange`, `CreateBuffer`, `DeclareCheckpoint`, `TextWindow`, slices, diffs, rope invariants, and typed text outcomes | Jim modes, commands, registers, cursor policy, Echo admission, host syscalls | Schema and oracle are frozen; executable sources are not yet authored |
+| `jedit.text` Edict capability | Reusable application-owned text model, operations, and optics | Buffer and head contracts, `ReplaceRange`, `CreateBuffer`, `DeclareCheckpoint`, `TextWindow`, slices, diffs, rope invariants, and typed text outcomes | Jim modes, commands, registers, cursor policy, Echo admission, host syscalls | Schema and oracle are frozen; a pure flat-text `ReplaceRange.edict` reference is authored, compiled, and verified; the persistent-rope operation and the other sources are not yet authored |
 | `jim.external-policy` | Jim's policy for external authorities | Import, export, provider selection, expected-fingerprint, guarantee-class, conflict, and reconciliation decisions | Ambient paths, raw syscalls, or claims that an external effect committed or was authored without matching evidence | Target contract defined here; no executable provider protocol yet |
 | `JimRelease` | Immutable executable application composition | Complete transitive package, standard-library, schema, codec, entry-point, instruction-set, execution-profile, verifier, effect-protocol, migration, and command-relevant provider closure | Ambient “latest package� lookup or reinterpretation of historical events | Target contract defined here; exact manifest schema, artifact store, and activation protocol remain unimplemented |
 | Edict | Language, compiler, package builder, and verifier boundary | Parsing, typing, authority closure, Core IR, Target IR lowering, canonical package construction, independent verification | Running Jim, choosing events, or committing graph state | Generic prerequisites have landed; Jim is the next real consumer |
@@ -1224,19 +1223,12 @@ but contradictory prose.
 | How does save survive a host crash or intervening writer? | The file is correctly described as an export projection, but no executable effect provider or compare-and-swap contract exists | Define stable intent and outcome identities, fingerprints, immutable content references, idempotency keys, guarantee and certainty classes, effect evidence, authorship classification, indeterminate supersession, leases and fencing where available, and recovery decisions |
 | Can the UI combine inconsistent bases? | Projections are disposable, but the current target has no canonical view-basis contract | Make every Jim state declare its presentation head and coordinate bases; render only a valid view basis and withhold optional Graft data when its basis differs |
 | Are all unhappy outcomes obstructions? | Current prose and contracts emphasize typed obstructions | Freeze separate normal-domain, obstruction, admission, compiler, external-effect, and runtime-fault result classes |
-| Is checkpoint declaration supported today? | The native host registers, admits, persists, and returns `RopeCheckpointDeclared` evidence; `docs/BEARING.md` records it as implemented | Remove stale claims that checkpoint always fails closed; retain the distinction from causal anchors and text mutation |
+| Is checkpoint declaration supported today? | The native host registers, admits, persists, and returns `RopeCheckpointDeclared` evidence; the README's *Current posture* records it as implemented | Remove stale claims that checkpoint always fails closed; retain the distinction from causal anchors and text mutation |
 | What exactly is a canonical event envelope? | The target sequences require one, but the final wire schema is not yet frozen | Define one opaque transport contract: Jedit decodes raw input, Echo carries the envelope without interpreting Jim fields, and only `jim.core` assigns editor meaning |
 | Which TypeScript paths still own semantics? | Vim parsing, motion resolution, coordinate conversion, operation selection, and transition planning are executable today | Classify them explicitly as compatibility authority, not merely import or migration plumbing |
 | Who owns text and rope contracts in target prose? | Some older documents say “Jedit� broadly, while the first draft grouped them under Jim | Name `jedit.text` as the application-owned text capability, `jim.core` as its semantic consumer, and Jedit as the product/body composition |
-| Do documentation tests prove the canonical section? | Some policy tests search required phrases anywhere in a document | Scope tests to the named ownership sections and assert the complete contract, including test-only direct `ReplaceRange` invocation |
 | Does the target exist in code? | A compiler-produced pure flat-text `ReplaceRange.edict` reference exists; the authored persistent-rope operation, `Jim.edict`, `TextWindow.edict`, `JimRelease`, authority realms, durable conflict resolution, and materialization guarantee providers remain absent or unproven | Keep every target statement labeled as target until compiler, runtime, recovery, and external-effect evidence exists |
 
-There is also a procedural gap. The clean architecture worktree is one commit
-ahead of current Jedit `main`, and PR #300 carries these ownership corrections,
-but it remains blocked by five unresolved review threads. This document is a
-review draft on that branch; it is not merged architecture doctrine and must
-not be cited as production evidence.
-
 In summary, the remaining disagreements are not about whether Echo should
 learn Jim vocabulary. They are about making every document and executable
 guard describe one pinned-release, durable-event, split Jim/text semantics,
@@ -1247,12 +1239,11 @@ generic-Echo model.
 
 This map was built by comparing canonical architecture claims with the code
 paths that currently make decisions. Documentation alone was insufficient,
-because the open architecture PR itself contains a stale checkpoint statement
-and under-classifies some compatibility authority.
+because documentation drifts from the code that actually decides.
 
 The audit followed these evidence layers:
 
-1. `ARCHITECTURE.md`, `docs/BEARING.md`, `docs/stack-map.md`, and
+1. `ARCHITECTURE.md`, the README's *Current posture*, and
    `docs/jedit-echo-end-to-end.md` supplied the declared target and current
    runtime corridor.
 2. `contracts/jedit/echo-text.graphql` supplied the current operation surface.
@@ -1266,9 +1257,8 @@ The audit followed these evidence layers:
 5. The frozen schema, codec vectors, and oracle under
    `contracts/jedit/lawpacks/replace-range-v1/` established what exists without
    pretending those artifacts are executable semantics.
-6. Live PR and issue state established that PR #300 is blocked, Jedit #296 is
-   the first operation slice, and the relevant generic Edict prerequisites have
-   landed.
+6. Issue state established that Jedit #296 is the first operation slice and
+   that the relevant generic Edict prerequisites have landed.
 
 One earlier line of thought treated a generic native rope capability as the
 likely answer. That was rejected because it would preserve application law
diff --git a/docs/method/backlog/asap/anchor-editor-integration.md b/docs/method/backlog/asap/anchor-editor-integration.md
deleted file mode 100644
index db77b973..00000000
--- a/docs/method/backlog/asap/anchor-editor-integration.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: anchor-editor-integration
-lane: asap
-owner: jedit editor
-priority: medium
-keywords:
-  - anchors
-  - editor
-  - selections
-  - diagnostics
-blocked_by:
-  - interval-anchor-semantics
-acceptance_criteria:
-  - The editor-facing model uses anchor semantics for at least selections and one additional range-bearing concept such as diagnostics, comments, or AI targets.
-  - Edits update those editor-facing ranges through the anchor law instead of ad hoc offset math.
-  - The cycle does not widen the text-domain contract; it consumes the existing point and interval semantics.
----
-
-# anchor-editor-integration
-
-Wire stable anchor semantics into the editor-facing model so selections,
-comments, diagnostics, and AI target ranges can survive text edits.
-
-This slice belongs after the anchor law is stable. The point is to prove the
-editor can consume the domain semantics cleanly instead of growing more ad hoc
-offset logic.
-
-## Non-goals
-
-- [ ] Redesigning the editor shell.
-- [ ] Echo adapter work.
-- [ ] Storage or persistence work.
diff --git a/docs/method/backlog/asap/anchor-friendly-buffer-positions.md b/docs/method/backlog/asap/anchor-friendly-buffer-positions.md
deleted file mode 100644
index b2fade11..00000000
--- a/docs/method/backlog/asap/anchor-friendly-buffer-positions.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-title: anchor-friendly-buffer-positions
-lane: asap
-owner: jedit runtime
-priority: medium
-keywords:
-  - anchors
-  - positions
-  - cursor
-  - selections
-  - runtime
-acceptance_criteria:
-  - Internal cursor/selection/bookmark positions move toward anchor-friendly semantics rather than brittle ad hoc offsets.
-  - The implementation leaves room for future point and interval anchor integration instead of hard-wiring UI-specific position logic everywhere.
-  - Editor-facing positions remain fast enough for current TUI use.
-  - The work does not require Echo or persistence to be useful.
----
-
-# anchor-friendly-buffer-positions
-
-Start paying down the gap between the current editor cursor model and the
-future anchor-based runtime model.
-
-Context:
-
-- The backlog already contains point and interval anchor law work.
-- `jedit` will eventually want comments, diagnostics, AI targets, and stable
-  selections that survive edits better than raw offsets do.
-- The editor does not need the full anchor system yet, but it should stop
-  making that future harder.
-
-## Non-Goals
-
-- Persisted anchor serialization.
-- Full anchor UI.
-- Echo adapter wiring.
diff --git a/docs/method/backlog/asap/anchor-persistence-contract.md b/docs/method/backlog/asap/anchor-persistence-contract.md
deleted file mode 100644
index fc6de6c7..00000000
--- a/docs/method/backlog/asap/anchor-persistence-contract.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-title: anchor-persistence-contract
-lane: asap
-owner: jedit runtime
-priority: medium
-keywords:
-  - anchors
-  - persistence
-  - serialization
-blocked_by:
-  - interval-anchor-semantics
-acceptance_criteria:
-  - The contract defines how point and interval anchors serialize and reload without leaking Echo storage details into the domain law.
-  - The design names the stable persisted fields for anchor identity, boundaries, and bias or gravity semantics.
-  - The cycle stays at the contract layer and does not require a production persistence adapter.
----
-
-# anchor-persistence-contract
-
-Define how point and interval anchors serialize and reload without leaking
-storage or Echo-specific persistence details into the domain contract.
-
-This slice should happen only after point and interval semantics are stable. The
-deliverable is a contract that can later be hosted by filesystem or Echo
-adapters without changing the domain law.
-
-## Non-goals
-
-- [ ] Production persistence implementation.
-- [ ] Echo adapter implementation.
-- [ ] Editor UI integration.
diff --git a/docs/method/backlog/asap/bounded-text-window-optic-reader.md b/docs/method/backlog/asap/bounded-text-window-optic-reader.md
deleted file mode 100644
index c20ac276..00000000
--- a/docs/method/backlog/asap/bounded-text-window-optic-reader.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: bounded-text-window-optic-reader
-lane: asap
-owner: jedit editor
-priority: high
-keywords:
-  - optic
-  - viewport
-  - text-window
-  - large-files
-  - observer
-acceptance_criteria:
-  - The editor-facing read path can request a bounded text window from an optic by cursor, viewport, and byte budget.
-  - The returned reading includes line numbers, text, byte spans, total line count, and before/after continuation flags.
-  - Source painting no longer requires a full-file string as the normal read result.
-  - Tests cover a file larger than the old eager-load cap and assert that the public reading is window-bounded.
-  - Any temporary internal materialization in the fake is documented as fake-only and not part of the app contract.
----
-
-# bounded-text-window-optic-reader
-
-Replace the normal source-read model with bounded Text File Optic readings.
-
-Context:
-
-- The current large-file fix removed a bad cap, but it still leaves the editor
-  conceptually close to whole-file loading.
-- The future editor should ask for the visible window plus a small margin.
-- The optic read should be a reading envelope, not a mutable buffer handle.
-
-This task should make source rendering depend on `TextWindowReading` style data
-before the real Echo API exists.
-
-## Non-Goals
-
-- Solving every scroll-cache and line-index performance detail.
-- Removing all full materialization paths used by explicit snapshot or save
-  operations.
-- Implementing Graft structural projection streaming.
-
diff --git a/docs/method/backlog/asap/braid-backed-file-projection-optic.md b/docs/method/backlog/asap/braid-backed-file-projection-optic.md
deleted file mode 100644
index e6188f3d..00000000
--- a/docs/method/backlog/asap/braid-backed-file-projection-optic.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: braid-backed-file-projection-optic
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - braid
-  - strand
-  - optic
-  - projection
-  - echo
-acceptance_criteria:
-  - The repo defines how a Text File Optic can focus a worldline plus an active braid.
-  - The first braid law is sequential: each new edit forks from the current braid projection frontier.
-  - Reads observe the projected braid state, not an editor-local patch list.
-  - Writes carry the braid frontier coordinate and either admit the next strand or return an obstruction.
-  - Tests or design examples cover `baseline + S0 + S1 + S2` projection behavior.
----
-
-# braid-backed-file-projection-optic
-
-Define the first braid-backed Text File Optic model.
-
-Context:
-
-- Echo has strands and braids as first-class concepts.
-- `jedit` wants a file to be readable and writable as a worldline plus active
-  braid projection.
-- For the first useful model, edits can be sequential: each next strand forks
-  from the current projected frontier.
-
-This task should keep the braid projection in Echo-shaped causal vocabulary
-rather than recreating a local patch-list authority inside the editor.
-
-## Non-Goals
-
-- Full multi-user merge policy.
-- Rich visual braid inspection UI.
-- Wormhole or history-compaction implementation.
-
diff --git a/docs/method/backlog/asap/buffer-truth-and-projection-boundary.md b/docs/method/backlog/asap/buffer-truth-and-projection-boundary.md
deleted file mode 100644
index 7fc75e3f..00000000
--- a/docs/method/backlog/asap/buffer-truth-and-projection-boundary.md
+++ /dev/null
@@ -1,41 +0,0 @@
----
-title: buffer-truth-and-projection-boundary
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - buffer
-  - projections
-  - architecture
-  - truth
-  - editor
-acceptance_criteria:
-  - The codebase makes a hard distinction between buffer truth and derived projections such as preview, outline, footer context, and future AST views.
-  - Source rendering, markdown preview, and Graft-backed views all consume projections rather than mutating buffer truth directly.
-  - Dirty-buffer posture becomes easier to state because saved-file and in-memory projections are not conflated.
-  - The seam is explicit enough to support future Echo/Graft adapters cleanly.
----
-
-# buffer-truth-and-projection-boundary
-
-Make it explicit that the editable buffer is the canonical runtime object and
-everything else is a projection.
-
-Context:
-
-- This has already shown up in conversation around causal editing, Markdown
-  preview, and Graft-backed structure.
-- If we let preview, outline, source paint, and save semantics blur together,
-  the editor will become harder to evolve before the real causal substrate
-  even exists.
-- The schema-authority path for buffer truth now starts at
-  `contracts/jedit/structural-history.graphql`, with
-  `docs/design/structural-history-graphql-authority.md` explaining how the
-  current in-memory TypeScript model maps into canonical GraphQL.
-
-This note is the architectural version of "don’t lie to yourself."
-
-## Non-Goals
-
-- Implementing Echo now.
-- Replacing plain files as the visible artifact.
diff --git a/docs/method/backlog/asap/causal-history-retention-and-compaction-policy.md b/docs/method/backlog/asap/causal-history-retention-and-compaction-policy.md
deleted file mode 100644
index f4303190..00000000
--- a/docs/method/backlog/asap/causal-history-retention-and-compaction-policy.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: causal-history-retention-and-compaction-policy
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - retention
-  - compaction
-  - receipts
-  - transactions
-  - checkpoints
-  - causal
-acceptance_criteria:
-  - The repo defines separate retention horizons for raw edit receipts, transactions, and checkpoints/admissions.
-  - Save semantics are explicit: save is a checkpoint, not a reset.
-  - The design states what survives within a session, across save, across restart, and into longer-term Echo-backed durable history.
-  - Compaction is explicitly allowed for fine-grained edit receipts without losing higher-level transaction truth or retained witness.
----
-
-# causal-history-retention-and-compaction-policy
-
-Decide how much editor causality we keep and for how long.
-
-Context:
-
-- `jedit` does not want to lose useful causal history on save.
-- `jedit` also should not keep every keystroke forever by default.
-- The causal runtime strata already suggest separate retention horizons for raw
-  receipts, transactions, checkpoints/admissions, retained suffixes, and
-  ecosystem exports.
-
-This note should turn that into an explicit retention and compaction policy so
-short-horizon receipts, durable Echo history, graph-like readings, and
-filesystem/Git projections have a lawful handoff.
-
-## Non-Goals
-
-- Finalizing every storage backend.
-- Committing to indefinite retention for raw keystroke history.
-- Treating save as a destructive boundary that discards editor truth.
diff --git a/docs/method/backlog/asap/causal-optic-pane-demo.md b/docs/method/backlog/asap/causal-optic-pane-demo.md
deleted file mode 100644
index e9d106d3..00000000
--- a/docs/method/backlog/asap/causal-optic-pane-demo.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: causal-optic-pane-demo
-lane: asap
-owner: jedit editor
-priority: medium
-keywords:
-  - pane
-  - optic
-  - preview
-  - focus
-  - ux
-acceptance_criteria:
-  - A temporary pane can show a proposal preview, checkpoint comparison, or second viewport as an Optic reading.
-  - The pane has a clear subject, basis posture, and dismiss path.
-  - Focus ownership is visible and footer hints change while the pane owns input.
-  - Inactive panes do not advertise active controls.
-  - Tests or scripted fixtures cover opening, focusing, and dismissing the pane.
----
-
-# causal-optic-pane-demo
-
-Prototype causal panes as focused Optic views instead of generic splits.
-
-Context:
-
-- The v1 direction says panes should be semantic views, not layout clutter.
-- The fake Echo demo needs a preview surface for proposal and checkpoint
-  comparisons.
-- This is the first chance to judge whether causal panes preserve the zen
-  editor feeling.
-
-First pane subjects:
-
-- current vs proposal
-- current vs last checkpoint
-- same file, different bounded window
-
-The pane should appear because the user is deciding something or inspecting a
-specific subject. It should be cheap to dismiss.
-
-## Non-Goals
-
-- Persistent multi-pane workspace management.
-- Complete split layout controls.
-- Rich graphical history visualization.
diff --git a/docs/method/backlog/asap/checkpoint-footer-posture.md b/docs/method/backlog/asap/checkpoint-footer-posture.md
deleted file mode 100644
index bd50e55c..00000000
--- a/docs/method/backlog/asap/checkpoint-footer-posture.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: checkpoint-footer-posture
-lane: asap
-owner: jedit editor
-priority: high
-keywords:
-  - checkpoint
-  - footer
-  - save
-  - ux
-  - causal
-acceptance_criteria:
-  - Saving through the demo submits a checkpoint Intent and receives checkpoint posture from the fake Echo-shaped transport.
-  - The footer distinguishes current mode, focus owner, checkpoint identity, and ahead-of-checkpoint edit count without Git-shaped wording.
-  - Dirty posture compares the current coordinate to the last checkpoint coordinate.
-  - A stale or failed checkpoint path has a calm visible recovery message.
-  - Tests cover footer strings for clean, ahead-of-checkpoint, and checkpoint obstruction states.
----
-
-# checkpoint-footer-posture
-
-Make save and dirty state feel like checkpoint truth in the editor footer.
-
-Context:
-
-- `jedit` should treat save as a checkpoint, not as Git authority.
-- The footer is the right first surface for checkpoint posture because it
-  carries operational truth without crowding the editor.
-- The demo should let the human judge whether the wording is too quiet, too
-  loud, or right.
-
-The first version should prefer compact language:
-
-```text
-NORMAL | file.ts | checkpoint C12
-NORMAL | file.ts | checkpoint C12 +1 edit
-NORMAL | file.ts | checkpoint blocked: refresh needed
-```
-
-## Non-Goals
-
-- Complete checkpoint history browsing.
-- Git export status.
-- A full save preferences UI.
diff --git a/docs/method/backlog/asap/dirty-buffer-honesty-for-graft-backed-drawers.md b/docs/method/backlog/asap/dirty-buffer-honesty-for-graft-backed-drawers.md
deleted file mode 100644
index 2ea6f5e7..00000000
--- a/docs/method/backlog/asap/dirty-buffer-honesty-for-graft-backed-drawers.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-title: dirty-buffer-honesty-for-graft-backed-drawers
-lane: asap
-owner: jedit editor
-priority: high
-keywords:
-  - graft
-  - dirty-buffers
-  - honesty
-  - drawer
-  - editor
-acceptance_criteria:
-  - Any Graft-backed drawer content makes clear whether it reflects the current buffer or only the last saved file state.
-  - Dirty editor buffers show an explicit stale or saved-state posture instead of silently reusing on-disk structure as if it were current.
-  - Saving or manual refresh updates the drawer posture deterministically.
-  - The user can still get value from last-saved structure while the buffer is dirty.
----
-
-# dirty-buffer-honesty-for-graft-backed-drawers
-
-Make every Graft-backed panel in `jedit` truthful about saved versus unsaved
-state.
-
-Context:
-
-- Today the editor can be ahead of disk.
-- Current Graft surfaces are largely file/workspace oriented.
-- Until Graft supports buffer-aware outline/syntax surfaces, the editor must
-  not blur those two truths together.
-
-This is a product integrity task more than a visual task. The drawer should be
-allowed to show useful structure from disk, but it must say when it is doing
-that.
-
-## Non-Goals
-
-- Implementing buffer-aware parsing in Graft from the jedit side.
-- Blocking all drawer use whenever a buffer is dirty.
diff --git a/docs/method/backlog/asap/dynamic-footprint-binding-contract.md b/docs/method/backlog/asap/dynamic-footprint-binding-contract.md
deleted file mode 100644
index 8162d1d5..00000000
--- a/docs/method/backlog/asap/dynamic-footprint-binding-contract.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: dynamic-footprint-binding-contract
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - wesley
-  - footprint
-  - rewrite
-  - echo
-  - jedit
-acceptance_criteria:
-  - The repo defines the split between static footprint schema and dynamic runtime binding.
-  - The design names the minimum footprint vocabulary needed for `jedit`: slots, bindings, closures, creates, updates, and forbidden surfaces.
-  - `ReplaceRangeAsTick` is specified as a bounded causal-text rewrite whose dynamic rope/anchor bindings stay inside a statically declared closure.
-  - The design includes at least one second rewrite family, such as `CreateCheckpoint`, to prove the model is not specific to range replacement alone.
-  - The packet distinguishes compile-time honesty failures from runtime binding failures.
----
-
-# dynamic-footprint-binding-contract
-
-Define how `jedit`'s real causal-text rewrites should stay dynamically bound at
-runtime while still admitting compile-time honesty checks through Wesley.
-
-Context:
-
-- `jedit` does not operate on abstract `Foo` and `Bar` nouns. It operates on
-  `BufferWorldline`, `RopeHead`, `RopeBranch`, `RopeLeaf`, `TextBlob`,
-  `Anchor`, `Tick`, `TickReceipt`, and `Checkpoint`.
-- The most important rewrite, `ReplaceRangeAsTick`, cannot know its exact rope
-  path, blob reuse, or affected anchors until runtime.
-- The stack still wants dishonest rewrite access to fail statically when the
-  implementation tries to reach outside its declared causal-text focus.
-
-This note should define the contract that makes both things true:
-
-- dynamic runtime binding of real editor data
-- static honesty of the rewrite capability surface
-
-## Non-Goals
-
-- Implementing the full Wesley directive grammar in this cycle.
-- Implementing Echo runtime bindings in this repo.
-- Designing strand and braid admission for `jedit` v1.
-- Pretending the compiler can know exact runtime node identities ahead of time.
diff --git a/docs/method/backlog/asap/echo-anchor-adapter-contract.md b/docs/method/backlog/asap/echo-anchor-adapter-contract.md
deleted file mode 100644
index f7ac38c1..00000000
--- a/docs/method/backlog/asap/echo-anchor-adapter-contract.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: echo-anchor-adapter-contract
-lane: asap
-owner: jedit runtime
-priority: medium
-keywords:
-  - anchors
-  - echo
-  - adapter
-  - warp
-blocked_by:
-  - interval-anchor-semantics
-acceptance_criteria:
-  - The design defines the first adapter contract that maps Echo or WARP receipts and heads into the text-domain anchor transform law.
-  - The contract makes clear which data belongs to the domain seam and which belongs to the Echo adapter boundary.
-  - The cycle proves Echo can host the anchor law without leaking graph or storage details back into the domain contract.
----
-
-# echo-anchor-adapter-contract
-
-Define the first Echo-facing adapter contract that maps real WARP or Echo
-receipts and heads into the text-domain anchor transform law.
-
-This slice should come after interval-anchor semantics are defined. The point is
-to prove the domain contract can be hosted in Echo without leaking adapter
-detail back into the core.
-
-## Non-goals
-
-- [ ] Implementing the full Echo-backed text runtime.
-- [ ] Replacing the domain contract with Echo-native types.
-- [ ] Editor UI integration.
diff --git a/docs/method/backlog/asap/echo-identity-doctrine.md b/docs/method/backlog/asap/echo-identity-doctrine.md
deleted file mode 100644
index 2a9a0afe..00000000
--- a/docs/method/backlog/asap/echo-identity-doctrine.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-title: echo-identity-doctrine
-lane: asap
-owner: jedit architecture
-priority: high
-keywords:
-  - identity
-  - echo
-  - content-addressing
-  - worldline
-  - binding
-  - basis
-acceptance_criteria:
-  - `docs/design/echo-identity-doctrine.md` exists and is treated as canonical for identity semantics in this repo.
-  - The doctrine is linked from `ARCHITECTURE.md`, `BEARING.md`, and `docs/echo-application-hosting-guide.md`.
-  - "Same-content, different-path" preserves `ContentRef` while not forcing semantic sameness of local context.
-  - Two empty files can share genesis bytes but have distinct `WorldlineId`.
-  - Rename preserves `WorldlineId` while re-associating local binding/path.
-  - Copy creates a new `WorldlineId`, reuses current content snapshot, and records `derived_from` history.
-  - Import behavior supports at least `inspect`, `fork`, and `adopt` and policy survives reopen.
-  - Local anchor resolution is scoped as `(NamespaceId, AnchorId) -> LocalPath` (or `(ImportInstanceId, AnchorId) -> LocalPath`), never `AnchorId -> LocalPath`.
-  - WSC exports capture provenance claims and local binding hints without requiring ambient fields inside canonical hashes.
-  - WSC provenance scope is explicit (complete package or horizon-bounded with listed external tails).
----
-
-# echo-identity-doctrine
-
-This is the execution lock for the doctrine discussed in the design freeze.
-
-## What to implement
-
-- Add a canonical identity policy document in `docs/design/echo-identity-doctrine.md`.
-- Ensure planning and architecture docs point to that policy so the team cannot miss
-  it in day-to-day work.
-- Enforce implementation policy:
-  - values are `ContentRef`/`RecordRef` hashed from canonical bytes,
-  - logical things get declared IDs,
-  - names are binding slots,
-  - views are Basis slices,
-  - import of history is explicit about `inspect`/`fork`/`adopt`.
-- Model rename and copy as distinct operations:
-  - Rename keeps the same `WorldlineId` and updates binding/path slot.
-  - Copy creates a fresh `WorldlineId`, reuses current content state, and records
-    `derived_from` lineage to the source worldline tick.
-- Model anchor-locality with an explicit scope key:
-  - `LocalAnchorBinding = (NamespaceId | ImportInstanceId, AnchorId) -> LocalPath`.
-- Make export provenance explicit:
-  - complete exports and horizon-bounded exports are both valid; horizon-bounded
-    exports must enumerate provenance gaps and prevent replay-accuracy false claims.
-
-## Acceptance matrix
-
-- [ ] Same-content/different-path test: path is not treated as semantic truth.
-- [ ] Two empty files share genesis hash but not worldline identity.
-- [ ] Rename preserves `WorldlineId` across local slot/path reassociation.
-- [ ] Copy creates a new `WorldlineId` and emits `derived_from` links.
-- [ ] Local anchor resolution keys include namespace/import context.
-- [ ] WSC roundtrip test confirms portable slices do not accidentally inherit local
-  machine or install fields.
-- [ ] Re-open + imported-worldline tests verify import policy persistence.
-- [ ] WSC provenance horizon handling (complete vs bounded) is explicit and machine-checkable.
-
-## Why this card exists
-
-If this is not locked in now, future work re-invites:
-- conflating `RecordRef` and document identity,
-- treating `path` as semantic truth,
-- and shipping ambient coordinates into canonical payloads.
diff --git a/docs/method/backlog/asap/fake-echo-causal-ux-demo-spine.md b/docs/method/backlog/asap/fake-echo-causal-ux-demo-spine.md
deleted file mode 100644
index f856811b..00000000
--- a/docs/method/backlog/asap/fake-echo-causal-ux-demo-spine.md
+++ /dev/null
@@ -1,47 +0,0 @@
----
-title: fake-echo-causal-ux-demo-spine
-lane: asap
-owner: jedit editor
-priority: high
-keywords:
-  - demo
-  - echo
-  - optic
-  - ux
-  - causal
-acceptance_criteria:
-  - A demo path exercises open, bounded read, edit, receipt, checkpoint, proposal preview, and proposal accept through the fake Echo-shaped transport.
-  - The user-facing UI does not branch on fake runtime internals.
-  - The central editor remains the default surface and does not show a permanent causal debug log.
-  - Tests or scripted fixtures cover the happy path and one stale-basis obstruction.
-  - The demo can be run before the real Echo Optic API exists.
----
-
-# fake-echo-causal-ux-demo-spine
-
-Build the first product-visible fake Echo causal editing demo.
-
-Context:
-
-- The architecture needs a fake Echo harness before real Echo Optics are ready.
-- The product needs a real-feeling loop so the human can judge checkpoint,
-  proposal, obstruction, and pane posture.
-- The demo should prove the app boundary and the editor feeling at the same
-  time.
-
-The narrow spine is:
-
-```text
-Open -> Read Window -> Edit -> Receipt -> Checkpoint -> Proposal -> Preview -> Accept
-```
-
-The fake may use a simple in-memory causal text runtime internally. The app
-surface must still speak in readings, Intents, receipts, obstructions,
-checkpoints, and proposals.
-
-## Non-Goals
-
-- Real Echo persistence.
-- A full time rail.
-- A broad AI assistant UI.
-- Git export or Git-derived dirty state.
diff --git a/docs/method/backlog/asap/fake-echo-optic-transport-harness.md b/docs/method/backlog/asap/fake-echo-optic-transport-harness.md
deleted file mode 100644
index aafbc223..00000000
--- a/docs/method/backlog/asap/fake-echo-optic-transport-harness.md
+++ /dev/null
@@ -1,41 +0,0 @@
----
-title: fake-echo-optic-transport-harness
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - optic
-  - echo
-  - fake
-  - transport
-  - tests
-acceptance_criteria:
-  - Tests exercise a fake Echo-backed Text File Optic only through `EchoWasmKernelTransport`.
-  - The fake accepts encoded query and mutation bytes and returns encoded readings, receipts, or obstructions.
-  - App tests cannot call the legacy in-memory `HotTextRuntimePort` directly for file mutations.
-  - Boundary encoding and decoding stay inside an adapter or codec module.
-  - The fake proves stale-base rejection or obstruction for at least one edit.
----
-
-# fake-echo-optic-transport-harness
-
-Build the test harness that lets `jedit` prepare for Echo Optics before Echo
-ships the real API.
-
-Context:
-
-- The current `createInMemoryJeditOpticClient` is GraphQL-shaped but still maps
-  directly to app runtime calls.
-- The future seam should look like Echo: encoded Intent or query bytes enter a
-  transport, and encoded result bytes come back.
-- The fake may use the in-memory runtime internally, but that must not leak to
-  app-facing tests.
-
-This task is the first executable step after the planning packet because it
-lets later slices prove architecture with tests instead of chat.
-
-## Non-Goals
-
-- Cloning Echo inside `jedit`.
-- Guessing final EINT wire bytes.
-- Implementing the real Wesley-generated client.
diff --git a/docs/method/backlog/asap/filetype-detection-and-language-modes.md b/docs/method/backlog/asap/filetype-detection-and-language-modes.md
deleted file mode 100644
index bc2b3cec..00000000
--- a/docs/method/backlog/asap/filetype-detection-and-language-modes.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: filetype-detection-and-language-modes
-lane: asap
-owner: jedit editor
-priority: medium
-keywords:
-  - filetypes
-  - language-modes
-  - source
-  - preview
-  - editor
-acceptance_criteria:
-  - jedit detects useful filetype/mode information from path and content where reasonable.
-  - The editor can route files into the correct local render and interaction mode without hard-coding everything in the main loop.
-  - Markdown preview remains explicit rather than accidentally enabled for every text file.
-  - The mode system leaves room for future Graft-backed syntax spans and diagnostics.
----
-
-# filetype-detection-and-language-modes
-
-Give the editor a real notion of what kind of file it is showing.
-
-Context:
-
-- `jedit` wants to open markdown, text, TeX, source files, and likely config
-  formats without feeling like a single anonymous string viewer.
-- Local syntax paint and future Graft surfaces both want a filetype/mode seam.
-
-This note is about the editor’s own language posture, not external tooling.
-
-## Non-Goals
-
-- Full plugin architecture.
-- Language-server integration.
diff --git a/docs/method/backlog/asap/graft-drawer-precision-panels-using-current-graft-surfaces.md b/docs/method/backlog/asap/graft-drawer-precision-panels-using-current-graft-surfaces.md
deleted file mode 100644
index e74f7555..00000000
--- a/docs/method/backlog/asap/graft-drawer-precision-panels-using-current-graft-surfaces.md
+++ /dev/null
@@ -1,61 +0,0 @@
----
-title: graft-drawer-precision-panels-using-current-graft-surfaces
-lane: asap
-owner: jedit editor
-priority: medium
-keywords:
-  - graft
-  - drawer
-  - code-show
-  - code-refs
-  - changed-since
-acceptance_criteria:
-  - The Graft drawer can expose more than the current outline-only view using surfaces that already exist today.
-  - The drawer can present at least one additional precision panel such as references, changed-since, or focused-symbol context.
-  - The UI keeps panel switching keyboard-driven and bounded.
-  - Dirty-buffer honesty remains visible whenever a panel is based on saved-file state rather than buffer truth.
----
-
-# graft-drawer-precision-panels-using-current-graft-surfaces
-
-Extract more value from the Graft APIs that already exist before waiting on new
-buffer-aware parser surfaces.
-
-Context:
-
-- `jedit` already uses Graft for outline/context.
-- Graft already exposes `code_show`, `code_find`, `code_refs`,
-  `changed_since`, and structural diff surfaces.
-- There is editor value available right now in richer drawer modes even before
-  syntax spans or buffer-aware outline exist.
-
-This note is about broadening the drawer from "outline only" into a small set
-of precise, navigable panels.
-
-## Projection posture
-
-Every drawer panel must name the projection source it is showing and whether
-that source is stale or obstructed. The current production drawer often uses
-saved-file Graft surfaces while the editor may display dirty, unmaterialized,
-or Echo-local buffer text. That is valid enrichment, but it is not live buffer
-truth.
-
-Required posture labels:
-
-- `saved-file`: structural data came from the host file on disk.
-- `live-buffer`: structural data came from current visible buffer text.
-- `current-Echo-frontier`: structural data came from a selected Echo frontier.
-- `colorful-prose`: prose projection is active, but not structural outline.
-- `unavailable`: no projection source is currently usable.
-- `stale`: the projection source does not include visible buffer edits.
-- `obstructed`: Graft could not answer the requested projection.
-
-Dirty-buffer honesty is mandatory. If a panel is based on saved-file state, the
-drawer must visibly say that unsaved buffer edits are not included. Source
-highlighting and structural drawer projection are related Graft-backed
-surfaces, but they are separate receipts and may have different freshness.
-
-## Non-Goals
-
-- Replacing the editor with an IDE dashboard.
-- Shipping fake buffer-aware structure where Graft does not yet support it.
diff --git a/docs/method/backlog/asap/graft-hot-structural-projections-over-rope-heads.md b/docs/method/backlog/asap/graft-hot-structural-projections-over-rope-heads.md
deleted file mode 100644
index 6d0cc154..00000000
--- a/docs/method/backlog/asap/graft-hot-structural-projections-over-rope-heads.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: "graft-hot-structural-projections-over-rope-heads"
-lane: asap
-owner: "jedit editor"
-priority: high
-keywords:
-  - "graft"
-  - "structured-buffer"
-  - "syntax"
-  - "folds"
-  - "diagnostics"
-  - "projections"
-acceptance_criteria:
-  - `jedit` has a clear adapter contract for asking Graft for structural projections over current rope heads or equivalent live buffer snapshots.
-  - The design covers syntax spans, folds, diagnostics, node lookup, structural selection, rename preview, and semantic summary.
-  - The contract is explicit that these surfaces are structural readings over causal text truth, not a replacement for the rope-worldline.
-  - The design is honest about unsupported languages, partial parses, and stale-versus-current posture.
----
-
-# graft-hot-structural-projections-over-rope-heads
-
-Define how Graft should interpret live editor truth.
-
-Context:
-
-- Graft already has a strong `StructuredBuffer` surface for dirty in-memory
-  content, but it is still a parsed snapshot API.
-- `jedit` wants Graft-backed syntax highlighting, folding, diagnostics,
-  structural selection, and AST-aware lenses that feel live while typing.
-- That only works if Graft follows current rope heads or transaction heads
-  rather than waiting for Git commits.
-
-This note should lock the adapter seam between causal text truth and structural
-readings.
-
-## Non-Goals
-
-- Making Graft the canonical editable buffer runtime.
-- Solving every language or parser coverage problem up front.
-- Designing Git export storage.
diff --git a/docs/method/backlog/asap/graphql-authored-observer-family-cutover.md b/docs/method/backlog/asap/graphql-authored-observer-family-cutover.md
deleted file mode 100644
index 33f64df4..00000000
--- a/docs/method/backlog/asap/graphql-authored-observer-family-cutover.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-title: graphql-authored-observer-family-cutover
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - graphql
-  - observer
-  - wesley
-  - continuum
-  - jedit
-acceptance_criteria:
-  - The repo states how the current `ObserverSpec` slice should be re-expressed under the stronger rule that authored truth is GraphQL plus directives.
-  - The packet distinguishes authored family, compiled plan artifacts, and later runtime-emitted reading values.
-  - The cut explains how `worldlineSnapshot` should remain a proving slice without preserving a side authoring DSL by accident.
-  - The design names what stays app-owned in `jedit` versus what belongs to the Continuum observer module boundary.
----
-
-# graphql-authored-observer-family-cutover
-
-Reconcile `jedit`'s current observer-spec work with the now-locked doctrine
-that GraphQL is the authored language and directives are the extension
-mechanism.
-
-Context:
-
-- `jedit` already has a useful first proving slice around
-  `worldlineSnapshot`.
-- the repo currently still treats `ObserverSpec` as an app-authored object in
-  TypeScript.
-- the broader stack later froze a stronger rule:
-  - authored truth is GraphQL
-  - directives carry specialized semantics
-  - there is no parallel side DSL
-
-This item should stop that tension from lingering as folklore.
-
-## Non-Goals
-
-- Deleting the first observer slice.
-- Rewriting the whole `jedit` runtime in this cycle.
-- Turning generic Wesley into an observer host again.
-
diff --git a/docs/method/backlog/asap/graphql-authored-observer-plan-lowering.md b/docs/method/backlog/asap/graphql-authored-observer-plan-lowering.md
deleted file mode 100644
index 627f0d7f..00000000
--- a/docs/method/backlog/asap/graphql-authored-observer-plan-lowering.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-title: graphql-authored-observer-plan-lowering
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - observer
-  - graphql
-  - wesley
-  - worldlineSnapshot
-  - optic
----
-
-# graphql-authored-observer-plan-lowering
-
-Define the jedit-owned observer authoring and lowering path for the get side of
-the hot text runtime boundary.
-
-Context:
-
-- GraphQL authors the set side for jedit contract operations.
-- jedit also needs a lawful get-side path for app-authored observer specs,
-  compiled observer plans, observer-state codecs, and reading codecs.
-- Wesley should provide generic compiler support, but jedit owns the first
-  product observer proof.
-
-## Hill
-
-jedit can lower one app-authored observer spec into a substrate-legal observer
-plan with explicit state/read codecs and without normalizing arbitrary callbacks.
-
-## Done looks like
-
-- one design packet names `ObserverSpec`, `ObserverPlan`, and
-  `ObserverInstance` as distinct layers
-- one compiler-facing authored shape is chosen for the first observer lane
-- output shapes are named for observer plan, observer state codec, reading
-  codec, and any needed hologram/frontier envelope helpers
-- the first proving target is `worldlineSnapshot` as a memoryless observer
-- one accumulative observer proof slice is named as follow-on work
-
-## Non-goals
-
-- Do not normalize arbitrary JavaScript or Rust callbacks into observer
-  legality.
-- Do not pretend a GraphQL query shape is already a full observer.
-- Do not collapse authored spec, compiled plan, hosted instance, and reading
-  into one object.
diff --git a/docs/method/backlog/asap/grouped-editor-transactions-and-undo-bursts.md b/docs/method/backlog/asap/grouped-editor-transactions-and-undo-bursts.md
deleted file mode 100644
index 50d39217..00000000
--- a/docs/method/backlog/asap/grouped-editor-transactions-and-undo-bursts.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: grouped-editor-transactions-and-undo-bursts
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - undo
-  - transactions
-  - editing
-  - runtime
-  - causal
-acceptance_criteria:
-  - The editor can group primitive text mutations into human-meaningful undo/redo bursts.
-  - Typing bursts, paste actions, deletes, and explicit commands do not all collapse into the same transaction policy.
-  - The grouping law is explicit enough to carry forward into future causal receipts.
-  - The implementation does not require Echo integration to be useful now.
----
-
-# grouped-editor-transactions-and-undo-bursts
-
-Move the editor from "one stack entry per low-level change" toward lawful
-editor transactions.
-
-Context:
-
-- We already know the future causal model should distinguish primitive text
-  receipts from higher-level human edits.
-- Even before Echo exists in the product, jedit should behave like it
-  understands typing bursts, pastes, and command edits as different kinds of
-  things.
-
-This is immediate UX work and future runtime work at the same time.
-
-## Non-Goals
-
-- Full causal history UI.
-- Persisted receipts or strands.
diff --git a/docs/method/backlog/asap/intent-only-editor-mutation-routing.md b/docs/method/backlog/asap/intent-only-editor-mutation-routing.md
deleted file mode 100644
index de4235a8..00000000
--- a/docs/method/backlog/asap/intent-only-editor-mutation-routing.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: intent-only-editor-mutation-routing
-lane: asap
-owner: jedit editor
-priority: high
-keywords:
-  - intent
-  - optic
-  - mutation
-  - editor
-  - receipts
-acceptance_criteria:
-  - Editor text mutations route through an optic write client instead of directly rewriting editor-owned canonical text.
-  - Each write carries a base coordinate or base head identity from the last accepted reading or receipt.
-  - Accepted writes advance editor state from receipts and follow-up readings.
-  - Rejected or obstructed writes have a visible app-level handling path.
-  - Tests cover insert, delete, paste or multi-character insert, and stale-base obstruction through the optic seam.
----
-
-# intent-only-editor-mutation-routing
-
-Move editor mutations onto the Intent-shaped Text File Optic path.
-
-Context:
-
-- The Echo-backed model says all file truth mutations happen through Intents.
-- The Optic can make writes ergonomic, but it must not act like a direct setter.
-- `jedit` needs this routing before the real Echo adapter arrives so UI code
-  does not grow around a local string model.
-
-This task should preserve current editing behavior while changing the authority
-path beneath it.
-
-## Non-Goals
-
-- Implementing collaborative settlement UI.
-- Replacing every local UI cache.
-- Removing all direct text helpers before the optic path has equivalent test
-  coverage.
-
diff --git a/docs/method/backlog/asap/interval-anchor-semantics.md b/docs/method/backlog/asap/interval-anchor-semantics.md
deleted file mode 100644
index dfc396b4..00000000
--- a/docs/method/backlog/asap/interval-anchor-semantics.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: interval-anchor-semantics
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - anchors
-  - intervals
-  - replace-range
-  - domain-law
-blocks:
-  - anchor-persistence-contract
-  - anchor-editor-integration
-  - echo-anchor-adapter-contract
-acceptance_criteria:
-  - The design packet defines interval-anchor semantics in terms of logical ReplaceRange receipts rather than rope maintenance.
-  - The red contract suite covers insertion at the start boundary, insertion at the end boundary, replacement fully inside the interval, overlap across one boundary, and full-swallow collapse.
-  - The runtime seam remains purely domain-level and does not require Echo, persistence, or editor UI wiring.
-  - The cycle clarifies whether a fully collapsed interval remains an interval anchor or normalizes to a point-anchor equivalent.
----
-
-# interval-anchor-semantics
-
-Define the first executable contract for interval-anchor semantics over logical
-ReplaceRange receipts.
-
-This is the next sharp seam after point-anchor semantics. It should pin down how
-a range anchor behaves when:
-
-- insertions land at the start boundary
-- insertions land at the end boundary
-- replacements happen fully inside the interval
-- a replacement overlaps one boundary
-- a replacement swallows the whole interval
-
-The goal is to make selections, comments, diagnostics, and AI target ranges
-lawful domain objects before persistence or UI integration is attempted.
-
-## Non-goals
-
-- [ ] Anchor persistence or serialization.
-- [ ] Echo adapter wiring.
-- [ ] Editor UI wiring.
-- [ ] Rope-maintenance transforms.
diff --git a/docs/method/backlog/asap/inverse-tick-unapply-intents.md b/docs/method/backlog/asap/inverse-tick-unapply-intents.md
deleted file mode 100644
index c71ee138..00000000
--- a/docs/method/backlog/asap/inverse-tick-unapply-intents.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-title: inverse-tick-unapply-intents
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - undo
-  - inverse
-  - tick
-  - intent
-  - causal
-acceptance_criteria:
-  - The contract has explicit `unapplyTick` and `unapplyTickSequence` planning shapes.
-  - Undo appends an inverse tick rather than deleting or rewriting old history.
-  - A test demonstrates `add h`, `add e`, `add l`, `add l`, `add o`, then unapplying one `l` to project `helo`.
-  - The result includes a receipt that records which tick or tick sequence was inversed.
-  - Stale, missing, or non-invertible target ticks return an obstruction rather than corrupting history.
----
-
-# inverse-tick-unapply-intents
-
-Model undo as Intent-admitted inverse history.
-
-Context:
-
-- In the Echo model, the file is its admitted changes at a coordinate.
-- Undo should not erase a tick from history.
-- The editor needs a direct way to say "admit the inverse of this tick" and
-  later "admit the inverse of this sequence."
-
-This task should add the contract and fake-runtime proof before connecting it
-to keyboard undo.
-
-## Non-Goals
-
-- Designing the full human undo grouping UI.
-- Guaranteeing that every future tick kind is invertible.
-- Compressing history or introducing wormholes.
-
diff --git a/docs/method/backlog/asap/optic-client-generation-cutover.md b/docs/method/backlog/asap/optic-client-generation-cutover.md
deleted file mode 100644
index adecdd11..00000000
--- a/docs/method/backlog/asap/optic-client-generation-cutover.md
+++ /dev/null
@@ -1,83 +0,0 @@
----
-title: optic-client-generation-cutover
-lane: asap
-owner: jedit runtime
-priority: medium
-keywords:
-  - optic
-  - wesley
-  - generated
-  - echo
-  - cutover
-acceptance_criteria:
-  - The fake/direct optic client and the future Wesley-generated Echo client share one app-facing port.
-  - Generated contract types become the source of input and reading shapes for optic operations.
-  - App code does not depend on fake-only operation names, codecs, or transport shortcuts.
-  - The cutover plan names exactly which adapter can be deleted when Echo supports hosted contract optics.
-  - Existing optic tests can run against the fake and later against a real Echo adapter with minimal fixture changes.
----
-
-# optic-client-generation-cutover
-
-Prepare the eventual switch from fake/direct Optic clients to Wesley-generated
-Echo Optic clients.
-
-Context:
-
-- `jedit` can do useful internal work before Echo ships contract optics.
-- That work must not create a second permanent client model.
-- The port should stay stable while adapters change beneath it.
-
-This task should define the cutover boundary so the fake remains a scaffold,
-not a forked runtime.
-
-## Current Safe Slice
-
-`jedit` now has a local readiness gate for the existing authored contract:
-
-- `contracts/jedit/hot-text-runtime.graphql` remains the canonical SDL surface.
-- `src/generated/jedit/hot-text-runtime.wesley.generated.ts` remains the
-  generated operation metadata used by the current TypeScript adapter layer.
-- `spec/hot-text-contract-readiness.spec.mjs` verifies that mutation
-  `@wes_footprint` metadata and bounded read operations are preserved before
-  any Echo Rust binding generation runs.
-- `contracts/jedit/structural-history.graphql` is now the canonical product
-  structural-history SDL.
-- `scripts/gen-structural-history-wesley.mjs` uses published `wesley-cli` 0.0.4
-  to emit the full structural-history TypeScript artifact into `.wesley-cache`
-  and extract the ignored `replaceTextRange` operation descriptor into
-  `src/generated/jedit/structural-history-replace-text-range.wesley.generated.ts`.
-  `src/app/structural-history-replace-text-range.ts` consumes that generated
-  source path as the canonical descriptor location.
-- `spec/structural-history-replace-text-range-metadata.spec.mjs` verifies that
-  the descriptor is ignored, mirrors Wesley output, and drives the hot-buffer
-  adapter operation identity without changing storage behavior.
-
-The deferred Echo-dependent step is:
-
-1. Use a lockfile-pinned Echo checkout, such as a future Continuum
-   `jedit-echo-dev` warpspace lock, or an explicit local path to select the Echo
-   checkout.
-2. Run `echo-wesley-gen` against `contracts/jedit/hot-text-runtime.graphql`.
-3. Write the generated Rust binding artifact into a jedit-owned Rust contract
-   crate.
-4. Install the generated package into Echo through trusted host authority.
-5. Submit edits through the app-facing jedit adapter, not trusted host control.
-6. Run scheduler work through trusted Echo host authority.
-7. Verify the generated registry artifact with
-   `echo_registry_api::verify_contract_artifact(...)`.
-
-Until Echo is free, do not add local sibling `../echo` dependencies to committed
-jedit manifests and do not generate a second, divergent SDL file.
-
-Historical release-gate correction: pre-cutover witness paths tried to send
-scheduler control through app-facing dispatch. The current opt-in real Echo WASM
-witness uses `hostTransport.trustedHost.dispatchControlIntentBytes(...)`, while
-the app transport intentionally omits `dispatchControlIntentBytes(...)`. Future
-cutovers must preserve that app/host authority split instead of weakening it.
-
-## Non-Goals
-
-- Depending on an Echo API that has not shipped yet.
-- Preserving fake-only codecs after the generated client exists.
-- Rewriting the entire app around generated types in one pass.
diff --git a/docs/method/backlog/asap/proposal-strand-demo.md b/docs/method/backlog/asap/proposal-strand-demo.md
deleted file mode 100644
index 53960e25..00000000
--- a/docs/method/backlog/asap/proposal-strand-demo.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-title: proposal-strand-demo
-lane: asap
-owner: jedit editor
-priority: high
-keywords:
-  - proposal
-  - strand
-  - suggestion
-  - ux
-  - causal
-acceptance_criteria:
-  - A larger suggestion appears as a proposal with basis coordinate, affected range, summary, preview action, accept action, and reject action.
-  - Creating and accepting the proposal route through Intent-shaped fake Echo transport calls.
-  - Preview uses a reading and does not silently mutate the current file projection.
-  - Rejecting the proposal dismisses it without admitting changes.
-  - Tests or scripted fixtures cover accept, reject, and stale proposal obstruction.
----
-
-# proposal-strand-demo
-
-Prototype the first proposal-as-strand user experience.
-
-Context:
-
-- Larger suggestions should be governed proposals, not invisible edits.
-- The user needs to understand scope and consequence without reading a chat
-  transcript.
-- The demo should help tune the amount of visible basis, summary, and preview
-  state.
-
-Good first proposal sources:
-
-- deterministic text transform over a selection
-- local repeated-token rename fixture
-- small formatting-like rewrite
-- inserted block with a known affected range
-
-The point is the UX contract, not AI quality.
-
-## Non-Goals
-
-- Full AI chat.
-- Multi-file proposal admission.
-- Full partial-accept UI.
-- Complete merge policy for competing proposal strands.
diff --git a/docs/method/backlog/asap/queryview-optic-convergence.md b/docs/method/backlog/asap/queryview-optic-convergence.md
deleted file mode 100644
index cf45c95e..00000000
--- a/docs/method/backlog/asap/queryview-optic-convergence.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-title: queryview-optic-convergence
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - echo
-  - optic
-  - queryview
-  - text-window
-  - stack-witness
-acceptance_criteria:
-  - >
-    QueryView reads are modeled as optic-shaped observations at the jedit
-    boundary instead of a permanent direct-query side door.
-  - >
-    jedit no longer needs raw default-worldline fixture evidence once an optic
-    or session capability owns basis/worldline resolution.
-  - >
-    The Stack Witness 0001 consumer path can run against a real Echo-hosted
-    ReadingEnvelope plus QueryBytes result when the Echo WASM package is
-    consumable from jedit.
-  - >
-    Text-window payload decoding happens only in the boundary adapter, and the
-    editor core continues to consume app-owned TextWindowReading objects.
-  - >
-    The cutover keeps create/edit/read tests intact for createBuffer,
-    replaceRange, and textWindow.
-  - >
-    The implementation does not add Continuum dependencies or redesign the
-    jedit contract surface.
----
-
-# queryview-optic-convergence
-
-Carry the Stack Witness 0001 `QueryView` read toward the intended optic-shaped
-boundary.
-
-The current jedit seam is already Echo-shaped: it submits intent bytes through
-an `EchoWasmKernelTransport` and observes through the same port. The fake host
-is still an app-local scaffold, though, and its `textWindow` response is already
-decoded into a jedit reading object rather than first consuming Echo's generic
-installed-observer boundary.
-
-The next convergence step is not to redesign jedit's contract. The next step is
-to install jedit-owned generated query observers into Echo and map the generic
-observer byte payload into the app-owned `TextWindowReading` shape.
-
-The current real-WASM witness still carries a derived Echo default-worldline id
-as explicit fixture evidence. That is temporary scaffolding for the raw
-`ObservationRequest` path. It must not become a product contract or a request
-for Echo to expose a default-worldline API. Durable jedit integration should
-receive basis/worldline resolution through an optic or session capability.
-
-## Desired Shape
-
-- jedit submits create/edit intent through an Echo transport.
-- jedit receives or opens an optic/session capability that owns the basis
-  coordinate for reads.
-- Echo admits or obstructs the intent and owns causal-history truth.
-- jedit observes an optic-shaped `textWindow` read.
-- Echo routes the query through an installed jedit-owned query observer and
-  returns `ReadingEnvelope + QueryBytes`.
-- the boundary adapter decodes those bytes into the existing app-facing
-  `TextWindowReading`.
-
-## Non-Goals
-
-- Implementing Continuum transport in this task.
-- Renaming the jedit product contract to match Echo's temporary fixture names.
-- Moving text editor nouns into Echo core.
-- Replacing the fake transport before the real Echo WASM package can be loaded
-  by jedit tests.
diff --git a/docs/method/backlog/asap/save-checkpoints-and-cold-witness-bridge.md b/docs/method/backlog/asap/save-checkpoints-and-cold-witness-bridge.md
deleted file mode 100644
index 23dac6c9..00000000
--- a/docs/method/backlog/asap/save-checkpoints-and-cold-witness-bridge.md
+++ /dev/null
@@ -1,41 +0,0 @@
----
-title: save-checkpoints-and-ecosystem-export-bridge
-lane: asap
-owner: jedit runtime
-priority: medium
-keywords:
-  - save
-  - checkpoints
-  - git-warp
-  - export
-  - projection
-acceptance_criteria:
-  - The repo defines how a save checkpoint in `jedit` relates to ecosystem export layers such as Git and `git-warp`.
-  - The design is explicit that Git commits export or mirror an editor projection rather than define when editor truth exists.
-  - The bridge design names what artifacts or summaries move from Echo causal history into filesystem and Git projections.
-  - The design stays honest about the difference between local editor checkpoints and Git commits.
----
-
-# save-checkpoints-and-ecosystem-export-bridge
-
-Define how `jedit` save checkpoints connect to filesystem and Git ecosystem
-exports.
-
-Context:
-
-- The editor needs save to behave like a checkpoint instead of a reset.
-- Echo owns canonical durable causal history.
-- The filesystem remains a working projection.
-- `git-warp` remains valuable for public hosting, CI, commit-shaped exchange,
-  and compatibility with existing repository ecosystems.
-- Without an explicit bridge, the stack risks either waiting on Git for live
-  truth or treating exports as unrelated side effects.
-
-This note should define how save checkpoints, explicit admissions, and future
-Git exports relate without pretending they are all the same event.
-
-## Non-Goals
-
-- Designing a full commit automation workflow.
-- Forcing every save to immediately become a Git export.
-- Collapsing local editor checkpoints into Git semantics.
diff --git a/docs/method/backlog/asap/search-and-buffer-switching-surface.md b/docs/method/backlog/asap/search-and-buffer-switching-surface.md
deleted file mode 100644
index a72fa21e..00000000
--- a/docs/method/backlog/asap/search-and-buffer-switching-surface.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-title: search-and-buffer-switching-surface
-lane: asap
-owner: jedit editor
-priority: medium
-keywords:
-  - search
-  - quick-open
-  - buffers
-  - switching
-  - ux
-acceptance_criteria:
-  - jedit has an in-buffer search flow with clear next/previous navigation.
-  - jedit has a quick-open or fuzzy-open path for files.
-  - jedit has a coherent open-buffer switching surface instead of overloading pane focus controls.
-  - Recent or open buffers remain visible enough that switching does not require rediscovering file paths every time.
----
-
-# search-and-buffer-switching-surface
-
-Turn file movement and text movement into first-class editor flows instead of
-making the user rely on the tree for everything.
-
-Context:
-
-- `tab` is now reserved for pane focus, not opening drawers.
-- The editor still needs a lawful way to move between matches, files, and open
-  buffers without collapsing back into noisy shell chrome.
-- This note groups search, quick-open, recent buffers, and smarter buffer
-  switching because they are one navigation surface from the user’s point of
-  view.
-
-## Non-Goals
-
-- Full project indexing or language-aware search.
-- A graphical tab bar that dominates the editor chrome.
diff --git a/docs/method/backlog/asap/sessions-migration.md b/docs/method/backlog/asap/sessions-migration.md
deleted file mode 100644
index 7a20a761..00000000
--- a/docs/method/backlog/asap/sessions-migration.md
+++ /dev/null
@@ -1,198 +0,0 @@
----
-title: sessions-migration
-lane: asap
-owner: jedit transport
-priority: high
-keywords:
-  - sessions
-  - transport
-  - session-port
-  - migration
-  - eint
-  - echo-0025
-blocked_by:
-  - echo cycle 0025 (sessions as causal contexts) — implementation phase
-acceptance_criteria:
-  - Jedit holds only a SessionId after migration, with no client-side cache of engine causal state.
-  - JeditWorldlineSessionPort and its in-memory adapter are deleted.
-  - The optic client surface uses sessionId-addressed intent submission and receives engine-emitted lifecycle events.
-  - The bad-code card optic-codec-mixes-wire-with-session.md is fully resolved (not just partially).
----
-
-# Sessions Migration
-
-Companion to **echo cycle 0025 — sessions as causal contexts**, documented
-in the Echo repository at
-`docs/design/0025-sessions-as-causal-contexts/design.md`. (A cross-repo
-relative-path link was avoided here because the two repositories are
-separate Git roots; the path is descriptive rather than clickable.)
-
-## Current smell
-
-The jedit Slice B EINT cutover (commit `26a8f43`) introduced
-`src/ports/jedit-worldline-session-port.ts` and its in-memory adapter as a
-**scaffold**, not an abstraction. The optic client registers
-`(worldlineId → session)` before each call; the in-process transport reads
-from the same port after EINT decode. They cooperate by sharing memory in
-the same process.
-
-This works because the optic client and the in-process transport are
-co-located. It does not work across a real WASM transport, and it forces
-jedit to invent an engine-flavored concept (causal context per writer) in
-client code. The bad-code card
-[optic-codec-mixes-wire-with-session.md](../bad-code/optic-codec-mixes-wire-with-session.md)
-named the underlying smell; Slice B addressed the surface but not the root.
-
-Echo cycle 0025 fixes the root by making Session a first-class causal-
-context node in Echo. This card tracks jedit's migration off the scaffold
-once that engine surface lands.
-
-## Desired jedit role
-
-Jedit should be **dumber** about Session. The optic client holds a
-`SessionId`, threads it through intent submission, and observes
-engine-emitted lifecycle events. It does not maintain a parallel mirror of
-engine causal state.
-
-Conceptual jedit surface, post-migration:
-
-```text
-openSession(writer, primaryWorldline?) → SessionHandle
-sendIntent(sessionId, intent)          → Promise
-observeReceipts(sessionId)             → AsyncIterable
-runUntilIdle(sessionId, until)         → Promise
-closeSession(sessionId, mode)          → Promise
-```
-
-The client may keep a UI-facing object like `EditorSession` — but as a
-**handle over a SessionId**, not a second source of truth. No worldline /
-state / tickMetadata / checkpointMetadata fields on the client side once
-the engine owns them.
-
-## Migration phases
-
-### Phase M1 — Echo surface available
-
-**Precondition:** Echo cycle 0025 implementation has shipped at least:
-
-- `SessionId`, `PrincipalRef` types
-- Session node + lifecycle events in the engine graph
-- EINT envelope carrying `session_id` + `intent_id` headers
-- `runUntilIdle(session, until)` engine API
-- Two-stage close
-
-### Phase M2 — Jedit dual-mode
-
-Optic client supports both wire shapes during the cutover window:
-
-- **Legacy mode** (current Slice B): uses `JeditWorldlineSessionPort`,
-  encodes EINT without session header, transport resolves via port.
-- **Session mode** (new): opens a session against Echo, encodes EINT with
-  session header, no session-port involvement.
-
-A feature flag or transport-capability detection chooses the mode. Both
-specs pass during this window.
-
-### Phase M3 — Default flip
-
-Session mode becomes default. Legacy mode retained only for unit tests of
-the legacy wire shape (kept for one release cycle to catch regressions).
-
-### Phase M4 — Deletion
-
-- Delete `src/ports/jedit-worldline-session-port.ts`
-- Delete `src/adapters/in-memory-jedit-worldline-session-port.ts`
-- Delete `src/adapters/installed-jedit-eint-bridge.ts` (the bridge's
-  responsibilities — EINT decode + session lookup — belong to Echo's
-  session machinery now; jedit's in-process transports go away with the
-  legacy mode, since the real transport handles everything)
-- Delete `EchoWasmKernelTransport.jeditSessionPort` field
-- Delete legacy-mode optic client paths
-- Update the bad-code card resolution status; delete it if fully clean.
-
-### Deletion criteria
-
-The session-port and bridge are deleted when **all** of these are true:
-
-1. Echo's Session surface is available in the production echo-wasm-kernel
-   transport (not just in-process fakes).
-2. All jedit specs that exercise transport semantics pass in session mode.
-3. No client-side code reads or writes the session-port outside of the
-   legacy-mode code paths slated for deletion.
-4. The bad-code card
-   [optic-codec-mixes-wire-with-session.md](../bad-code/optic-codec-mixes-wire-with-session.md)
-   has no remaining caveats.
-
-## What becomes dumber
-
-| Today (Slice B)                                                  | Post-migration                                              |
-| ---------------------------------------------------------------- | ----------------------------------------------------------- |
-| Optic client maintains `JeditWorldlineSession` per worldline     | Optic client holds opaque `SessionId`                       |
-| `JeditIntentRequest` carries `session: JeditWorldlineSession`    | Wire carries `session_id`; engine resolves                  |
-| In-process bridge decodes EINT, looks up session, dispatches     | Engine does it                                              |
-| `requestRunUntilIdle()` is a microtask stub                      | Real engine query against bounded child work                |
-| Tab close = drop UI state; engine doesn't know                   | `closeSession(id, mode)` — engine emits `SessionClosed`     |
-| Multi-writer scenarios indistinguishable from single-writer      | Each writer's work has a distinct lane the engine can audit |
-
-## What remains client-local
-
-Some state legitimately belongs to jedit and does not migrate:
-
-- **Editor view state** — cursor positions, viewport, mode (insert /
-  normal / visual), selection. Not causal. UI-only.
-- **Read basis handles** (`ReadBasisHandleRegistry`) — these are opaque
-  client-issued tokens that resolve to worldline coordinates at observe
-  time. They are a jedit-side capability, not engine causal state.
-- **Local UI session handle** — the `EditorSession` object that wraps the
-  `SessionId` for the React/TUI layer to consume. It is a UI binding, not
-  a duplicate of engine state.
-
-## Impact on async correlation (Phase 4)
-
-The current `JeditOpticClient` async surface (Slice B) returns Promises
-that resolve immediately in a microtask, because the in-process transport
-is synchronous underneath. Post-migration, those Promises resolve when the
-engine emits `IntentReceiptIssued` for the corresponding `intent_id` —
-which can genuinely defer. The client's responsibility shrinks: it
-correlates response Promises by `intent_id`, full stop. Lane ordering and
-causal scope are engine concerns.
-
-## Impact on run-until-idle (Phase 6)
-
-The current `requestRunUntilIdle()` is `await Promise.resolve()`. Post-
-migration, it becomes:
-
-```ts
-await transport.runUntilIdle(sessionId, until);
-```
-
-where `until` is `'receipt' | 'quiescent'`. Jedit's text-buffer-session
-will probably default to `'receipt'` for interactive flows and
-`'quiescent'` for save / test / determinism paths.
-
-## Temporary compatibility bridge
-
-During M2, the optic client capability-detects the engine. If the engine
-exposes Session surface, use it; otherwise fall back to session-port.
-Capability detection should be a single boolean check against the
-transport's reported kernel info — not a feature-flag environment variable
-that could drift between processes.
-
-## Cross-repo coordination
-
-- Echo cycle 0025 must reach at least Phase M1 surface before this card
-  unblocks. Track via `echo/docs/design/0025-sessions-as-causal-contexts/`.
-- Wesley schema gets a Session node type as part of 0025; jedit consumes
-  generated `SessionId` and related types via the existing Wesley TS
-  emit path.
-- The `echo-session-proto` rename (existing `up-next` card) needs to
-  resolve naming-collision before jedit's generated types land, or jedit
-  imports become ambiguous between "transport session" and "causal-context
-  session."
-
-## Source
-
-This card grew out of a cross-repo design conversation rooted in the
-jedit Slice B EINT cutover (commit `26a8f43`). The Echo-side design is
-**0025 — Sessions as Causal Contexts**, in the Echo repository at
-`docs/design/0025-sessions-as-causal-contexts/design.md`.
diff --git a/docs/method/backlog/asap/set-side-result-vs-read-side-envelope-audit.md b/docs/method/backlog/asap/set-side-result-vs-read-side-envelope-audit.md
deleted file mode 100644
index 3602b29d..00000000
--- a/docs/method/backlog/asap/set-side-result-vs-read-side-envelope-audit.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: set-side-result-vs-read-side-envelope-audit
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - result
-  - reading
-  - receipt
-  - envelope
-  - jedit
-acceptance_criteria:
-  - The repo audits where `jedit` currently treats mutation result, receipt, and later reading as distinct versus blurred.
-  - The audit names any places where app code accidentally collapses set-side and read-side boundaries.
-  - The output leaves one explicit rule for future work: mutation result and later reading remain separate surfaces even when they share underlying contract families.
----
-
-# set-side-result-vs-read-side-envelope-audit
-
-Audit whether `jedit` is still cleanly separating:
-
-- set-side intent result
-- receipt or proof surface
-- later read-side reading envelope
-
-This matters because `jedit` is the app-boundary proving ground. If it blurs
-those surfaces, the rest of the stack will likely follow.
-
-Context:
-
-- the legacy-named hot-text contract already defines mutation families and a
-  first read-side shape
-- the runtime glue already wraps a `WorldlineSnapshotReadingEnvelope`
-- that does not yet prove the full boundary is being respected everywhere
-
-## Non-Goals
-
-- Designing the final debugger protocol here.
-- Inventing a new runtime family from scratch.
-- Changing Echo semantics inside the `jedit` repo.
diff --git a/docs/method/backlog/asap/source-render-pipeline-that-can-swap-local-and-graft-highlighting.md b/docs/method/backlog/asap/source-render-pipeline-that-can-swap-local-and-graft-highlighting.md
deleted file mode 100644
index 1bfb72eb..00000000
--- a/docs/method/backlog/asap/source-render-pipeline-that-can-swap-local-and-graft-highlighting.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-title: source-render-pipeline-that-can-swap-local-and-graft-highlighting
-lane: asap
-owner: jedit editor
-priority: high
-keywords:
-  - source
-  - renderer
-  - syntax-highlighting
-  - graft
-  - tui
-acceptance_criteria:
-  - The source pane uses a dedicated render/classification boundary rather than mixing syntax decisions into buffer editing logic.
-  - Local syntax paint and future Graft syntax spans can flow through the same renderer contract.
-  - Styling remains a paint-time concern; buffer text stays free of ANSI or style escapes.
-  - Unsupported languages degrade cleanly to plain source rendering.
----
-
-# source-render-pipeline-that-can-swap-local-and-graft-highlighting
-
-Put the source pane on the same architectural footing as the new markdown
-preview renderer: classification on one side, paint on the other.
-
-Context:
-
-- `jedit` can already paint per-cell color in the terminal.
-- Current Graft direct API surfaces are still structural, not token/span oriented.
-- We want visible editor improvement now without painting ourselves into a
-  corner before Graft grows buffer-aware syntax span APIs.
-
-This note is the seam that makes that possible. The source renderer should have
-one contract for "here are spans/classes to paint" regardless of whether those
-classes come from local heuristics today or Graft AST spans later.
-
-## Non-Goals
-
-- Shipping full syntax highlighting by itself.
-- Designing the future Graft API inside jedit.
-- Entangling rendering with the editor’s buffer mutation logic.
diff --git a/docs/method/backlog/asap/text-file-optic-contract-surface.md b/docs/method/backlog/asap/text-file-optic-contract-surface.md
deleted file mode 100644
index b1dc1d75..00000000
--- a/docs/method/backlog/asap/text-file-optic-contract-surface.md
+++ /dev/null
@@ -1,47 +0,0 @@
----
-title: text-file-optic-contract-surface
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - optic
-  - graphql
-  - wesley
-  - text-window
-  - intent
-acceptance_criteria:
-  - `contracts/jedit/hot-text-runtime.graphql` names a Text File Optic surface without removing the current `worldlineSnapshot` proving read.
-  - The contract distinguishes bounded read operations from mutation Intent operations.
-  - The read surface includes explicit viewport/window budgets and never requires returning the full file for source painting.
-  - The write surface includes base coordinate or base head identity so stale writes can be rejected or obstructed.
-  - The contract states which nouns are `jedit` text semantics and which are generic Echo substrate concepts.
----
-
-# text-file-optic-contract-surface
-
-Define the GraphQL-authored Text File Optic contract surface.
-
-Context:
-
-- `jedit` already has `createBufferWorldline`, `replaceRangeAsTick`,
-  `createCheckpoint`, and `worldlineSnapshot`.
-- That proves the first mutation and observer slices, but the source editor
-  still needs bounded reads and Intent-shaped writes through an optic.
-- The planning packet is
-  [optic-backed-file-model](../../../design/0006-optic-backed-file-model/optic-backed-file-model.md).
-
-This task should evolve the authored contract vocabulary toward:
-
-- `TextFileOptic`
-- `TextWindowReading`
-- `TextLineReading`
-- `openTextFileOptic`
-- `textWindow`
-- `replaceTextRange` or the optic-facing successor to `replaceRangeAsTick`
-
-## Non-Goals
-
-- Removing `worldlineSnapshot` before the bounded read family is proven.
-- Implementing real Echo Optic hosting.
-- Making Echo core aware of text files or editor ranges.
-
diff --git a/docs/method/backlog/asap/toggleable-line-number-gutter.md b/docs/method/backlog/asap/toggleable-line-number-gutter.md
deleted file mode 100644
index 0722baf4..00000000
--- a/docs/method/backlog/asap/toggleable-line-number-gutter.md
+++ /dev/null
@@ -1,47 +0,0 @@
----
-title: toggleable line-number gutter
-lane: asap
-owner: jedit editor
-priority: medium
-keywords:
-  - tui
-  - editor
-  - gutter
-  - line-numbers
-  - ux
-acceptance_criteria:
-  - The editor can render a left-side gutter alongside the text buffer.
-  - The gutter can be toggled on and off without disturbing core editing behavior.
-  - The gutter supports absolute line numbers.
-  - The gutter supports relative line numbers based on the current cursor position.
-  - The user can switch between absolute and relative numbering modes.
-  - Rendering remains stable in source mode when the cursor moves, scrolls, or edits occur.
----
-
-# toggleable line-number gutter
-
-Add an editor gutter that can display line numbers and can be toggled on or off. The gutter should support both absolute numbering and numbering relative to the current cursor line.
-
-Context:
-
-- `jedit` now has a quieter source pane and footer, which makes a purposeful gutter more useful than permanent chrome.
-- This work is part of the "get the editor surface right before deeper Graft/Echo integration" tranche.
-- The gutter should stay small, lawful, and source-mode focused rather than becoming a dumping ground for IDE widgets.
-
-## Acceptance Criteria
-- The editor can render a left-side gutter alongside the text buffer.
-- The gutter can be toggled on and off without disturbing core editing behavior.
-- The gutter supports absolute line numbers.
-- The gutter supports relative line numbers based on the current cursor position.
-- The user can switch between absolute and relative numbering modes.
-- Rendering remains stable in source mode when the cursor moves, scrolls, or edits occur.
-
-## Non-Goals
-- Diagnostics, breakpoints, blame, or other IDE-style gutter decorations.
-- Preview-mode gutter behavior unless the editor surface explicitly needs it.
-- Full visual redesign of the editor chrome.
-
-## Notes
-
-- This should compose cleanly with future current-line highlighting and viewport polish work.
-- Relative numbers should be computed from the visible cursor line, not from file start or stale scroll state.
diff --git a/docs/method/backlog/asap/unsaved-change-guardrails.md b/docs/method/backlog/asap/unsaved-change-guardrails.md
deleted file mode 100644
index 40b8d289..00000000
--- a/docs/method/backlog/asap/unsaved-change-guardrails.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: unsaved-change-guardrails
-lane: asap
-owner: jedit editor
-priority: medium
-keywords:
-  - save
-  - quit
-  - dirty
-  - guardrails
-  - editor
-acceptance_criteria:
-  - jedit warns before destructive actions that would drop unsaved changes.
-  - Quit, close, and file-switch flows have a defined posture when the active buffer is dirty.
-  - The dirty marker in the title/footer stays consistent with the actual save state.
-  - The guardrail UX stays terse and keyboard-first.
----
-
-# unsaved-change-guardrails
-
-Add the minimum lawful save/quit protection so the editor does not casually let
-the user destroy work.
-
-Context:
-
-- `jedit` now has real editing, save, preview, drawer interaction, and growing
-  buffer navigation needs.
-- That makes accidental loss more likely unless quit/close/switch behavior is
-  explicit.
-
-This is not about modal dialog theatrics. It is about a strong default posture
-that respects dirty buffers.
-
-## Non-Goals
-
-- Full autosave.
-- Session recovery or crash journal design.
diff --git a/docs/method/backlog/asap/viewport-and-current-line-polish.md b/docs/method/backlog/asap/viewport-and-current-line-polish.md
deleted file mode 100644
index 49a94ecc..00000000
--- a/docs/method/backlog/asap/viewport-and-current-line-polish.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: viewport-and-current-line-polish
-lane: asap
-owner: jedit editor
-priority: medium
-keywords:
-  - viewport
-  - scroll
-  - cursor
-  - highlight
-  - polish
-acceptance_criteria:
-  - Cursor visibility, scrolling, paging, and viewport math stay stable across drawer combinations and footer states.
-  - The active source line can be visually distinguished without drowning the screen in chrome.
-  - The editor feels spatially steady during movement rather than jittery or over-compensated.
-  - Preview and source modes keep their viewport responsibilities separate and explicit.
----
-
-# viewport-and-current-line-polish
-
-Polish the physical feel of the editor surface.
-
-Context:
-
-- We already fixed one real viewport bug after the pane refactor.
-- The next tranche should make source-mode movement feel intentional rather
-  than merely correct.
-- Current-line emphasis belongs in the same conversation because it changes
-  how the user reads and locates themselves on the screen.
-
-## Non-Goals
-
-- Fancy animation.
-- Multi-cursor or minimap work.
diff --git a/docs/method/backlog/asap/wesley-generated-artifact-adoption.md b/docs/method/backlog/asap/wesley-generated-artifact-adoption.md
deleted file mode 100644
index 51448dd6..00000000
--- a/docs/method/backlog/asap/wesley-generated-artifact-adoption.md
+++ /dev/null
@@ -1,49 +0,0 @@
----
-title: wesley-generated-artifact-adoption
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - wesley
-  - generated-artifacts
-  - hot-text
-  - contract
-  - echo
----
-
-# wesley-generated-artifact-adoption
-
-Adopt Wesley-generated artifacts as jedit's authority surface for the hot text
-runtime boundary.
-
-Context:
-
-- Wesley can emit Rust and TypeScript model plus operation-binding artifacts
-  from the hermetic jedit hot text runtime GraphQL fixture.
-- The next proof belongs in the repos that own the runtime behavior, not in
-  generic Wesley.
-- jedit should replace handwritten shadow model metadata where the authored
-  GraphQL schema already owns the operation identity.
-
-## Hill
-
-jedit consumes Wesley-generated artifacts as the shared protocol surface for hot
-text runtime capabilities, with no handwritten shadow models competing with the
-authored GraphQL schema.
-
-## Done looks like
-
-- jedit replaces handwritten hot text runtime shape definitions with generated
-  Wesley Rust/TypeScript artifacts where those artifacts are the source of
-  authority.
-- jedit adapters keep product behavior and editor runtime semantics app-owned.
-- Echo consumption stays behind intent and observation boundaries; jedit does
-  not import Echo substrate internals.
-- Any missing generator configurability is brought back to Wesley as a specific
-  source-level requirement with a fixture and failing test.
-
-## Non-goals
-
-- Do not move editor behavior into Wesley.
-- Do not make Echo core aware of text files, buffers, ranges, or ropes.
-- Do not treat generated fixture bytes as a permanent codec contract.
diff --git a/docs/method/backlog/asap/worldlineSnapshot-family-authority-cut.md b/docs/method/backlog/asap/worldlineSnapshot-family-authority-cut.md
deleted file mode 100644
index 8ad1913e..00000000
--- a/docs/method/backlog/asap/worldlineSnapshot-family-authority-cut.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: worldlineSnapshot-family-authority-cut
-lane: asap
-owner: jedit runtime
-priority: high
-keywords:
-  - worldlineSnapshot
-  - graphql
-  - generated
-  - reading
-  - authority
-acceptance_criteria:
-  - The repo states exactly which parts of `worldlineSnapshot` are authored family truth, which are generated artifacts, and which are later runtime-emitted values.
-  - The packet explains how the generated observer-plan artifact relates to the GraphQL-authored family without becoming a second source of truth.
-  - The cut leaves downstream maintainers with one clean authority story for the `worldlineSnapshot` slice.
----
-
-# worldlineSnapshot-family-authority-cut
-
-Freeze the authority story for `worldlineSnapshot`.
-
-Right now the slice is useful but easy to misread because several layers are
-present at once:
-
-- GraphQL-authored contract family
-- generated observer-plan artifact
-- runtime reading-envelope wrapper
-
-This item should make the layers explicit so that future work does not treat a
-generated artifact or runtime wrapper as peer authority with the authored
-contract itself.
-
-## Non-Goals
-
-- Widening `worldlineSnapshot` to solve every future read need.
-- Replacing the whole app projection layer in one move.
-
diff --git a/docs/method/backlog/bad-code/generated-rope-codec-manual-fixes.md b/docs/method/backlog/bad-code/generated-rope-codec-manual-fixes.md
deleted file mode 100644
index faf3572f..00000000
--- a/docs/method/backlog/bad-code/generated-rope-codec-manual-fixes.md
+++ /dev/null
@@ -1,123 +0,0 @@
----
-title: generated-rope-codec-manual-fixes
-lane: bad-code
-owner: jedit transport
-priority: high
-keywords:
-  - generated-code
-  - codec
-  - wesley
-  - jedit
-  - trailing-bytes
-  - regen
-blocked_by:
-  - Wesley TS emitter support for top-level vars trailing-byte checks
-acceptance_criteria:
-  - Wesley TS emitter generates top-level vars trailing-byte checks for mutation and query vars decoders.
-  - Regenerating jedit/src/generated/jedit/rope.codec.generated.ts preserves mutation and query checks.
-  - Tests fail (RED) if any generated mutation or query vars decoder accepts trailing bytes.
-  - No manual post-generation edits remain in generated codec output.
----
-
-# Generated rope codec carries hand-edits that regen would erase
-
-## The smell
-
-`src/generated/jedit/rope.codec.generated.ts` is marked as generated
-output, but it currently carries hand-applied behavior:
-
-- Trailing-byte rejection in the top-level vars decoders
-  (`decodeCreateBufferWorldlineVars`, `decodeReplaceRangeAsTickVars`,
-  `decodeCreateCheckpointVars`, plus the two query vars decoders) was
-  added by commit `6da5a8f` ("Fix: reject trailing bytes in top-level
-  vars decoders"). The check uses `Reader.remaining()` and throws
-  `CodecError` when bytes remain after a structurally-complete decode.
-
-The commit message itself flagged the risk:
-
-> Same regeneration caveat as previous codec edits (commits 640b07d
-> and b1eed88): a regen will need the wesley emitter to produce this
-> check too.
-
-That caveat is the bug. The file says "generated. Do not edit." and
-yet it carries an edit. The next time someone runs the codegen
-pipeline against this schema, the trailing-byte checks vanish, the
-fix is undone silently, and the canonical-vars-plus-garbage replay /
-submission-identity invariant break it was added to prevent comes
-back.
-
-This is structurally identical to the two earlier hand-edits in the
-same file (commits `640b07d` and `b1eed88`). Three accumulated hand-
-edits without a regen-resistance story is now an explicit anti-
-pattern.
-
-## Why this matters
-
-- The replay / submission-identity invariant ("canonical input bytes
-  uniquely identify the mutation submission") depends on the
-  trailing-byte check. Losing it means two distinct byte strings can
-  decode to the same operation under different recorded submission
-  IDs.
-- Regen pressure will arrive naturally with Wesley updates, schema
-  changes, or the 0025 Phase 2 migration that touches the rope
-  schema and Session attribution. Any of those triggers the bug.
-- The contract that generated output is regenerable is a load-
-  bearing METHOD assumption — Wesley is the contract compiler. A
-  generated file that requires hand-fixes silently breaks that
-  contract for every downstream user.
-
-## The fix shape
-
-Two-step:
-
-1. **Upstream**: the Wesley TypeScript emitter learns to emit the
-   trailing-byte check as part of every top-level vars decoder. The
-   shape is mechanical — after decoding all declared fields, assert
-   `r.remaining() === 0` and throw `CodecError` otherwise. The Rust
-   emitter side is parallel; if it already does this, the TS emitter
-   just mirrors the policy.
-2. **Downstream**: regenerate `rope.codec.generated.ts` from the
-   updated emitter. Diff against the hand-edited version. Diff must
-   be empty (or trivially equivalent — formatting only). If non-
-   empty, the emitter is missing a case.
-
-Then `spec/rope-codec.spec.mjs` keeps trailing-byte regression tests
-for both mutation vars decoders and query vars decoders
-(`decodeWorldlineSnapshotVars`, `decodeTextWindowVars`) as the gate:
-any future regen that drops the checks turns those tests red
-immediately, before the broken file gets committed.
-
-## Related cards
-
-- `docs/method/backlog/bad-code/optic-codec-mixes-wire-with-session.md`
-  — sibling concern about a different codec file carrying transport-
-  level conflation. Both want the same Wesley-emitter alignment.
-- `echo/docs/method/backlog/bad-code/echo-wesley-gen-local-emitter-duplication.md`
-  (companion) — echo carries a parallel set of hand-applied
-  generator behavior (codec_id normalization, trait imports,
-  fnv1_step naming, no_std ID list encoding) waiting on the same
-  wesley-core / emitter alignment.
-
-## Out of scope here
-
-- Implementing the Wesley emitter change. That belongs in the
-  Wesley repo (or its echo-vendored copy, if relevant) and lands
-  behind a regen + diff-empty proof.
-- Re-running the regen pipeline against the current emitter and
-  shipping the result. This card stays open until the regen
-  preserves the trailing-byte checks AND the rest of the hand-
-  edited surface.
-
-## Trigger
-
-Resolve this card when:
-
-1. The Wesley TS emitter emits the trailing-byte check for every
-   top-level vars decoder.
-2. A regenerated `rope.codec.generated.ts` compiles, passes
-   `spec/rope-codec.spec.mjs` (including mutation and query
-   trailing-byte regressions), and shows zero functional drift from
-   the current hand-edited file.
-3. The commit-message caveat about "regen will need the wesley
-   emitter to produce this check too" no longer applies and can be
-   removed from any future codec-related commit.
diff --git a/docs/method/backlog/bad-code/global-next-root-id-counter.md b/docs/method/backlog/bad-code/global-next-root-id-counter.md
deleted file mode 100644
index b67e4acf..00000000
--- a/docs/method/backlog/bad-code/global-next-root-id-counter.md
+++ /dev/null
@@ -1,72 +0,0 @@
----
-title: global-next-root-id-counter
-lane: bad-code
-owner: jedit domain
-priority: resolved
-resolved_by:
-  cycle: WF-0153
-  issue: 267
-  date: 2026-07-12
-  resolution: |
-    Option A implemented, extended with chain-threaded allocation state:
-    createBufferRoot/createTextFragment/emptyFragment take explicit ids,
-    replaceRange takes the next root id, TickAdmissionState and
-    HotTextBufferState thread nextRootId as value state, and
-    admitReplaceRangeTick is the single allocation authority (takes
-    fragment text, allocates fragment + next root ids). Witnessed by
-    spec/root-identity-determinism.spec.mjs.
-keywords:
-  - domain
-  - text-edit-contract
-  - purity
-  - testing
-  - mutable-state
----
-
-# global-next-root-id-counter
-
-`src/domain/text-edit-contract.ts` contains a module-level mutable counter:
-
-```typescript
-let nextRootId = 1;
-```
-
-This counter is incremented inside `createBufferRoot` every time a new root is
-allocated. It is the only piece of mutable state in the otherwise pure domain
-layer.
-
-## Why this is a smell
-
-The domain layer is meant to be pure — no external deps, no side effects, pure
-functions in and out. This counter violates that contract. Specifically:
-
-- Two tests that both exercise `createBufferRoot` share this counter across
-  calls. Root IDs bleed between tests.
-- In practice tests probably do not assert on specific root ID values, so this
-  hasn't caused failures yet. But it is a time bomb: if any test ever pins a
-  root ID expectation, test ordering becomes load-bearing.
-- The domain cannot be instantiated fresh per-test without reloading the module.
-
-## Fix
-
-Pass an ID allocator explicitly. Two options:
-
-**Option A — pass an opaque ID in:**
-
-```typescript
-export function createBufferRoot(id: number, text: string): BufferRoot
-```
-
-Callers (the adapter layer) own the counter. The domain is now purely
-functional.
-
-**Option B — pass an allocator function:**
-
-```typescript
-export function createBufferRoot(allocateId: () => number, text: string): BufferRoot
-```
-
-Slightly more flexible; callers can inject a mock counter in tests.
-
-Either option removes all mutable state from `src/domain/` and makes the
-counter's ownership explicit at the layer that should own it (adapters).
diff --git a/docs/method/backlog/bad-code/installed-transport-execute-intent-table-driven.md b/docs/method/backlog/bad-code/installed-transport-execute-intent-table-driven.md
deleted file mode 100644
index ee1636e8..00000000
--- a/docs/method/backlog/bad-code/installed-transport-execute-intent-table-driven.md
+++ /dev/null
@@ -1,83 +0,0 @@
----
-title: installed-transport-execute-intent-table-driven
-lane: bad-code
-owner: jedit transport
-priority: medium
-keywords:
-  - transport
-  - duplication
-  - dispatch
-  - operation-table
----
-
-# `executeXxxIntent` functions are near-identical copy-paste
-
-## Where
-
-`src/adapters/installed-jedit-contract-echo-transport.ts`:
-
-- `executeCreateBufferIntent`
-- `executeReplaceRangeIntent`
-- `executeCreateCheckpointIntent`
-
-## Smell
-
-Each function is ~15 lines doing the same shape:
-
-```ts
-const invocation = invokeSchedulerHandler(mutations, invocationSink, (registry) => (
-    registry.executeMutation(request)
-));
-if (invocation.status === JEDIT_HANDLER_INVOCATION_STATUS_BLOCKED) {
-    return obstructedIntent(request, invocation.obstruction);
-}
-return {
-    status: JEDIT_TRANSPORT_STATUS_OK,
-    operationName: ,
-    execution: invocation.result,
-};
-```
-
-The only differences are the registry method called and the literal
-operation-name constant. Three near-identical functions; `executeIntent`
-is a hand-written switch routing to them.
-
-## Suggested refactor
-
-Table-driven dispatch keyed by `operationName`:
-
-```ts
-const MUTATION_DISPATCH = {
-  [CREATE_BUFFER_WORLDLINE_OPERATION]: (registry, request) =>
-    registry.executeCreateBufferWorldlineMutation(request),
-  [REPLACE_RANGE_AS_TICK_OPERATION]: (registry, request) =>
-    registry.executeReplaceRangeAsTickMutation(request),
-  [CREATE_CHECKPOINT_OPERATION]: (registry, request) =>
-    registry.executeCreateCheckpointMutation(request),
-} as const;
-```
-
-`executeIntent` becomes:
-
-```ts
-const handler = MUTATION_DISPATCH[request.operationName];
-const invocation = invokeSchedulerHandler(mutations, invocationSink, (r) => handler(r, request));
-if (invocation.status === JEDIT_HANDLER_INVOCATION_STATUS_BLOCKED) {
-    return obstructedIntent(request, invocation.obstruction);
-}
-return { status: JEDIT_TRANSPORT_STATUS_OK, operationName: request.operationName, execution: invocation.result };
-```
-
-Three handlers + one switch + three result-builders collapse to one
-table + one builder.
-
-## Why it matters
-
-The pattern recurs in `fake-echo-jedit-optic-transport.ts` and will
-recur in the EINT cutover when the transport learns to dispatch by
-op_id. Doing it three more times multiplies the smell.
-
-## Related
-
-- [[optic-codec-mixes-wire-with-session]] — the EINT cutover is a
-  good moment to also collapse this dispatch into a single table.
diff --git a/docs/method/backlog/bad-code/optic-codec-mixes-wire-with-session.md b/docs/method/backlog/bad-code/optic-codec-mixes-wire-with-session.md
deleted file mode 100644
index 1fb1bcc8..00000000
--- a/docs/method/backlog/bad-code/optic-codec-mixes-wire-with-session.md
+++ /dev/null
@@ -1,93 +0,0 @@
----
-title: optic-codec-mixes-wire-with-session
-lane: bad-code
-owner: jedit transport
-priority: high
-keywords:
-  - transport
-  - codec
-  - architecture
-  - wire-protocol
-  - session-lifecycle
----
-
-# `JeditIntentRequest` mixes wire data with client-side session
-
-## Where
-
-- `src/adapters/jedit-echo-optic-codec.ts` — defines
-  `JeditIntentRequest` discriminated union
-- `src/adapters/installed-jedit-contract-echo-transport.ts` —
-  decodes from JSON, dispatches handlers
-- `src/app/jedit-contract-mutation-handlers.ts` — handlers read
-  `request.session`
-
-## Smell
-
-`JeditIntentRequest` carries `session: JeditWorldlineSession` for
-`replaceRangeAsTick` and `createCheckpoint`. The session is the
-client-side cache of worldline state — `worldline`, `state`,
-`tickMetadata`, `checkpointMetadata`.
-
-The session belongs to the optic client. The wire (what flows
-through `submitIntentBytes`) belongs to the transport. Mixing them in
-one type means:
-
-- You cannot ship `JeditIntentRequest` over a real WASM transport
-  (the engine has no session concept)
-- The in-process transport is the only valid receiver because it can
-  read the session field directly
-- Every transport implementation has to know about jedit's
-  session-tracking strategy
-
-## Why it matters
-
-This is exactly what blocked the Phase 5 wire swap during the
-2026-05-28 0024 codec work. The EINT envelope can only carry
-`(op_id, encoded_input_bytes)` — session has no place there. So
-"swap encoder for encoder" can't happen without also restructuring
-how sessions reach handlers.
-
-## Suggested refactor (slice B of the EINT cutover)
-
-1. Add `JeditWorldlineSessionPort` (in-memory map of worldlineId →
-   session)
-2. Optic client registers session on the port before each call
-3. Transport unpacks EINT → `(opId, vars)`, decodes `vars` → input,
-   looks up session via the port using `input.worldlineId`
-4. Drop `session` from `JeditIntentRequest`; treat the type as a
-   pure transport-side dispatch shape
-
-## Side benefits when done
-
-- `encodeJsonIntentRequest` / Zod schemas covering session structure
-  become unreachable code — net deletion
-- Sets up Phase 4 (optic client async): the session port is also the
-  natural place for request-correlation state and lifecycle hooks
-- Real WASM transport gains parity with in-process transport
-
-## Surface when
-
-Starting the EINT cutover for the optic client. There's a Think
-handoff entry from 2026-05-28 that walks through the change in
-detail — see `[[handoff-1780002453726]]`.
-
-## Status update — 2026-05-29
-
-Partially resolved by Slice B of the EINT cutover (jedit commit
-`26a8f43`). The wire no longer carries session — only `(op_id, vars)`.
-A client-side `JeditWorldlineSessionPort` resolves session-by-worldlineId
-on the transport side after EINT decode.
-
-That fix is a **scaffold**, not a full resolution. The port is jedit code
-inventing an engine-flavored concept (causal context per writer) because
-Echo had no name for it. It works only because the optic client and the
-in-process transport share memory in the same process; it cannot ship
-across a real WASM transport.
-
-The full resolution is tracked by echo cycle 0025 — sessions as causal
-contexts (`echo/docs/design/0025-sessions-as-causal-contexts/design.md`)
-and its jedit-side companion [[sessions-migration]] in
-`docs/method/backlog/asap/`. When 0025 ships and jedit completes the
-migration phases, the session-port, its adapter, and the EINT bridge get
-deleted, and this card is fully resolved.
diff --git a/docs/method/backlog/cool-ideas/JEDIT_why-is-this-character-here-debugger.md b/docs/method/backlog/cool-ideas/JEDIT_why-is-this-character-here-debugger.md
deleted file mode 100644
index 840fa051..00000000
--- a/docs/method/backlog/cool-ideas/JEDIT_why-is-this-character-here-debugger.md
+++ /dev/null
@@ -1,135 +0,0 @@
----
-title: why-is-this-character-here-debugger
-lane: cool-ideas
-owner: jedit ui
-priority: medium-strategic
-keywords:
-  - jedit
-  - debugger
-  - causal-history
-  - echo
-  - sessions
-  - ui
-blocked_by:
-  - echo cycle 0025 Phase 2 (Session / event attribution shipping)
-  - jedit migration off the temporary session-port scaffold (leash fires)
-acceptance_criteria:
-  - A jedit motion (e.g. `g?`) on any glyph in the active buffer emits a structured causal-origin report.
-  - The report names the glyph, buffer offset, worldline, tick, originating intent kind, session id, and principal.
-  - The report's identifiers are queryable: clicking through to a session id opens its SessionEventLog projection, etc.
-  - Works against the real Echo transport; the fake/in-process transport is allowed to return a synthetic "no causal history available" sentinel rather than a fake answer.
----
-
-# `why are you here?` — point at a character, get its causal origin
-
-## The proposal
-
-A jedit UI gesture (motion `g?`, or the right-mouse equivalent) that
-takes the glyph under the cursor and asks Echo to attribute it.
-
-The answer:
-
-```text
-glyph:           "x"
-buffer offset:   1842
-worldline:       wl_2fac9d
-tick:            4729
-intent kind:     ReplaceRange { start: 1840, end: 1842, text: "ax" }
-session:         sess_3ce17b
-principal:       james@local        (or system/genesis for primordial bytes)
-receipt:         rcpt_8be9...
-causal parents:  [tick 4728, tick 4725]
-```
-
-That is not an editor feature. It is a category violation.
-
-Most text editors can answer:
-
-- "What file is this?" → trivially
-- "What commit last touched this line?" → `git blame`
-
-No editor in production can answer:
-
-- "What causal event created this byte, in which session, by which
-  principal, and what tick produced it?"
-
-Echo / jedit can — once Phase 2 of cycle 0025 ships engine-side
-Session attribution and SessionEventLog projections. This card
-records the UI gesture that turns that capability into a thing a
-normal human can use.
-
-## Why this is the killer feature
-
-The causal architecture is, today, invisible to the user. A typical
-session looks like a normal editor with extra contracts under the
-hood. The first feature that makes the architecture _visible_ —
-that lets the user reach in and ask Echo to explain a single byte —
-is the one that converts the engine investment into product
-differentiation.
-
-It also opens a follow-up surface (not in scope for this card):
-
-- "show me every byte attributed to session X" (visual highlight
-  over the buffer)
-- "show me every byte authored after tick N" (time-travel scrub
-  bar)
-- "rewind the buffer to before this intent" (worldline-level undo)
-- "fork from this tick" (split the worldline cleanly at a point in
-  the past)
-
-The first card surface is the gesture. The rest grow from it.
-
-## Dependencies
-
-- **Echo 0025 Phase 2** must land first. Without engine-side
-  `Session` / `SessionEventLog` / `IntentAccepted` attribution,
-  there is nothing to query. The query surface itself probably
-  belongs in the engine and the optic client surfaces it through
-  a new read-side observation.
-- **Jedit migration off the temporary session-port scaffold** must
-  complete. The current scaffold (leashed in
-  `docs/method/backlog/leash/jedit-session-port.md`) does not carry
-  engine-side session identity through; the query target would not
-  exist until that migration lands.
-
-This card stays in `cool-ideas/` until both dependencies clear. It
-is recorded now so it does not get reinvented from scratch later.
-
-## Why now (as a card, not as work)
-
-- The 2026-05-30 brainstorm captured this as the jedit-side
-  product differentiator. Carding it makes sure the idea survives
-  the noise.
-- Phase 2 RED authors should know this feature exists in the
-  backlog. If the engine-side query surface needs a particular
-  shape (e.g. a `byte_origin(worldline_id, offset, tick)` read
-  observation), it is easier to build that shape during Phase 2
-  GREEN than to retrofit it after.
-- The blocked-by chain is honest: this is not next-cycle work.
-  But the moment the chain clears, this is the first thing jedit
-  should build.
-
-## Out of scope here
-
-- The UI rendering of the causal report. A popover, a separate
-  pane, an MCP-mediated drawer — all reasonable; pick at
-  implementation time.
-- Performance work for large buffers. The query is per-glyph;
-  buffer-wide attribution (highlight every byte by session) is a
-  separate card.
-- "Why is this _line_ here?" The first cut is glyph-precision
-  because Echo's attribution is intent-precise; line-precision
-  invents a synthesis layer that does not yet have a natural
-  shape.
-
-## Companion
-
-- `docs/method/backlog/leash/jedit-session-port.md` — when this
-  leash fires, this card becomes implementable.
-- (Echo) `docs/design/0025-sessions-as-causal-contexts/phase-2-handoff.md`
-  — the engine-side `SessionEventLog` invariants this UI gesture
-  depends on.
-- (Echo) `docs/design/0025-sessions-as-causal-contexts/phase-2-notes.md`
-  — the pinned implementation decisions; in particular D4 (Session
-  storage module) and D5 (SessionEventLog strategy) determine the
-  read-side query shape this UI will call.
diff --git a/docs/method/backlog/cool-ideas/causal-undo-family.md b/docs/method/backlog/cool-ideas/causal-undo-family.md
deleted file mode 100644
index d67c9423..00000000
--- a/docs/method/backlog/cool-ideas/causal-undo-family.md
+++ /dev/null
@@ -1,109 +0,0 @@
----
-title: causal-undo-family
-lane: cool-ideas
-owner: jedit product
-priority: high-strategic
-keywords:
-  - jedit
-  - undo
-  - causal-history
-  - proposal-strands
-  - basis
-  - anchors
-  - agents
-blocked_by:
-  - Historical Basis Preview (goalpost 3)
-  - Search Sets / proposal strand preview + :admit (goalpost 4)
-  - why-is-this-character-here-debugger (g? attribution)
-acceptance_criteria:
-  - Every causal-undo variant lands as a forward counter-edit proposal strand that is previewed and admitted; no history deletion, ever.
-  - Regional time-rewind restores a cursor-scoped range to its state at a named time/checkpoint via materialize + diff + replaceRange proposal.
-  - Surgical revert attributes a line to its originating fact, synthesizes the inverse, and commutes it to head via anchor transforms; overlap surfaces as a typed obstruction offering cascade.
-  - Cascade revert computes downstream dependency closure from basis-bound edit evidence (edits whose reading basis included the reverted region), optionally refined by Graft structural dependencies.
-  - Principal-scoped cascade works: "revert everything this agent's edit caused downstream" produces one reviewable proposal strand.
----
-
-# Causal undo — the signature loop pointed backwards
-
-## The proposal
-
-Undo as a family of causal operations, not a stack pop:
-
-WF-0154 already provenance-named standard `u`/`ctrl+r`; this family leaves
-those commands unchanged and adds separately previewed forward counter-edits.
-
-1. **Surgical revert** — cursor on a line: "undo the change that introduced
-   this line." Attribution (`g?` machinery) -> inverse synthesis -> commute
-   to head via `transformPointAnchor` -> proposal strand. Overlap with later
-   edits = typed obstruction offering cascade or abort. Prior art: Berlage
-   selective undo; Darcs/Pijul unrecord + patch commutation.
-
-2. **Regional time-rewind** — "undo everything in this range since last
-   Wednesday." Spatially-scoped `:earlier`. No commutation needed:
-   materialize the historical window (Historical Basis Preview machinery),
-   diff against current, propose the restoring replaceRange. Cheapest slice;
-   ship first.
-
-3. **Cascade revert** — "undo this and its downstream causality." Dependency
-   closure over basis-bound edits: an edit whose reading basis/aperture
-   included the reverted region is downstream by construction. Bounded
-   observation apertures are what make this precise — narrow apertures =
-   tight causal graphs. Optional lenses: range-overlap (coarse), basis
-   (canonical), Graft structural (semantic).
-
-## Doctrine
-
-Every variant is authored counter-history (VISION "undo as authored
-counter-history, not deletion"): explain -> preview -> admit -> recover,
-pointed at history. Plain `u` stays dumb and instant; this family lives near
-`:why` / `g?`, never on `u`.
-
-## Agent-lane payoff
-
-Principal-scoped cascade is the accountable-editing demo in one command:
-"revert everything agent X's edit caused downstream," previewed as one
-proposal strand, admitted by a human. Structurally unavailable to editors
-without basis-bound reads.
-
-## Open design question to pin early
-
-Do `RopeDiff` facts retain replaced bytes (local inverse synthesis is cheap)
-or ranges only (inversion must materialize adjacent states / checkpoints)?
-Decides whether surgical revert is cheap or checkpoint-dependent.
-
-## Blast radius containment (design laws)
-
-The butterfly-effect failure mode is real and has exactly two causes to
-reject by design:
-
-1. **Dependency is non-commutation, never temporal order.** E2 depends on E1
-   only if E1's inverse fails to commute past it (spatial overlap /
-   anchor-transform failure). Treating "came after" as "depends on"
-   degenerates cascade into global `:earlier`.
-2. **Bases on edit intents must be minimal and honest** — the touched range
-   plus explicit reads, not the viewport. Aperture tightness is the knob
-   that decides scalpel vs bulldozer.
-
-Containment UX:
-
-- Preview shows concentric rings with counts before details: overlapping
-  edits / basis-dependent / structurally related (Graft). User picks the cut.
-- Hard radius budget: over N edits -> typed obstruction offering narrower
-  range, shallower ring, or surgical mode.
-- Surgical escape valve always offered: revert only the target, leave
-  downstream standing, emit conflict markers where the inverse cannot
-  commute (git-revert semantics).
-- Classify pathological chains: whitespace/format edits are transparent to
-  closure (commute aggressively through them); rename-shaped edits display
-  as one group, not per-site entries.
-- Huge radius is information, not failure: "212 edits stand on this line"
-  is an answer only this substrate can compute. Acting on it stays behind
-  preview -> admit.
-
-## Slice ladder
-
-1. `g?` attribution at coordinate (existing cool-idea, blocked on Echo
-   session/event attribution).
-2. Regional time-rewind via materialize + diff -> proposal -> `:admit`.
-3. Surgical revert with anchor-transform commutation + obstructions.
-4. Basis-closure cascade, then principal-scoped cascade.
diff --git a/docs/method/backlog/cool-ideas/echo-history-worldline-jump.md b/docs/method/backlog/cool-ideas/echo-history-worldline-jump.md
deleted file mode 100644
index 7810a106..00000000
--- a/docs/method/backlog/cool-ideas/echo-history-worldline-jump.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: echo-history-worldline-jump
-tags:
-  - echo
-  - history
-  - workspace
----
-
-# Echo History Worldline Jump
-
-Add the port-backed Enter action for the Echo History drawer.
-
-The drawer can already select workspace-visible Echo evidence rows. The missing
-piece is a jedit-owned port that asks Echo for a bounded reading at the selected
-evidence basis, then reprojects the editor without mutating current Echo
-history.
-
-Acceptance:
-
-- Enter on a selected history row requests a bounded historical basis through a
-  port, not through UI-local cache mutation.
-- The editor view shows the selected historical reading.
-- Footer or title posture makes historical-basis viewing explicit.
-- Esc or a clear command returns to the current basis.
-- Tests cover successful jump, obstruction, and current-history preservation.
diff --git a/docs/method/backlog/cool-ideas/inverse-fragment-digest-undo-proof.md b/docs/method/backlog/cool-ideas/inverse-fragment-digest-undo-proof.md
deleted file mode 100644
index 146f9570..00000000
--- a/docs/method/backlog/cool-ideas/inverse-fragment-digest-undo-proof.md
+++ /dev/null
@@ -1,62 +0,0 @@
----
-title: inverse-fragment-digest-undo-proof
-lane: cool-ideas
-owner: jedit runtime / echo
-priority: medium
-keywords:
-  - undo
-  - inverse-history
-  - RopeDiff
-  - inverseFragmentDigest
-  - causal
-acceptance_criteria:
-  - The idea documents how inverseFragmentDigest already encodes the information needed for tick-level undo.
-  - A plausible implementation path is sketched without requiring changes to the SDL.
----
-
-# inverse-fragment-digest-undo-proof
-
-The `RopeDiff` type in `contracts/jedit/rope.graphql` already has this field:
-
-```graphql
-type RopeDiff {
-    inverseFragmentDigest: String
-    # ...
-}
-```
-
-This is the SHA-256 hash of the bytes that were deleted by a `replaceRangeAsTick`
-operation. It exists specifically to support undo-as-inverse-history.
-
-## What this means
-
-Undo-as-inverse-history doesn't require storing the deleted bytes everywhere —
-it only requires being able to *look up* the deleted bytes by digest when an
-undo is requested. The full undo proof for any tick is:
-
-1. Find the `RopeDiff` for `tickId N`.
-2. Retrieve the deleted fragment by `inverseFragmentDigest` (from a blob store
-   or the in-memory roots array).
-3. Apply a new `replaceRangeAsTick` with `startByte = ropeDiff.startByte`,
-   `endByte = ropeDiff.startByte + ropeDiff.insertedByteLength`,
-   `insertText = deletedFragmentText`.
-
-This is already structurally encoded in the schema. The implementation is one
-step away from being provable.
-
-## Why this is interesting
-
-- The schema is already telling you the answer to "how do you undo?" — the
-  field exists, the semantics are specified, the causal chain is there.
-- Undo becomes a first-class causal *operation* rather than a snapshot pop.
-  The undo itself gets a tick, a receipt, and a `RopeDiff` — meaning undo is
-  auditable, replayable, and can itself be undone (redo).
-- The current snapshot-based undo (`undoStack: HistoryEntry[]`) can coexist
-  while this is built — the snapshots keep the UX working, the tick-based path
-  proves the substrate is ready.
-
-## The open question
-
-Echo needs to be able to retrieve a blob by digest (for the deleted fragment
-content). Once durable blob retention is wired, this path is open. The
-`missing_retention` posture marker is the exact gap this would close.
diff --git a/docs/method/backlog/cool-ideas/observer-plan-explainer-panel.md b/docs/method/backlog/cool-ideas/observer-plan-explainer-panel.md
deleted file mode 100644
index b4f380ac..00000000
--- a/docs/method/backlog/cool-ideas/observer-plan-explainer-panel.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: observer-plan-explainer-panel
-lane: cool-ideas
-owner: jedit runtime
-priority: medium
-keywords:
-  - observer
-  - plan
-  - explainer
-  - ui
-  - jedit
-acceptance_criteria:
-  - The idea describes one panel or debug surface that shows authored family, generated plan, and runtime reading together.
-  - The idea stays an explainer/debug surface rather than turning into product clutter by default.
----
-
-# observer-plan-explainer-panel
-
-Create a developer-facing explainer panel or debug view that shows the whole
-observer path for one app-owned read slice:
-
-- authored family
-- generated plan artifact
-- current runtime reading envelope
-
-Why it is interesting:
-
-- it would make the app/runtime split legible
-- it would help catch authority drift quickly
-- it would turn a lot of abstract doctrine into one concrete local view
-
-This is not a requirement for the product's main UI. It is a powerful
-developer-facing teaching and debugging surface.
-
diff --git a/docs/method/backlog/cool-ideas/partial-surface-region-caching.md b/docs/method/backlog/cool-ideas/partial-surface-region-caching.md
deleted file mode 100644
index 9ae2a8f0..00000000
--- a/docs/method/backlog/cool-ideas/partial-surface-region-caching.md
+++ /dev/null
@@ -1,64 +0,0 @@
----
-title: partial-surface-region-caching
-lane: cool-ideas
-owner: jedit ui
-priority: low
-keywords:
-  - rendering
-  - performance
-  - Surface
-  - bijou
-  - caching
-acceptance_criteria:
-  - The idea describes which Surface regions are candidates for caching and under what model conditions they are invalidated.
-  - The trade-off between cache complexity and allocation reduction is acknowledged.
----
-
-# partial-surface-region-caching
-
-`renderWorkspace` currently recomputes every region on every frame — header,
-file drawer, graft drawer, editor body, footer, overlays. Most of these regions
-are unchanged on a typical keystroke.
-
-## Candidate regions and their invalidation conditions
-
-| Region | Changes when... |
-|--------|-----------------|
-| File drawer | `entries`, `selectedIndex`, `fileDrawerProgress`, `graftDrawerProgress`, or `focusPane` changes |
-| Graft drawer | `graftInfo`, `graftDrawerProgress`, `graftSelectedIndex`, or `focusPane` changes |
-| Header | `editor.path`, `editor.dirty`, `cwd`, or `entries[selectedIndex]` changes |
-| Footer | `editor.mode`, `editor.dirty`, `textRuntimeProfile`, `focusPane` changes |
-| Editor body | `editor.lines`, `editor.cursorRow`, `editor.scrollRow`, `sourceHighlight`, `viewMode` change |
-
-On a typical Insert-mode keystroke, only the editor body and footer change.
-The drawers and header could be blitted from a cached `Surface` rather than
-recomputed.
-
-## Why it is interesting
-
-- The editor body is the region that changes most and is the most expensive to
-  compute (syntax highlighting, viewport clipping, cursor rendering). Caching
-  everything *except* the editor body flips the cost model — the expensive
-  region is always recomputed, but the cheap regions stop contributing.
-- For large terminals (wide drawers, tall graft panels), the saving could be
-  meaningful in terms of object allocation per frame.
-- The cache invalidation logic is straightforward — it is just a structural
-  equality check on the relevant model fields (or a generation counter bump).
-
-## Trade-off
-
-Adding a cache layer to `renderWorkspace` introduces state (the cached
-`Surface` values) into what is currently a pure function. The cache would need
-to live somewhere — either in the `WorkspaceModel` (making it explicit but
-adding size) or in a mutable closure in the adapter (hiding it from the model
-but breaking purity).
-
-A generation-counter approach is probably the cleanest: each cacheable region
-has a `number` in the model that increments when relevant fields change. The
-renderer checks the counter; if it matches the cached surface's counter, it
-blits the cache. If not, it recomputes and updates. This keeps the cache
-invalidation logic in `update` (where model mutations happen) and keeps
-`renderWorkspace` referentially transparent given the same model.
-
-This is an optimization, not a correctness concern — defer until profiling
-shows it is needed.
diff --git a/docs/method/backlog/cool-ideas/phase-4-and-session-port-coalesce.md b/docs/method/backlog/cool-ideas/phase-4-and-session-port-coalesce.md
deleted file mode 100644
index 87c65bae..00000000
--- a/docs/method/backlog/cool-ideas/phase-4-and-session-port-coalesce.md
+++ /dev/null
@@ -1,77 +0,0 @@
----
-title: phase-4-and-session-port-coalesce
-lane: cool-ideas
-owner: jedit transport
-priority: medium
-keywords:
-  - architecture
-  - async
-  - session-port
-  - eint
-  - lifecycle
-acceptance_criteria:
-  - The idea names why Phase 4 (optic client async) and the session-port refactor are one design.
-  - A composition sketch shows how both land in a single coherent middleware seam.
----
-
-# Phase 4 (optic client async) and the EINT session port are one slice
-
-## Observation
-
-The user's 7-phase plan for the rope codec migration treats:
-
-- Phase 4 (mutations become Promises to model real EINT round-trip)
-- Phase 5 (drop JSON wire, speak EINT + LE binary vars)
-- Phase 6 (`requestRunUntilIdle()` lifecycle wiring)
-
-as three separate phases. Architecturally they want to land together.
-
-## Why
-
-The structural change required by Phase 5 (per
-[[optic-codec-mixes-wire-with-session]]) introduces a
-`JeditWorldlineSessionPort` — a per-worldline lookup so the transport
-can resolve sessions from `worldlineId` after EINT decode. That port
-is also the natural seam for:
-
-- **Async correlation** (Phase 4): the optic client doesn't have an
-  immediate response; the port tracks pending requests by some
-  correlation id; the response arrives later and the port resolves
-  the matching Promise.
-- **Lifecycle hooks** (Phase 6): `requestRunUntilIdle()` is "drive
-  the scheduler until the in-flight requests have settled" — the
-  port already knows what's in-flight.
-
-If we build the session port for Phase 5 alone, we'll likely build it
-synchronously, then bolt async on top in Phase 4, then bolt lifecycle
-on top in Phase 6. Three bolt-ons compound into the wrong shape.
-
-## Sketch
-
-```ts
-interface JeditOpticTransportSeam {
-  // Register before dispatch, retrieve from transport side
-  registerSession(session: JeditWorldlineSession): void;
-
-  // Dispatch returns a Promise; correlation id is internal
-  dispatchEint(bytes: Uint8Array): Promise;
-
-  // Lifecycle: resolves when all in-flight requests settle
-  requestRunUntilIdle(): Promise;
-}
-```
-
-One port. One seam. All three phases land at once.
-
-## Risk
-
-Bigger atomic refactor. Higher chance of mid-flight regressions. But
-the alternative (three bolt-on revisions) is worse — each one
-re-touches the same files.
-
-## Surface when
-
-Starting slice B of the EINT cutover (see Think handoff
-`[[handoff-1780002453726]]`). Pause before committing to the
-single-port-sync design and consider whether async + lifecycle fit
-the same seam.
diff --git a/docs/method/backlog/cool-ideas/startup-modal-activity-picker.md b/docs/method/backlog/cool-ideas/startup-modal-activity-picker.md
deleted file mode 100644
index aa34b97e..00000000
--- a/docs/method/backlog/cool-ideas/startup-modal-activity-picker.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: startup-modal-activity-picker
-lane: cool-ideas
-owner: jedit ui
-priority: medium
-keywords:
-  - startup
-  - modal
-  - activity
-  - workspace
-  - echo-history
----
-
-# startup-modal-activity-picker
-
-Extend the startup file modal into a richer activity picker after the
-current-directory path is stable.
-
-The current modal deliberately starts with `WorkspaceModel.entries` so it can
-reuse the existing file-open and directory-navigation paths. A future iteration
-could add additional tabs or sections without replacing that foundation:
-
-- current directory files;
-- recently opened files from jedit-owned local posture;
-- recent Echo receipts or retained readings relevant to the workspace;
-- project roots discovered from explicit user action.
-
-Acceptance:
-
-- The current-directory section remains available and deterministic.
-- Any Echo activity section names the receipt, basis, and evidence posture
-  instead of presenting activity as an opaque log line.
-- Project or recent-file state is jedit-owned UI state, not Echo core state.
-- The picker still fits the Bijou small-terminal posture and falls back to the
-  existing minimum-terminal notice.
-- Tests cover section switching, filtering, selection, and opening without
-  bypassing the production text authority path.
diff --git a/docs/method/backlog/cool-ideas/symbol-capability-handle.md b/docs/method/backlog/cool-ideas/symbol-capability-handle.md
deleted file mode 100644
index 3d158974..00000000
--- a/docs/method/backlog/cool-ideas/symbol-capability-handle.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-title: symbol-capability-handle
-lane: cool-ideas
-owner: jedit app
-priority: low
-keywords:
-  - capability
-  - ReadBasisHandle
-  - symbol
-  - security
-  - optic
-acceptance_criteria:
-  - The idea describes how Symbol replaces WeakMap for ReadBasisHandle identity.
-  - The tradeoffs versus the current WeakMap approach are documented.
----
-
-# symbol-capability-handle
-
-The current `ReadBasisHandle` uses a `WeakMap` to
-store the binding between a handle object and a worldline. Object identity makes
-the handle unforgeable — you can't construct a fake handle that passes the
-registry lookup.
-
-A simpler mechanism exists: `Symbol()`.
-
-```typescript
-// Each call to Symbol() produces a value that is unique in the universe.
-// It cannot be serialized, cloned, or fabricated.
-const handle = Symbol('read-basis');
-const binding = new Map();
-binding.set(handle, { worldlineId: session.worldline.worldlineId });
-```
-
-## Why it is interesting
-
-- A `Symbol` is its own identity — no wrapper object needed.
-- Symbols are non-enumerable and cannot appear in JSON. Serializing one
-  produces `undefined`. There is no accidental leakage through `JSON.stringify`.
-- `Object.freeze` becomes unnecessary — you cannot assign properties to a Symbol.
-- A regular `Map` replaces the `WeakMap`. The binding is
-  explicitly owned by the registry and released when the optic closes the
-  session.
-- The handle type would change from `{ kind, id }` to a branded `symbol`, which
-  is arguably more honest — it *is* an opaque token, not a data record.
-
-## Trade-off vs current design
-
-The current `WeakMap` approach has one advantage: GC automatically reclaims the
-binding when the handle object is GC'd. A `Map` requires explicit
-cleanup (call `registry.release(handle)` when the session ends). For the
-current usage this is not a problem — sessions are explicitly opened and closed
-— but it is a maintenance consideration.
-
-The `{ kind, id }` shape of the current handle is also useful for diagnostics:
-the `id` string appears in logs and witness reports. A raw Symbol is opaque even
-in debug output (it serializes as nothing). A hybrid — keep the `{ kind, id }`
-data record for diagnostics, but bind authority to a Symbol field on the record
-— might be the best of both.
diff --git a/docs/method/backlog/cool-ideas/title-scene-primary-ray-acceleration.md b/docs/method/backlog/cool-ideas/title-scene-primary-ray-acceleration.md
deleted file mode 100644
index 2150518b..00000000
--- a/docs/method/backlog/cool-ideas/title-scene-primary-ray-acceleration.md
+++ /dev/null
@@ -1,66 +0,0 @@
-# Title Scene Primary-Ray Acceleration
-
-The title-scene mesh path still spends most close-camera render time traversing
-the mesh BVH before it reaches triangle tests.
-
-Evidence from `title/perf-scene-facts` after primary front-face culling:
-
-```bash
-node --cpu-prof \
-  --cpu-prof-dir /tmp/jedit-title-profile-frontface \
-  --cpu-prof-name title-mesh-frontface.cpuprofile \
-  scripts/title-scene-profile.mjs \
-  --scene neon-dispersion.jedit-scene \
-  --theme graphite \
-  --width 150 \
-  --height 43 \
-  --frames 60 \
-  --warmup 2 \
-  --camera-radius 2.6
-```
-
-Top self-time:
-
-```text
-rayIntersectsBounds        2744.5 ms  33.4%
-visitMeshNode               765.4 ms   9.3%
-titleMeshTriangleBarycentric 629.4 ms  7.6%
-sub                         559.9 ms   6.8%
-intersectTitleMeshTriangle  506.5 ms   6.2%
-```
-
-Potential next cuts:
-
-- Build a primary-only visible node list per frame or tile.
-- Add node-level facing/normal-cone rejection for primary camera rays.
-- Render primary rays in coherent tiles so adjacent samples reuse traversal
-  posture.
-- Consider a coarser screen-space silhouette/depth prepass for one-mesh title
-  scenes before expensive optical shading.
-- Add an offline mesh LOD build step for dense title meshes. The default title
-  mesh could ship with close, medium, and far variants selected from the camera
-  radius or projected screen coverage.
-- Explore a quantized temporal ray-hit cache keyed by scene id, mesh identity,
-  transform version, camera bucket, sample coordinate, and ray depth. Exact
-  ray keys are unlikely to repeat during camera motion, so this should behave
-  like temporal reprojection with explicit invalidation rather than a naive
-  `(origin, direction)` memo table.
-
-Implemented cut on `title/perf-scene-facts`:
-
-- The Braille title renderer now supports a temporal sample cache with
-  phase-based tracing. When the title scene is slow and the previous Braille
-  frame had high screen activity, live title frames trace half or quarter of
-  the Braille subpixels and reuse cached samples for the rest.
-- The adaptive policy keeps the last reduced phase count while screen activity
-  stays high, so close-camera mesh frames do not bounce between slow full
-  traces and fast reduced traces.
-- The pressure signal is ray-work based when the shader provides it:
-  intersection count divided by rays shot. Braille glyph activity is only the
-  fallback for shaders that do not expose ray pressure metadata.
-- When that pressure stays high and the title camera is actively settling, the
-  renderer drops to one traced subpixel per Braille cell for motion LOD, then
-  refines through the normal reduced phase policy after motion settles.
-- `scripts/title-scene-profile.mjs --braille-phase-count 4` reports traced,
-  reused, cold-miss, ray-pressure, and active sample facts so performance
-  claims can be measured instead of inferred from FPS alone.
diff --git a/docs/method/backlog/leash/jedit-session-port.md b/docs/method/backlog/leash/jedit-session-port.md
deleted file mode 100644
index a52cc237..00000000
--- a/docs/method/backlog/leash/jedit-session-port.md
+++ /dev/null
@@ -1,157 +0,0 @@
----
-scaffold: JeditWorldlineSessionPort
-repo: jedit
-introduced_by:
-  pr: 33
-  merged_sha: 90245c73
-  date: 2026-05-30
-  title: "feat(transport): jedit Slice A+B EINT cutover with first-class session port"
-reason: |
-  Echo cycle 0024 (universal LE binary codec) landed the wire-level
-  codec that the EINT cutover needs, but cycle 0025 (sessions as
-  causal contexts) only landed Phase 1 design — there is no engine-
-  side first-class Session / WorldlineId surface yet. To unblock the
-  jedit transport cutover without waiting on cycle 0025 Phase 2 GREEN,
-  PR #33 carries a client-side transitional session-port mirror so
-  the optic client can register a JeditWorldlineSession before each
-  call and the transport can look it up by the worldlineId embedded
-  in the decoded input. The cross-repo coordination argument was the
-  rebuttal posted on the resolved coderabbit Major thread at
-  src/ports/jedit-worldline-session-port.ts:30.
-deletion_trigger:
-  repo: echo
-  cycle: "0025-sessions-as-causal-contexts"
-  phase: "Phase 2 GREEN"
-  description: |
-    Once warp-core ships engine-side Session and WorldlineId as first-
-    class types (Phase 2 GREEN of echo cycle 0025), jedit deletes this
-    scaffold and threads SessionId / IntentId / IngressAddress through
-    instead. No client-side causal-context mirroring after that point.
-symbols:
-  - JeditWorldlineSessionPort
-  - JeditWorldlineSessionNotRegisteredError
-  - JeditWorldlineId
-  - JeditTransportSeam
-  - jeditSessionPort
-  - createInMemoryJeditWorldlineSessionPort
-  - installed-jedit-eint-bridge
-files:
-  - src/ports/jedit-worldline-session-port.ts
-  - src/ports/jedit-transport-seam.ts
-  - src/adapters/in-memory-jedit-worldline-session-port.ts
-  - src/adapters/installed-jedit-eint-bridge.ts
-  - spec/in-memory-jedit-worldline-session-port.spec.mjs
-  - spec/installed-jedit-eint-bridge.spec.mjs
-status: active
-companion_cards:
-  - docs/method/backlog/asap/sessions-migration.md
-  - docs/method/backlog/bad-code/optic-codec-mixes-wire-with-session.md
-related_threads:
-  - "PR #33 / src/ports/jedit-worldline-session-port.ts:30 (resolved, rebutted with cross-repo coordination rationale)"
-convention_card: echo/docs/method/backlog/cool-ideas/METHOD_leash-files.md
----
-
-# Leash: `JeditWorldlineSessionPort` (and the surrounding transitional session surface)
-
-This file is the structural, machine-readable record of the
-`JeditWorldlineSessionPort` scaffold's deletion contract. It is
-maintained as a sibling to the prose narrative card in
-`docs/method/backlog/asap/sessions-migration.md`; the prose is for
-humans, this file is for tooling. See
-[`echo/docs/method/backlog/cool-ideas/METHOD_leash-files.md`](https://github.com/flyingrobots/echo/blob/main/docs/method/backlog/cool-ideas/METHOD_leash-files.md)
-for the convention this file follows.
-
-## What is on the leash
-
-The transitional session surface introduced by PR #33 — the
-worldline session port itself, its in-memory adapter, the transport
-seam that prevents jedit-specific state from leaking back into the
-generic `EchoWasmKernelTransport`, the installed EINT bridge that
-mediates between the optic client and the kernel transport, and the
-associated spec files. These exist because Echo's engine has not yet
-published a first-class Session type; once it does, this whole layer
-collapses into a thin "thread `SessionId` through" pattern and the
-named symbols are deleted.
-
-## Deletion proof
-
-When the deletion trigger fires (echo cycle 0025 Phase 2 GREEN),
-the scaffold is considered deleted only when:
-
-1. `git grep` for each entry in `symbols` returns zero hits in
-   `src/` and `spec/`.
-2. The `companion_cards` are also retired:
-   - `docs/method/backlog/asap/sessions-migration.md` moves to
-     `docs/method/retro//` with the deletion SHA appended.
-   - `docs/method/backlog/bad-code/optic-codec-mixes-wire-with-session.md`
-     is fully resolved (not just partially), per its own acceptance
-     criteria.
-3. This leash file moves to `docs/method/graveyard/leash/` with the
-   deletion SHA appended.
-
-## Why both `JeditTransportSeam` and `jeditSessionPort` are on the list
-
-`JeditTransportSeam` is the TypeScript interface; `jeditSessionPort`
-is the runtime field name it requires (see
-`src/ports/jedit-transport-seam.ts` and the `isJeditTransportSeam`
-type guard). The grep proof needs the runtime key too, because a
-caller in `src/adapters/fake-echo-jedit-optic-transport.ts`,
-`src/adapters/installed-jedit-contract-echo-transport.ts`, or
-`spec/jedit-optic-client.spec.mjs` that still constructs a
-`{ jeditSessionPort: ... }` literal would be invisible to a grep
-that only searched for the interface name (TS types are
-compile-time; the runtime key is what survives into the emitted
-JS surface).
-
-## Adjacent symbols deliberately NOT on the leash
-
-- `JeditWorldlineSession` (from `src/app/jedit-contract-runtime.ts`)
-  is the real contract-runtime session and survives Phase 2; only
-  its identity backing changes. The `JeditWorldlineId` alias is on
-  the leash because its replacement by the engine-side `WorldlineId`
-  is part of the Phase 2 GREEN contract per its own JSDoc on
-  `src/ports/jedit-worldline-session-port.ts:11-30`.
-- The fake/installed transport adapters, optic-client surfaces, and
-  EINT codecs survive Phase 2 too; they thread `SessionId` through
-  instead of carrying client-side causal state. Do not leash them
-  here.
-
-## What this scaffold is NOT
-
-- Not a long-term API. Anything that grows out of these symbols
-  during the leash window should be considered guilty until proven
-  innocent; bias toward declining new responsibilities on the
-  session-port surface.
-- Not the right home for new transport features. New transport
-  capability that would otherwise want to live here should be
-  weighed against landing it on the engine side post-Phase-2
-  instead.
-
-## When the leash fires
-
-The trigger condition (`echo cycle 0025-sessions-as-causal-contexts /
-Phase 2 GREEN`) closes when warp-core ships the engine-side
-SessionId / WorldlineId / SessionEventLog / admission gate / system
-genesis session surface called out in
-`echo/docs/design/0025-sessions-as-causal-contexts/design.md` and
-`echo/docs/design/0025-sessions-as-causal-contexts/phase-2-handoff.md`.
-
-At that point, jedit's response is the migration described in the
-companion `asap/sessions-migration.md` card:
-
-- Jedit holds only a `SessionId` after migration, with no client-side
-  cache of engine causal state.
-- The named symbols above are deleted.
-- The optic client surface uses sessionId-addressed intent submission
-  and receives engine-emitted lifecycle events.
-- `optic-codec-mixes-wire-with-session.md` is fully resolved.
-
-## What this leash blocks
-
-If new code is being added to any of the named symbol surfaces while
-this leash is `active`, the right move is almost always to write the
-new capability in shape-of-Phase-2 (a thin pass-through that will
-trivially survive the deletion) rather than as a fully-featured port-
-side implementation. If that turns out to be impossible for a real
-near-term need, escalate by promoting this leash to the `escalated`
-status and tagging the next cycle.
diff --git a/docs/method/ci.md b/docs/method/ci.md
new file mode 100644
index 00000000..0ad9a18a
--- /dev/null
+++ b/docs/method/ci.md
@@ -0,0 +1,59 @@
+# Continuous Integration
+
+This document owns how Jedit CI decides what to run. The executable rules live in `scripts/ci/` and `.github/workflows/ci.yml`; when this page and those files disagree, the scripts are right and this page is wrong.
+
+## Jobs
+
+`.github/workflows/ci.yml` runs these jobs:
+
+| Job | Runs |
+| --- | --- |
+| `plan` | `scripts/ci/changed-shards.mjs` chooses the test shards and whether the release gate runs. |
+| `static / build` | `npm ci`, the TypeScript build, and the native Echo host; uploads `dist` and the host binary. |
+| `test / ` | One job per planned shard, using the uploaded `dist` with `JEDIT_DIST_PREBUILT=1`. |
+| `quality` | `scripts/quality-gate.mjs`, then `scripts/ci/shellcheck.sh` (see [ShellCheck](#shellcheck)). |
+| `release-gate / jedit-echo` | The Echo host witness, when the plan requires it. |
+| `edict / replace-range package and pure runtime chain` | The pinned Edict and Echo package chain for `edict/replace-range`, on every change. |
+| `check` | The required aggregate. It fails if plan, build, quality, or the Edict chain did not succeed, or if shards or the release gate failed rather than being skipped. |
+
+## Shards
+
+`scripts/ci/test-shards.mjs` assigns every spec under `spec/` and `tests/` to exactly one shard by file-name pattern:
+
+| Shard | Scope |
+| --- | --- |
+| `contract-api` | Contract, codec, observer, operation, and generated API specs. |
+| `cycle-proofs` | Cycle proof specs under `tests/`. |
+| `echo-authority` | Echo hosting, production text, restart, and release-authority specs. |
+| `misc-fast` | Small specs no narrower shard owns. |
+| `title-rendering` | Title scene, title screen, mesh, camera, and theme-rendering specs. |
+| `workspace-ui` | Workspace, drawer, key binding, footer, editor, panel, and UI interaction specs. |
+
+Specs that import compiled modules load them through `spec/dist-helpers.mjs`, so shard jobs never rebuild TypeScript.
+
+## Planning rules
+
+- The required GitHub check is `check`.
+- Pushes to `main`, manual runs with `full`, and pull requests labelled `full-ci` run every shard and the release gate.
+- Changes to `.github/`, `scripts/ci/`, the quality gate, TypeScript configuration, or non-Bijou package changes run every shard and the release gate. A package change that only bumps Bijou dependencies runs a narrower compatibility set.
+- Contract and generated-contract changes run `contract-api`, `echo-authority`, and the release gate. Echo authority surfaces run `echo-authority`, `workspace-ui`, and the release gate. Workspace, title, and other UI surfaces run their owning shards. Changes under `docs/`, `ARCHITECTURE.md`, and `README.md` run no test shard, because tests never read documentation; other root documents count as unrecognised paths. A changed spec runs its own shard.
+- A path the planner does not recognise runs every shard and the release gate.
+- Every plan runs build and quality.
+- Local `npm run check` runs the build, the full test suite, and the quality gate. ShellCheck runs in CI; run `scripts/ci/shellcheck.sh` locally when ShellCheck is installed.
+
+## ShellCheck
+
+`scripts/ci/shellcheck.sh` runs ShellCheck over every tracked shell script and
+over the `pre-commit` and `pre-push` launchers that `scripts/install-hooks.sh`
+generates, installed into a throwaway repository. A tracked file counts as a
+shell script when it ends in `.sh` or its shebang names `bash` or `sh` (Markdown
+files are never read, so they are never shell scripts), either
+directly (`#!/bin/sh`) or through a plain `env` (`#!/usr/bin/env bash`, with
+optional `NAME=value` assignments). An `env` shebang that uses options, quotes,
+or escapes (such as `#!/usr/bin/env -S bash -e`) fails the check with a message
+naming the file: use a plain shebang or a `.sh` extension. The classifier is
+`scripts/ci/lib/shebang.sh`, pinned by `spec/ci-shellcheck-shebang.spec.mjs`.
+
+## Title-scene freeze
+
+Pull requests that change frozen title-scene paths fail in `plan` unless they carry the `title-unfreeze` label. `scripts/ci/frozen-paths.mjs` defines the frozen patterns, and [title-scene-freeze.md](title-scene-freeze.md) records why the surface is frozen and how the freeze ends.
diff --git a/docs/method/documentation-lifecycle.md b/docs/method/documentation-lifecycle.md
new file mode 100644
index 00000000..07fabb61
--- /dev/null
+++ b/docs/method/documentation-lifecycle.md
@@ -0,0 +1,45 @@
+# Documentation Lifecycle
+
+This document owns when repository documentation is kept, rewritten, or deleted. It is listed in the ownership register in [durable-decisions.md](durable-decisions.md); `AGENTS.md` links here and adds nothing that contradicts it.
+
+## Git history is the archive
+
+Documentation in this repository describes what is true now and what is decided for the future. It is not a museum. Git history keeps every earlier version, so the working tree never needs to.
+
+- Delete documentation for retired interfaces, removed generation paths, superseded contracts, and abandoned implementation plans.
+- Do not keep a document solely as historical evidence, and do not create archive, graveyard, or "legacy" directories or banners to hold one.
+- When a document is deleted or moved, repair every link, router, index, and entrance that pointed at it in the same change.
+- Record what was deleted and why in the pull request description, not in a permanent file.
+
+## Deciding that something is obsolete
+
+A reference to code that no longer exists is a reason to look, not a verdict. Before classifying a document, confirm what happened to each thing it names:
+
+- removed, renamed, or moved (and to where);
+- generated at build time into an ignored path;
+- owned by another repository (Echo, Edict, Graft, Bijou);
+- planned by an accepted design that is still active.
+
+Check current code, build and generation scripts, accepted decisions, and open work. Then:
+
+- **Keep** a document that is accurate and current.
+- **Rewrite** a document whose purpose is current but whose passages are false. Fix the passages; do not add a caveat that the rest is outdated.
+- **Delete** a document whose subject is retired or whose only remaining value is narrating how something used to be built.
+
+Current accepted architecture and ownership rules stay explicit. An active, authorized design is not obsolete because its implementation is incomplete; it must say plainly which parts are implemented and which are target. Speculative plans and unsupported aspirations belong in GitHub issues, not in documents that present them as capabilities.
+
+## Design cycle documents
+
+A focused `docs/design/` document owns its cycle while the cycle is active, and afterwards only while it is still the canonical statement of a rule in force. When a cycle lands:
+
+- Move any rule that is still binding into its canonical owner (see the register in [durable-decisions.md](durable-decisions.md)) if it is not already there.
+- If the document then only narrates the cycle, delete it.
+- If it remains the canonical owner of a current rule, keep it current like any other owner.
+
+## Tests do not read documentation
+
+No spec, test, quality gate, or CI check reads a document's content or asserts what it says, so editing, moving, or deleting a document can never change a check's result. Copying a directory byte-for-byte into a fixture is not reading it; parsing a document, even only its first line, is. Tests pin behavior: package APIs, runtime output, rendered frames, command results, schemas, and tooling. A document is checked by the people who read it, not by a test, so a documentation change never needs a test change and a test never fails because prose moved. Inaccurate documentation is fixed; behavioral tests and release gates are not weakened to make a documentation change pass.
+
+## Unresolved authority
+
+If whether a document still governs anything is genuinely unclear, open an issue that states the question and the evidence on each side, and leave that document unchanged until it is answered. One unresolved document does not block the rest of a cleanup.
diff --git a/docs/method/durable-decisions.md b/docs/method/durable-decisions.md
index 21b19ac6..3a2ac213 100644
--- a/docs/method/durable-decisions.md
+++ b/docs/method/durable-decisions.md
@@ -17,12 +17,12 @@ a decision, but they are not its canonical repository home.
    `ARCHITECTURE.md` owns repository-wide doctrine;
    `docs/jim-component-ownership.md` owns the Jim/Jedit/Edict/Echo target
    ownership and causal model; a focused `docs/design/` document owns a design
-   cycle; `docs/method/` owns workflow policy; and `docs/BEARING.md` owns current
-   execution gravity.
+   cycle; `docs/method/` owns workflow policy; and `README.md` (*Current posture*)
+   owns current execution gravity.
 2. Record the accepted rule, its current-versus-target posture, and explicit
    refinement, supersession, dependency, and related-document edges.
 3. Update the relevant documentation entrance or router when a durable page is
-   added, moved, or renamed.
+   added, moved, renamed, or deleted.
 4. Link to the canonical owner from reader-specific pages instead of copying
    the same rule into several places.
 5. Keep implementation checklists in their cycle owner and live review or
@@ -31,6 +31,10 @@ a decision, but they are not its canonical repository home.
 6. Revisit the same canonical owner whenever later work refines the decision.
    A refinement is not complete while code, schemas, packages, runtime
    evidence, or release behavior disagree with the documented rule.
+7. When a decision retires or supersedes a document, move any rule that still
+   binds into its canonical owner and delete the old document, as
+   [documentation-lifecycle.md](documentation-lifecycle.md) requires. A
+   superseded document is not kept beside its replacement.
 
 ## Ownership register
 
@@ -40,7 +44,10 @@ a decision, but they are not its canonical repository home.
 | Jim/Jedit/Edict/Echo target ownership and causal model | `docs/jim-component-ownership.md` |
 | A design cycle | the focused `docs/design/` document for that cycle |
 | Workflow policy, including this policy | `docs/method/` |
-| Current execution gravity | `docs/BEARING.md` |
+| When documentation is kept, rewritten, or deleted (Git history is the archive) | `docs/method/documentation-lifecycle.md` |
+| What CI runs for a change | `docs/method/ci.md` |
+| Current execution gravity | `README.md` (*Current posture*) |
+| Product direction | `README.md` (*Where Jim is going*) |
 
 Rule 1 applies to this document too: workflow policy belongs in `docs/method/`,
 which is why the policy body lives here rather than in `AGENTS.md`.
diff --git a/docs/method/graveyard/anchor-transform-semantics.md b/docs/method/graveyard/anchor-transform-semantics.md
deleted file mode 100644
index c46bf477..00000000
--- a/docs/method/graveyard/anchor-transform-semantics.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: Anchor Transform Semantics
-lane: graveyard
-owner: jedit runtime
-priority: high
-acceptance_criteria:
-  - The cycle packet defines anchor transforms in terms of logical ReplaceRange receipts rather than rope maintenance.
-  - The red contract suite covers left-biased insertion, right-biased insertion, forward shift after replacement, and collapse inside deletion for point anchors.
-  - The runtime seam lives in src/domain/anchor-transform-contract.ts and remains intentionally minimal.
-  - The cycle scope explicitly excludes interval anchors, anchor persistence, and rope-maintenance events.
----
-
-# Anchor Transform Semantics
-
-## Disposition
-
-Cycle 0002 completed the point-anchor contract that this backlog item described. Keeping the umbrella note in `asap` now creates queue drift because its acceptance criteria are already satisfied. The remaining worthwhile work is narrower and should live as separate follow-on items: interval-anchor semantics, anchor persistence, editor integration, and the Echo adapter contract.
-
-## Original Proposal
-
-After `ReplaceRange`, the next sharp seam is anchor behavior. The point of
-this task is not to implement the full anchor system; it is to define the first
-contract for how a point anchor moves when a logical text edit happens.
-
-This slice should stay narrow:
-
-- point anchors only
-- logical ReplaceRange receipts only
-- bias-aware insertion behavior
-- forward shift and deletion collapse behavior
-
-## Non-goals
-
-- [ ] Interval anchors.
-- [ ] Anchor persistence or serialization.
-- [ ] Rope-maintenance transforms.
-- [ ] Wiring anchors into the current Bijou editor UI.
diff --git a/docs/method/graveyard/local-source-highlighting-before-graft-spans.md b/docs/method/graveyard/local-source-highlighting-before-graft-spans.md
deleted file mode 100644
index 0116937b..00000000
--- a/docs/method/graveyard/local-source-highlighting-before-graft-spans.md
+++ /dev/null
@@ -1,50 +0,0 @@
----
-title: local-source-highlighting-before-graft-spans
-lane: graveyard
-owner: jedit editor
-priority: medium
-keywords:
-  - source
-  - highlighting
-  - local
-  - fallback
-  - ux
-acceptance_criteria:
-  - jedit can colorize common source constructs locally without requiring new Graft APIs.
-  - The implementation stays explicitly limited to honest local syntax paint rather than pretending to be semantic understanding.
-  - At minimum, comments, strings, numbers, and obvious keyword classes are visually distinguishable in supported local modes.
-  - Unsupported or ambiguous languages fall back to plain source rather than misleading colorization.
----
-
-# local-source-highlighting-before-graft-spans
-
-## Disposition
-
-This note assumed jedit needed a local-highlighting stopgap before Graft had a usable dirty-buffer syntax surface. Repo truth changed: Graft now exposes a real StructuredBuffer API with syntax spans and related structural projections over in-memory content. The queue should prefer the renderer seam plus Graft-backed warm projections rather than a local fallback-first plan.
-
-Replacement: `docs/method/backlog/asap/source-render-pipeline-that-can-swap-local-and-graft-highlighting.md`
-
-## Original Proposal
-
-Ship useful local source paint before Graft buffer-aware syntax spans exist.
-
-Context:
-
-- The editor does not need to wait for new Graft features to become nicer to
-  read.
-- We already decided that fake AST claims are worse than honest local syntax
-  paint.
-- This note is the near-term user-facing improvement that sits on top of the
-  renderer pipeline seam.
-
-The important product posture is honesty:
-
-- local syntax paint is allowed
-- semantic claims are not
-- dirty buffers must never masquerade as parser-backed truth
-
-## Non-Goals
-
-- AST-truthful semantic highlighting.
-- Language-server style semantic token support.
-- Perfect coverage for every language jedit may eventually open.
diff --git a/docs/method/process.md b/docs/method/process.md
index 37a5bc76..53da605e 100644
--- a/docs/method/process.md
+++ b/docs/method/process.md
@@ -11,8 +11,9 @@ exercises the real software surface: package API, runtime behavior, rendered
 output, scripted app flow, command behavior, schema validation, lower-mode
 output, or CI/tooling behavior.
 
-Design-doc assertions may be tested as evidence-ledger checks, but they cannot
-be the only acceptance test for product, runtime, UI, or tooling work.
+Tests never read documentation: no spec, test, or quality gate reads a
+document's content or asserts its wording. See
+[documentation-lifecycle.md](documentation-lifecycle.md).
 
 A good jedit design doc is specific enough that another engineer or agent can
 write the RED test from it without asking what behavior is supposed to exist. A
@@ -39,7 +40,7 @@ Use `docs/method/roadmap-planning.md` when work spans multiple cycles, defines
 a release-gate batch, claims versioned-release readiness, or coordinates a set
 of user stories and slices.
 
-The roadmap policy does not replace this process. It explains how `BEARING.md`,
+The roadmap policy does not replace this process. It explains how the README's *Current posture*,
 release-gate docs, full-cycle design docs, GitHub issues, slices, PRs, and
 witnesses relate. The same proof rule still applies: roadmap and design docs
 define intent, while tests, release gates, generated artifacts, model facts, and
@@ -74,7 +75,7 @@ branch changes, fetch and merge the target branch normally.
 - Do not expand a slice because nearby cleanup is tempting.
 - If a slice exposes follow-on work, create a GitHub issue instead of hiding it
   in prose.
-- Keep `docs/BEARING.md` current when execution gravity changes.
+- Keep the README's *Current posture* current when execution gravity changes.
 
 ## Ready For Review
 
@@ -93,9 +94,10 @@ A cycle PR is ready only when:
 
 After a cycle lands:
 
-- Keep the design doc as the historical record when it remains useful.
-- Move superseded design material into feature docs, retrospectives, or
-  `docs/method/graveyard/`.
+- Move any rule the design doc still binds into its canonical owner, then keep
+  or delete the design doc as
+  [documentation-lifecycle.md](documentation-lifecycle.md) requires. Git
+  history is the archive; there is no retrospective or graveyard directory.
 - Close linked follow-on issues only when their executable witness exists.
 - Do not treat a landed design doc as runtime truth. Tests, code, generated
   artifacts, command output, and user-visible behavior are the proof.
diff --git a/docs/method/release-runbook.md b/docs/method/release-runbook.md
deleted file mode 100644
index af904ce0..00000000
--- a/docs/method/release-runbook.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Release Runbook
-
-Describe the sequential release pre-flight for this repository.
diff --git a/docs/method/release.md b/docs/method/release.md
deleted file mode 100644
index 6452a148..00000000
--- a/docs/method/release.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Release
-
-Describe when and how externally meaningful releases ship.
diff --git a/docs/method/releases/README.md b/docs/method/releases/README.md
deleted file mode 100644
index e713b29a..00000000
--- a/docs/method/releases/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Release Packets
-
-Store internal release design and verification artifacts here.
diff --git a/docs/method/retro/0001-replace-range-contract/replace-range-contract.md b/docs/method/retro/0001-replace-range-contract/replace-range-contract.md
deleted file mode 100644
index 5e387742..00000000
--- a/docs/method/retro/0001-replace-range-contract/replace-range-contract.md
+++ /dev/null
@@ -1,41 +0,0 @@
----
-title: "replace-range-contract"
-cycle: "0001-replace-range-contract"
-design_doc: "docs/design/0001-replace-range-contract/replace-range-contract.md"
-outcome: hill-met
-drift_check: yes
----
-
-# replace-range-contract Retro
-
-## Summary
-
-This cycle established the first executable `ReplaceRange` seam for the future
-text kernel and left behind passing contract evidence for the runtime behavior.
-Agent and human playback are now explicitly documented in the witness packet.
-
-## Playback Witness
-
-- [README.md](./witness/README.md)
-- [playback.md](./witness/playback.md)
-- [verification.md](./witness/verification.md)
-
-Both agent and human playback are now documented in the witness packet.
-
-## Drift
-
-- None recorded.
-
-## New Debt
-
-- None recorded.
-
-## Cool Ideas
-
-- None recorded.
-
-## Backlog Maintenance
-
-- [ ] Inbox processed
-- [ ] Priorities reviewed
-- [ ] Dead work buried or merged
diff --git a/docs/method/retro/0001-replace-range-contract/witness/README.md b/docs/method/retro/0001-replace-range-contract/witness/README.md
deleted file mode 100644
index abd4ad57..00000000
--- a/docs/method/retro/0001-replace-range-contract/witness/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: "Witness Index"
----
-
-This cycle now has explicit split playback evidence. Agent and human playback
-are both documented from repo-visible artifacts.
-
-## Artifacts
-
-- [playback.md](./playback.md)
-  Completed human and agent playback answers for the
-  `replace-range-contract` cycle, plus executable human-verification
-  instructions and sandbox setup steps.
-- [verification.md](./verification.md)
-  Reproducible build, test, and drift output captured during the cycle closeout.
-
-## Review Notes
-
-- The agent half is supported by committed tests, committed runtime source, and
-  rerunnable verification output.
-- The human half is now explicitly verified and the packet retains executable
-  local and sandboxed verification steps in `playback.md`.
-- This witness packet was expanded after the initial close so the repo matches
-  the updated METHOD playback rule requiring matching-perspective verification.
diff --git a/docs/method/retro/0001-replace-range-contract/witness/playback.md b/docs/method/retro/0001-replace-range-contract/witness/playback.md
deleted file mode 100644
index 2d8b7f95..00000000
--- a/docs/method/retro/0001-replace-range-contract/witness/playback.md
+++ /dev/null
@@ -1,189 +0,0 @@
----
-title: "Playback Witness"
----
-
-Date: 2026-04-13
-
-This cycle delivered the first executable `ReplaceRange` seam for the future
-text kernel.
-
-> **Retired:** This playback records a historical full-string implementation,
-> not the current architecture. The referenced source and tests were deleted
-> when Jim stopped simulating text authority and Echo admission in TypeScript.
-> The commands below are preserved as historical evidence and do not run at
-> the current tree.
-
-## Human Playback
-
-Status: Verified by the human operator on 2026-04-13.
-
-### How to execute this playback
-
-Quick local verification from the repo root:
-
-```sh
-npm run build
-node --test spec/replace-range.contract.spec.mjs tests/replace-range-cycle.spec.mjs
-npm run quality
-```
-
-Sandbox verification in an isolated copy when you do not want to use the live
-working tree:
-
-```sh
-export JEDIT_SANDBOX="$(mktemp -d /tmp/jedit-replace-range-playback.XXXXXX)"
-rsync -a --delete --exclude node_modules --exclude dist ./ "$JEDIT_SANDBOX"/
-cd "$JEDIT_SANDBOX"
-npm ci
-npm run build
-node --test spec/replace-range.contract.spec.mjs tests/replace-range-cycle.spec.mjs
-npm run quality
-```
-
-Expected outcome:
-
-- build exits `0`
-- the focused ReplaceRange contract tests pass
-- the quality gate exits `0`
-- the design and runtime files below match the stated human claims
-
-### ReplaceRange is named as the first kernel seam in this cycle.
-
-Yes.
-
-Suggested inspection:
-
-- [replace-range-contract.md](../../../design/0001-replace-range-contract/replace-range-contract.md)
-- [text-edit-algebra.md](../../../../design/text-edit-algebra.md)
-- [verification.md](./verification.md)
-
-Suggested commands:
-
-```sh
-sed -n '1,80p' docs/design/0001-replace-range-contract/replace-range-contract.md
-sed -n '1,120p' docs/design/text-edit-algebra.md
-```
-
-What to confirm:
-
-- the hill names `ReplaceRange` as the first explicit seam
-- the design treats it as current repo truth, not a future placeholder
-
-### This cycle pins down insert/materialization, delete-by-empty-fragment, and logical no-op.
-
-Yes.
-
-Suggested inspection:
-
-- [replace-range-contract.md](../../../design/0001-replace-range-contract/replace-range-contract.md)
-- [historical replace-range.contract.spec.mjs](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/spec/replace-range.contract.spec.mjs)
-- [verification.md](./verification.md)
-
-Suggested commands:
-
-```sh
-sed -n '20,70p' docs/design/0001-replace-range-contract/replace-range-contract.md
-sed -n '1,220p' spec/replace-range.contract.spec.mjs
-```
-
-What to confirm:
-
-- the design names insert/materialization, delete-by-empty-fragment, and no-op
-- the executable spec asserts those same three behaviors
-
-### This cycle limits scope to the minimal ReplaceRange seam.
-
-Yes.
-
-Suggested inspection:
-
-- [replace-range-contract.md](../../../design/0001-replace-range-contract/replace-range-contract.md)
-- [historical text-edit-contract.ts](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/src/domain/text-edit-contract.ts)
-- [verification.md](./verification.md)
-
-Suggested commands:
-
-```sh
-sed -n '35,95p' docs/design/0001-replace-range-contract/replace-range-contract.md
-sed -n '1,220p' src/domain/text-edit-contract.ts
-```
-
-What to confirm:
-
-- the non-goals exclude anchors, strands, admission, and rope persistence
-- the runtime file exposes only the minimal seam needed for this slice
-
-### This cycle makes accessibility, localization, and agent inspectability explicit.
-
-Yes.
-
-Suggested inspection:
-
-- [replace-range-contract.md](../../../design/0001-replace-range-contract/replace-range-contract.md)
-
-Suggested commands:
-
-```sh
-sed -n '55,95p' docs/design/0001-replace-range-contract/replace-range-contract.md
-```
-
-What to confirm:
-
-- accessibility and assistive reading are named explicitly
-- localization and directionality are named explicitly
-- agent inspectability and explainability are named explicitly
-
-## Agent Playback
-
-### ReplaceRange insertion satisfies the materialization law.
-
-Yes.
-
-Evidence:
-
-- [historical replace-range.contract.spec.mjs](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/spec/replace-range.contract.spec.mjs) asserted the insertion case directly.
-- [historical text-edit-contract.ts](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/src/domain/text-edit-contract.ts) implemented replacement by byte-range splice and materialization.
-- [verification.md](./verification.md) captures the passing contract suite.
-
-### ReplaceRange deletion is replacement by the empty fragment.
-
-Yes.
-
-Evidence:
-
-- [historical replace-range.contract.spec.mjs](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/spec/replace-range.contract.spec.mjs) asserted deletion via `emptyFragment()`.
-- [historical text-edit-contract.ts](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/src/domain/text-edit-contract.ts) applied the same replacement primitive to deletion.
-- [verification.md](./verification.md) captures the passing contract suite.
-
-### ReplaceRange returns the same root and no receipt for a logical no-op.
-
-Yes.
-
-Evidence:
-
-- [historical replace-range.contract.spec.mjs](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/spec/replace-range.contract.spec.mjs) asserted the no-op case directly.
-- [historical text-edit-contract.ts](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/src/domain/text-edit-contract.ts) compared replaced bytes against inserted bytes and returned the original root with no receipt when they matched.
-- [verification.md](./verification.md) captures the passing contract suite.
-
-### The runtime contract stays a minimal ReplaceRange seam rather than a full rope engine.
-
-Yes.
-
-Evidence:
-
-- [historical replace-range-cycle.spec.mjs](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/tests/replace-range-cycle.spec.mjs) checked the constrained export surface.
-- [historical text-edit-contract.ts](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/src/domain/text-edit-contract.ts) exposed only the minimal root, range, fragment, and receipt seam.
-- [replace-range-contract.md](../../../design/0001-replace-range-contract/replace-range-contract.md) keeps rope storage, anchors, strands, and admission out of scope.
-
-### The workspace satisfies build, quality, and the ReplaceRange contract suite.
-
-Yes.
-
-Evidence:
-
-- [verification.md](./verification.md) captures passing `npm test` output and clean drift output.
-- [historical replace-range-cycle.spec.mjs](https://github.com/flyingrobots/jedit/blob/e93b2e1a138a762d7a33da6179d3ad8b8b2a9c6e/tests/replace-range-cycle.spec.mjs) asserted the workspace-level verification surface.
-
-## Outcome
-
-Agent and human playback are both evidenced and complete.
diff --git a/docs/method/retro/0001-replace-range-contract/witness/verification.md b/docs/method/retro/0001-replace-range-contract/witness/verification.md
deleted file mode 100644
index d207a7ba..00000000
--- a/docs/method/retro/0001-replace-range-contract/witness/verification.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-title: "Verification Witness for Cycle 1"
----
-
-# Verification Witness for Cycle 1
-
-This witness proves that `replace-range-contract` now carries the required
-behavior and adheres to the repo invariants.
-
-## Test Results
-
-```text
-
-> test
-> node --test spec/**/*.spec.mjs tests/**/*.spec.mjs
-
-✔ quality gate holds the current baseline without regression (844.317083ms)
-✔ ReplaceRange inserts a fragment and satisfies the materialization law (1739.422333ms)
-✔ ReplaceRange deletes a range when given the empty fragment (1102.980417ms)
-✔ ReplaceRange returns the same root and no receipt for a logical no-op (1050.634791ms)
-✔ ReplaceRange is named as the first kernel seam in this cycle. (1.751ms)
-✔ This cycle pins down insert/materialization, delete-by-empty-fragment, and logical no-op. (0.3075ms)
-✔ This cycle limits scope to the minimal ReplaceRange seam. (0.148083ms)
-✔ This cycle makes accessibility, localization, and agent inspectability explicit. (0.151292ms)
-✔ ReplaceRange insertion satisfies the materialization law. (1688.642ms)
-✔ ReplaceRange deletion is replacement by the empty fragment. (0.162834ms)
-✔ ReplaceRange returns the same root and no receipt for a logical no-op. (0.103375ms)
-✔ The runtime contract stays a minimal ReplaceRange seam rather than a full rope engine. (0.931166ms)
-✔ The workspace satisfies build, quality, and the ReplaceRange contract suite. (1572.561958ms)
-ℹ tests 13
-ℹ suites 0
-ℹ pass 13
-ℹ fail 0
-ℹ cancelled 0
-ℹ skipped 0
-ℹ todo 0
-ℹ duration_ms 4035.936792
-
-```
-
-## Drift Results
-
-```text
-No playback-question drift found.
-Scanned 1 active cycle, 9 playback questions, 9 test descriptions.
-Search basis: exact normalized match in tests/**/*.test.* and tests/**/*.spec.* descriptions.
-
-```
-
-## Manual Verification
-
-- [x] Automated capture completed successfully.
diff --git a/docs/method/retro/0002-anchor-transform-semantics/anchor-transform-semantics.md b/docs/method/retro/0002-anchor-transform-semantics/anchor-transform-semantics.md
deleted file mode 100644
index 40bff975..00000000
--- a/docs/method/retro/0002-anchor-transform-semantics/anchor-transform-semantics.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: "anchor-transform-semantics"
-cycle: "0002-anchor-transform-semantics"
-design_doc: "docs/design/0002-anchor-transform-semantics/anchor-transform-semantics.md"
-outcome: hill-met
-drift_check: yes
----
-
-# anchor-transform-semantics Retro
-
-## Summary
-
-This cycle established the first point-anchor transform seam over logical
-`ReplaceRange` receipts and left behind passing contract evidence for the four
-scoped behaviors. Agent and human playback are now explicitly documented in the
-witness packet.
-
-## Playback Witness
-
-- [README.md](./witness/README.md)
-- [playback.md](./witness/playback.md)
-- [verification.md](./witness/verification.md)
-
-Both agent and human playback are now documented in the witness packet.
-
-## Drift
-
-- None recorded.
-
-## New Debt
-
-- None recorded.
-
-## Cool Ideas
-
-- None recorded.
-
-## Backlog Maintenance
-
-- [ ] Inbox processed
-- [ ] Priorities reviewed
-- [ ] Dead work buried or merged
diff --git a/docs/method/retro/0002-anchor-transform-semantics/witness/README.md b/docs/method/retro/0002-anchor-transform-semantics/witness/README.md
deleted file mode 100644
index 569e0ad4..00000000
--- a/docs/method/retro/0002-anchor-transform-semantics/witness/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: "Witness Index"
----
-
-This cycle now has explicit split playback evidence. Agent and human playback
-are both documented from repo-visible artifacts.
-
-## Artifacts
-
-- [playback.md](./playback.md)
-  Completed human and agent playback answers for the
-  `anchor-transform-semantics` cycle, plus executable human-verification
-  instructions and sandbox setup steps.
-- [verification.md](./verification.md)
-  Reproducible build, test, and drift output captured during the cycle closeout.
-
-## Review Notes
-
-- The agent half is supported by committed tests, committed runtime source, and
-  rerunnable verification output.
-- The human half is now explicitly verified and the packet retains executable
-  local and sandboxed verification steps in `playback.md`.
-- This witness packet was expanded after the initial close so the repo matches
-  the updated METHOD playback rule requiring matching-perspective verification.
diff --git a/docs/method/retro/0002-anchor-transform-semantics/witness/playback.md b/docs/method/retro/0002-anchor-transform-semantics/witness/playback.md
deleted file mode 100644
index dbe42c3b..00000000
--- a/docs/method/retro/0002-anchor-transform-semantics/witness/playback.md
+++ /dev/null
@@ -1,193 +0,0 @@
----
-title: "Playback Witness"
----
-
-Date: 2026-04-13
-
-This cycle delivered the first point-anchor transform seam over logical
-`ReplaceRange` receipts.
-
-## Human Playback
-
-Status: Verified by the human operator on 2026-04-13.
-
-### How to execute this playback
-
-Quick local verification from the repo root:
-
-```sh
-npm run build
-node --test spec/anchor-transform.contract.spec.mjs tests/anchor-transform-cycle.spec.mjs
-npm run quality
-```
-
-Sandbox verification in an isolated copy when you do not want to use the live
-working tree:
-
-```sh
-export JEDIT_SANDBOX="$(mktemp -d /tmp/jedit-anchor-transform-playback.XXXXXX)"
-rsync -a --delete --exclude node_modules --exclude dist ./ "$JEDIT_SANDBOX"/
-cd "$JEDIT_SANDBOX"
-npm ci
-npm run build
-node --test spec/anchor-transform.contract.spec.mjs tests/anchor-transform-cycle.spec.mjs
-npm run quality
-```
-
-Expected outcome:
-
-- build exits `0`
-- the focused anchor-transform contract tests pass
-- the quality gate exits `0`
-- the design and runtime files below match the stated human claims
-
-### Anchor transforms are defined in terms of logical ReplaceRange receipts rather than rope maintenance.
-
-Yes.
-
-Suggested inspection:
-
-- [anchor-transform-semantics.md](../../../design/0002-anchor-transform-semantics/anchor-transform-semantics.md)
-- [anchor-transform-contract.ts](../../../../src/domain/anchor-transform-contract.ts)
-- [verification.md](./verification.md)
-
-Suggested commands:
-
-```sh
-sed -n '1,90p' docs/design/0002-anchor-transform-semantics/anchor-transform-semantics.md
-sed -n '1,220p' src/domain/anchor-transform-contract.ts
-```
-
-What to confirm:
-
-- the design defines semantics in terms of logical `ReplaceRange` receipts
-- the runtime seam contains no rope-maintenance behavior
-
-### This cycle pins down left-bias, right-bias, forward shift, and collapse semantics for point anchors.
-
-Yes.
-
-Suggested inspection:
-
-- [anchor-transform-semantics.md](../../../design/0002-anchor-transform-semantics/anchor-transform-semantics.md)
-- [anchor-transform.contract.spec.mjs](../../../../spec/anchor-transform.contract.spec.mjs)
-- [verification.md](./verification.md)
-
-Suggested commands:
-
-```sh
-sed -n '20,70p' docs/design/0002-anchor-transform-semantics/anchor-transform-semantics.md
-sed -n '1,220p' spec/anchor-transform.contract.spec.mjs
-```
-
-What to confirm:
-
-- the design names left-bias, right-bias, forward shift, and collapse
-- the executable spec asserts those same four behaviors
-
-### This cycle limits scope to point anchors over ReplaceRange receipts.
-
-Yes.
-
-Suggested inspection:
-
-- [anchor-transform-semantics.md](../../../design/0002-anchor-transform-semantics/anchor-transform-semantics.md)
-- [anchor-transform-contract.ts](../../../../src/domain/anchor-transform-contract.ts)
-- [verification.md](./verification.md)
-
-Suggested commands:
-
-```sh
-sed -n '30,100p' docs/design/0002-anchor-transform-semantics/anchor-transform-semantics.md
-sed -n '1,220p' src/domain/anchor-transform-contract.ts
-```
-
-What to confirm:
-
-- the non-goals exclude interval anchors, persistence, rope maintenance, and UI
-- the runtime seam stays point-anchor only
-
-### This cycle makes accessibility, localization, and agent inspectability explicit.
-
-Yes.
-
-Suggested inspection:
-
-- [anchor-transform-semantics.md](../../../design/0002-anchor-transform-semantics/anchor-transform-semantics.md)
-
-Suggested commands:
-
-```sh
-sed -n '55,100p' docs/design/0002-anchor-transform-semantics/anchor-transform-semantics.md
-```
-
-What to confirm:
-
-- accessibility and assistive reading are named explicitly
-- localization and directionality are named explicitly
-- agent inspectability and explainability are named explicitly
-
-## Agent Playback
-
-### A left-biased point anchor stays before inserted text at its byte.
-
-Yes.
-
-Evidence:
-
-- [anchor-transform.contract.spec.mjs](../../../../spec/anchor-transform.contract.spec.mjs) asserts the left-bias insertion behavior directly.
-- [anchor-transform-contract.ts](../../../../src/domain/anchor-transform-contract.ts) keeps the anchor at the insertion byte when the bias is left.
-- [verification.md](./verification.md) captures the passing contract suite.
-
-### A right-biased point anchor moves after inserted text at its byte.
-
-Yes.
-
-Evidence:
-
-- [anchor-transform.contract.spec.mjs](../../../../spec/anchor-transform.contract.spec.mjs) asserts the right-bias insertion behavior directly.
-- [anchor-transform-contract.ts](../../../../src/domain/anchor-transform-contract.ts) advances the anchor by the inserted byte length when the bias is right.
-- [verification.md](./verification.md) captures the passing contract suite.
-
-### A point anchor after a replacement shifts by the replacement byte delta.
-
-Yes.
-
-Evidence:
-
-- [anchor-transform.contract.spec.mjs](../../../../spec/anchor-transform.contract.spec.mjs) asserts the forward-shift case directly.
-- [anchor-transform-contract.ts](../../../../src/domain/anchor-transform-contract.ts) applies the replacement byte delta to anchors after the replaced range.
-- [verification.md](./verification.md) captures the passing contract suite.
-
-### A point anchor inside a deleted span collapses to the replacement start.
-
-Yes.
-
-Evidence:
-
-- [anchor-transform.contract.spec.mjs](../../../../spec/anchor-transform.contract.spec.mjs) asserts the deletion-collapse case directly.
-- [anchor-transform-contract.ts](../../../../src/domain/anchor-transform-contract.ts) collapses anchors inside the replaced span to the replacement start.
-- [verification.md](./verification.md) captures the passing contract suite.
-
-### The runtime contract stays a minimal point-anchor seam rather than a full anchor system.
-
-Yes.
-
-Evidence:
-
-- [tests/anchor-transform-cycle.spec.mjs](../../../../tests/anchor-transform-cycle.spec.mjs) checks the constrained export surface.
-- [anchor-transform-contract.ts](../../../../src/domain/anchor-transform-contract.ts) exposes only the point-anchor and logical-receipt seam.
-- [anchor-transform-semantics.md](../../../design/0002-anchor-transform-semantics/anchor-transform-semantics.md) keeps interval anchors, persistence, rope maintenance, and UI integration out of scope.
-
-### The workspace satisfies build, quality, and the anchor transform contract suite.
-
-Yes.
-
-Evidence:
-
-- [verification.md](./verification.md) captures passing `npm test` output and clean drift output.
-- [tests/anchor-transform-cycle.spec.mjs](../../../../tests/anchor-transform-cycle.spec.mjs) asserts the workspace-level verification surface.
-
-## Outcome
-
-Agent and human playback are both evidenced and complete.
diff --git a/docs/method/retro/0002-anchor-transform-semantics/witness/verification.md b/docs/method/retro/0002-anchor-transform-semantics/witness/verification.md
deleted file mode 100644
index ce88bb5d..00000000
--- a/docs/method/retro/0002-anchor-transform-semantics/witness/verification.md
+++ /dev/null
@@ -1,66 +0,0 @@
----
-title: "Verification Witness for Cycle 2"
----
-
-# Verification Witness for Cycle 2
-
-This witness proves that `anchor-transform-semantics` now carries the required
-behavior and adheres to the repo invariants.
-
-## Test Results
-
-```text
-
-> test
-> node --test spec/**/*.spec.mjs tests/**/*.spec.mjs
-
-✔ A left-biased point anchor stays before inserted text at its byte (3160.906667ms)
-✔ A right-biased point anchor moves after inserted text at its byte (2872.463ms)
-✔ A point anchor after a replacement shifts by the replacement byte delta (2699.159333ms)
-✔ A point anchor inside a deleted span collapses to the replacement start (1847.179417ms)
-✔ quality gate holds the current baseline without regression (988.007666ms)
-✔ ReplaceRange inserts a fragment and satisfies the materialization law (2989.810125ms)
-✔ ReplaceRange deletes a range when given the empty fragment (3062.696625ms)
-✔ ReplaceRange returns the same root and no receipt for a logical no-op (2594.167084ms)
-✔ Anchor transforms are defined in terms of logical ReplaceRange receipts rather than rope maintenance. (3.543333ms)
-✔ This cycle pins down left-bias, right-bias, forward shift, and collapse semantics for point anchors. (0.308125ms)
-✔ This cycle limits scope to point anchors over ReplaceRange receipts. (0.163542ms)
-✔ This cycle makes accessibility, localization, and agent inspectability explicit. (0.12725ms)
-✔ A left-biased point anchor stays before inserted text at its byte. (3263.788916ms)
-✔ A right-biased point anchor moves after inserted text at its byte. (0.109417ms)
-✔ A point anchor after a replacement shifts by the replacement byte delta. (0.108458ms)
-✔ A point anchor inside a deleted span collapses to the replacement start. (0.081708ms)
-✔ The runtime contract stays a minimal point-anchor seam rather than a full anchor system. (1.971959ms)
-✔ The workspace satisfies build, quality, and the anchor transform contract suite. (3924.367416ms)
-✔ ReplaceRange is named as the first kernel seam in this cycle. (1.124042ms)
-✔ This cycle pins down insert/materialization, delete-by-empty-fragment, and logical no-op. (0.233042ms)
-✔ This cycle limits scope to the minimal ReplaceRange seam. (0.142625ms)
-✔ This cycle makes accessibility, localization, and agent inspectability explicit. (0.141542ms)
-✔ ReplaceRange insertion satisfies the materialization law. (3032.772917ms)
-✔ ReplaceRange deletion is replacement by the empty fragment. (0.321666ms)
-✔ ReplaceRange returns the same root and no receipt for a logical no-op. (0.217084ms)
-✔ The runtime contract stays a minimal ReplaceRange seam rather than a full rope engine. (1.092875ms)
-✔ The workspace satisfies build, quality, and the ReplaceRange contract suite. (3915.977083ms)
-ℹ tests 27
-ℹ suites 0
-ℹ pass 27
-ℹ fail 0
-ℹ cancelled 0
-ℹ skipped 0
-ℹ todo 0
-ℹ duration_ms 10747.689792
-
-```
-
-## Drift Results
-
-```text
-No playback-question drift found.
-Scanned 1 active cycle, 10 playback questions, 19 test descriptions.
-Search basis: exact normalized match in tests/**/*.test.* and tests/**/*.spec.* descriptions.
-
-```
-
-## Manual Verification
-
-- [x] Automated capture completed successfully.
diff --git a/docs/method/roadmap-planning.md b/docs/method/roadmap-planning.md
index 7ce130b0..e5181c17 100644
--- a/docs/method/roadmap-planning.md
+++ b/docs/method/roadmap-planning.md
@@ -31,7 +31,7 @@ an executable or inspectable software surface.
 | Acceptance Criteria | Completion contract | Docs and issue bodies |
 | Validation Plan | Required proof commands | Design docs and PR bodies |
 | Pull Request | Review and merge vehicle | GitHub PR |
-| Changelog Entry | Historical ledger | `CHANGELOG.md` or `docs/BEARING.md` |
+| Changelog Entry | Release notes | `CHANGELOG.md` |
 
 ## Relationship Model
 
@@ -196,33 +196,22 @@ Versioned release planning has four jobs:
 4. Define the release gate that must be true before the version can be called
    landed.
 
-The current roadmap instance is the Echo-hosted jedit `v0.1.0` completion
-roadmap:
-
-- Roadmap index:
-  `docs/BEARING.md`
-- Baseline release-gate design:
-  `docs/design/0024-jedit-powered-by-echo-release-gate.md`
-- Production cutover design:
-  `docs/design/0027-echo-hosted-production-cutover.md`
-- Recovery and WSC scope:
-  `docs/design/0033-echo-authoritative-recovery-gate-b.md`
-  and `docs/design/0035-jedit-wsc-durability-scope.md`
-- Goalpost docs and umbrella issues:
-  create or update them when the `v0.1.0` roadmap is scaffolded under this
-  policy
+No versioned release roadmap is active. The `v0.1.0` roadmap was retired after
+its authority claim was invalidated; current direction is the README's *Current posture*
+and the [Jim.edict goalpost](https://github.com/flyingrobots/jedit/issues/295).
+A new roadmap starts from this policy when a release is planned.
 
 ### Versioned Release Contract
 
 ```text
 VersionedRelease = {
-  id: "v0.1.0",
-  name: "Echo-Hosted jedit Completion Roadmap",
+  id: "vMAJOR.MINOR.PATCH",
+  name: string,
   roadmapDoc: MarkdownDocument,
   goalposts: Goalpost[],
   releaseGate: ChecklistItem[],
   totalSliceBudget: PositiveInteger,
-  status: "planned" | "active" | "landed" | "superseded"
+  status: "planned" | "active" | "landed"
 }
 ```
 
@@ -231,45 +220,8 @@ VersionedRelease = {
 A versioned release is ready when every goalpost in the release is landed and
 the release-level gate is satisfied.
 
-For Echo-hosted jedit `v0.1.0`, the release gate is:
-
-- [ ] The production text model is Echo-hosted; non-Echo runtime profiles are
-      not exposed as product paths.
-- [ ] jedit app code submits product intents and observes readings through
-      product ports such as `TextBufferSessionPort` and `TextBufferOptic`.
-- [ ] Trusted host code owns package install, scheduler lifecycle, fault
-      recovery, and runtime control.
-- [ ] jedit never exposes Echo runtime coordinates as app-facing product
-      authority.
-- [ ] Graft remains structural intelligence, not editing truth.
-- [ ] Workspace render caches, footer state, preview, highlighting, save/export,
-      and recovery flows do not become hidden text authority.
-- [ ] Missing Echo retention, replay, WSC, or recovery evidence is reported as
-      explicit obstruction or unavailable posture, not local fallback truth.
-- [ ] UI behavior is proven through model/render/runtime tests or lower-mode
-      facts, not screenshots alone.
-- [ ] A single validation command or release checklist proves readiness.
-
-### Release Sequencing
-
-```mermaid
-flowchart LR
-  V010[v0.1.0 Release]
-  V010 --> GP1[GP1 Echo-Hosted Text Authority]
-  V010 --> GP2[GP2 Interactive Workspace Cutover]
-  V010 --> GP3[GP3 Echo Recovery And WSC Durability]
-  V010 --> GP4[GP4 File Lifecycle And Export]
-  V010 --> GP5[GP5 Vim UX And Command Surface]
-  V010 --> GP6[GP6 Release Quality And Packaging]
-
-  GP1 --> GP2
-  GP1 --> GP3
-  GP2 --> GP4
-  GP3 --> GP4
-  GP2 --> GP5
-  GP4 --> GP6
-  GP5 --> GP6
-```
+Each roadmap document states its release gate as a checklist of executable
+conditions.
 
 ### Version Naming
 
@@ -277,9 +229,8 @@ Use SemVer roadmap names when a body of work has a release-level definition of
 complete. Release IDs must include the leading `v` and all three SemVer
 positions:
 
-- `v0.1.0`: first version that can reasonably be called Echo-hosted.
-- `v0.2.0`: compatible feature or workflow release after `v0.1.0`.
-- `v0.2.1`: patch release for fixes, docs, or proof hardening.
+- `v0.3.0`: a feature or workflow release before the first complete version.
+- `v0.3.1`: a patch release for fixes, docs, or proof hardening.
 - `v1.0.0`: first version that can reasonably be called complete from a user's
   perspective.
 
@@ -301,7 +252,7 @@ Authority flows in this order:
    generated artifacts, command output, and CI checks.
 3. GitHub Issues and pull requests.
 4. Design docs and roadmap docs.
-5. `CHANGELOG.md`, `docs/BEARING.md`, and release notes.
+5. `CHANGELOG.md`, the README's *Current posture*, and release notes.
 6. Coordination memory.
 
 Memory notes help coordination, but they do not override files, commits,
@@ -312,7 +263,7 @@ witnesses.
 
 ```text
 Goalpost = {
-  id: "JEDIT-V0.1-GP",
+  id: "JEDIT-V.-GP",
   title: string,
   umbrellaIssue: GitHubIssue,
   designDoc: MarkdownDocument,
@@ -321,7 +272,7 @@ Goalpost = {
   checklist: Slice[],
   acceptanceCriteria: ChecklistItem[],
   validationPlan: CommandOrWitness[],
-  completionState: "planned" | "active" | "landed" | "superseded"
+  completionState: "planned" | "active" | "landed"
 }
 ```
 
@@ -430,9 +381,9 @@ stateDiagram-v2
   Active --> ReviewReady: slices complete + validation green
   ReviewReady --> Landed: PR merged
   ReviewReady --> Active: review issues found
-  Active --> Superseded: roadmap changes
+  Active --> Retired: roadmap changes; its document is deleted
   Landed --> [*]
-  Superseded --> [*]
+  Retired --> [*]
 ```
 
 ### Cycle Lifecycle
@@ -476,25 +427,6 @@ Acceptable proof includes:
 Docs can explain the contract. They cannot be the only evidence that the
 contract works.
 
-## Current Roadmap Instance
-
-| Goalpost | Slice budget | Umbrella issue |
-| --- | ---: | --- |
-| JEDIT-V0.1-GP1 Echo-Hosted Text Authority | 18 | TBD |
-| JEDIT-V0.1-GP2 Interactive Workspace Cutover | 22 | TBD |
-| JEDIT-V0.1-GP3 Echo Recovery And WSC Durability | 24 | TBD |
-| JEDIT-V0.1-GP4 File Lifecycle And Export | 18 | TBD |
-| JEDIT-V0.1-GP5 Vim UX And Command Surface | 18 | TBD |
-| JEDIT-V0.1-GP6 Release Quality And Packaging | 16 | TBD |
-
-Current release: `v0.1.0`.
-
-Total planned budget: 116 slices.
-
-The `TBD` umbrella issues should be created when the roadmap is formally
-scaffolded under this policy. Until then, do not report percentage progress
-from this table as landed truth.
-
 ## Operating Invariants
 
 - Every versioned release has a roadmap document.
@@ -514,50 +446,18 @@ from this table as landed truth.
 - Bijou owns terminal runtime mechanics, not causal semantics.
 - Changes are committed as normal commits, never amended.
 - Branches, commits, and PRs do not use a `codex` prefix.
-- PRs are non-draft unless repo policy changes.
-
-## Vision And Bearing Recommendation
-
-jedit should keep `BEARING.md` and `VISION.md`.
-
-### Keep `BEARING.md`
-
-`BEARING.md` already exists and is useful. It should remain the short
-operational orientation document:
-
-- what jedit is right now
-- what recently shipped
-- what is currently risky
-- what open loops matter next
-- what constraints an agent or engineer should remember before touching the
-  repo
-
-`BEARING.md` should be updated frequently and should stay factual. It should
-not become a product manifesto, backlog, or issue tracker.
-
-### Keep `VISION.md`
-
-Root-level `VISION.md` is the stable north star for jedit. It should answer:
-
-- Who is jedit for?
-- What job should it become excellent at?
-- What does "complete" mean from a user's perspective?
-- What should jedit refuse to become?
-- What product principles should guide roadmap tradeoffs?
-- Which workflows define success one year from now?
-
-`VISION.md` should change rarely. It should guide release roadmaps without
-becoming a roadmap itself.
+- Draft pull requests follow `docs/method/process.md`.
 
-### Recommended Separation
+## Planning Document Roles
 
 | Document | Time horizon | Primary question | Update frequency |
 | --- | --- | --- | --- |
-| `VISION.md` | Long-term | Where are we going? | Rare |
-| `BEARING.md` | Current state | Where are we now? | Frequent |
+| `README.md` *Where Jim is going* | Long-term | Where are we going? | Rare |
+| `README.md` *Current posture* | Current state | Where are we now? | Frequent |
 | Roadmap docs | Release cycle | What must land for this version? | Per release |
 | Goalpost docs | Milestone | What will this goalpost prove? | Per goalpost |
-| GitHub Issues | Execution | What work remains? | Continuous |
+| GitHub issues | Execution | What work remains? | Continuous |
 
-Keep `BEARING.md` explicitly pointed at `VISION.md` for long-term direction and
-to roadmap docs for release execution.
+*Current posture* stays factual; it is not a manifesto, backlog, or issue
+tracker. When a roadmap or goalpost is finished or abandoned, its document
+is deleted as [documentation-lifecycle.md](documentation-lifecycle.md) requires.
diff --git a/docs/method/backlog/leash/title-scene-freeze.md b/docs/method/title-scene-freeze.md
similarity index 87%
rename from docs/method/backlog/leash/title-scene-freeze.md
rename to docs/method/title-scene-freeze.md
index 4d76bad6..c146f692 100644
--- a/docs/method/backlog/leash/title-scene-freeze.md
+++ b/docs/method/title-scene-freeze.md
@@ -40,7 +40,8 @@ escape_hatch: |
 
 # title-scene-freeze
 
-The ray-traced title scene is frozen. It stays exactly as beautiful as it is
-today. PRs that touch frozen title paths fail the CI plan step unless they
+The ray-tracer engine and scene assets are frozen. Since DX-0160 the title
+screen shows a static logo, and the engine is reachable only through the
+`title:preview`, `title:profile`, and `title:record` tools. PRs that touch frozen title paths fail the CI plan step unless they
 carry the `title-unfreeze` label. See frontmatter for enforcement, escape
 hatch, and the deletion trigger.
diff --git a/docs/releases/README.md b/docs/releases/README.md
deleted file mode 100644
index 0d4c90b5..00000000
--- a/docs/releases/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# Releases
-
-Store user-facing release notes and migration guides here.
-
-- [v0.1.0 Echo release gate](v0.1.0/README.md)
-- [v0.1.0 quickstart](v0.1.0/quickstart.md)
diff --git a/docs/releases/v0.1.0/README.md b/docs/releases/v0.1.0/README.md
deleted file mode 100644
index 6225b2a3..00000000
--- a/docs/releases/v0.1.0/README.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# jedit v0.1.0 Echo Release Gate
-
-Status: **retired and invalidated**.
-
-The former v0.1.0 release gate claimed that Jim was powered by Echo for a
-narrow edit/read workflow. Audit showed that the normal path admitted work,
-scheduled it, mutated text, constructed receipts, stored graph facts, and
-served observations inside process-local TypeScript. Echo-shaped interfaces
-did not make that execution Echo authority.
-
-## What Was Removed
-
-- the full-snapshot text runtime fixture from production source;
-- the TypeScript graph-rope execution runtime;
-- the local installed-contract transport and EINT bridge;
-- local mutation handlers, query observers, submission ledgers, and state
-  authority used by that path;
-- fake Echo transports and production fixture CLIs;
-- executable documentation that promoted local replay as Echo evidence.
-
-## Current Boundary
-
-Jim now launches a trusted native Echo host, registers a package generated
-from a narrow GraphQL contract by Echo's Wesley extension, and performs
-create/open, single-range replacement, and bounded reads through real Echo
-admission, scheduling, graph history, receipts, observations, and WAL recovery.
-Unsupported operations fail closed.
-
-Echo remains generic. Jim owns rope and editor semantics. Edict will replace
-the transitional Wesley/Rust invocation corridor. Echo owns admission,
-scheduling, ticks, receipts, witnessed causal history, and basis-pinned
-observations.
-
-## Evidence Commands
-
-```bash
-npm run build
-node scripts/jedit-production-cutover-guard.mjs
-npm run witness:echo
-npm run check
-```
-
-## Historical Artifacts
-
-The following files are retained only as audit artifacts:
-
-- [`final-witness-report.json`](final-witness-report.json)
-- [`local-replay-report.json`](local-replay-report.json)
-- [`pr-notes.md`](pr-notes.md)
-
-Their successful statuses describe the retired local witness. They are not
-current Echo integration receipts and must not be cited as proof of production
-authority.
-
-See [quickstart.md](quickstart.md) for the honest current startup posture.
diff --git a/docs/releases/v0.1.0/final-witness-report.json b/docs/releases/v0.1.0/final-witness-report.json
deleted file mode 100644
index cf41a4d3..00000000
--- a/docs/releases/v0.1.0/final-witness-report.json
+++ /dev/null
@@ -1,202 +0,0 @@
-{
-  "ok": true,
-  "schemaVersion": 1,
-  "transport": "installed-jedit-contract",
-  "dryRun": false,
-  "install": {
-    "packageId": "jedit.hot-text-runtime",
-    "version": "0.1.0-release-gate",
-    "schemaId": "contracts/jedit/hot-text-runtime.graphql",
-    "artifactId": "src/generated/jedit/hot-text-runtime.wesley.generated.ts",
-    "codecId": "jedit-hot-text-runtime-json-v1"
-  },
-  "authority": {
-    "appFacingSessionPort": "TextBufferSessionPort",
-    "appFacingBufferCapability": "TextBufferOptic",
-    "appCanTick": false,
-    "trustedLifecyclePort": "TrustedEchoRuntimeLifecyclePort"
-  },
-  "lifecycleRequests": [
-    {
-      "tickIntervalSeconds": 0.016666666666666666
-    },
-    {
-      "cycleLimit": 4
-    }
-  ],
-  "startup": {
-    "accepted": true,
-    "lastRunCompletion": "started"
-  },
-  "drain": {
-    "accepted": true,
-    "lastRunCompletion": "quiesced"
-  },
-  "stopRequests": [
-    {
-      "requested": true
-    }
-  ],
-  "shutdown": {
-    "accepted": true,
-    "lastRunCompletion": "stopped",
-    "appCanTick": false
-  },
-  "report": {
-    "bufferId": "text-buffer:0",
-    "bufferKey": "agent-demo.txt",
-    "outcome": {
-      "status": "APPLIED",
-      "intent": {
-        "kind": "jedit-intent-handle",
-        "operationName": "replaceRangeAsTick",
-        "submissionId": "jedit-submission:7b226275666665724964223a22746578742d6275666665723a30222c22656e6442797465223a302c22696e7365727454657874223a2268656c6c6f204563686f222c22737461727442797465223a307d"
-      },
-      "receipt": {
-        "kind": "jedit-receipt-handle",
-        "receiptId": "receipt:1"
-      }
-    },
-    "outcomeTrail": [
-      {
-        "status": "ACCEPTED_PENDING",
-        "intent": {
-          "kind": "jedit-intent-handle",
-          "operationName": "replaceRangeAsTick",
-          "submissionId": "jedit-submission:7b226275666665724964223a22746578742d6275666665723a30222c22656e6442797465223a302c22696e7365727454657874223a2268656c6c6f204563686f222c22737461727442797465223a307d"
-        }
-      },
-      {
-        "status": "APPLIED",
-        "intent": {
-          "kind": "jedit-intent-handle",
-          "operationName": "replaceRangeAsTick",
-          "submissionId": "jedit-submission:7b226275666665724964223a22746578742d6275666665723a30222c22656e6442797465223a302c22696e7365727454657874223a2268656c6c6f204563686f222c22737461727442797465223a307d"
-        },
-        "receipt": {
-          "kind": "jedit-receipt-handle",
-          "receiptId": "receipt:1"
-        }
-      }
-    ],
-    "evidencePosture": {
-      "scope": "LOCAL_PROCESS_WITNESS",
-      "receiptCorrelation": "RECEIPT_CORRELATION_MISSING",
-      "ticketedRuntimeIngress": "TICKETED_RUNTIME_INGRESS_MISSING",
-      "durableAcceptedSubmissionRecovery": "UNAVAILABLE",
-      "syntheticReceiptClaimed": false
-    },
-    "receiptCorrelation": {
-      "status": "RECEIPT_CORRELATION_MISSING",
-      "submissionId": "jedit-submission:7b226275666665724964223a22746578742d6275666665723a30222c22656e6442797465223a302c22696e7365727454657874223a2268656c6c6f204563686f222c22737461727442797465223a307d",
-      "obstruction": {
-        "code": "JEDIT_RECEIPT_CORRELATION_UNAVAILABLE",
-        "reason": "Echo receipt correlation is not available for this submission"
-      }
-    },
-    "ticketedRuntimeIngress": {
-      "status": "TICKETED_RUNTIME_INGRESS_MISSING",
-      "submissionId": "jedit-submission:7b226275666665724964223a22746578742d6275666665723a30222c22656e6442797465223a302c22696e7365727454657874223a2268656c6c6f204563686f222c22737461727442797465223a307d",
-      "obstruction": {
-        "code": "JEDIT_TICKETED_RUNTIME_INGRESS_UNAVAILABLE",
-        "reason": "Echo admission ticket and ticketed runtime ingress are not exposed in this release-gate slice"
-      }
-    },
-    "retainedEvidence": {
-      "refs": [
-        {
-          "kind": "jedit-retained-evidence-ref",
-          "role": "PACKAGE_IDENTITY",
-          "semanticCoordinate": {
-            "kind": "semantic-coordinate",
-            "packageId": "jedit.hot-text-runtime",
-            "operationName": "package-install",
-            "coordinate": "jedit.hot-text-runtime"
-          },
-          "byteIdentity": {
-            "kind": "byte-identity",
-            "byteHash": "package:jedit.hot-text-runtime"
-          },
-          "posture": "PRESENT_INLINE"
-        },
-        {
-          "kind": "jedit-retained-evidence-ref",
-          "role": "RECEIPT",
-          "semanticCoordinate": {
-            "kind": "semantic-coordinate",
-            "packageId": "jedit.hot-text-runtime",
-            "operationName": "replaceRangeAsTick",
-            "coordinate": "receipt:1"
-          },
-          "byteIdentity": {
-            "kind": "byte-identity",
-            "byteHash": "receipt:receipt:1"
-          },
-          "posture": "PRESENT_INLINE"
-        },
-        {
-          "kind": "jedit-retained-evidence-ref",
-          "role": "READING_ENVELOPE",
-          "semanticCoordinate": {
-            "kind": "semantic-coordinate",
-            "packageId": "jedit.hot-text-runtime",
-            "operationName": "textWindow",
-            "coordinate": "envelope:text-window:head:3:0:1:1024"
-          },
-          "byteIdentity": {
-            "kind": "byte-identity",
-            "byteHash": "reading-envelope:text-window:head:3:0:1:1024"
-          },
-          "posture": "PRESENT_INLINE"
-        },
-        {
-          "kind": "jedit-retained-evidence-ref",
-          "role": "READING_PAYLOAD",
-          "semanticCoordinate": {
-            "kind": "semantic-coordinate",
-            "packageId": "jedit.hot-text-runtime",
-            "operationName": "textWindow",
-            "coordinate": "payload:text-window:head:3:0:1:1024"
-          },
-          "byteIdentity": {
-            "kind": "byte-identity",
-            "byteHash": "reading-payload:text-window:head:3:0:1:1024"
-          },
-          "posture": "PRESENT_INLINE"
-        }
-      ]
-    },
-    "restartPosture": {
-      "status": "PARTIAL",
-      "stateOwner": "PROCESS_LOCAL_HANDLER_STATE",
-      "echoHostedStatePosture": "ECHO_PACKAGE_AND_EVIDENCE_ONLY",
-      "acceptedSubmissionRecovery": "UNAVAILABLE",
-      "halfAcceptedSubmissionClaimed": false,
-      "obstruction": {
-        "code": "DURABLE_ACCEPTED_SUBMISSION_RECOVERY_UNAVAILABLE",
-        "reason": "jedit contract handler state is process-local in this release-gate slice"
-      }
-    },
-    "receiptId": "receipt:1",
-    "readingId": "text-window:head:3:0:1:1024",
-    "text": "hello Echo",
-    "lines": [
-      {
-        "lineNumber": 0,
-        "startByte": 0,
-        "endByte": 10,
-        "text": "hello Echo"
-      }
-    ],
-    "truncated": false
-  },
-  "reading": {
-    "readingId": "text-window:head:3:0:1:1024",
-    "lineCount": 1,
-    "truncated": false
-  },
-  "replay": {
-    "status": "UNAVAILABLE",
-    "reason": "use --replay-local for local replay; durable and Continuum replay remain unavailable"
-  }
-}
diff --git a/docs/releases/v0.1.0/local-replay-report.json b/docs/releases/v0.1.0/local-replay-report.json
deleted file mode 100644
index 03ba2b32..00000000
--- a/docs/releases/v0.1.0/local-replay-report.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
-  "ok": true,
-  "schemaVersion": 1,
-  "transport": "installed-jedit-contract",
-  "dryRun": false,
-  "replayLocal": {
-    "status": "MATCH",
-    "first": {
-      "packageId": "jedit.hot-text-runtime",
-      "outcomeStatus": "APPLIED",
-      "receiptId": "receipt:1",
-      "readingId": "text-window:head:3:0:1:1024",
-      "text": "hello"
-    },
-    "second": {
-      "packageId": "jedit.hot-text-runtime",
-      "outcomeStatus": "APPLIED",
-      "receiptId": "receipt:1",
-      "readingId": "text-window:head:3:0:1:1024",
-      "text": "hello"
-    },
-    "mismatchField": null,
-    "wallClockCadenceSemantic": false
-  }
-}
diff --git a/docs/releases/v0.1.0/pr-notes.md b/docs/releases/v0.1.0/pr-notes.md
deleted file mode 100644
index 19ba7121..00000000
--- a/docs/releases/v0.1.0/pr-notes.md
+++ /dev/null
@@ -1,39 +0,0 @@
-# jedit + Echo Release-Gate PR Notes
-
-## Summary
-
-This branch closes the twenty-slice local release gate for proving a narrow
-jedit edit/read workflow is powered by Echo while Echo remains generic.
-
-jedit now owns the hot text package descriptor, preflight, mutation handlers,
-query observers, app-facing `TextBufferOptic`, agent witness surfaces, MCP-style
-witness adapter, release quickstart, and release-gate command. Echo is treated
-as the generic package/operation/query/handler/observer/evidence runtime
-boundary; no jedit text nouns are introduced into Echo.
-
-## Evidence
-
-- `npm run release-gate:jedit-echo`
-- `npm run check`
-- `node scripts/jedit-echo-powered-session.mjs --json --dry-run`
-- `node scripts/jedit-echo-powered-session.mjs --json --allow-full-snapshot-fixture --text "hello Echo"`
-- `node scripts/jedit-echo-powered-session.mjs --json --allow-full-snapshot-fixture --replay-local`
-- `node scripts/jedit-production-text-session.mjs --json --allow-full-snapshot-fixture --text "hello Echo"`
-- `node scripts/jedit-production-text-session.mjs --json --allow-full-snapshot-fixture --replay-local`
-
-Recorded reports:
-
-- [`final-witness-report.json`](final-witness-report.json)
-- [`local-replay-report.json`](local-replay-report.json)
-
-## Honest Limits
-
-- Handler state is still process-local in this release-gate branch.
-- Durable accepted-submission recovery remains unavailable.
-- Local replay is proven; Continuum transport and distributed replay are not.
-- Query observers are read-only and do not implement the full observer-rights
-  lattice.
-- Application code still has no tick, start, stop, install, or lifecycle
-  authority.
-- The production TUI has no non-Echo text runtime profile; focused tests use
-  direct fake-port injection instead of a runtime mode.
diff --git a/docs/releases/v0.1.0/quickstart.md b/docs/releases/v0.1.0/quickstart.md
deleted file mode 100644
index 3b140c6f..00000000
--- a/docs/releases/v0.1.0/quickstart.md
+++ /dev/null
@@ -1,66 +0,0 @@
-# jedit + Echo v0.1.0 Historical Quickstart
-
-> **Status:** Retired. The original release-gate claim was invalidated because
-> its edit/read path executed inside process-local TypeScript rather than Echo.
-
-The commands that used full-snapshot fixtures, local installed-contract
-transports, and local replay have been removed. They are not supported
-compatibility modes.
-
-## Current Verification
-
-Build the repository and verify that production cannot recover a local
-authority path:
-
-```bash
-npm run build
-node scripts/jedit-production-cutover-guard.mjs
-npm run witness:echo
-```
-
-The cutover guard rejects production source that introduces fake, fixture,
-in-memory, full-snapshot, local installed-contract, handwritten EINT, or
-graph-rope runtime authority.
-
-## Interactive Startup
-
-```bash
-npm start
-```
-
-Startup launches the trusted native Echo host, registers the GraphQL/Wesley
-compatibility package, and admits supported text operations through Echo.
-Create/open, single-range replacement, and bounded text reads work. Operations
-outside that narrow corridor return typed obstructions. No process-local text
-authority is installed.
-
-## Historical Reports
-
-The JSON files in this directory record what the retired witness reported at
-the time. They are preserved for audit, not as evidence that Jim was powered by
-Echo. In particular, a locally deterministic replay does not prove durable
-Echo admission, scheduler execution, receipts, or recovery.
-
-## Current Acceptance Bar
-
-The current native witness demonstrates this complete transitional path:
-
-```text
-Jim command
--> typed process adapter
--> Wesley-generated installed package
--> real Echo admission
--> installed Jim operation
--> Echo-owned tick and receipt
--> witnessed Jim facts
--> basis-pinned Echo observation
--> Jim UI
-```
-
-Edict will replace the Wesley/Rust compatibility operation. Nothing shorter
-than the full path above may be described as Echo-powered. This is not the
-target application composition: final production delivers canonical events to
-`Jim.edict`, which requests bounded readings, derives Jim-owned operation
-intents, handles outcomes, and advances editor state. Generated clients remain
-semantic-free transport stubs, and Echo remains unaware of editor or rope
-vocabulary.
diff --git a/docs/stack-map.md b/docs/stack-map.md
deleted file mode 100644
index 18db2d0a..00000000
--- a/docs/stack-map.md
+++ /dev/null
@@ -1,147 +0,0 @@
-# Stack Map
-
-> **Cutover correction (2026-08-18):** References below to Wesley-generated Jim
-> operation metadata or local structural-history execution are historical or
-> compatibility evidence. The target is not a frontend invoking a collection of
-> Echo-installed operations. `Jim.edict` is the application and active observer;
-> Jim-owned Edict lawpacks define operations and optics; Edict compiles and
-> verifies generic packages; Echo realizes them without learning application
-> vocabulary; Jedit/Bijou/native code supplies I/O and rendering.
-
-## Doctrine
-
-Product pressure determines architecture truth.
-
-The stack advances in this order:
-
-```text
-product pressure
--> witness
--> boundary
--> contract
--> protocol, if deserved
-```
-
-## Layers
-
-| Layer | Job | Sends down | Receives up |
-| :--- | :--- | :--- | :--- |
-| Jedit/Bijou/native | Jim's I/O body | canonical events, package addresses, raw adapter results | render projections, typed artifacts |
-| `Jim.edict` | Editor mind and application state machine | observation requests, operation intents | canonical events, readings, outcomes, obstructions |
-| Jim Edict lawpacks | Application operations, optics, facts, and obstructions | authored law and declared closure | typed application values |
-| Edict | Language, checking, lowering, packaging, and verification | verified generic packages and semantic-free codecs | Jim-authored source and lawpack closure |
-| Echo | Generic runtime substrate truth | admitted effects, readings, receipts, recovery evidence | verified programs, events, observation requests |
-| Wesley | Transitional compatibility compiler | generated artifacts, codecs, operation metadata | authored GraphQL contracts |
-| Graft | Structural intelligence | spans, outlines, syntax/semantic structure | buffer snapshots or text surfaces |
-| Bijou | Terminal UI substrate | input/render events | screen output and interaction state |
-| Continuum | Deferred publication/protocol layer | shared protocol families, once earned | proven local seams |
-
-## Must never know
-
-| Layer | Must never know |
-| :--- | :--- |
-| Jedit/Bijou/native | command meaning, operation choice, Jim state transitions, scheduler internals |
-| `Jim.edict` and lawpacks | scheduler internals, WAL identities, direct graph mutation authority |
-| Edict | runtime state, transport timing, editor policy |
-| Echo | Jim, Buffer, Rope, ReplaceRange, TextWindow, panes, cursors, Vim semantics |
-| Wesley | runtime state, transport timing, editor policy |
-| Graft | causal truth, mutation authority |
-| Bijou | causal semantics |
-| Continuum | unproven local seams pretending to be universal protocol |
-
-## Current proof
-
-Stack Witness 0001:
-
-```text
-jedit-shaped bytes
--> trusted-host run request
--> textWindow observation request
--> UNSUPPORTED_QUERY without installed observer
-```
-
-The old Stack Witness text fixture is historical. Echo no longer contains
-hardcoded `createBuffer`, `replaceRange`, or `textWindow` semantics. The next
-real proof begins with Jim-owned `ReplaceRange.edict`, built through Edict's
-public application boundary and interpreted as a verified generic program by
-Echo. The retained Jedit oracle is expectation evidence only.
-
-The current Echo `v0.1.0` release-gate proof starts from the implemented
-structural-history contract:
-
-```text
-jedit-authored `contracts/jedit/structural-history.graphql`
--> `replaceTextRange` operation identity
--> Wesley generated artifacts
--> Echo package install
--> app-safe edit intent submission
--> trusted-host lifecycle loop
--> scheduler-owned tick receipt
--> observed outcome
--> bounded text reading
--> retained-evidence inventory
--> replay posture
-```
-
-The next release-gate slice plan is recorded in
-`docs/design/0019-echo-runtime-control-release-slices/echo-runtime-control-release-slices.md`.
-
-## Current scaffolding
-
-- Fake Echo-shaped transport remains valid as a controlled witness posture.
-- Real Echo WASM witness remains opt-in and now uses the app/host authority
-  split: app intent submission stays on the app transport, while scheduler
-  lifecycle requests use the trusted-host lifecycle port.
-- The current real Echo witness fails closed with `UNSUPPORTED_QUERY` unless a
-  jedit-owned generated query observer is installed. The local report fixture
-  can still name inline reading posture, but that is not Echo kernel text
-  semantics.
-- The current replay surface is a shell: `--replay` returns
-  `durable_replay_unavailable` until Echo exposes durable replay evidence
-  through the adapter.
-- Start/Stop/cadence are trusted host runtime-control history. They are not
-  jedit contract intents and they do not create ticks directly.
-- `TrustedEchoRuntimeLifecyclePort.requestRunUntilIdle(...)` wraps raw trusted
-  Echo control bytes so witness and host code do not talk in external tick
-  vocabulary.
-- `TrustedEchoRuntimeLifecyclePort.requestStop()` wraps trusted Stop control
-  without exposing app-controlled cancellation or half-tick interruption.
-- `scripts/jedit-echo-powered-session.mjs --json --dry-run` gives agents a fast
-  installed-package plan over the `TextBufferOptic` and trusted lifecycle
-  wrapper. The explicit `--allow-full-snapshot-fixture` command remains a
-  transitional compatibility witness; the default TUI and release-gate path do
-  not silently construct fixture text authority, and the opt-in real Echo WASM
-  witness remains the substrate proof.
-- `stopTrustedEchoRuntime(...)` is the deterministic host shutdown primitive
-  for Echo lifecycle control. It is not app-facing stop/cancel behavior.
-- Fixture vars bytes are not the durable Wesley runtime codec.
-- `TextBufferSessionPort` is the jedit app-facing session port. It returns
-  `TextBufferOptic` buffer capabilities while keeping the backing runtime
-  behind adapters.
-- `createEchoBackedTextBufferSession(...)` is the Echo-backed adapter. It
-  composes the app-facing session port without exposing trusted lifecycle
-  control. Host loops drain Echo separately.
-- `ReadBasisHandle` is an opaque supporting token, not the complete optic
-  protocol.
-- Structural-history SDL is now the product contract authority for text
-  revisions, replacement events, edit groups, checkpoints, provenance, command
-  status, and evidence-bearing readings.
-- `replaceTextRange` operation identity is consumed from build-generated Wesley
-  metadata while the old TypeScript runtime remains the transitional executor.
-- `scripts/jedit-echo-powered-session.mjs --json --allow-full-snapshot-fixture`
-  reports the structural `replaceTextRange` edit intent in the compatibility
-  witness summary. The structural-history generated-package descriptor now
-  installs through the generic Echo package port. The fixture witness also
-  reports a mutation/query round trip where structural-history owns the
-  mutation/receipt coordinate and the transitional hot-text package still owns
-  the bounded `textWindow` observer.
-- `scripts/jedit-echo-release-gate.mjs --json-report` is the current
-  consolidated jedit/Echo proof report. It joins the happy path, unsupported
-  mutation path, local replay posture, retained evidence refs, and authority
-  checks into one JSON artifact.
-- Continuum remains deferred until the seam is proven enough to publish.
-
-## Operating rule
-
-If a layer needs forbidden knowledge to make progress, the boundary is wrong or
-the witness is not ready.
diff --git a/docs/technical-teardown.md b/docs/technical-teardown.md
index c4eb585e..f0596fff 100644
--- a/docs/technical-teardown.md
+++ b/docs/technical-teardown.md
@@ -12,7 +12,7 @@ Jim-owned Edict lawpacks define application operations and optics; Edict emits
 independently verified generic packages; and Echo supplies only generic runtime
 authority. Generated TypeScript is a codec/transport stub and renderer, not
 Jim. See [ARCHITECTURE.md](../ARCHITECTURE.md) and
-[BEARING.md](BEARING.md).
+the README's [Current posture](../README.md#current-posture).
 
 This document is a progressive, end-to-end technical explanation of `jedit` aimed at a reader with no prior knowledge of this codebase, its domain vocabulary, or the surrounding runtime stack. Each section builds on the last.
 
@@ -23,12 +23,11 @@ active roadmap and should not be treated as the freshest status ledger.
 
 Use these documents for current planning posture:
 
-- [`docs/BEARING.md`](BEARING.md) for compact current truth and next goalpost.
-- [`docs/stack-map.md`](stack-map.md) for the layer map.
+- The README's [Current posture](../README.md#current-posture) for current truth and the roadmap.
 - [`docs/method/roadmap-planning.md`](method/roadmap-planning.md) for roadmap
   process.
-- [`docs/design/0105-vim-power-moves-causal-parity.md`](design/0105-vim-power-moves-causal-parity.md)
-  for the active Jim/Vim power-move roadmap.
+- [#128](https://github.com/flyingrobots/jedit/issues/128) for the Jim/Vim
+  power-move work.
 - [`docs/jedit-echo-end-to-end.md`](jedit-echo-end-to-end.md) for the current
   jedit plus Echo proof path.
 
diff --git a/docs/topics/ui/command-line-and-completions.md b/docs/topics/ui/command-line-and-completions.md
index 148a2475..e8b97a01 100644
--- a/docs/topics/ui/command-line-and-completions.md
+++ b/docs/topics/ui/command-line-and-completions.md
@@ -33,7 +33,7 @@ Common commands:
 | Command | Purpose |
 | --- | --- |
 | `:edit ` | Open a file or descend into a directory completion. |
-| `:write` | Save the current buffer. |
+| `:write` | Save the current buffer. In production this currently ends in a typed export obstruction. |
 | `:quit` | Quit when it is safe. |
 | `:wq` | Write and quit. |
 | `:why` | Explain the last meaningful command. |
diff --git a/docs/topics/ui/drawers-and-panels.md b/docs/topics/ui/drawers-and-panels.md
index a9b8029d..b31b329a 100644
--- a/docs/topics/ui/drawers-and-panels.md
+++ b/docs/topics/ui/drawers-and-panels.md
@@ -83,6 +83,13 @@ The Graft drawer is a projection surface. It can show symbols, structure, and
 projection posture, but it does not own source text. If the projection is stale
 or unavailable, the drawer should say so directly.
 
+When Graft supplies provider-neutral projection lanes (for example an Edict Core
+projection, Echo Target IR, or an opaque obstruction receipt), the drawer shows
+each lane and any bounded review payload for display only. Jedit never executes
+Echo, computes digests, or admits artifacts on the strength of a lane; payloads
+that exceed the adapter bounds are shown as omitted rather than truncated
+silently.
+
 ## Causal History
 
 Jim does not currently expose a history drawer. The previous drawer projected
diff --git a/docs/topics/ui/editor-chrome.md b/docs/topics/ui/editor-chrome.md
index 84924bfc..7996d5f9 100644
--- a/docs/topics/ui/editor-chrome.md
+++ b/docs/topics/ui/editor-chrome.md
@@ -61,6 +61,10 @@ or import head. A same-text causal
 reversion can therefore remain marked when the retained touch history says the
 line changed.
 
+In production today the causal line-diff observation returns a typed
+obstruction, so the `+`, `~`, and `-` markers are not shown; they become
+available when that observation is Echo-owned.
+
 `?` and `!` are app-owned execution posture, not Echo facts. While optimistic
 text is visible, Jim withholds admitted markers whose old line coordinates no
 longer match the rendered projection. After settlement and a basis-matched
diff --git a/docs/topics/ui/help-and-discovery.md b/docs/topics/ui/help-and-discovery.md
index 50adb25b..2c8db936 100644
--- a/docs/topics/ui/help-and-discovery.md
+++ b/docs/topics/ui/help-and-discovery.md
@@ -16,7 +16,7 @@ Jim uses several help surfaces:
 | Command completions | Command names, aliases, and one-line descriptions. |
 | Inline command help | Argument shape and focused-command details. |
 | `:help` | Browseable help for commands and concepts. |
-| `:why` | Causal explanation of a command or selected range. |
+| `:why` | Causal explanation of the last command. Range explanation currently returns a typed obstruction. |
 | Settings descriptions | Short explanations for preferences. |
 
 ## `:help`
diff --git a/docs/topics/ui/settings-menu.md b/docs/topics/ui/settings-menu.md
index 69e45d02..4251a1c6 100644
--- a/docs/topics/ui/settings-menu.md
+++ b/docs/topics/ui/settings-menu.md
@@ -71,6 +71,10 @@ compares with the current admitted head:
 | `Last save` | The head used for the latest successful file materialization. |
 | `Import` | The head created when the buffer entered the current Jim session. |
 
+Save/export currently returns a typed obstruction in production, so `Last save`
+has no materialized head to compare with, and the gutter markers themselves are
+not yet shown (see [Editor Chrome](editor-chrome.md)).
+
 Selected-checkpoint and selected-tick choices were removed with the
 process-local history drawer. They may return only when a bounded Echo
 observation supplies matching opaque head and receipt evidence.
diff --git a/docs/topics/ui/title-screen.md b/docs/topics/ui/title-screen.md
index 2719cee6..182d386a 100644
--- a/docs/topics/ui/title-screen.md
+++ b/docs/topics/ui/title-screen.md
@@ -57,7 +57,46 @@ behavior. Below the 60×12 minimum, Jim shows its existing size notice.
 
 The ray-tracer engine and scene assets remain available to the explicit
 `title:preview`, `title:profile`, and `title:record` tools. They are separate
-from the live workspace; no title-screen action loads them.
+from the live workspace; no title-screen action loads them. The engine and
+assets are frozen (see
+[title-scene-freeze.md](../../method/title-scene-freeze.md)). Each tool renders
+headlessly, without a terminal UI, and each has a machine-readable output that
+agents can consume.
+
+`npm run title:record` (`scripts/title-scene-record.mjs`) exports frames of a
+scene. Options: `--format json|text|html|ansi` (default `json`), `--frames`
+(default 1), `--width` (default 96), `--height` (default 28), `--start`
+(default 0) and `--step` (default 0.5) in seconds, `--scene`, `--theme`,
+`--render-mode braille|ascii`, `--camera-angle`, `--camera-radius`, and
+`--output `. JSON output has a top-level `recording` object (format,
+width, height, frame count, start and step, scene, theme, render mode, and
+camera) and a `frames` array whose entries have a stable `index`,
+`timeSeconds`, `glyphRows` (one string per terminal row), and `colorRows` (one
+row per terminal row, one `{ fgRGB, bgRGB }` object per cell). The same options
+produce byte-identical output. Invalid options print usage to stderr and exit
+with code 2. `spec/title-scene-record-cli.spec.mjs` pins this.
+
+`npm run title:preview` (`scripts/title-scene-preview.mjs`) renders one frame
+for authoring inspection. `--json` emits a deterministic report with a
+`preview` object (scene, render mode, time) and an `inspector` object (including
+the selected scene object); `--no-frame` omits the rendered frame. Without
+`--json` it prints a plain frame with inspector text.
+`spec/title-scene-preview-cli.spec.mjs` pins this.
+
+`npm run title:profile` (`scripts/title-scene-profile.mjs`) times rendering
+over `--frames` frames after `--warmup` frames. `--json` emits a report with
+`scene` (name, object count), `render` (mode, width, height, frames, primary
+samples per frame and in total), `timing` (including `minMs`, `avgMs`, and
+`maxMs`), and a `checksum` of the rendered output; without `--json` it prints a
+plain report. In Braille render mode the report also carries an `allocation`
+witness from `scripts/title-scene-allocation-witness.mjs`. Its `posture` is evidence,
+not a proof of allocation behavior: it is `unmeasured` when allocation
+instrumentation is unavailable (run Node with `--expose-gc`), and also when the
+forced-GC retained-heap delta is zero, because a zero retained delta does not
+show that no allocation happened. Only a positive retained delta reports
+`allocating`. The witness never reports `bounded-after-warmup` or
+`zero-hot-loop`. `spec/title-scene-profile-cli.spec.mjs` pins this, including
+Braille temporal sampling and these postures.
 
 ## Implementation Map
 
diff --git a/edict/replace-range-probes/buffer-decoder/.gitattributes b/edict/replace-range-probes/buffer-decoder/.gitattributes
deleted file mode 100644
index edea5c09..00000000
--- a/edict/replace-range-probes/buffer-decoder/.gitattributes
+++ /dev/null
@@ -1,2 +0,0 @@
-# Preserve the original cleanup transcript, including its final blank line.
-evidence/resource-stop/partial-toolchain-cleanup.txt whitespace=-blank-at-eof
diff --git a/edict/replace-range-probes/buffer-decoder/Decimal.edict b/edict/replace-range-probes/buffer-decoder/Decimal.edict
deleted file mode 100644
index 4eb03ae4..00000000
--- a/edict/replace-range-probes/buffer-decoder/Decimal.edict
+++ /dev/null
@@ -1,75 +0,0 @@
-package jedit.text.replace_range@1;
-
-// Jim's JSON boundary codec. These are internal scanner values, not intent inputs.
-// A later bounded scanner must obtain each token from the retained Buffer atom.
-type JsonByte = Bytes;
-type DecimalState = variant { Start, Zero, Digits(U64) };
-type DecimalStep = variant { More(DecimalState), End(U64), Invalid, Overflow };
-type DecimalDigit = variant { Digit(U64), NotDigit };
-
-// An End result leaves the delimiter unconsumed for the enclosing JSON scanner.
-// Whitespace terminates a number; canonical-byte policy belongs to that scanner.
-fn isNumberDelimiter(token: JsonByte) -> Bool {
-  return token == b"," || token == b"]" || token == b"}"
-    || token == b" " || token == b"\t" || token == b"\r" || token == b"\n";
-}
-
-fn decimalDigit(token: JsonByte) -> DecimalDigit {
-  return if token == b"0" then DecimalDigit::Digit(0u64)
-    else if token == b"1" then DecimalDigit::Digit(1u64)
-    else if token == b"2" then DecimalDigit::Digit(2u64)
-    else if token == b"3" then DecimalDigit::Digit(3u64)
-    else if token == b"4" then DecimalDigit::Digit(4u64)
-    else if token == b"5" then DecimalDigit::Digit(5u64)
-    else if token == b"6" then DecimalDigit::Digit(6u64)
-    else if token == b"7" then DecimalDigit::Digit(7u64)
-    else if token == b"8" then DecimalDigit::Digit(8u64)
-    else if token == b"9" then DecimalDigit::Digit(9u64)
-    else DecimalDigit::NotDigit;
-}
-
-fn appendScaled(scaled: U64, digit: U64, limit: U64) -> DecimalStep {
-  let sum = checkedAdd(scaled, digit);
-  return if isSome(sum) then
-    if unwrap(sum) <= limit then DecimalStep::More(DecimalState::Digits(unwrap(sum)))
-    else DecimalStep::Overflow
-  else DecimalStep::Overflow;
-}
-
-fn appendDigit(value: U64, digit: U64, limit: U64) -> DecimalStep {
-  let decimalRadix = 10u64;
-  let product = checkedMul(value, decimalRadix);
-  return if isSome(product) then appendScaled(unwrap(product), digit, limit)
-    else DecimalStep::Overflow;
-}
-
-fn startDecimal(token: JsonByte, limit: U64) -> DecimalStep {
-  return match decimalDigit(token) {
-    Digit(value) => if value > limit then DecimalStep::Overflow
-      else if value == 0u64 then DecimalStep::More(DecimalState::Zero)
-      else DecimalStep::More(DecimalState::Digits(value)),
-    NotDigit => DecimalStep::Invalid,
-  };
-}
-
-fn continueDecimal(value: U64, token: JsonByte, limit: U64) -> DecimalStep {
-  return if value == 0u64 then DecimalStep::Invalid
-    else if value > limit then DecimalStep::Overflow
-    else match decimalDigit(token) {
-      Digit(digit) => appendDigit(value, digit, limit),
-      NotDigit => if isNumberDelimiter(token) then DecimalStep::End(value)
-        else DecimalStep::Invalid,
-    };
-}
-
-// canonical_head_id members use limit 255; version uses 18446744073709551615.
-// The enclosing scanner owns these schema limits and starts at Start.
-// Empty token, sign, leading zero, fraction, exponent and non-ASCII byte refuse.
-fn stepJsonUnsigned(state: DecimalState, token: JsonByte, limit: U64) -> DecimalStep {
-  return match state {
-    Start => startDecimal(token, limit),
-    Zero => if isNumberDelimiter(token) then DecimalStep::End(0u64)
-      else DecimalStep::Invalid,
-    Digits(value) => continueDecimal(value, token, limit),
-  };
-}
diff --git a/edict/replace-range-probes/buffer-decoder/README.md b/edict/replace-range-probes/buffer-decoder/README.md
deleted file mode 100644
index 8ef30107..00000000
--- a/edict/replace-range-probes/buffer-decoder/README.md
+++ /dev/null
@@ -1,72 +0,0 @@
-# Buffer decoder: authored decimal transitions
-
-This is incomplete Jim-owned codec work for [#296](https://github.com/flyingrobots/jedit/issues/296), retained in draft [#302](https://github.com/flyingrobots/jedit/pull/302). The intended outcome remains decoding the actual retained Buffer atom and deriving its canonical Head and version before the ReplaceRange basis check. The frozen application and producer pins remain unchanged.
-
-[`Decimal.edict`](Decimal.edict) specifies an unsigned JSON-number transition for the Buffer codec: decimal digit recognition, no leading zeros, delimiters left unconsumed, checked multiplication/addition, and the schema's U8 or U64 limit. It accepts internal scanner state and a byte token. These are **not operation inputs or authoritative caller-supplied decoded fields**. The enclosing scanner must own the limit, obtain tokens from actual retained bytes, and start at `Start`.
-
-[`cases.json`](cases.json) contains handwritten literal expectations, including 255/256, U64 maximum, and both addition/multiplication overflow. They remain an unexecuted conformance specification. `End` stops before its delimiter; `More` at end-of-input is incomplete. Whitespace can terminate a number, but the enclosing scanner must decide its encoding policy. These transitions neither impose canonical Buffer bytes nor implement the whole JSON grammar.
-
-## Observed public compiler boundaries
-
-The [original result](evidence/original/public-build.json), assembled sources, raw JSONL streams, positive-control artifacts, compiler-source manifest, and failed wrapper evidence are preserved. The authored source is unchanged from that run, SHA-256 `9fc1b006c298866463ab83a28fcb1e54769b970970c571f11d0868d79edc6d87`.
-
-| Input | Actual public build result |
-| --- | --- |
-| Unchanged atom-read control | Exit 0; package and separate verification report, no diagnostics |
-| Read control with one unused identity function declaration | Exit 2; `InvalidApplicationSource`, `ExpectedToken`, `expected type, enum, or intent declaration` at `fn`, bytes 151–153; no application artifacts |
-| Read control with the authored decimal declarations | Exit 2; `InvalidApplicationSource`, `Lex`, `invalid string escape`, bytes 861–862 at the carriage-return escape; no application artifacts |
-
-These are distinct boundaries. The lexer processes the source before declaration parsing, so the decimal source stops at its `b"\r"` spelling; it did not reach the function-declaration diagnostic. The trivial function control independently establishes that missing parser production. Neither refusal establishes function-body typing, arithmetic, Option proofs, byte-literal support beyond the observed point, lowering, or evaluation.
-
-The original harness incorrectly expected `ApplicationCompilationFailed` for both negative controls. It wrote all three actual results and completed its input/source/binary integrity checks, then failed the `fn-control` assertion. The [guard log](evidence/original/guard.log), [result](evidence/original/guard.result.json), [launch contract](evidence/original/guard.launch.json), [lock receipt](evidence/original/git-locks-receipt.jsonl), and [original runner](evidence/original/run.py) retain this wrapper **exit 1**. No success marker was produced. Correcting the expectations does not turn that historical run green.
-
-The current runner distinguishes the observed diagnostic kinds and rejects changes to the authored source, read-control source, or provider file hashes. It also requires the exact historical compiler-source manifest and an explicitly pinned compiler binary. The corrected source reproduction described below passed. The original outputs remain evidence of the three compiler invocations inside a historically failed witness harness.
-
-The first corrected-run attempt stopped before compilation or any application-build invocation. Rust 1.95.0 was absent, and invoking it began an automatic toolchain download; the external resource guard stopped the attempt when accounted data exceeded the project limit. The [attempt log](evidence/resource-stop/guard.log) and [launch contract](evidence/resource-stop/guard.launch.json) are retained. The [controller observation](evidence/resource-stop/observer-record.json) records 4,325,788,505 data bytes against the 4,294,967,296-byte limit; it is explicitly observer-authored from the displayed exception, not raw controller stdout. The [cleanup transcript](evidence/resource-stop/partial-toolchain-cleanup.txt) and [subsequent usage](evidence/resource-stop/after-cleanup-usage.json) record removal of only the new partial toolchain/downloads. This resource stop is neither a compiler RED nor a corrected-harness result.
-
-## Corrected source reproduction
-
-The [corrected witness](evidence/reproduction196/public-build.json) passed with wrapper exit 0 and `JIM_BUFFER_DECIMAL_DISTINCT_SOURCE_BOUNDARIES_CONFIRMED`. Its [build/run log](evidence/reproduction196/guard.log), [launch contract](evidence/reproduction196/guard.launch.json), [guard result](evidence/reproduction196/guard.result.json), assembled sources, raw streams, and read-control artifacts are retained separately from the original failure.
-
-The exact same 449-file compiler source was rebuilt with the already installed Rust 1.96.0 (`ac68faa20c58cbccd01ee7208bf3b6e93a7d7f96`) in the reusable worker and stable target. The resulting CLI SHA-256 is `83c70b3fdbb42ac43f0967a0c559c0cc8b66599987774a40412bda4fbc028d36`; this explicit pin was passed to the runner. It reproduces the source boundaries with a different compiler binary, not the historical Rust 1.95.0 binary.
-
-All three assembled source hashes match the original run. The read-control package and report are byte-identical to the originals. The negative cases retain the same kinds and source spans, with raw stderr hashes differing because the diagnostic paths name the new work root. Source, binary, application, and provider integrity checks completed. The executed runner matches checked-in `run.py`, SHA-256 `0d6f644eeccd8acbd0841f7c5420bd0d5353a55948471d3ed13f24618d5e0868`.
-
-This is a successful reproduction of one public-build control and two expected source refusals. No decimal case, scanner, rope algorithm, evaluator, or broader Jim application suite ran in this replay.
-
-## Exact inputs and artifact identities
-
-The experiment used compiler commit `17397e2aad18a83ffc617d1afd628764501f49cd`, tree `bcfd3112cd8b3d4630738a88761860679b45714b`, rebuilt with Rust 1.95.0 in the existing guarded Docker worker. All 449 compiler-source files were checked against the [Git blob manifest](evidence/compiler-source.json) before and after the public builds. Its raw manifest SHA-256 is `625592ab9dd715349255bece0133378c64b3d4539fb50e437d116c2a4296f016`; the compiler binary SHA-256 is `e2700698829b03f437c66425ed9878b002ef7a34ac183a39bac4eaf6a758cc6d`.
-
-The separate read-capable provider is pinned by its complete file-hash map in the result. Its [manifest](evidence/provider-manifest.echo.json) has raw SHA-256 `5b38ae704a071b88aa0cc2f85020de41cb69e76d037afe3592a4d319e22587c8`. Lowerer and verifier component hashes are respectively `4b594a8165079f0a973741b9e27b468cf041f4ad53108fccae641dc35355bd2a` and `d0be4d283399aefc45d75b395b3568f9983521ca5543c9dfd23b9495758050ed`. This witness records those exact package bytes; it does not claim to reproduce their component builds or independently establish their source commit.
-
-The retained read-control [package](evidence/original/read-control/application/executable-operation-package.cbor) has SHA-256 `afd931700018312d6c0d1e249871313d2c21c0ece1ae41d1f17f2be7af9e5284`; its [report](evidence/original/read-control/application/verification-report.cbor) has SHA-256 `9114fdd983d456eb83f69969475f558b6e608be23520212a5db5f26bb095d04b`. These artifacts were produced only for the unchanged read control. No decoder package was emitted and no evaluator was invoked.
-
-## Source contract and composition obligation
-
-The source follows the documented direction for non-recursive, first-order pure `fn` declarations, byte literals, checked arithmetic, and guarded Option handling. The observed failures show that the executable compiler subset is narrower. The experiment uses Edict's public application build; it supplies no native decoder, invented intrinsic, or handwritten Core/Target IR.
-
-The public application format accepts one source module. The experiment inserts the exact helper declarations into the retained [control](control/src/ReplaceRange.edict) before its first type declaration. The unchanged operation does not call the helpers. The assembled sources are retained alongside their diagnostics. Merely accepting unused declarations would not prove executable functions or a decoder.
-
-[Edict #226](https://github.com/flyingrobots/edict/issues/226) owns the full source-function compiler and semantic-contract prerequisite. [Echo #752](https://github.com/flyingrobots/echo/issues/752) depends on it for generic function admission and execution in both pure and bounded-read programs. Their acceptance must exercise called bodies, evaluate arguments once, preserve lexical scope and conditional evaluation, and enforce bounded costs through compiler-produced packages and separate verification. These are outstanding obligations, not capabilities established by this declaration-only probe. Jim #296 continues to own the actual retained-byte scanner and complete rope operation.
-
-The next authored work must scan actual Buffer `FactBytes`: variable-length UTF-8 key and optional path, JSON escapes, exactly 32 decimal head bytes, and version. It must preserve fields needed for encoding and derive the basis from retained state. Immutable list-only statement loops currently provide no result-producing accumulator; bytes are not an iterable List, and no generic fold is implemented. A one-byte `slice` retains the source maximum and drops exact/minimum length, so the `JsonByte` input requires a justified narrowing path. Source aliases, variants, Option, and checked arithmetic also remain separate compiler/evaluator obligations. Function parsing alone cannot complete this scanner.
-
-Native references are [`BufferFact` and its codec](../../../native/jedit-echo-host/src/records.rs), [`plan_replace_with_reason`](../../../native/jedit-echo-host/src/rope/replace.rs), and the [frozen schema](../../../contracts/jedit/lawpacks/replace-range-v1/text-schema-v1.json). Native Buffer reads do not perform the retained Head's universal decode/re-encode/content-identity checks; preserve that distinction. NoOp must precede version/sequence overflow. Full replacement still requires pending intermediate split facts, canonical identities, write ordering, atomic settlement, all forty oracle cases, and recovery.
-
-## Reproduction
-
-Use the existing shared guarded Docker worker and stable Cargo target under workstation git-locks admission. Do not rebuild or start a worker merely to repeat this historical observation. The corrected runner reuses the portable public-build functions in `../leaf-slice/run.py`. Copy this probe, that helper, and the retained control into the accounted worker input tree. Supply the exact compiler-source and provider identities above. By default the runner requires the historical Rust 1.95.0 binary hash. If that binary is unavailable, a controlled rebuild of the same source with an already installed toolchain may supply its own explicit `--compiler-sha256` pin. Retain the build command, toolchain version, source checks, and actual binary hash; such a run reproduces the source boundary, not the historical compiler binary. A self-reported hash alone does not establish which source built a binary. Run inside the guarded lease:
-
-```sh
-python3 "$PROBE_ROOT/run.py" \
-  --compiler "$EDICT_BINARY" \
-  --compiler-sha256 "$EDICT_BINARY_SHA256" \
-  --compiler-source "$EDICT_SOURCE" \
-  --compiler-manifest "$PROBE_ROOT/evidence/compiler-source.json" \
-  --application-source "$PROBE_ROOT/control" \
-  --provider-package "$PROVIDER_PACKAGE" \
-  --work-root /tmp/echo-726-runtime/jim-buffer-decoder-reproduction
-```
-
-The work root must be absent. The runner validates input hashes, records separate case outcomes, and expects `JIM_BUFFER_DECIMAL_DISTINCT_SOURCE_BOUNDARIES_CONFIRMED` only after all assertions pass. That marker describes successful reproduction of compiler refusals, never a working decoder. The external guard must enforce the project build/data/log budgets and stop the owned process group on timeout or monitoring failure; the runner's per-process timeout is not a disk quota. Older probe Dockerfiles that bake build output into images are historical recipes.
diff --git a/edict/replace-range-probes/buffer-decoder/cases.json b/edict/replace-range-probes/buffer-decoder/cases.json
deleted file mode 100644
index 06a337a0..00000000
--- a/edict/replace-range-probes/buffer-decoder/cases.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
-  "status": "Handwritten conformance specification; not executed",
-  "procedure": "Start at DecimalState::Start. Feed each listed byte in order to stepJsonUnsigned with the stated schema limit. Continue only through More. Stop at the first End, Invalid or Overflow. End leaves its delimiter unconsumed. A trailing More means an incomplete number, not successful decoding.",
-  "cases": [
-    {"name":"zero-array-member","bytesHex":"302c","limit":"255","expected":{"kind":"End","value":"0","consumedDigits":1}},
-    {"name":"zero-version","bytesHex":"307d","limit":"18446744073709551615","expected":{"kind":"End","value":"0","consumedDigits":1}},
-    {"name":"u8-max","bytesHex":"3235355d","limit":"255","expected":{"kind":"End","value":"255","consumedDigits":3}},
-    {"name":"u8-overflow","bytesHex":"3235365d","limit":"255","expected":{"kind":"Overflow","atByte":2}},
-    {"name":"u64-max","bytesHex":"31383434363734343037333730393535313631357d","limit":"18446744073709551615","expected":{"kind":"End","value":"18446744073709551615","consumedDigits":20}},
-    {"name":"u64-add-overflow","bytesHex":"31383434363734343037333730393535313631367d","limit":"18446744073709551615","expected":{"kind":"Overflow","atByte":19}},
-    {"name":"u64-multiply-overflow","bytesHex":"39393939393939393939393939393939393939397d","limit":"18446744073709551615","expected":{"kind":"Overflow","atByte":19}},
-    {"name":"leading-zero","bytesHex":"30302c","limit":"255","expected":{"kind":"Invalid","atByte":1}},
-    {"name":"zero-followed-by-digit","bytesHex":"30317d","limit":"18446744073709551615","expected":{"kind":"Invalid","atByte":1}},
-    {"name":"negative","bytesHex":"2d315d","limit":"255","expected":{"kind":"Invalid","atByte":0}},
-    {"name":"plus-sign","bytesHex":"2b315d","limit":"255","expected":{"kind":"Invalid","atByte":0}},
-    {"name":"fraction","bytesHex":"312e305d","limit":"255","expected":{"kind":"Invalid","atByte":1}},
-    {"name":"exponent","bytesHex":"3165325d","limit":"255","expected":{"kind":"Invalid","atByte":1}},
-    {"name":"missing-number","bytesHex":"5d","limit":"255","expected":{"kind":"Invalid","atByte":0}},
-    {"name":"raw-non-ascii","bytesHex":"ff5d","limit":"255","expected":{"kind":"Invalid","atByte":0}},
-    {"name":"quote-is-not-number-delimiter","bytesHex":"3122","limit":"255","expected":{"kind":"Invalid","atByte":1}},
-    {"name":"space-terminator","bytesHex":"32353520","limit":"255","expected":{"kind":"End","value":"255","consumedDigits":3}},
-    {"name":"tab-terminator","bytesHex":"3109","limit":"255","expected":{"kind":"End","value":"1","consumedDigits":1}},
-    {"name":"carriage-return-terminator","bytesHex":"310d","limit":"255","expected":{"kind":"End","value":"1","consumedDigits":1}},
-    {"name":"line-feed-terminator","bytesHex":"310a","limit":"255","expected":{"kind":"End","value":"1","consumedDigits":1}},
-    {"name":"incomplete-nonzero","bytesHex":"3130","limit":"255","expected":{"kind":"More","state":"Digits","value":"10"}},
-    {"name":"incomplete-zero","bytesHex":"30","limit":"255","expected":{"kind":"More","state":"Zero"}},
-    {"name":"empty-stream","bytesHex":"","limit":"255","expected":{"kind":"Unstarted"}}
-  ],
-  "singleStepCases": [
-    {"name":"empty-token","state":"Start","tokenHex":"","limit":"255","expected":{"kind":"Invalid"}},
-    {"name":"invalid-zero-digits-state","state":{"Digits":"0"},"tokenHex":"2c","limit":"255","expected":{"kind":"Invalid"}},
-    {"name":"over-limit-state","state":{"Digits":"256"},"tokenHex":"2c","limit":"255","expected":{"kind":"Overflow"}}
-  ]
-}
diff --git a/edict/replace-range-probes/buffer-decoder/control/edict.application.json b/edict/replace-range-probes/buffer-decoder/control/edict.application.json
deleted file mode 100644
index 9bad89fb..00000000
--- a/edict/replace-range-probes/buffer-decoder/control/edict.application.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-  "schema": "edict.application/v1",
-  "coordinate": "jedit.text.replace_range@1",
-  "sources": [
-    "src/ReplaceRange.edict"
-  ],
-  "lawpacks": [
-    {
-      "manifest": "vendor/atom-read/manifest.cbor",
-      "exports": "vendor/atom-read/exports.cbor",
-      "adapter": "vendor/atom-read/adapter.cbor",
-      "targetConfiguration": "vendor/atom-read/echo-operation-configuration.cbor"
-    }
-  ],
-  "target": {
-    "profile": "echo.dpo@1",
-    "providerPackage": ".build/echo-provider"
-  },
-  "outputDirectory": ".build/application"
-}
diff --git a/edict/replace-range-probes/buffer-decoder/control/src/ReplaceRange.edict b/edict/replace-range-probes/buffer-decoder/control/src/ReplaceRange.edict
deleted file mode 100644
index 1031dfc9..00000000
--- a/edict/replace-range-probes/buffer-decoder/control/src/ReplaceRange.edict
+++ /dev/null
@@ -1,18 +0,0 @@
-package jedit.text.replace_range@1;
-use lawpack jedit.text@1 digest "sha256:2ea164293719d2b03231c4904eb75ddcdf55fd29cc31f4fc5a5319d9ae5e60e7" as text;
-type Input = { address: text.FactAddress, expected: text.FactBytes };
-intent replaceRange(input: Input) returns text.FactBytes
-  profile text.replaceRange
-  basis input.address.nodeId
-  budget <= text.replaceRangeBudget
-{
-  let actual: text.FactBytes = text.readFact(input.address)
-    else {
-      missing(address) => text.FactMissing,
-      typeMismatch(address) => text.FactMalformed,
-      notAtom(address) => text.FactMalformed,
-      tooLarge(address) => text.FactMalformed,
-    };
-  require actual == input.expected else text.BasisNotCanonical;
-  return actual;
-}
diff --git a/edict/replace-range-probes/buffer-decoder/control/vendor/.atom-read.edict-lawpack-build.lock b/edict/replace-range-probes/buffer-decoder/control/vendor/.atom-read.edict-lawpack-build.lock
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/adapter.cbor b/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/adapter.cbor
deleted file mode 100644
index 5353b583..00000000
Binary files a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/adapter.cbor and /dev/null differ
diff --git a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/adapter.sha256 b/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/adapter.sha256
deleted file mode 100644
index fe16ec8c..00000000
--- a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/adapter.sha256
+++ /dev/null
@@ -1 +0,0 @@
-sha256:bcb72bfbc93276506d8a9175263ca1742d78d5125cd3fdc49e0da7f474473c85
diff --git a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/echo-operation-configuration.cbor b/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/echo-operation-configuration.cbor
deleted file mode 100644
index 4b130f95..00000000
Binary files a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/echo-operation-configuration.cbor and /dev/null differ
diff --git a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/echo-operation-configuration.sha256 b/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/echo-operation-configuration.sha256
deleted file mode 100644
index 8b8e8c0b..00000000
--- a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/echo-operation-configuration.sha256
+++ /dev/null
@@ -1 +0,0 @@
-sha256:56921f7058a4b68027c3e5415150b2c6ef4388b000c2ea649cd7a14d3f565f7e
diff --git a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/edict.lawpack-output.json b/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/edict.lawpack-output.json
deleted file mode 100644
index 2f0be4de..00000000
--- a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/edict.lawpack-output.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
-  "schema": "edict.lawpack-output/v1",
-  "lawpackId": "jedit.text",
-  "lawpackVersion": "1",
-  "artifacts": [
-    {
-      "path": "manifest.cbor",
-      "kind": "manifest",
-      "coordinate": "edict.lawpack/v1",
-      "digest": "sha256:2ea164293719d2b03231c4904eb75ddcdf55fd29cc31f4fc5a5319d9ae5e60e7"
-    },
-    {
-      "path": "manifest.sha256",
-      "kind": "manifestDigest",
-      "coordinate": "edict.lawpack/v1",
-      "digest": "sha256:2ea164293719d2b03231c4904eb75ddcdf55fd29cc31f4fc5a5319d9ae5e60e7"
-    },
-    {
-      "path": "exports.cbor",
-      "kind": "exports",
-      "coordinate": "jedit.text.exports/v1",
-      "digest": "sha256:ba805443d67297ea5cbe9775049a461eafda46af27aeb4a5712d2c6289b62f21"
-    },
-    {
-      "path": "exports.sha256",
-      "kind": "exportsDigest",
-      "coordinate": "jedit.text.exports/v1",
-      "digest": "sha256:ba805443d67297ea5cbe9775049a461eafda46af27aeb4a5712d2c6289b62f21"
-    },
-    {
-      "path": "echo-operation-configuration.cbor",
-      "kind": "localResource",
-      "coordinate": "echo.operation-lowering-configuration/v1",
-      "digest": "sha256:56921f7058a4b68027c3e5415150b2c6ef4388b000c2ea649cd7a14d3f565f7e"
-    },
-    {
-      "path": "echo-operation-configuration.sha256",
-      "kind": "localResourceDigest",
-      "coordinate": "echo.operation-lowering-configuration/v1",
-      "digest": "sha256:56921f7058a4b68027c3e5415150b2c6ef4388b000c2ea649cd7a14d3f565f7e"
-    },
-    {
-      "path": "verifier-rules.cbor",
-      "kind": "localResource",
-      "coordinate": "jedit.text.verifier-rules/v1",
-      "digest": "sha256:364fb4ff98ae64fcd8d793aae3d7cb133ff8a1ce661330cea47688b13a0a823f"
-    },
-    {
-      "path": "verifier-rules.sha256",
-      "kind": "localResourceDigest",
-      "coordinate": "jedit.text.verifier-rules/v1",
-      "digest": "sha256:364fb4ff98ae64fcd8d793aae3d7cb133ff8a1ce661330cea47688b13a0a823f"
-    },
-    {
-      "path": "adapter.cbor",
-      "kind": "adapter",
-      "coordinate": "jedit.text.echo-adapter/v1",
-      "digest": "sha256:bcb72bfbc93276506d8a9175263ca1742d78d5125cd3fdc49e0da7f474473c85"
-    },
-    {
-      "path": "adapter.sha256",
-      "kind": "adapterDigest",
-      "coordinate": "jedit.text.echo-adapter/v1",
-      "digest": "sha256:bcb72bfbc93276506d8a9175263ca1742d78d5125cd3fdc49e0da7f474473c85"
-    }
-  ]
-}
diff --git a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/exports.cbor b/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/exports.cbor
deleted file mode 100644
index c8a2eebc..00000000
--- a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/exports.cbor
+++ /dev/null
@@ -1 +0,0 @@
-¦etypesƒ¢jcoordinatexjedit.text@1.FactAddressjdefinitionxLRecord,typeId:Bytes,warpId:Bytes>¢jcoordinatevjedit.text@1.FactBytesjdefinitionrBytes¢jcoordinatexjedit.text@1.ObstructionDetailjdefinitionx"Stringgeffects�ªiinputTypexjedit.text@1.FactAddressjcoordinateujedit.text@1.readFactjoutputTypevjedit.text@1.FactByteslguardSupportõncostObligationxjedit.text@1.replaceRangeBudgetneffectFailures¤gmissing¢kpayloadTypexjedit.text@1.FactAddressnauthorityClassmresourceFaultgnotAtom¢kpayloadTypexjedit.text@1.FactAddressnauthorityClassnintegrityFaulthtooLarge¢kpayloadTypexjedit.text@1.FactAddressnauthorityClassnintegrityFaultltypeMismatch¢kpayloadTypexjedit.text@1.FactAddressnauthorityClassnintegrityFaultneffectKindHintdreadnexecutionClassgruntimentypeParameters€sfootprintObligationx"jedit.text@1.replaceRangeFootprinticonstants€lobstructionsƒ£jcoordinatexjedit.text@1.BasisNotCanonicalmpayloadSchemaxjedit.text@1.ObstructionDetailnauthorityClassndomainMappable£jcoordinatexjedit.text@1.FactMissingmpayloadSchemaxjedit.text@1.ObstructionDetailnauthorityClassmresourceFault£jcoordinatexjedit.text@1.FactMalformedmpayloadSchemaxjedit.text@1.ObstructionDetailnauthorityClassnintegrityFaultmpureFunctions€qoperationProfiles¡xjedit.text@1.replaceRange¢mopticTemplate¦iopticKindsaffectReintegrationlboundaryKindfaffectmbasisTemplatexjedit.text@1.exactHeadBasismsupportPolicyxjedit.text@1.basisBoundSupportolossDispositionujedit.text@1.losslesssapertureRequirement¢crefx"jedit.text@1.replaceRangeFootprintdkindxabstractFootprintObligationoeffectPredicatex jedit.text@1.replaceRangeEffects
\ No newline at end of file
diff --git a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/exports.sha256 b/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/exports.sha256
deleted file mode 100644
index 9a176821..00000000
--- a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/exports.sha256
+++ /dev/null
@@ -1 +0,0 @@
-sha256:ba805443d67297ea5cbe9775049a461eafda46af27aeb4a5712d2c6289b62f21
diff --git a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/manifest.cbor b/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/manifest.cbor
deleted file mode 100644
index 40a95127..00000000
--- a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/manifest.cbor
+++ /dev/null
@@ -1,2 +0,0 @@
-ªbidjjedit.textgexports¢bidujedit.text.exports/v1fdigest‚fsha256X º€TCÖr—ê\¾—ušF¯ÚF¯'®´¥q-,b‰¶/!gversiona1hverifier¢eclasskdeclarativegruleset¢bidxjedit.text.verifier-rules/v1fdigest‚fsha256X 6O´ÿ˜®düØ×“ªã×Ë?ø¡Îf0Τvˆ±:
-‚?japiVersionpedict.lawpack/v1ldependencies€mcompatibility¢bidxjedit.text.compatibility/v1fdigest‚fsha256X *߃÷˜ _RcjÖL¤Qxó:ŽÆc‡OŠaHL”^0RntargetAdapters�£gadapter¢bidxjedit.text.echo-adapter/v1fdigest‚fsha256X ¼·+ûÉ2vPmŠ‘u&<¡t-xÕ\ÓýÄž
§ôtG<…pacceptedTargetIr¢bidoecho.span-ir/v2fdigest‚fsha256X >€]Åè1è‹ïìLÔžÀ,9…‹o9�ÚŠsµ`†®9uacceptedTargetProfile¢bidjecho.dpo@1fdigest‚fsha256X .$”ìõæ¢Ù õû…@ˆ%Ó”v_­AHLAc—É ûoacceptedCoreAbi�medict.core/v1xconformanceFixtureCorpus¢bidx jedit.text.ReplaceRange.oracle@1fdigest‚fsha256X ¹´p}Õàx—Ëç¯6؉(@‡æ¯]}ˆ¨ÖM»
\ No newline at end of file
diff --git a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/manifest.sha256 b/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/manifest.sha256
deleted file mode 100644
index bc42c481..00000000
--- a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/manifest.sha256
+++ /dev/null
@@ -1 +0,0 @@
-sha256:2ea164293719d2b03231c4904eb75ddcdf55fd29cc31f4fc5a5319d9ae5e60e7
diff --git a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/verifier-rules.cbor b/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/verifier-rules.cbor
deleted file mode 100644
index ef8836e5..00000000
--- a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/verifier-rules.cbor
+++ /dev/null
@@ -1 +0,0 @@
-¤fschemasjedit.text.schema@1lschemaDigestxGsha256:f49b0ff6c9c7010d3a72b46734d47832853f496739a083edc41dddec3431bac7oruntimeOntologyugeneric-bounded-graphworacleIsExecutableInputô
\ No newline at end of file
diff --git a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/verifier-rules.sha256 b/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/verifier-rules.sha256
deleted file mode 100644
index f8f7a387..00000000
--- a/edict/replace-range-probes/buffer-decoder/control/vendor/atom-read/verifier-rules.sha256
+++ /dev/null
@@ -1 +0,0 @@
-sha256:364fb4ff98ae64fcd8d793aae3d7cb133ff8a1ce661330cea47688b13a0a823f
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/compiler-source.json b/edict/replace-range-probes/buffer-decoder/evidence/compiler-source.json
deleted file mode 100644
index e39610bf..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/compiler-source.json
+++ /dev/null
@@ -1,1802 +0,0 @@
-{
-  "commit": "17397e2aad18a83ffc617d1afd628764501f49cd",
-  "tree": "bcfd3112cd8b3d4630738a88761860679b45714b",
-  "files": [
-    {
-      "path": ".cargo/config.toml",
-      "gitBlob": "5592118f6c54bf8b53b16848e04ece896dd56384"
-    },
-    {
-      "path": ".github/workflows/auto-release-tag.yml",
-      "gitBlob": "87404ceb685191afd496c93494b0bc61e2a59504"
-    },
-    {
-      "path": ".github/workflows/ci.yml",
-      "gitBlob": "c6c6a17f59b6b96db88e3d4b2775bc64b7fe01f3"
-    },
-    {
-      "path": ".github/workflows/release.yml",
-      "gitBlob": "2c612fc786998bfa5b11e76ae1185114a7cc535f"
-    },
-    {
-      "path": ".gitignore",
-      "gitBlob": "30d7faf0fc8b7f010f99280302d4ed269d5da9ba"
-    },
-    {
-      "path": ".markdownlint.json",
-      "gitBlob": "f3ec2c8dc2fbacc425154a2baedec50c7474aefa"
-    },
-    {
-      "path": "AGENTS.md",
-      "gitBlob": "0c48a5794454cf84e20640994a372316efde7bb5"
-    },
-    {
-      "path": "ARCHITECTURE.md",
-      "gitBlob": "5b513dd25028092e7e75c8974f1d5f3cc31889ed"
-    },
-    {
-      "path": "CHANGELOG.md",
-      "gitBlob": "cd40892f0f2ed2e5667c65e274f9a1ead1619990"
-    },
-    {
-      "path": "CODE_OF_CONDUCT.md",
-      "gitBlob": "784cf2799bcf8d2a69db5f5781359ef7e18a05fc"
-    },
-    {
-      "path": "CONTRIBUTING.md",
-      "gitBlob": "9676914060f734dc59eabd9075898dc8170d4d19"
-    },
-    {
-      "path": "Cargo.lock",
-      "gitBlob": "bacb208de0583f182379af7b5e078d31b25e2ca5"
-    },
-    {
-      "path": "Cargo.toml",
-      "gitBlob": "b2e7106eb78f79230c091492ef21b497bdc9ed19"
-    },
-    {
-      "path": "EDICT.md",
-      "gitBlob": "35376134195082d506f0161ba7ecb97efa8b770a"
-    },
-    {
-      "path": "LICENSE",
-      "gitBlob": "261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64"
-    },
-    {
-      "path": "NOTICE",
-      "gitBlob": "c300687bdd9d931d1f257d291e1cb6ff9d7d3607"
-    },
-    {
-      "path": "README.md",
-      "gitBlob": "0812ef9a0c4611bf655dfc67d2ecc3631af9a536"
-    },
-    {
-      "path": "ROADMAP.md",
-      "gitBlob": "d0e0135780537afab1d1a3f53808b363b35a63f4"
-    },
-    {
-      "path": "SECURITY.md",
-      "gitBlob": "0bcc4e7375442e1334405a2d046df316cee05cd5"
-    },
-    {
-      "path": "crates/edict-cli/Cargo.toml",
-      "gitBlob": "e9d844553c395bd312f84e806eb5bac30c5c3a54"
-    },
-    {
-      "path": "crates/edict-cli/src/application_build.rs",
-      "gitBlob": "9c56ae6b4dd4eef0b9fe6db40316e100b2ffa699"
-    },
-    {
-      "path": "crates/edict-cli/src/lawpack_build.rs",
-      "gitBlob": "55e9579153f34a3d5b139141c9de6640808cd386"
-    },
-    {
-      "path": "crates/edict-cli/src/lawpack_build_windows.rs",
-      "gitBlob": "f71d03b368ae83becc1608bbba11cd5f1afa4f07"
-    },
-    {
-      "path": "crates/edict-cli/src/lib.rs",
-      "gitBlob": "60883af60cf4b441680952ecce7ef4fcbfeabb97"
-    },
-    {
-      "path": "crates/edict-cli/src/main.rs",
-      "gitBlob": "0dd9776642c4090479322111e4164ee7049fb9d0"
-    },
-    {
-      "path": "crates/edict-cli/tests/golden_cli.rs",
-      "gitBlob": "9897caad3bcc6fa8bb0f20a1d0e18032285b1fa7"
-    },
-    {
-      "path": "crates/edict-cli/tests/jsonl_cli.rs",
-      "gitBlob": "9ed353ca27d073fc7da49d3800c81ba4c58edd5d"
-    },
-    {
-      "path": "crates/edict-cli/tests/lawpack_authoring_cli.rs",
-      "gitBlob": "0a0c53baaedd0854d0c25bc591cb38db9c2c009b"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/Cargo.toml",
-      "gitBlob": "ebeeb941f09012293d9923fe0e6039b2761b328e"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/conversion.rs",
-      "gitBlob": "62c3cd4a85eb156b8c9a405ef3ea4d8a09b80cc3"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/invocation.rs",
-      "gitBlob": "a4d6680d289094afebc0f1063abccf706f8149db"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/lib.rs",
-      "gitBlob": "353ea7394f265219ebdecad56a3070c9e7d2685c"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/limits.rs",
-      "gitBlob": "9e4d12c1b606d2b180f732db17bfbc78f8e26e3a"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/replay.rs",
-      "gitBlob": "b8fa7be7c7ee5039793dad4cd0fa6a4f14ce388e"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/tests/invocation.rs",
-      "gitBlob": "7a59a3192852a80bc01221ebf3dd1c437bda9508"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/tests/preflight.rs",
-      "gitBlob": "a295e7547b0294f0355a85d5b9b8d045c8fceefd"
-    },
-    {
-      "path": "crates/edict-provider-schema/Cargo.toml",
-      "gitBlob": "0e74f58acdc054ecce192cb8341afeaddc40deb5"
-    },
-    {
-      "path": "crates/edict-provider-schema/src/contract_pack.rs",
-      "gitBlob": "370480d9c606134dd08ee62ae29ef143941e2f54"
-    },
-    {
-      "path": "crates/edict-provider-schema/src/lib.rs",
-      "gitBlob": "51f5bee8892c9fb2122cb20022edc4d414759ff7"
-    },
-    {
-      "path": "crates/edict-provider-schema/src/recursive_dispatch.rs",
-      "gitBlob": "6d97565b96f941b359d16f7a1c201189968fbeff"
-    },
-    {
-      "path": "crates/edict-provider-schema/src/schema_safety.rs",
-      "gitBlob": "a2f605f62a2bfedcb84b68e37db9ff84b1dc3b05"
-    },
-    {
-      "path": "crates/edict-provider-schema/tests/authority_facts_abi.rs",
-      "gitBlob": "7dd4d0302805ceecffc2045cdb91e386f8e08517"
-    },
-    {
-      "path": "crates/edict-provider-schema/tests/provider_contract_pack.rs",
-      "gitBlob": "a26be8054b39215048825dd8cae7e9bddcfe27c9"
-    },
-    {
-      "path": "crates/edict-provider-schema/tests/registry.rs",
-      "gitBlob": "bdd13ec00e441aef9e67ba49f6592ecbc7dcb303"
-    },
-    {
-      "path": "crates/edict-syntax/Cargo.toml",
-      "gitBlob": "f55bb23e528af78b1e97b52f9b72cbd876a44ba7"
-    },
-    {
-      "path": "crates/edict-syntax/src/admission.rs",
-      "gitBlob": "471430dd13a617bac886fcd44afbf15263e7db3b"
-    },
-    {
-      "path": "crates/edict-syntax/src/ast.rs",
-      "gitBlob": "2a5d208a53a82408f8a18d9a13ccb133ec6a7a2e"
-    },
-    {
-      "path": "crates/edict-syntax/src/authority_facts.rs",
-      "gitBlob": "644de86d63983bdbfbf1279fdbf1dbdaecc151d5"
-    },
-    {
-      "path": "crates/edict-syntax/src/canonical.rs",
-      "gitBlob": "6fb29d50ea4a55eb888a1b9600cdcb31713a6e20"
-    },
-    {
-      "path": "crates/edict-syntax/src/compiler.rs",
-      "gitBlob": "d9661e2605f23f503a8fdf4471462cc0b9bad4c1"
-    },
-    {
-      "path": "crates/edict-syntax/src/compiler/byte_concat.rs",
-      "gitBlob": "185d11c0ae20931cd2737774a34cac92b13d6712"
-    },
-    {
-      "path": "crates/edict-syntax/src/compiler/byte_length.rs",
-      "gitBlob": "0d8d6291064415baee9253d9fe1e11ad87945773"
-    },
-    {
-      "path": "crates/edict-syntax/src/compiler/byte_slice.rs",
-      "gitBlob": "84385fffdf4e38e21285e1fde252e9185a3a76fa"
-    },
-    {
-      "path": "crates/edict-syntax/src/compiler/unsigned_subtraction.rs",
-      "gitBlob": "c2ef2deda74afb52e4346076a310df341556e1c8"
-    },
-    {
-      "path": "crates/edict-syntax/src/contract_bundle.rs",
-      "gitBlob": "9a31645f0e30879d019787e29c21c82eebf58129"
-    },
-    {
-      "path": "crates/edict-syntax/src/core_ir.rs",
-      "gitBlob": "4c6f350b325d13a27947687dd1f4114edf6d548d"
-    },
-    {
-      "path": "crates/edict-syntax/src/highlight.rs",
-      "gitBlob": "28b3f7dcdfe8d4982bdcfb05759f769ccdbffc7f"
-    },
-    {
-      "path": "crates/edict-syntax/src/lawpack.rs",
-      "gitBlob": "54f85bda48c960ad0b7bc316d332b379ab5b6ae0"
-    },
-    {
-      "path": "crates/edict-syntax/src/lawpack_adapter.rs",
-      "gitBlob": "e425960e2437faa2f9eeb5d089ff507417d39586"
-    },
-    {
-      "path": "crates/edict-syntax/src/lawpack_authoring.rs",
-      "gitBlob": "11ff578f458b8a4c8e4df75c0c616e37fa468d49"
-    },
-    {
-      "path": "crates/edict-syntax/src/lib.rs",
-      "gitBlob": "7323475cc7f846e11c2d73f4c26a5e581b7e6157"
-    },
-    {
-      "path": "crates/edict-syntax/src/lowerability.rs",
-      "gitBlob": "c6a1323fd6a79b0460b43aaf338956c3906a633e"
-    },
-    {
-      "path": "crates/edict-syntax/src/parser.rs",
-      "gitBlob": "0b3650e3012e49023ccbb9cc9effe9b5b102f19d"
-    },
-    {
-      "path": "crates/edict-syntax/src/provider.rs",
-      "gitBlob": "18fa661d880979c53dd335fb7e68d5445b638d4c"
-    },
-    {
-      "path": "crates/edict-syntax/src/provider_invocation.rs",
-      "gitBlob": "2526168f0a6f2d1d9b6181b689ff43e203434122"
-    },
-    {
-      "path": "crates/edict-syntax/src/provider_lowering.rs",
-      "gitBlob": "50a4e60b561127cb8c78e3f7c04c6bbaca068e52"
-    },
-    {
-      "path": "crates/edict-syntax/src/result_projection.rs",
-      "gitBlob": "79ba246d4c58960fe368eaca4c7d135fe187832a"
-    },
-    {
-      "path": "crates/edict-syntax/src/semantic.rs",
-      "gitBlob": "76bd133ef5859bf7722d1987613f7fd84836ab62"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir.rs",
-      "gitBlob": "9dd759a18ea3a171837baa50e88c67987c84da13"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/byte_concat.rs",
-      "gitBlob": "bff3a35e1d3183813ffb1e69655934f65f2c9131"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/byte_length.rs",
-      "gitBlob": "972e6ffa943bc7a7a943d76f0af42b342e3d2aac"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/byte_slice.rs",
-      "gitBlob": "62a1c0b9e84a331bb17ab78090cce6d8eb8da486"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/execution_order.rs",
-      "gitBlob": "e69a28805dc5e414a64afdaafee34161c217a044"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/totality.rs",
-      "gitBlob": "a4fb9573d59e1a4bb9d7c250402c5b7e1da0a8c3"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/unsigned_subtraction.rs",
-      "gitBlob": "b83522bfe9a2b506413b4d306f4bc49f8b053f36"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_profile.rs",
-      "gitBlob": "dd514f7380243e795f0655a78aecd06ee3fa2eda"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_profile_contract_resources.rs",
-      "gitBlob": "4efd22961c2fd7591440efd6087944ecaf21e991"
-    },
-    {
-      "path": "crates/edict-syntax/src/token.rs",
-      "gitBlob": "2768586eea6d42d5df357c4cc62a011ee7f455de"
-    },
-    {
-      "path": "crates/edict-syntax/tests/admission.rs",
-      "gitBlob": "57edbc320307c1d6daba85f03d8dc79558d7b849"
-    },
-    {
-      "path": "crates/edict-syntax/tests/authority_facts.rs",
-      "gitBlob": "add9d272be6e8eb1cd6fdde2999a5fb452ecd852"
-    },
-    {
-      "path": "crates/edict-syntax/tests/authority_facts_cbor.rs",
-      "gitBlob": "7359f047d9f731fee208efb5f69072b612d69547"
-    },
-    {
-      "path": "crates/edict-syntax/tests/byte_concat.rs",
-      "gitBlob": "f013cade690112b266dd79b1e5405cc65c6f2d07"
-    },
-    {
-      "path": "crates/edict-syntax/tests/byte_length.rs",
-      "gitBlob": "50945944e8c2223abcc6b1081322432bc540c017"
-    },
-    {
-      "path": "crates/edict-syntax/tests/byte_slice.rs",
-      "gitBlob": "99aae98ac1637a95532cdd833463210bbaa5a5be"
-    },
-    {
-      "path": "crates/edict-syntax/tests/canonical_encoding.rs",
-      "gitBlob": "e4c5d59a88f88193f522eb555359919f7034a264"
-    },
-    {
-      "path": "crates/edict-syntax/tests/common/mod.rs",
-      "gitBlob": "89560bfacb3dab031485c2dfa30d7eb325966574"
-    },
-    {
-      "path": "crates/edict-syntax/tests/compiler_spine.rs",
-      "gitBlob": "2237318cfc0d4209e8a629e45320e42a4b72dbef"
-    },
-    {
-      "path": "crates/edict-syntax/tests/contract_bundle.rs",
-      "gitBlob": "e6a2948335a0efc86d8bbb2e9e2c3d634e53965a"
-    },
-    {
-      "path": "crates/edict-syntax/tests/core_golden_fixtures.rs",
-      "gitBlob": "0e0e42d19b52dc0557902dad9e1b85f37edf53f8"
-    },
-    {
-      "path": "crates/edict-syntax/tests/core_graph_depth.rs",
-      "gitBlob": "1d95462ad2426d29b5974e6bb56ab8c125a92837"
-    },
-    {
-      "path": "crates/edict-syntax/tests/external_action_requests.rs",
-      "gitBlob": "20aac8c03325ea0cdab8f4f54660cb980b4667c4"
-    },
-    {
-      "path": "crates/edict-syntax/tests/highlighting.rs",
-      "gitBlob": "17e6b9ba08c96f0efb6efd440590f0fc917316e2"
-    },
-    {
-      "path": "crates/edict-syntax/tests/lawpack.rs",
-      "gitBlob": "a675999ed96309358c8552a9d32781b5eede20dc"
-    },
-    {
-      "path": "crates/edict-syntax/tests/lawpack_authoring.rs",
-      "gitBlob": "de5e9102d8cfd43706074e482d407ac5f4c6fd26"
-    },
-    {
-      "path": "crates/edict-syntax/tests/lowerability.rs",
-      "gitBlob": "5cfa58f5cbc51cccc7f119caddc1c3fcbc2e4806"
-    },
-    {
-      "path": "crates/edict-syntax/tests/operation_prerequisites.rs",
-      "gitBlob": "753659e1a6e7751c455b8518226fa0902157a745"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_control_flow.rs",
-      "gitBlob": "5245561866d8902c1fbd5ab21f2e34807d568e17"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_greeting.rs",
-      "gitBlob": "f214d0c17745b8203d562780caa8f37b71c1e62c"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_hello.rs",
-      "gitBlob": "bf7b1b065277188f4be8754eb11ace94298394ba"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_keywords.rs",
-      "gitBlob": "78d8a64d785136d42a32655afda3df240c54f884"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_loops.rs",
-      "gitBlob": "d9ece2fce96fd6835d080055f06955d139c7e0ce"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_negative.rs",
-      "gitBlob": "17fdb983b8250470368a8f19d3a7bd9680052548"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_review_regressions.rs",
-      "gitBlob": "560215cfe044a528e190aa1ea7670e52b9365bdf"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_variants.rs",
-      "gitBlob": "8849f68f5ca1e2b06d0f66496e59b20d1c0fd022"
-    },
-    {
-      "path": "crates/edict-syntax/tests/provider.rs",
-      "gitBlob": "7e8a596109b1e1fd3f22b3a0ef82f4755f127291"
-    },
-    {
-      "path": "crates/edict-syntax/tests/provider_invocation.rs",
-      "gitBlob": "402647dd6701be65a9e693fd3f5688f26d84988e"
-    },
-    {
-      "path": "crates/edict-syntax/tests/provider_lowering.rs",
-      "gitBlob": "411c306f3ab641de9dc2f7aed229767eba9dbd72"
-    },
-    {
-      "path": "crates/edict-syntax/tests/result_projection.rs",
-      "gitBlob": "a74dd2a419266cb77d846d83da27f726095660f1"
-    },
-    {
-      "path": "crates/edict-syntax/tests/semantic_validation.rs",
-      "gitBlob": "a127988d178c00ed12a0a25f70df6b7fd5e6d931"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_ir.rs",
-      "gitBlob": "928e1cf921dead0b559bd115bb6eef3faaddd37e"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_ir/ordered.rs",
-      "gitBlob": "a1b05db81a97a43ec5a2dc2d9bcc9578bc286f30"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_profile.rs",
-      "gitBlob": "42f1c907f6c60dea1e8a9b4558b56ffd0b3a59ab"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_profile_contract_resources.rs",
-      "gitBlob": "270c180a12dc10fb7e208cc4dc1e202da82c85fb"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_unsigned_subtraction.rs",
-      "gitBlob": "e30d91f896afda48eb3cf11617bccf1f9d160e32"
-    },
-    {
-      "path": "crates/edict-syntax/tests/unsigned_subtraction.rs",
-      "gitBlob": "fbd24482fdad4c8ceb4df41302b33595ada337ec"
-    },
-    {
-      "path": "crates/edict/Cargo.toml",
-      "gitBlob": "525403f4f36db4040531e4dd747ec2398f9052cd"
-    },
-    {
-      "path": "crates/edict/README.md",
-      "gitBlob": "a1ecf50bff3443d25a23fabfa6374d3f0a28ca82"
-    },
-    {
-      "path": "crates/edict/src/lib.rs",
-      "gitBlob": "169d820759d6333f27a45ebb712bfcc4f0115107"
-    },
-    {
-      "path": "crates/edict/tests/artifact_models.rs",
-      "gitBlob": "b923109c7195ce2c0071dc54179f0746b95329f0"
-    },
-    {
-      "path": "crates/edict/tests/public_surface.rs",
-      "gitBlob": "a24c4bc9d9484f540da9b280790896701922968a"
-    },
-    {
-      "path": "deny.toml",
-      "gitBlob": "e3f0f54060cead9a0d48b96ed86948d0909c4f78"
-    },
-    {
-      "path": "docs/DESIGN_runtime-neutral-edict-sha-lock-assurance.md",
-      "gitBlob": "ea3badf78ebd19545147a93671fdb5f9af4a61ea"
-    },
-    {
-      "path": "docs/GUIDE_edict-assurance-transparency.md",
-      "gitBlob": "100321157ec43055c45794f1c161b1e5281ba6b4"
-    },
-    {
-      "path": "docs/README.md",
-      "gitBlob": "e21739b842be14d91a17f2508b1a1b629754af01"
-    },
-    {
-      "path": "docs/REQUIREMENTS.md",
-      "gitBlob": "fd69cf5b3f57af39cda8bcf7f94ff21666a34636"
-    },
-    {
-      "path": "docs/RETRO_phase1-parser.md",
-      "gitBlob": "5cfb7b85ca2f140fc58f9186c47e4635e94a1e6f"
-    },
-    {
-      "path": "docs/SPEC_continuum-admission-v1.md",
-      "gitBlob": "0a74a0bfc642337d5d7a85133ce50a0a22caffbd"
-    },
-    {
-      "path": "docs/SPEC_continuum-contract-bundle-v1.md",
-      "gitBlob": "65b36bb33a34beb1f246d1f97384631c83ca631e"
-    },
-    {
-      "path": "docs/SPEC_edict-language-v1.md",
-      "gitBlob": "dd3f1584b000678a12232b76836172e4e66be71b"
-    },
-    {
-      "path": "docs/SPEC_edict-lawpack-abi-v1.md",
-      "gitBlob": "ea1d801f07ab3677f7a411a1f58a28feda589ec3"
-    },
-    {
-      "path": "docs/SPEC_edict-target-profile-abi-v1.md",
-      "gitBlob": "91687bfe45565a21f5f93f6ce9eed84095268691"
-    },
-    {
-      "path": "docs/TECHNICAL_EXPLANATION.md",
-      "gitBlob": "d88561c0552c0e75d1ecc2eef6f9afd003e99674"
-    },
-    {
-      "path": "docs/abi/edict-authority-facts.cddl",
-      "gitBlob": "e9a6d8685706ae0d8dabda401655234161e94299"
-    },
-    {
-      "path": "docs/abi/edict-common.cddl",
-      "gitBlob": "836c11b92425beb6d42b378c0defe6f02d144dd7"
-    },
-    {
-      "path": "docs/abi/edict-core.cddl",
-      "gitBlob": "862f02939fcc3858b4a60cb75f9bf149eae8ffda"
-    },
-    {
-      "path": "docs/abi/edict-lawpack-adapter.cddl",
-      "gitBlob": "8e887c2e196ba7502470ddb45dc7cfd10116ad6b"
-    },
-    {
-      "path": "docs/abi/edict-lawpack.cddl",
-      "gitBlob": "96efd51d437ec785b108b51835e9e8bf87aeab51"
-    },
-    {
-      "path": "docs/abi/edict-result-projection.cddl",
-      "gitBlob": "98b5c2e861e7e9b66b7481502287cb041f6e77e6"
-    },
-    {
-      "path": "docs/abi/edict-target-ir.cddl",
-      "gitBlob": "98134f277ded1920a3a36e5e3946c51153f2e84d"
-    },
-    {
-      "path": "docs/abi/edict-target-profile.cddl",
-      "gitBlob": "746ae03001310f3a83524e5332819dad1a4eea5a"
-    },
-    {
-      "path": "docs/abi/edict-target-provider.wit",
-      "gitBlob": "0efa5903a52d38dc61e429619d86322c6c5f1fa0"
-    },
-    {
-      "path": "docs/audit/2026-06-28_code-quality.md",
-      "gitBlob": "143cbf4f4491a76a6649e919c6edaba73f0bcf4b"
-    },
-    {
-      "path": "docs/audit/2026-06-28_documentation-quality.md",
-      "gitBlob": "656b4fa8dea43306af1818f8622cafd72e82a370"
-    },
-    {
-      "path": "docs/audit/2026-06-28_ship-readiness.md",
-      "gitBlob": "b9d34a8693564d0134f550092e7645e5d5137442"
-    },
-    {
-      "path": "docs/design/authority-fact-governance.md",
-      "gitBlob": "8531061cf718c47ec791f5712b2f357d92adc9e4"
-    },
-    {
-      "path": "docs/design/canonical-target-ir-v0.11.md",
-      "gitBlob": "a46acb84e3523b51e2348c776cfdb63a8b98107a"
-    },
-    {
-      "path": "docs/design/contract-bundle-assembly-v0.11.md",
-      "gitBlob": "a364f8ade5445808f87cf0c63ab3484c03ad616a"
-    },
-    {
-      "path": "docs/design/crate-scope-v0.11.md",
-      "gitBlob": "92fe92285d02465d84bbe82e29d051fdc461f3a6"
-    },
-    {
-      "path": "docs/design/obstruction-strands-v0.md",
-      "gitBlob": "81f70fd688c12798cd23472a4e810191e61eabe2"
-    },
-    {
-      "path": "docs/design/provider-artifact-pipeline-alpha.md",
-      "gitBlob": "60eefa7dc160aba986bcd1188b79610ff5e9f299"
-    },
-    {
-      "path": "docs/design/schema-as-sot-codegen.md",
-      "gitBlob": "d818e0e3f1fafd1d3aba26cb37c739f3ebe69763"
-    },
-    {
-      "path": "docs/design/v2-obligation-closure.md",
-      "gitBlob": "816d22d843a33c6f7e143da4cb45e80679609dc8"
-    },
-    {
-      "path": "docs/releases/v0.1.0-alpha.1.md",
-      "gitBlob": "5dd96057ba7f109cf5e5acde16e29d18627f98d3"
-    },
-    {
-      "path": "docs/releases/v0.10.0-alpha.1.md",
-      "gitBlob": "363c4e9ed6f5ea5758198c7124681b520098e583"
-    },
-    {
-      "path": "docs/releases/v0.11.0-alpha.1.md",
-      "gitBlob": "4612dbb5a1aaf20710bdb199b658ded7ced4ebab"
-    },
-    {
-      "path": "docs/releases/v0.2.0-alpha.1.md",
-      "gitBlob": "7302ef93ed5ff9b562d9cec92d49d85a6b789b27"
-    },
-    {
-      "path": "docs/releases/v0.3.0-alpha.1.md",
-      "gitBlob": "bf023ba4ca2c38f0120c461781447d58fe239ae0"
-    },
-    {
-      "path": "docs/releases/v0.4.0-alpha.1.md",
-      "gitBlob": "769500b59800c02c536b76b0eb850d06d6cd8f58"
-    },
-    {
-      "path": "docs/releases/v0.5.0-alpha.1.md",
-      "gitBlob": "7c7354e89846ea816992aaf55d4ad04367d61a10"
-    },
-    {
-      "path": "docs/releases/v0.6.0-alpha.1.md",
-      "gitBlob": "3f2a0edfc4bccd9f3c60a7443ef4f8cbcbac1971"
-    },
-    {
-      "path": "docs/releases/v0.7.0-alpha.1.md",
-      "gitBlob": "57671d5ef5a6b9f16d1674e0a35ddeb86ff126a8"
-    },
-    {
-      "path": "docs/releases/v0.8.0-alpha.1.md",
-      "gitBlob": "12f77bda185c54fbbd136bf0dc7292716ecdfa39"
-    },
-    {
-      "path": "docs/releases/v0.9.0-alpha.1.md",
-      "gitBlob": "fa295fcf0967415bb052f238256919b32b3fe6ba"
-    },
-    {
-      "path": "docs/schemas/edict.cli-check-result.v1.schema.json",
-      "gitBlob": "eef8cd11f07e06d68b7051efa60ae05f2cfd8a63"
-    },
-    {
-      "path": "docs/schemas/edict.cli-diagnostic.v1.schema.json",
-      "gitBlob": "92a2151a76893c598a4191ed6cecd8a0e671613f"
-    },
-    {
-      "path": "docs/schemas/edict.cli-event.v1.schema.json",
-      "gitBlob": "705d82a893c2ea91caa91ad6977a9be8646b47bb"
-    },
-    {
-      "path": "docs/schemas/edict.cli-info.v1.schema.json",
-      "gitBlob": "2d9a0777b4190b56ff569625275d352d17363afa"
-    },
-    {
-      "path": "docs/schemas/edict.compiler-input.v1.schema.json",
-      "gitBlob": "26da3ba0fe85fab4c826ad79f13968ce09c4f29b"
-    },
-    {
-      "path": "docs/schemas/edict.compiler-settings.v1.schema.json",
-      "gitBlob": "a3e8ba469895b84ab81724da1075c73141a8dd0c"
-    },
-    {
-      "path": "docs/schemas/edict.projection-core.v1.schema.json",
-      "gitBlob": "8c0afe3834256abd1e18efb5f31eae1c4bdf0374"
-    },
-    {
-      "path": "docs/schemas/edict.projection-diagnostics.v1.schema.json",
-      "gitBlob": "28cfb0a67dff7b8f879122c74433158dc0a4e5df"
-    },
-    {
-      "path": "docs/schemas/edict.projection-syntax.v1.schema.json",
-      "gitBlob": "a85f2e14f536863f5e7b107b1a9f3f10816e6234"
-    },
-    {
-      "path": "docs/schemas/edict.projection-target-ir.v1.schema.json",
-      "gitBlob": "8bbb6495ad8800d775d1c08506e85351038d678a"
-    },
-    {
-      "path": "docs/topics/README.md",
-      "gitBlob": "99b06d3124c71cb62dfe6faff7604c13063162a7"
-    },
-    {
-      "path": "docs/topics/admission/README.md",
-      "gitBlob": "755dcba96c0a428eec18d58a529f3e26d57d118c"
-    },
-    {
-      "path": "docs/topics/admission/test-plan.md",
-      "gitBlob": "68ee0a2d2502103285985bf862de9fadf2bac5a0"
-    },
-    {
-      "path": "docs/topics/assurance/README.md",
-      "gitBlob": "cf382008f3d3094a5380a687abbf07538e07404d"
-    },
-    {
-      "path": "docs/topics/assurance/test-plan.md",
-      "gitBlob": "0ea6c971924db763088577a0a52bbd30bfec814c"
-    },
-    {
-      "path": "docs/topics/authority-facts/README.md",
-      "gitBlob": "c5589d2489d6e4a5729c0df2b2655ff281d8d88d"
-    },
-    {
-      "path": "docs/topics/authority-facts/test-plan.md",
-      "gitBlob": "e3769edf8309347b23ffa2e8f0901e06feabd654"
-    },
-    {
-      "path": "docs/topics/cli/README.md",
-      "gitBlob": "af38946c9ccae8da343877c3861b0f52b6076e1b"
-    },
-    {
-      "path": "docs/topics/cli/test-plan.md",
-      "gitBlob": "d72d69ef1d340ffd7057a63dd7bc07e3dfb2c166"
-    },
-    {
-      "path": "docs/topics/compiler-spine/README.md",
-      "gitBlob": "d09184ef695252b85d05fc79017015f18c3869ee"
-    },
-    {
-      "path": "docs/topics/compiler-spine/test-plan.md",
-      "gitBlob": "1b2aaa924d95408bf0ef621d7a1a92b88a00611e"
-    },
-    {
-      "path": "docs/topics/contract-bundles/README.md",
-      "gitBlob": "2347499e8da9dd57bb1588faf67fe386c7a70c03"
-    },
-    {
-      "path": "docs/topics/contract-bundles/test-plan.md",
-      "gitBlob": "3ae4c7362f90fa89081ab9ff2bf1c3db1a811874"
-    },
-    {
-      "path": "docs/topics/core-ir/README.md",
-      "gitBlob": "d747a18d1f53de2b29473ada7a06b819c77cd162"
-    },
-    {
-      "path": "docs/topics/core-ir/canonical-encoding.md",
-      "gitBlob": "34927c69fb1de10b685294a155fc46bb4ac21628"
-    },
-    {
-      "path": "docs/topics/core-ir/test-plan.md",
-      "gitBlob": "0f80304a4dd6b160c78674b73605bdbbb7e11066"
-    },
-    {
-      "path": "docs/topics/developer-tooling/README.md",
-      "gitBlob": "8648d3c1bdf4f6b774bc5fec71c71aa8c59b0ce8"
-    },
-    {
-      "path": "docs/topics/developer-tooling/test-plan.md",
-      "gitBlob": "9240f717434dfbca08a6366e6d3ebafd4ef2c908"
-    },
-    {
-      "path": "docs/topics/documentation/README.md",
-      "gitBlob": "34fa7f4db136c274a88b680f99619d657fda15d5"
-    },
-    {
-      "path": "docs/topics/documentation/test-plan.md",
-      "gitBlob": "47964954fbf640211bc30b0dd361c44c9955c488"
-    },
-    {
-      "path": "docs/topics/external-action-requests/README.md",
-      "gitBlob": "45bc73e469919d3eff6e7eddbe9baa0383c7d91b"
-    },
-    {
-      "path": "docs/topics/external-action-requests/test-plan.md",
-      "gitBlob": "38e7e53827d223c031d414f4ecd63720eb78eae0"
-    },
-    {
-      "path": "docs/topics/fixtures/README.md",
-      "gitBlob": "c8b3b196109fb6d4e37d8ffa17635166010075fb"
-    },
-    {
-      "path": "docs/topics/fixtures/test-plan.md",
-      "gitBlob": "624357dbc544d365835390d3d3c2f11015b7b82f"
-    },
-    {
-      "path": "docs/topics/lawpack-authoring/README.md",
-      "gitBlob": "a7f781666822977d4ca2483024e1e451605cf9f5"
-    },
-    {
-      "path": "docs/topics/lawpack-authoring/test-plan.md",
-      "gitBlob": "1cc83e6b0865257feb89a88787b1eb3b983d1f84"
-    },
-    {
-      "path": "docs/topics/lawpacks/README.md",
-      "gitBlob": "dedaa524dc55663a44bf8101241ab4b6d4755531"
-    },
-    {
-      "path": "docs/topics/lawpacks/test-plan.md",
-      "gitBlob": "f8aa2c7ce40dad2665134956dc95d951d311808f"
-    },
-    {
-      "path": "docs/topics/lowerability/README.md",
-      "gitBlob": "fb9519af3539d846dc5bf2915bf5ca86816e46f8"
-    },
-    {
-      "path": "docs/topics/lowerability/test-plan.md",
-      "gitBlob": "e0fbff0799ba805c9531097d6b8aeea657e2b815"
-    },
-    {
-      "path": "docs/topics/obstruction-strands/README.md",
-      "gitBlob": "a2930645065390cecff8008bfd48b7f034bfcd18"
-    },
-    {
-      "path": "docs/topics/obstruction-strands/test-plan.md",
-      "gitBlob": "20c54ffcaa19930a5bc772a49a5f01119054be2d"
-    },
-    {
-      "path": "docs/topics/providers/README.md",
-      "gitBlob": "8b5a07fb9c708b753861a4e156b866115f4d687b"
-    },
-    {
-      "path": "docs/topics/providers/architecture.md",
-      "gitBlob": "664b38347ccaf37f298d6ac9f19d3423c0277f9e"
-    },
-    {
-      "path": "docs/topics/providers/test-plan.md",
-      "gitBlob": "95c55f9e132ca6859fd9df70470973e678ed8d92"
-    },
-    {
-      "path": "docs/topics/public-rust-api/README.md",
-      "gitBlob": "c64a1081b7f693b02bd2ea63329f2610bae9d84c"
-    },
-    {
-      "path": "docs/topics/public-rust-api/test-plan.md",
-      "gitBlob": "4c3b9e9662afd9edb790ba2b5c57ed5e93df595c"
-    },
-    {
-      "path": "docs/topics/release-process/README.md",
-      "gitBlob": "a474ab8b6a4a58c5c73334c9e677be7c20d1837c"
-    },
-    {
-      "path": "docs/topics/release-process/policy.toml",
-      "gitBlob": "e40b4f4ec721ae61210ec1bb022a847bcb49fb4a"
-    },
-    {
-      "path": "docs/topics/release-process/runbook.md",
-      "gitBlob": "0b6bd8ef44cbfe8c7cdc347273fa74b7c96c4823"
-    },
-    {
-      "path": "docs/topics/release-process/test-plan.md",
-      "gitBlob": "61ecded1d2318d7dd74070cd1c6155f353c947e9"
-    },
-    {
-      "path": "docs/topics/result-projections/README.md",
-      "gitBlob": "d5c2f85a7681a15dcdc3e35f992a389c50d13461"
-    },
-    {
-      "path": "docs/topics/result-projections/test-plan.md",
-      "gitBlob": "9e69d58c88d6a9b7389334a78b994a3449721faa"
-    },
-    {
-      "path": "docs/topics/review-process/README.md",
-      "gitBlob": "25190d37dc30110f75ba5d3a41494575ffecc1c3"
-    },
-    {
-      "path": "docs/topics/review-process/policy.toml",
-      "gitBlob": "a826ba58aad2e509220b65aa8f96c290b600e094"
-    },
-    {
-      "path": "docs/topics/review-process/test-plan.md",
-      "gitBlob": "f1a50aeae47913e4513a8149c1679d9a94c5ef21"
-    },
-    {
-      "path": "docs/topics/rust-standards/README.md",
-      "gitBlob": "2fe29258705d117f4d10604a83fd832a8476e303"
-    },
-    {
-      "path": "docs/topics/rust-standards/test-plan.md",
-      "gitBlob": "0e0d6b306cd2b58db07a7a5da6a752925fe58764"
-    },
-    {
-      "path": "docs/topics/semantic-validation/README.md",
-      "gitBlob": "51cd9761755e7b5879069bf3774eeb487982ca97"
-    },
-    {
-      "path": "docs/topics/semantic-validation/test-plan.md",
-      "gitBlob": "b43969d8eb0a884c1663ab761662f9622617bb3b"
-    },
-    {
-      "path": "docs/topics/syntax/README.md",
-      "gitBlob": "b2a372bf41b1976567c61f400bf000f33abc20cc"
-    },
-    {
-      "path": "docs/topics/syntax/test-plan.md",
-      "gitBlob": "a69efaf12dfe12661fca049b8790b37fa3fb3665"
-    },
-    {
-      "path": "docs/topics/target-ir/README.md",
-      "gitBlob": "73d6b50a99a6231bd0d337ded95bd2a960590328"
-    },
-    {
-      "path": "docs/topics/target-ir/test-plan.md",
-      "gitBlob": "4ec0f497fc0c9e73599d602417acfbfe74e65ff0"
-    },
-    {
-      "path": "docs/topics/target-profiles/README.md",
-      "gitBlob": "6a88f4d732f8069855b2ed2cb9a8769a117b2f60"
-    },
-    {
-      "path": "docs/topics/target-profiles/test-plan.md",
-      "gitBlob": "90084c3f3a1296745469cd86e9b5f2bc928825be"
-    },
-    {
-      "path": "docs/topics/tests/README.md",
-      "gitBlob": "4ad079b6a9718e2a8446a6c67ff45735015bef84"
-    },
-    {
-      "path": "docs/topics/tests/test-plan.md",
-      "gitBlob": "46bc0572d02a41e86f71c6d46baf5be611a462a6"
-    },
-    {
-      "path": "docs/topics/v2-design/README.md",
-      "gitBlob": "b33a07599e43e660aa4def7f119ddd02df6a16de"
-    },
-    {
-      "path": "docs/topics/v2-design/test-plan.md",
-      "gitBlob": "f17f96d381f81b20842393f70ff55b9597858b84"
-    },
-    {
-      "path": "editors/README.md",
-      "gitBlob": "7a933576262bc58bac197f9264fdbf649dd5e696"
-    },
-    {
-      "path": "editors/vscode/.vscodeignore",
-      "gitBlob": "f15b3142e4b8af11d580789a0c82acee3499f571"
-    },
-    {
-      "path": "editors/vscode/README.md",
-      "gitBlob": "8b29840ae9ec8f618b7364022329f694d0ed9746"
-    },
-    {
-      "path": "editors/vscode/language-configuration.json",
-      "gitBlob": "b7f583841649c9c437785edbfcb70ee24e495c79"
-    },
-    {
-      "path": "editors/vscode/package.json",
-      "gitBlob": "cd9e391e7c9afb6f9393fcead118e0e55aadc839"
-    },
-    {
-      "path": "editors/vscode/syntaxes/edict.tmLanguage.json",
-      "gitBlob": "5847d8edfdb32d822f0f3950f41d00c947982185"
-    },
-    {
-      "path": "fixtures/README.md",
-      "gitBlob": "470e3e0fc3aa00654930ecdef892ee9df8a42c8d"
-    },
-    {
-      "path": "fixtures/authority-facts/canonical/README.md",
-      "gitBlob": "28692ce70add5d4f2d4ff5318309c3353924caf9"
-    },
-    {
-      "path": "fixtures/authority-facts/canonical/example-effectful.authority-facts.cbor",
-      "gitBlob": "fe2e59a8e2602e02c52094010a130db2637c5227"
-    },
-    {
-      "path": "fixtures/authority-facts/canonical/example-effectful.authority-facts.json",
-      "gitBlob": "009faa5d2dc1dcf55cf284dcfd14c0b6405f3e0d"
-    },
-    {
-      "path": "fixtures/authority-facts/canonical/example-effectful.authority-facts.sha256",
-      "gitBlob": "a3d68f0a3b3a586e85b6a84cbd884866e662951f"
-    },
-    {
-      "path": "fixtures/bundle/assembly/bounded-hello.bundle-digests.txt",
-      "gitBlob": "da5402db7bd41dd88c6152b7799723561130c91e"
-    },
-    {
-      "path": "fixtures/cli/01-source-ok/expected.stdout.jsonl",
-      "gitBlob": "e08ccf8fdedd3a73beef5d06c443a1bc60274ce1"
-    },
-    {
-      "path": "fixtures/cli/01-source-ok/request.jsonl",
-      "gitBlob": "002fea597e6b93c8468d6972b73cc1344600fa87"
-    },
-    {
-      "path": "fixtures/cli/02-source-parse-rejection/exit",
-      "gitBlob": "d00491fd7e5bb6fa28c517a0bb32b8b506539d4d"
-    },
-    {
-      "path": "fixtures/cli/02-source-parse-rejection/expected.stderr.jsonl",
-      "gitBlob": "1077b73c9a7c02eae99f737bea7b6ff8c64d04da"
-    },
-    {
-      "path": "fixtures/cli/02-source-parse-rejection/request.jsonl",
-      "gitBlob": "dce01f0466bd9384fc6f5cbe2845b6e0bd9a9cfd"
-    },
-    {
-      "path": "fixtures/cli/03-source-semantic-rejection/exit",
-      "gitBlob": "d00491fd7e5bb6fa28c517a0bb32b8b506539d4d"
-    },
-    {
-      "path": "fixtures/cli/03-source-semantic-rejection/expected.stderr.jsonl",
-      "gitBlob": "5ec447700da52d0b4ce1f75825eb9bffaed4884b"
-    },
-    {
-      "path": "fixtures/cli/03-source-semantic-rejection/request.jsonl",
-      "gitBlob": "ddfd529e5448760387961febbd4ce013e49de435"
-    },
-    {
-      "path": "fixtures/cli/04-cli-missing-settings/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/04-cli-missing-settings/expected.stderr.jsonl",
-      "gitBlob": "5060bd2fd773ba9ea3ea6db8c80b86a846bfadbd"
-    },
-    {
-      "path": "fixtures/cli/04-cli-missing-settings/request.jsonl",
-      "gitBlob": "8eb12e58d427bd64ccfe339190e05bdccf4c8634"
-    },
-    {
-      "path": "fixtures/cli/05-path-input-ok/expected.stdout.jsonl",
-      "gitBlob": "a05fc582efc41b6414e785167b5deeb7532088ef"
-    },
-    {
-      "path": "fixtures/cli/05-path-input-ok/inputs/hello.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/05-path-input-ok/request.jsonl",
-      "gitBlob": "18facaab79dc198134c535df389cba79efe7dce7"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/expected.stdout.jsonl",
-      "gitBlob": "ef59591526e2084ddf5057249bbc96ab660cf256"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/inputs/a.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/inputs/ignore.txt",
-      "gitBlob": "ed34ae8da336ff94a67b6125fbd6be730c976d91"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/inputs/nested/b.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/request.jsonl",
-      "gitBlob": "bd9aad14fe79caccacaa6d00ffd32b5e13b3551f"
-    },
-    {
-      "path": "fixtures/cli/07-path-list-ok/expected.stdout.jsonl",
-      "gitBlob": "643ecb3e659c10cb98255ec1aced772778e76eb0"
-    },
-    {
-      "path": "fixtures/cli/07-path-list-ok/inputs/first.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/07-path-list-ok/inputs/second.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/07-path-list-ok/request.jsonl",
-      "gitBlob": "f11265b02c5b7559ced4d975471a78b5bef3ee27"
-    },
-    {
-      "path": "fixtures/cli/08-glob-expansion-ok/expected.stdout.jsonl",
-      "gitBlob": "90164a7fce6c51abdadef8f0586d2c56113d9712"
-    },
-    {
-      "path": "fixtures/cli/08-glob-expansion-ok/inputs/x.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/08-glob-expansion-ok/inputs/y.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/08-glob-expansion-ok/request.jsonl",
-      "gitBlob": "9335acf3a008ab8fb9942b3e22d73c456ed3827e"
-    },
-    {
-      "path": "fixtures/cli/09-shape-source-ok/expected.stdout.jsonl",
-      "gitBlob": "ac6f9259502ebfe484e1c07a5f53865888dd8207"
-    },
-    {
-      "path": "fixtures/cli/09-shape-source-ok/request.jsonl",
-      "gitBlob": "64c75d9a7b40985bacf0e59a943a16e20419c602"
-    },
-    {
-      "path": "fixtures/cli/10-input-extra-field/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/10-input-extra-field/expected.stderr.jsonl",
-      "gitBlob": "2f5a8fba093b71d15a5b37504ad0352191c8299c"
-    },
-    {
-      "path": "fixtures/cli/10-input-extra-field/request.jsonl",
-      "gitBlob": "6052212c652d41f03144a7d3d4018b1cdd18cd09"
-    },
-    {
-      "path": "fixtures/cli/11-input-hybrid-kind/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/11-input-hybrid-kind/expected.stderr.jsonl",
-      "gitBlob": "7b6d2ac0c8afbf5e3991498846c2fc4847ac9453"
-    },
-    {
-      "path": "fixtures/cli/11-input-hybrid-kind/request.jsonl",
-      "gitBlob": "b893b640aa6631c77f2a889a807afa31632ac2db"
-    },
-    {
-      "path": "fixtures/cli/12-input-too-large/env.json",
-      "gitBlob": "ab0c7f13fc6b22d61fc73da2f1787ff3aa298ecb"
-    },
-    {
-      "path": "fixtures/cli/12-input-too-large/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/12-input-too-large/expected.stderr.jsonl",
-      "gitBlob": "ebda022d79c978d4ff511579512be2c642e3e902"
-    },
-    {
-      "path": "fixtures/cli/12-input-too-large/request.jsonl",
-      "gitBlob": "1e2fbb102503356bbcc627f49a5b58590859f170"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/allowed/.gitkeep",
-      "gitBlob": "8b137891791fe96927ad78e64b0aad7bded08bdc"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/expected.stderr.jsonl",
-      "gitBlob": "9c5b8567a755c9ea2ee6e0168bf96f429185f675"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/outside/outside.edict",
-      "gitBlob": "44abebc15811c38cc266007484dd74ae10a26a4d"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/request.jsonl",
-      "gitBlob": "116dbbb4b1a80938bc042e41747872cb6da161cd"
-    },
-    {
-      "path": "fixtures/cli/README.md",
-      "gitBlob": "9388df4182fedec41c353e85cf9210e88906fa3d"
-    },
-    {
-      "path": "fixtures/core/canonical/README.md",
-      "gitBlob": "d9a0ca79557c3623c0b843d9eff4808f94fd7b18"
-    },
-    {
-      "path": "fixtures/core/canonical/bounded-hello.core.cbor",
-      "gitBlob": "a0ec54aa1a5e20624192091526445cfd803e6f0c"
-    },
-    {
-      "path": "fixtures/core/canonical/bounded-hello.core.sha256",
-      "gitBlob": "86ba062c26a3ad3fd733ccd8c80d7faa7ed62d94"
-    },
-    {
-      "path": "fixtures/core/canonical/statement-branch.core.hex",
-      "gitBlob": "c22760cace0e4d146a2fdc8d7c7b50c38497622a"
-    },
-    {
-      "path": "fixtures/core/canonical/statement-branch.core.sha256",
-      "gitBlob": "0b62657b192232390479319f0a1c8f601020a58f"
-    },
-    {
-      "path": "fixtures/core/canonical/workspace-snapshot.core.cbor",
-      "gitBlob": "58e4f724610861f5b61537bf386a87062e8a57a7"
-    },
-    {
-      "path": "fixtures/core/canonical/workspace-snapshot.core.sha256",
-      "gitBlob": "4bcb3e0813cd3f4a7afc7cf311d846f1dfdd0a9d"
-    },
-    {
-      "path": "fixtures/core/schema/accepted/core-fn-body-minimal.fields",
-      "gitBlob": "bef3ca412ab0ea97465b8658499ae5e05e1ec760"
-    },
-    {
-      "path": "fixtures/core/schema/accepted/core-intent-minimal.fields",
-      "gitBlob": "268b28ce942fed4f139aafe5c7cd50c15a0ee640"
-    },
-    {
-      "path": "fixtures/core/schema/accepted/core-module-minimal.fields",
-      "gitBlob": "249ff76349f936c9a5ff6cb65d81de8e80d53de8"
-    },
-    {
-      "path": "fixtures/core/schema/rejected/core-fn-body-effect-node-field.fields",
-      "gitBlob": "9af8fa3540b25ec810936bc4dc82e26f6dd0dd48"
-    },
-    {
-      "path": "fixtures/core/schema/rejected/core-intent-unknown-verified-mode.fields",
-      "gitBlob": "667ae032ee117f32c1bcbafd21393e406621f517"
-    },
-    {
-      "path": "fixtures/core/schema/rejected/core-module-missing-intents.fields",
-      "gitBlob": "17f37c7ac4c199de4eace7f31e6a59b9a6d3a0f6"
-    },
-    {
-      "path": "fixtures/core/schema/rejected/local-ref-missing-alpha-name.fields",
-      "gitBlob": "456a89528ffe74d892be40c9c9be4a078ff5c18a"
-    },
-    {
-      "path": "fixtures/lang/bounds/bounded-hello.edict",
-      "gitBlob": "e3443a1d3b1c8f0e137ac698b621dd2f3afb673b"
-    },
-    {
-      "path": "fixtures/lang/effects/conditional-blob.edict",
-      "gitBlob": "1e4f2ca6112f26d57ee4d20058666ec7cd693b75"
-    },
-    {
-      "path": "fixtures/lang/effects/read-greeting.edict",
-      "gitBlob": "5e3838d1547be171e0a0384a7a200f52a2b9d139"
-    },
-    {
-      "path": "fixtures/lang/external-actions/workspace-snapshot.edict",
-      "gitBlob": "e54b0fbccad2fd680505f3ee46ca28d39d7e776e"
-    },
-    {
-      "path": "fixtures/lang/operations/explicit-basis-u64.edict",
-      "gitBlob": "444d8ca77b9827746df81885f0620dce2d1a3b73"
-    },
-    {
-      "path": "fixtures/lang/tooling/highlight-smoke.edict",
-      "gitBlob": "8c2d91084be22e5e1594a42159992aca95c73612"
-    },
-    {
-      "path": "fixtures/lang/types/color-match.edict",
-      "gitBlob": "dd98d6de677904f36d7601165a0094d92928e536"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/README.md",
-      "gitBlob": "52e8cc1e2af8aea86c1090a1b20b5f5ab3e07c06"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/adapter.cbor",
-      "gitBlob": "3b0c8b1b3a8591a322b6e785d9f963899319310c"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/adapter.sha256",
-      "gitBlob": "f8231bc941e1fbe02279865a82e183cbeeb0988a"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/echo-operation-configuration.cbor",
-      "gitBlob": "24527d30d0146b567fda157561ac6a2587cae919"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/echo-operation-configuration.sha256",
-      "gitBlob": "d293c8a14b1955a3e171703400c4df620c7871a1"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/exports.cbor",
-      "gitBlob": "384f4839adfe8e5b0f1aa848bfe2aeb1c3f640b6"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/exports.sha256",
-      "gitBlob": "4f836f6b03497338a1f8eacc55480cbe1a3b49e9"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/manifest.cbor",
-      "gitBlob": "b9311a236d7898861a0b90b1f30b852b35cef623"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/manifest.sha256",
-      "gitBlob": "685fd6a6c72fc3100d595d009b6198a81c731a40"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/README.md",
-      "gitBlob": "79f6612f1f5608a8f7dc4835e5470878cd27f96e"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/adapter.cbor",
-      "gitBlob": "24e2f546e2b97747b53462a72faaa1d5d85d62f1"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/adapter.sha256",
-      "gitBlob": "91df491028061e026ecaaeb4e1598e2ac369af44"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.core.cbor",
-      "gitBlob": "246b6135855c415def0bd89b275f0457752ee563"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.core.sha256",
-      "gitBlob": "9adc71605e0a275349161809614bd17de97d129c"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.edict",
-      "gitBlob": "825d50565230bd71d62bfbeb59d0399a89864b4c"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.result-projection.cbor",
-      "gitBlob": "981cba6e1c7ab6bdae6829116749c4796167e4e6"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.result-projection.sha256",
-      "gitBlob": "d55e4083771e1d9791f59cf87fd5cc5f1ea3b9f4"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.target-ir.cbor",
-      "gitBlob": "c8a934cefec17dbab0a43d9be9cebd2533268798"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.target-ir.sha256",
-      "gitBlob": "20186cbe9482e8a7df7c44fabec13ffd4efbcf36"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/echo-operation-configuration.cbor",
-      "gitBlob": "84838ab0d8627237232fa5a9b9fa39087bcc5f8a"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/echo-operation-configuration.sha256",
-      "gitBlob": "0898688f14067560dd22abd04b97f020071fd3e8"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/exports.cbor",
-      "gitBlob": "0e1220ceed9442a7b35870eeb02fcb65454d8c5c"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/exports.sha256",
-      "gitBlob": "e1f3e9223de9ce935bc7f60dda3cfa7d12d54fdc"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/manifest.cbor",
-      "gitBlob": "d715900f03ec454a0ad96e6710f52a46120d0b9d"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/manifest.sha256",
-      "gitBlob": "20171199b401cecace2dd74e18f3cc1d5c7ed3de"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/README.md",
-      "gitBlob": "67cd35f2e0660aa7455de1c197ad821d5438679b"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/adapter.cbor",
-      "gitBlob": "2d6f09a7e2fab381b97a05cfad1e692902e878c3"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/adapter.sha256",
-      "gitBlob": "d44eb9675e126716e8a5ef3c53fd39ade49d76fb"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.core.cbor",
-      "gitBlob": "6a88c127e426288a3e51d4749d5c31d5b0cb60cb"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.core.sha256",
-      "gitBlob": "0204b6f1d8b346a67800a7738ee39df49e78571f"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.edict",
-      "gitBlob": "6e11a3d022a53a8fb2c20a77e35e29840f5fe086"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.target-ir.cbor",
-      "gitBlob": "a6124a995a3cdbb5d39cd0a6e046b329048703aa"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.target-ir.sha256",
-      "gitBlob": "f7ac419ce15b32d491e09bddbe7c75f8227f51d8"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/exports.cbor",
-      "gitBlob": "3a6fd19dc8059b9fe1bde74fb1da61398b0e80cc"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/exports.sha256",
-      "gitBlob": "b301dd883a31fffe324e9306ec90ae2b1ec44520"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/input-schema.cbor",
-      "gitBlob": "3045d9b696864fefe111c3eb641b3b68532752d2"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/input-schema.sha256",
-      "gitBlob": "9f1284b4f0a2c7f6dbe1915a6113cd13a9700cb8"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/manifest.cbor",
-      "gitBlob": "77e56c7525f0e64ab191f0adfeac12b540c87848"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/manifest.sha256",
-      "gitBlob": "8316978e68565f29a30a6978d33d907710185857"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/reconciliation-law.cbor",
-      "gitBlob": "0736b75f81913fca7ac95c56ec45f66b95aea4cf"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/reconciliation-law.sha256",
-      "gitBlob": "de31fc9fda59fa3c29397e5fc48db224e8e1fee7"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/request-profile-configuration.cbor",
-      "gitBlob": "5e2870b2f562bafaa73a91a3fc192f5ed39257c7"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/request-profile-configuration.sha256",
-      "gitBlob": "4345ae2e39ce3f4d9cfa6b0dddf4ce56d56c035c"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/settlement-schema.cbor",
-      "gitBlob": "0a93ac19c51b341602eeba524769147e962d5d60"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/settlement-schema.sha256",
-      "gitBlob": "f1bb3fb0313dd6815b4184345194949ec40fe9e1"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/README.md",
-      "gitBlob": "996bd1d29b28769fff477084d9118d0833ca2970"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/adapter.cbor",
-      "gitBlob": "9be4ea568b602b56269af505deb809989a3fa8b5"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/adapter.sha256",
-      "gitBlob": "1e287be0a322e5444dea15fa14bcfc7cf12975c4"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/exports.cbor",
-      "gitBlob": "33fe04db74775c191d4b7400e1fb2b6393c5a010"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/exports.sha256",
-      "gitBlob": "e057cac7fc360e6599b7ddab88508aaf0f2f55f8"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/input-schema.cbor",
-      "gitBlob": "49c849169946e44c8b5f300279dd085bd6b63aeb"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/input-schema.sha256",
-      "gitBlob": "9dd7bb6e48192e90d19fc346d1705f736b1d85d7"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/manifest.cbor",
-      "gitBlob": "d4e58e3d4646ca967170a6882f2a617cb8d81390"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/manifest.sha256",
-      "gitBlob": "0edb311125a89a5816ee3fa0c9b700c9b3bcff3d"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.core.cbor",
-      "gitBlob": "a4b249dfb197f1a6b4adc06855f16e4305a1c798"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.core.sha256",
-      "gitBlob": "ea6b914d14907d9fd915058e579aff33c954da2c"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.edict",
-      "gitBlob": "c2c10f1ef1009796d67061b9722c4db9bb4e031b"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.target-ir.cbor",
-      "gitBlob": "bdab1b0c55a34360c7e9ab304af91fe2b1e4afce"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.target-ir.sha256",
-      "gitBlob": "7342aaa96221d6c8efa75ead2af5563791ccfeff"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/reconciliation-law.cbor",
-      "gitBlob": "df55572b350002a3df98ccb3e72dd60c86b9aead"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/reconciliation-law.sha256",
-      "gitBlob": "957cd04c78c130b07d2cad2fd7e07ae69978be57"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/request-profile-configuration.cbor",
-      "gitBlob": "708f18918ee1703491a910df82e129e711a4cc46"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/request-profile-configuration.sha256",
-      "gitBlob": "d9953d9dcaa41c98387226d1980f40b24d2bc3cb"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/settlement-schema.cbor",
-      "gitBlob": "f01ad68531267666e6bf93bf30a37d5b311c1676"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/settlement-schema.sha256",
-      "gitBlob": "06fcc0ee2b976a09b3017bd93132a3c51eb1317e"
-    },
-    {
-      "path": "fixtures/obstruction-strands/v0/stale-basis/README.md",
-      "gitBlob": "25efbfa04e2e6104c5434f329128333e895e2b0a"
-    },
-    {
-      "path": "fixtures/obstruction-strands/v0/stale-basis/source.edict",
-      "gitBlob": "e487b46e81220c50e6f928922dada29f3a21ca6a"
-    },
-    {
-      "path": "fixtures/provider-contracts/v1/README.md",
-      "gitBlob": "447692907f9268ce3b6b78c43b7cbbb0417aeadf"
-    },
-    {
-      "path": "fixtures/provider-contracts/v1/edict-provider-contracts.cddl",
-      "gitBlob": "07048aeeadb5062eabb89e995713cbc0893b7d7e"
-    },
-    {
-      "path": "fixtures/provider-contracts/v1/manifest.json",
-      "gitBlob": "d2c8de5d61049e9f4182c630bf82b138f0f96792"
-    },
-    {
-      "path": "fixtures/providers/README.md",
-      "gitBlob": "c26ee60a4930e3e0784c76cb855e48234a5c6b58"
-    },
-    {
-      "path": "fixtures/providers/components/guests/Cargo.lock",
-      "gitBlob": "d7858ce7bc67deabb5ff352a24c85a7caa0ef4b0"
-    },
-    {
-      "path": "fixtures/providers/components/guests/Cargo.toml",
-      "gitBlob": "450a24aed25dc73661b0ae8adfe2630dfecc9b07"
-    },
-    {
-      "path": "fixtures/providers/components/guests/lowerer/Cargo.toml",
-      "gitBlob": "568aa137fa215b6b973fe31e12322530b393b9dc"
-    },
-    {
-      "path": "fixtures/providers/components/guests/lowerer/src/lib.rs",
-      "gitBlob": "b39a8a0b18fe9ed7cb90277f793056434afa1318"
-    },
-    {
-      "path": "fixtures/providers/components/guests/verifier/Cargo.toml",
-      "gitBlob": "f814f2c8c248bbf03389f5a0936f80cd4dada5b6"
-    },
-    {
-      "path": "fixtures/providers/components/guests/verifier/src/lib.rs",
-      "gitBlob": "3f07ffdfd808ff95b206a2c08c2d481ccaf0e165"
-    },
-    {
-      "path": "fixtures/providers/components/instantiation-failure-lowerer.component.wasm",
-      "gitBlob": "bd2d7c0d31798d7676aedab0bd0d289fc2053bef"
-    },
-    {
-      "path": "fixtures/providers/components/instantiation-failure-lowerer.wat",
-      "gitBlob": "f6f5a70edb80d3a7fa1dee13b34ab5b8b44274d7"
-    },
-    {
-      "path": "fixtures/providers/components/instantiation-fuel-lowerer.component.wasm",
-      "gitBlob": "0804d26d3ddb428682ca87ecad03cf0e05ef64af"
-    },
-    {
-      "path": "fixtures/providers/components/instantiation-fuel-lowerer.wat",
-      "gitBlob": "80e972463ef593602d27c7d7cec78d87d22ff727"
-    },
-    {
-      "path": "fixtures/providers/components/inventory.json",
-      "gitBlob": "45cf2e8e937a17a8ee05dfa8d68e94dcc155e129"
-    },
-    {
-      "path": "fixtures/providers/components/lowerer.component.wasm",
-      "gitBlob": "6c1cf123a44284d15b7b1e90f1905ae94e65c158"
-    },
-    {
-      "path": "fixtures/providers/components/malformed-lowerer.component.wasm",
-      "gitBlob": "be873af81100dc76ed1f3f1f818a41da45a38e4c"
-    },
-    {
-      "path": "fixtures/providers/components/malformed-lowerer.wat",
-      "gitBlob": "1e7bfffe0a0baf230d9fb5766083f82198f4029c"
-    },
-    {
-      "path": "fixtures/providers/components/verifier.component.wasm",
-      "gitBlob": "671adbe7931d0a9a5e0c78d459c244d37a135a69"
-    },
-    {
-      "path": "fixtures/providers/echo-generated/provider-manifest.json",
-      "gitBlob": "22c8560e7ddecacd5da388e52d3935d7fc1474b9"
-    },
-    {
-      "path": "fixtures/providers/echo-target-profile/README.md",
-      "gitBlob": "350c33dcda2d66d2d50e589c58db7c6d7b14a80b"
-    },
-    {
-      "path": "fixtures/providers/echo-target-profile/generated/primary/target-profile.echo-dpo.cbor",
-      "gitBlob": "9fa43529b1021dfd8e3a33256c832d4eee6f4a47"
-    },
-    {
-      "path": "fixtures/providers/wit/legacy-target-profile.wit",
-      "gitBlob": "ae7d6af764012b16bf06bfa260ccba98a7f04868"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/echo-effectful.target-ir.cbor",
-      "gitBlob": "727a80eb37319dbdbea40d7d9b4e37f0d93d8d84"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/echo-effectful.target-ir.sha256",
-      "gitBlob": "6d050bb46ac8981ea8e47c7a52371027b941fd89"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/gitwarp-append.target-ir.cbor",
-      "gitBlob": "89b46b138a7b90252a4397c0e8b622bceff10a33"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/gitwarp-append.target-ir.sha256",
-      "gitBlob": "a59a4ab9d46095d5be1797ed9e60fe841f821bce"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/workspace-snapshot.target-ir.cbor",
-      "gitBlob": "1854eeb549b3719fa2b0114867dbece6db1819d4"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/workspace-snapshot.target-ir.sha256",
-      "gitBlob": "4d0e501323d415ef9e64c0a3d25bdd57dabfc998"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/README.md",
-      "gitBlob": "32dcab1dd9376a4eed2c73bb1b1a29255fe3ea05"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/canonical-cbor.cbor",
-      "gitBlob": "4a95ba3bd9dff190ca5ec9c83262bfa6254a91d3"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/canonical-cbor.sha256",
-      "gitBlob": "2168df5d4bf77ed2347139dd7c45fd808df8ec7e"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/determinism.cbor",
-      "gitBlob": "09cd11c36048939961408550763c04fad8241557"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/determinism.sha256",
-      "gitBlob": "5376d6bfe23bea659463a7e3c56ad1e8afd4095f"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/diagnostics.cbor",
-      "gitBlob": "c47fa05f463e0da745fbcdf8daf94d70e134eb8d"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/diagnostics.sha256",
-      "gitBlob": "69613ec4014f27b23245e23fbf7c9447566516b2"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/fuel.cbor",
-      "gitBlob": "b5a3484ec5b2bf7343c2fcedc67bcb2b63a37104"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/fuel.sha256",
-      "gitBlob": "6ec1c830358ee35bb12bd04cc1a6edf47fb20997"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/wasm-component.cbor",
-      "gitBlob": "6344996c283e0d1c332ea3ce597ad4593882a3c5"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/wasm-component.sha256",
-      "gitBlob": "24bf3e552e4216d8258d2b85c8878af46a176c52"
-    },
-    {
-      "path": "grammars/textmate/README.md",
-      "gitBlob": "fc116a669725d4e965d658234d32d779955d5dc8"
-    },
-    {
-      "path": "grammars/textmate/edict.tmLanguage.json",
-      "gitBlob": "5847d8edfdb32d822f0f3950f41d00c947982185"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/README.md",
-      "gitBlob": "e2992a839d6719f1461db78c4e3f33d2e5ab0c09"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/grammar.js",
-      "gitBlob": "a82f5b9d9b78525f17a59272543fdcddd7a0da40"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/queries/highlights.scm",
-      "gitBlob": "0f46530b36996d13449901aed4e376a126577cba"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/grammar.json",
-      "gitBlob": "55df730a06b83c9f622e3ec17845fc9897c7d8c0"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/node-types.json",
-      "gitBlob": "520f6c4f7b30cd6892dd60faf6d76f3fbaa6a5c7"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/parser.c",
-      "gitBlob": "81cc4713cb5e05f9aa8dac16da202a864faefee6"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/tree_sitter/alloc.h",
-      "gitBlob": "1abdd1201578605b8d05a3001f01ebc0d58826d9"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/tree_sitter/array.h",
-      "gitBlob": "56fc8cd470996ded64a5452be25e26dbd2aa682a"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/tree_sitter/parser.h",
-      "gitBlob": "858107deb9e4a1ffcd2ed5e6ffe98a5fcab3e1f6"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/test/corpus/current-subset.txt",
-      "gitBlob": "732c5eda8e1bf95eef799476296a6ee061eb58eb"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/tree-sitter.json",
-      "gitBlob": "97d3fdd498a3bef509c8615d98b9560b527c03cb"
-    },
-    {
-      "path": "scripts/consumer-witnesses/README.md",
-      "gitBlob": "2b7d2b9d81f9598fd8df232b3a76bef106ff7ef2"
-    },
-    {
-      "path": "scripts/consumer-witnesses/jedit-state-read.Dockerfile",
-      "gitBlob": "7462059be67686090d0097b24b9d14bfbbd4c6f7"
-    },
-    {
-      "path": "scripts/consumer-witnesses/jedit-state-read.Dockerfile.dockerignore",
-      "gitBlob": "ee41b3ca0a68fd5eb20e1b777b4b368fd8b44e63"
-    },
-    {
-      "path": "scripts/consumer-witnesses/jedit-state-read.py",
-      "gitBlob": "26db295d4eabfc4e57813fc9bf17314c23350777"
-    },
-    {
-      "path": "scripts/consumer-witnesses/run-jedit-state-read.sh",
-      "gitBlob": "18cd72bbbdfb17a5ea30a7821d47035071556d10"
-    },
-    {
-      "path": "spec.lock.json",
-      "gitBlob": "ef8b02386e0f269a99c1d2121764f70b76e67620"
-    },
-    {
-      "path": "xtask/Cargo.toml",
-      "gitBlob": "795c70a5172363bfcd55174b1bc76c9c131d21a3"
-    },
-    {
-      "path": "xtask/src/contract_check.rs",
-      "gitBlob": "9e80393accf79936033972fde0f2aa2cf40f1be3"
-    },
-    {
-      "path": "xtask/src/goldens.rs",
-      "gitBlob": "713f1f8266d9f6993684ae86db105fcd7d69ee2a"
-    },
-    {
-      "path": "xtask/src/lawpack_goldens.rs",
-      "gitBlob": "c499e8581c73313794b83c261937144b3917850a"
-    },
-    {
-      "path": "xtask/src/main.rs",
-      "gitBlob": "6c2c06038bb5ecdde60620071b200d8191dc116c"
-    },
-    {
-      "path": "xtask/src/provider_components.rs",
-      "gitBlob": "ee9d6a1028f9fbfad879faab4b15a94b996ef6d4"
-    },
-    {
-      "path": "xtask/src/provider_contract_pack.rs",
-      "gitBlob": "cf60d89892b7a57cc33300f273d2522a6e8f43f9"
-    },
-    {
-      "path": "xtask/src/provider_dependencies.rs",
-      "gitBlob": "c4b0539ed593d2a2777d294090d2a891b13ae628"
-    },
-    {
-      "path": "xtask/src/release_dates.rs",
-      "gitBlob": "1c6d7acb872f6d820eab3a30ca580e9c5cfba2ee"
-    },
-    {
-      "path": "xtask/src/release_prep.rs",
-      "gitBlob": "01ed64ccbb28c9d1e908b7b800ff58076e5e1a2b"
-    },
-    {
-      "path": "xtask/src/tests.rs",
-      "gitBlob": "9a3f6543c2dbae31d53e93d56f781e5d54f74f41"
-    },
-    {
-      "path": "xtask/src/util.rs",
-      "gitBlob": "c1bf39e93460c43ffdcfd9a76e0424750cbb9dfd"
-    }
-  ]
-}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/decimal/ReplaceRange.edict b/edict/replace-range-probes/buffer-decoder/evidence/original/decimal/ReplaceRange.edict
deleted file mode 100644
index 3927ed0e..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/original/decimal/ReplaceRange.edict
+++ /dev/null
@@ -1,93 +0,0 @@
-package jedit.text.replace_range@1;
-use lawpack jedit.text@1 digest "sha256:2ea164293719d2b03231c4904eb75ddcdf55fd29cc31f4fc5a5319d9ae5e60e7" as text;
-
-// Jim's JSON boundary codec. These are internal scanner values, not intent inputs.
-// A later bounded scanner must obtain each token from the retained Buffer atom.
-type JsonByte = Bytes;
-type DecimalState = variant { Start, Zero, Digits(U64) };
-type DecimalStep = variant { More(DecimalState), End(U64), Invalid, Overflow };
-type DecimalDigit = variant { Digit(U64), NotDigit };
-
-// An End result leaves the delimiter unconsumed for the enclosing JSON scanner.
-// Whitespace terminates a number; canonical-byte policy belongs to that scanner.
-fn isNumberDelimiter(token: JsonByte) -> Bool {
-  return token == b"," || token == b"]" || token == b"}"
-    || token == b" " || token == b"\t" || token == b"\r" || token == b"\n";
-}
-
-fn decimalDigit(token: JsonByte) -> DecimalDigit {
-  return if token == b"0" then DecimalDigit::Digit(0u64)
-    else if token == b"1" then DecimalDigit::Digit(1u64)
-    else if token == b"2" then DecimalDigit::Digit(2u64)
-    else if token == b"3" then DecimalDigit::Digit(3u64)
-    else if token == b"4" then DecimalDigit::Digit(4u64)
-    else if token == b"5" then DecimalDigit::Digit(5u64)
-    else if token == b"6" then DecimalDigit::Digit(6u64)
-    else if token == b"7" then DecimalDigit::Digit(7u64)
-    else if token == b"8" then DecimalDigit::Digit(8u64)
-    else if token == b"9" then DecimalDigit::Digit(9u64)
-    else DecimalDigit::NotDigit;
-}
-
-fn appendScaled(scaled: U64, digit: U64, limit: U64) -> DecimalStep {
-  let sum = checkedAdd(scaled, digit);
-  return if isSome(sum) then
-    if unwrap(sum) <= limit then DecimalStep::More(DecimalState::Digits(unwrap(sum)))
-    else DecimalStep::Overflow
-  else DecimalStep::Overflow;
-}
-
-fn appendDigit(value: U64, digit: U64, limit: U64) -> DecimalStep {
-  let decimalRadix = 10u64;
-  let product = checkedMul(value, decimalRadix);
-  return if isSome(product) then appendScaled(unwrap(product), digit, limit)
-    else DecimalStep::Overflow;
-}
-
-fn startDecimal(token: JsonByte, limit: U64) -> DecimalStep {
-  return match decimalDigit(token) {
-    Digit(value) => if value > limit then DecimalStep::Overflow
-      else if value == 0u64 then DecimalStep::More(DecimalState::Zero)
-      else DecimalStep::More(DecimalState::Digits(value)),
-    NotDigit => DecimalStep::Invalid,
-  };
-}
-
-fn continueDecimal(value: U64, token: JsonByte, limit: U64) -> DecimalStep {
-  return if value == 0u64 then DecimalStep::Invalid
-    else if value > limit then DecimalStep::Overflow
-    else match decimalDigit(token) {
-      Digit(digit) => appendDigit(value, digit, limit),
-      NotDigit => if isNumberDelimiter(token) then DecimalStep::End(value)
-        else DecimalStep::Invalid,
-    };
-}
-
-// canonical_head_id members use limit 255; version uses 18446744073709551615.
-// The enclosing scanner owns these schema limits and starts at Start.
-// Empty token, sign, leading zero, fraction, exponent and non-ASCII byte refuse.
-fn stepJsonUnsigned(state: DecimalState, token: JsonByte, limit: U64) -> DecimalStep {
-  return match state {
-    Start => startDecimal(token, limit),
-    Zero => if isNumberDelimiter(token) then DecimalStep::End(0u64)
-      else DecimalStep::Invalid,
-    Digits(value) => continueDecimal(value, token, limit),
-  };
-}
-
-type Input = { address: text.FactAddress, expected: text.FactBytes };
-intent replaceRange(input: Input) returns text.FactBytes
-  profile text.replaceRange
-  basis input.address.nodeId
-  budget <= text.replaceRangeBudget
-{
-  let actual: text.FactBytes = text.readFact(input.address)
-    else {
-      missing(address) => text.FactMissing,
-      typeMismatch(address) => text.FactMalformed,
-      notAtom(address) => text.FactMalformed,
-      tooLarge(address) => text.FactMalformed,
-    };
-  require actual == input.expected else text.BasisNotCanonical;
-  return actual;
-}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/decimal/stderr.jsonl b/edict/replace-range-probes/buffer-decoder/evidence/original/decimal/stderr.jsonl
deleted file mode 100644
index a4cb8dfc..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/original/decimal/stderr.jsonl
+++ /dev/null
@@ -1,2 +0,0 @@
-{"command":"build","input":{"kind":"stdin"},"kind":"InvalidApplicationSource","message":"Edict source `/tmp/echo-726-runtime/jim-buffer-decoder-results/decimal/src/ReplaceRange.edict` did not parse: ParseError { kind: Lex, message: \"invalid string escape\", span: Span { start: 861, end: 862 } }","schema":"edict.cli.diagnostic/v1","severity":"error","stage":"cli","type":"diagnostic"}
-{"checked":0,"command":"build","errors":1,"exitCode":2,"schema":"edict.cli.event/v1","status":"error","type":"status"}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/decimal/stdout.jsonl b/edict/replace-range-probes/buffer-decoder/evidence/original/decimal/stdout.jsonl
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/fn-control/ReplaceRange.edict b/edict/replace-range-probes/buffer-decoder/evidence/original/fn-control/ReplaceRange.edict
deleted file mode 100644
index fe87ae1b..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/original/fn-control/ReplaceRange.edict
+++ /dev/null
@@ -1,20 +0,0 @@
-package jedit.text.replace_range@1;
-use lawpack jedit.text@1 digest "sha256:2ea164293719d2b03231c4904eb75ddcdf55fd29cc31f4fc5a5319d9ae5e60e7" as text;
-fn retainFact(value: text.FactBytes) -> text.FactBytes { return value; }
-
-type Input = { address: text.FactAddress, expected: text.FactBytes };
-intent replaceRange(input: Input) returns text.FactBytes
-  profile text.replaceRange
-  basis input.address.nodeId
-  budget <= text.replaceRangeBudget
-{
-  let actual: text.FactBytes = text.readFact(input.address)
-    else {
-      missing(address) => text.FactMissing,
-      typeMismatch(address) => text.FactMalformed,
-      notAtom(address) => text.FactMalformed,
-      tooLarge(address) => text.FactMalformed,
-    };
-  require actual == input.expected else text.BasisNotCanonical;
-  return actual;
-}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/fn-control/stderr.jsonl b/edict/replace-range-probes/buffer-decoder/evidence/original/fn-control/stderr.jsonl
deleted file mode 100644
index 3ab04b49..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/original/fn-control/stderr.jsonl
+++ /dev/null
@@ -1,2 +0,0 @@
-{"command":"build","input":{"kind":"stdin"},"kind":"InvalidApplicationSource","message":"Edict source `/tmp/echo-726-runtime/jim-buffer-decoder-results/fn-control/src/ReplaceRange.edict` did not parse: ParseError { kind: ExpectedToken, message: \"expected `type`, `enum`, or `intent` declaration, found Ident(\\\"fn\\\")\", span: Span { start: 151, end: 153 } }","schema":"edict.cli.diagnostic/v1","severity":"error","stage":"cli","type":"diagnostic"}
-{"checked":0,"command":"build","errors":1,"exitCode":2,"schema":"edict.cli.event/v1","status":"error","type":"status"}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/fn-control/stdout.jsonl b/edict/replace-range-probes/buffer-decoder/evidence/original/fn-control/stdout.jsonl
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/git-locks-receipt.jsonl b/edict/replace-range-probes/buffer-decoder/evidence/original/git-locks-receipt.jsonl
deleted file mode 100644
index 0e22e065..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/original/git-locks-receipt.jsonl
+++ /dev/null
@@ -1,5 +0,0 @@
-{"event":"claimed","job":"B7E81F92-3E24-4EE9-936A-8A34AC6B0DFA","holder":"jim-edict-authoring","note":"Guarded exact17397 compiler build and actual Buffer decimal fn refusal with accepted atom-read control","claimed":1791167534,"expires":1791168434,"paths":["host/docker/echo-read-runtime/","host/heavy-work"],"record":"df6150b65a0fff4e49c96bcf7ca1679687da1ca7","acquisition":"1791167534-76497-3105025734"}
-PRE {"build": 6792403497, "data": 2956552745, "logs": 9643305, "host_free": 715318206464, "vm_free": 679804174336} CONTRACT /private/tmp/echo-739-resume/jim-buffer-public.launch.json
-POST {"build": 6451069687, "data": 2959639287, "logs": 9646863, "host_free": 715316690944, "vm_free": 679804174336} EXIT 1
-GUARD_EXIT 1
-{"event":"released","job":"B7E81F92-3E24-4EE9-936A-8A34AC6B0DFA","paths":2}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/guard.launch.json b/edict/replace-range-probes/buffer-decoder/evidence/original/guard.launch.json
deleted file mode 100644
index f3648fa5..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/original/guard.launch.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
-  "worker": "echo-read-runtime",
-  "image": "echo-read-runtime:red",
-  "lock": "/tmp/echo-validation-host.lock",
-  "inner_lock": "/tmp/echo-validation.lock",
-  "source": "/echo-audit",
-  "outputs": [
-    "/lease-target",
-    "/usr/local/cargo",
-    "/tmp/echo-726-runtime",
-    "all container writable-layer paths",
-    "/dev/shm",
-    "/private/tmp/echo-739-resume/jim-buffer-public.log"
-  ],
-  "measurements": {
-    "build": 6792403497,
-    "data": 2956552745,
-    "logs": 9643305,
-    "host_free": 715318206464,
-    "vm_free": 679804174336
-  },
-  "build_limit": 21474836480,
-  "data_limit": 4294967296,
-  "log_limit": 134217728,
-  "cpus": 4.0,
-  "memory": 6442450944,
-  "logging": {
-    "Type": "json-file",
-    "Config": {
-      "max-file": "5",
-      "max-size": "20m"
-    }
-  },
-  "timeout_seconds": 600,
-  "guard": "2-second fail-closed monitor; freeze owned process group across the entire size measurement, including cache du; pause container for snapshotter; accept an absent process group only after confirmed owned docker-exec completion; of aggregate writable layers, shared memory, host scratch and logs; no host binds or volumes",
-  "termination": "docker stop/kill owned worker and host docker-exec process group on monitoring failure or limit/timeout",
-  "command": "test ! -e /tmp/echo-726-runtime/jim-buffer-decoder-input\nmkdir /tmp/echo-726-runtime/jim-buffer-decoder-input\ntar -xf /tmp/echo-726-runtime/jim-buffer-decoder-input.tar -C /tmp/echo-726-runtime/jim-buffer-decoder-input\npython3 - <<'INNER'\nfrom pathlib import Path\nimport runpy,subprocess\nroot=Path('/tmp/echo-726-runtime/jim-buffer-decoder-input')\ncommon=runpy.run_path(str(root/'edict/replace-range-probes/leaf-slice/run.py'))\nprint(common['verify_compiler_source'](Path('/edict-207'),root/'compiler-source.json','17397e2aad18a83ffc617d1afd628764501f49cd'),flush=True)\nassert subprocess.check_output(['git','-C','/edict-207','rev-parse','HEAD'],text=True).strip()=='17397e2aad18a83ffc617d1afd628764501f49cd'\nassert not subprocess.check_output(['git','-C','/edict-207','status','--porcelain'],text=True).strip()\nINNER\ncd /edict-207\nexport CARGO_TARGET_DIR=/lease-target CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=4 CARGO_PROFILE_DEV_DEBUG=0 CARGO_PROFILE_TEST_DEBUG=0\ncargo +1.95.0 clean -p edict-cli -p edict-syntax\ncargo +1.95.0 build --locked -p edict-cli\nsha256sum /lease-target/debug/edict\npython3 /tmp/echo-726-runtime/jim-buffer-decoder-input/edict/replace-range-probes/buffer-decoder/run.py --compiler /lease-target/debug/edict --compiler-source /edict-207 --compiler-manifest /tmp/echo-726-runtime/jim-buffer-decoder-input/compiler-source.json --application-source /read-evidence/single --provider-package /read-provider --work-root /tmp/echo-726-runtime/jim-buffer-decoder-results\n"
-}
\ No newline at end of file
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/guard.log b/edict/replace-range-probes/buffer-decoder/evidence/original/guard.log
deleted file mode 100644
index 2a0ac02c..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/original/guard.log
+++ /dev/null
@@ -1,17 +0,0 @@
-{'commit': '17397e2aad18a83ffc617d1afd628764501f49cd', 'tree': 'bcfd3112cd8b3d4630738a88761860679b45714b', 'fileCount': 449, 'manifestSha256': '625592ab9dd715349255bece0133378c64b3d4539fb50e437d116c2a4296f016'}
-     Removed 575 files, 474.9MiB total
-   Compiling edict-syntax v0.11.0-alpha.1 (/edict-207/crates/edict-syntax)
-   Compiling edict-provider-schema v0.11.0-alpha.1 (/edict-207/crates/edict-provider-schema)
-   Compiling edict-provider-host-wasmtime v0.11.0-alpha.1 (/edict-207/crates/edict-provider-host-wasmtime)
-   Compiling edict-cli v0.11.0-alpha.1 (/edict-207/crates/edict-cli)
-    Finished `dev` profile [unoptimized] target(s) in 6.08s
-e2700698829b03f437c66425ed9878b002ef7a34ac183a39bac4eaf6a758cc6d  /lease-target/debug/edict
-{"artifactSha256": {"executable-operation-package.cbor": "afd931700018312d6c0d1e249871313d2c21c0ece1ae41d1f17f2be7af9e5284", "verification-report.cbor": "9114fdd983d456eb83f69969475f558b6e608be23520212a5db5f26bb095d04b"}, "artifacts": ["executable-operation-package.cbor", "verification-report.cbor"], "case": "read-control", "diagnostics": [], "exitCode": 0, "sourceSha256": "4ec3cbf32fd5d98987cbeeaff95d7c9c5ab734dac555e443aac52e8ab02bfbc5", "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61"}
-{"artifactSha256": {}, "artifacts": [], "case": "fn-control", "diagnostics": [{"command": "build", "input": {"kind": "stdin"}, "kind": "InvalidApplicationSource", "message": "Edict source `/tmp/echo-726-runtime/jim-buffer-decoder-results/fn-control/src/ReplaceRange.edict` did not parse: ParseError { kind: ExpectedToken, message: \"expected `type`, `enum`, or `intent` declaration, found Ident(\\\"fn\\\")\", span: Span { start: 151, end: 153 } }", "schema": "edict.cli.diagnostic/v1", "severity": "error", "stage": "cli", "type": "diagnostic"}], "exitCode": 2, "sourceSha256": "97475b0e6aaf24d3268736efa3312df377b9153b89c8e59f0e2ceb25ce691218", "stderrSha256": "001929f74b4648fdd8c7946bdb80b1ccea0fae03e5f208012bb454d0ab94a831", "stdoutSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}
-{"artifactSha256": {}, "artifacts": [], "case": "decimal", "diagnostics": [{"command": "build", "input": {"kind": "stdin"}, "kind": "InvalidApplicationSource", "message": "Edict source `/tmp/echo-726-runtime/jim-buffer-decoder-results/decimal/src/ReplaceRange.edict` did not parse: ParseError { kind: Lex, message: \"invalid string escape\", span: Span { start: 861, end: 862 } }", "schema": "edict.cli.diagnostic/v1", "severity": "error", "stage": "cli", "type": "diagnostic"}], "exitCode": 2, "sourceSha256": "860712eaae8fad67499967e2475d9a2bef9d072762b3eab1004a3ddf4dba2b94", "stderrSha256": "04838a07257a87554d0c8d0f397c0a661adf68719f0e7f604c642217190bae8b", "stdoutSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}
-Traceback (most recent call last):
-  File "/tmp/echo-726-runtime/jim-buffer-decoder-input/edict/replace-range-probes/buffer-decoder/run.py", line 75, in 
-    main()
-  File "/tmp/echo-726-runtime/jim-buffer-decoder-input/edict/replace-range-probes/buffer-decoder/run.py", line 70, in main
-    raise RuntimeError(f"{name} did not reach the source function parser boundary")
-RuntimeError: fn-control did not reach the source function parser boundary
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/guard.result.json b/edict/replace-range-probes/buffer-decoder/evidence/original/guard.result.json
deleted file mode 100644
index 9c7c9295..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/original/guard.result.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "measurements": {
-    "build": 6451069687,
-    "data": 2959639287,
-    "logs": 9646863,
-    "host_free": 715316690944,
-    "vm_free": 679804174336
-  },
-  "exit_code": 1
-}
\ No newline at end of file
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/public-build.json b/edict/replace-range-probes/buffer-decoder/evidence/original/public-build.json
deleted file mode 100644
index 63bd674f..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/original/public-build.json
+++ /dev/null
@@ -1,101 +0,0 @@
-{
-  "compiler": {
-    "commit": "17397e2aad18a83ffc617d1afd628764501f49cd",
-    "tree": "bcfd3112cd8b3d4630738a88761860679b45714b",
-    "fileCount": 449,
-    "manifestSha256": "625592ab9dd715349255bece0133378c64b3d4539fb50e437d116c2a4296f016",
-    "binarySha256": "e2700698829b03f437c66425ed9878b002ef7a34ac183a39bac4eaf6a758cc6d"
-  },
-  "providerManifestSha256": "5b38ae704a071b88aa0cc2f85020de41cb69e76d037afe3592a4d319e22587c8",
-  "providerFiles": {
-    "components/lowerer.echo-dpo.component.wasm": "4b594a8165079f0a973741b9e27b468cf041f4ad53108fccae641dc35355bd2a",
-    "components/verifier.echo-dpo.component.wasm": "d0be4d283399aefc45d75b395b3568f9983521ca5543c9dfd23b9495758050ed",
-    "generated/evidence/provenance.provider-generation.json": "11a8ef81063f769ccfe431047be3473523fadd49582d6c935b7f7f8d7ccd81d5",
-    "generated/evidence/review.provider-generation.json": "24836f4170809f343a64dcce095a66765cdb922d652458a658d2f896d7547b78",
-    "generated/primary/authority-facts.echo-dpo.cbor": "e2a6a539a7156296c18ff1bc02f80dcabf62b42bb4314d0737527869e43986d6",
-    "generated/primary/authority-facts.echo-lawpack.cbor": "ce1af559551f8b8242c4b290b620c5a28323b9e43f8bc6bb161a191001b6f4b9",
-    "generated/primary/generated-artifact-profile.echo-dpo-registration.cbor": "4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34",
-    "generated/primary/lawpack.echo-dpo.cbor": "8c570362671a0b1cd1a992d8210e4a90ffd153ad06dcdf1e0cb36033cc971e2c",
-    "generated/primary/schema.echo-provider-artifacts.cddl": "e8b2f078445f1e970bf8e92a33c69bded54a025469791dc3f4a7a418892a3252",
-    "generated/primary/target-profile.echo-dpo.cbor": "1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e",
-    "generated/resources/resource.conformance-corpus.cbor": "f1f29d990f83c5af33952a69b16e9c9bbb7c2feb1d3989860b74c9e6c2c19b08",
-    "generated/resources/resource.lawpack-compatibility.cbor": "642945761cb7d60e133008620dc2a6b48fd0f77901b985e02b1d3398fb1411af",
-    "generated/resources/resource.lawpack-exports.cbor": "e80f3597830f30079bae7428cc6fe1ca27e9f2626614284338c5f5c7bfd9f8b8",
-    "generated/resources/resource.lawpack-target-adapter.cbor": "d0cf6a5310c7aa3d5bf291e40221a50a9be676d0e7f9947b71de0c52f03f9a41",
-    "generated/resources/resource.lawpack-verifier.cbor": "a0ca53486f2e1181027cab255792150735a68fc01a93669ab90b58e7c32bd36e",
-    "generated/resources/resource.target-bundle-profile.cbor": "95cc3aab106f0d6d77ec76e88591ee24acac58f4345c031b77cfd1ecf2aa0db8",
-    "generated/resources/resource.target-cost-algebra.cbor": "29cc941cc96ffdb420a24a377146f0e9d5409a89f84cdbb2ad597e78dfde3503",
-    "generated/resources/resource.target-footprint-algebra.cbor": "c08b853b22fa1920cb8971b60a6622e4d8f400c68b8027a9c4f246c5cb4a222c",
-    "generated/resources/resource.target-intrinsics.cbor": "d4080b044ad95d88763f605d25d678dad0d44bbfdc32c212334a962eaf456588",
-    "generated/resources/resource.target-ir.cbor": "f0ead7a5dcb41532d5df9067a9735d7078456b59cc267b3a9f6bb6437431000c",
-    "generated/resources/resource.target-lowerer-contract.cbor": "c4d788a8ae876cfe8c9e9875144014d551d38ff13b4d90bb9dfc46bc562bf280",
-    "generated/resources/resource.target-obstruction-taxonomy.cbor": "5eb85dc3fbb53890f4f5accf6a7a3c03889bd25bf00e7c2a23c43e497652328e",
-    "generated/resources/resource.target-operation-profiles.cbor": "3d560e8df1bfb38e8ba9b70b0a4bc843c848a7900e3af76d8f798db51b6b1077",
-    "generated/resources/resource.target-verifier-contract.cbor": "9cef12fac8190156e152e7c8ab5adeed077bf2bdadf3add2225ce90ab4be8710",
-    "provider-manifest.echo.json": "5b38ae704a071b88aa0cc2f85020de41cb69e76d037afe3592a4d319e22587c8"
-  },
-  "authoredSourceSha256": "9fc1b006c298866463ab83a28fcb1e54769b970970c571f11d0868d79edc6d87",
-  "literalCasesStatus": "not executed",
-  "compositionStatus": "helpers are not connected to a retained-byte scanner",
-  "results": {
-    "read-control": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "4ec3cbf32fd5d98987cbeeaff95d7c9c5ab734dac555e443aac52e8ab02bfbc5",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "afd931700018312d6c0d1e249871313d2c21c0ece1ae41d1f17f2be7af9e5284",
-        "verification-report.cbor": "9114fdd983d456eb83f69969475f558b6e608be23520212a5db5f26bb095d04b"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "fn-control": {
-      "exitCode": 2,
-      "diagnostics": [
-        {
-          "command": "build",
-          "input": {
-            "kind": "stdin"
-          },
-          "kind": "InvalidApplicationSource",
-          "message": "Edict source `/tmp/echo-726-runtime/jim-buffer-decoder-results/fn-control/src/ReplaceRange.edict` did not parse: ParseError { kind: ExpectedToken, message: \"expected `type`, `enum`, or `intent` declaration, found Ident(\\\"fn\\\")\", span: Span { start: 151, end: 153 } }",
-          "schema": "edict.cli.diagnostic/v1",
-          "severity": "error",
-          "stage": "cli",
-          "type": "diagnostic"
-        }
-      ],
-      "artifacts": [],
-      "sourceSha256": "97475b0e6aaf24d3268736efa3312df377b9153b89c8e59f0e2ceb25ce691218",
-      "artifactSha256": {},
-      "stdoutSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
-      "stderrSha256": "001929f74b4648fdd8c7946bdb80b1ccea0fae03e5f208012bb454d0ab94a831"
-    },
-    "decimal": {
-      "exitCode": 2,
-      "diagnostics": [
-        {
-          "command": "build",
-          "input": {
-            "kind": "stdin"
-          },
-          "kind": "InvalidApplicationSource",
-          "message": "Edict source `/tmp/echo-726-runtime/jim-buffer-decoder-results/decimal/src/ReplaceRange.edict` did not parse: ParseError { kind: Lex, message: \"invalid string escape\", span: Span { start: 861, end: 862 } }",
-          "schema": "edict.cli.diagnostic/v1",
-          "severity": "error",
-          "stage": "cli",
-          "type": "diagnostic"
-        }
-      ],
-      "artifacts": [],
-      "sourceSha256": "860712eaae8fad67499967e2475d9a2bef9d072762b3eab1004a3ddf4dba2b94",
-      "artifactSha256": {},
-      "stdoutSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
-      "stderrSha256": "04838a07257a87554d0c8d0f397c0a661adf68719f0e7f604c642217190bae8b"
-    }
-  }
-}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/read-control/ReplaceRange.edict b/edict/replace-range-probes/buffer-decoder/evidence/original/read-control/ReplaceRange.edict
deleted file mode 100644
index 1031dfc9..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/original/read-control/ReplaceRange.edict
+++ /dev/null
@@ -1,18 +0,0 @@
-package jedit.text.replace_range@1;
-use lawpack jedit.text@1 digest "sha256:2ea164293719d2b03231c4904eb75ddcdf55fd29cc31f4fc5a5319d9ae5e60e7" as text;
-type Input = { address: text.FactAddress, expected: text.FactBytes };
-intent replaceRange(input: Input) returns text.FactBytes
-  profile text.replaceRange
-  basis input.address.nodeId
-  budget <= text.replaceRangeBudget
-{
-  let actual: text.FactBytes = text.readFact(input.address)
-    else {
-      missing(address) => text.FactMissing,
-      typeMismatch(address) => text.FactMalformed,
-      notAtom(address) => text.FactMalformed,
-      tooLarge(address) => text.FactMalformed,
-    };
-  require actual == input.expected else text.BasisNotCanonical;
-  return actual;
-}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/read-control/application/executable-operation-package.cbor b/edict/replace-range-probes/buffer-decoder/evidence/original/read-control/application/executable-operation-package.cbor
deleted file mode 100644
index a14f9ea2..00000000
Binary files a/edict/replace-range-probes/buffer-decoder/evidence/original/read-control/application/executable-operation-package.cbor and /dev/null differ
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/read-control/application/verification-report.cbor b/edict/replace-range-probes/buffer-decoder/evidence/original/read-control/application/verification-report.cbor
deleted file mode 100644
index fb4ef5d0..00000000
Binary files a/edict/replace-range-probes/buffer-decoder/evidence/original/read-control/application/verification-report.cbor and /dev/null differ
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/read-control/stderr.jsonl b/edict/replace-range-probes/buffer-decoder/evidence/original/read-control/stderr.jsonl
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/read-control/stdout.jsonl b/edict/replace-range-probes/buffer-decoder/evidence/original/read-control/stdout.jsonl
deleted file mode 100644
index a668538e..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/original/read-control/stdout.jsonl
+++ /dev/null
@@ -1 +0,0 @@
-{"checked":1,"command":"build","errors":0,"exitCode":0,"schema":"edict.cli.event/v1","status":"ok","type":"status"}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/original/run.py b/edict/replace-range-probes/buffer-decoder/evidence/original/run.py
deleted file mode 100644
index 22125b03..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/original/run.py
+++ /dev/null
@@ -1,75 +0,0 @@
-"""Retain the real Buffer decimal helper's first public compiler boundary."""
-
-import argparse
-import json
-from pathlib import Path
-import runpy
-
-
-COMPILER_COMMIT = "17397e2aad18a83ffc617d1afd628764501f49cd"
-TRIVIAL_FUNCTION = b"fn retainFact(value: text.FactBytes) -> text.FactBytes { return value; }\n\n"
-
-
-def main():
-    parser = argparse.ArgumentParser(description=__doc__)
-    for name in ("compiler", "compiler-source", "compiler-manifest", "application-source",
-                 "provider-package", "work-root"):
-        parser.add_argument("--" + name, type=Path, required=True)
-    args = parser.parse_args()
-    if not Path("/.dockerenv").is_file():
-        raise RuntimeError("Run under shared git-locks admission and the guarded Docker lease")
-    if not args.work_root.resolve().is_relative_to(Path("/tmp/echo-726-runtime")):
-        raise RuntimeError("Work must stay inside the declared runtime-data accounting root")
-    common = runpy.run_path(str(Path(__file__).parent.parent / "leaf-slice/run.py"))
-    sha256, snapshot, verify = common["sha256"], common["snapshot"], common["verify_compiler_source"]
-    compiler = verify(args.compiler_source, args.compiler_manifest, COMPILER_COMMIT)
-    compiler["binarySha256"] = sha256(args.compiler)
-    before = {"application": snapshot(args.application_source), "provider": snapshot(args.provider_package)}
-    original = (args.application_source / "src/ReplaceRange.edict").read_bytes()
-    authored = (Path(__file__).parent / "Decimal.edict").read_bytes()
-    package, declarations = authored.split(b"\n", 1)
-    if not original.startswith(package + b"\n") or b"type Input" not in original:
-        raise RuntimeError("Expected the unchanged generic read control's source layout")
-    sources = {
-        "read-control": original,
-        "fn-control": original.replace(b"type Input", TRIVIAL_FUNCTION + b"type Input", 1),
-        "decimal": original.replace(b"type Input", declarations + b"\ntype Input", 1),
-    }
-    args.work_root.mkdir()
-    evidence = {"compiler": compiler,
-                "providerManifestSha256": sha256(args.provider_package / "provider-manifest.echo.json"),
-                "providerFiles": before["provider"],
-                "authoredSourceSha256": sha256(Path(__file__).parent / "Decimal.edict"),
-                "literalCasesStatus": "not executed",
-                "compositionStatus": "helpers are not connected to a retained-byte scanner",
-                "results": {}}
-    for name, source in sources.items():
-        root = args.work_root / name
-        common["prepare"](root, args.application_source, args.provider_package, source)
-        evidence["results"][name] = common["build"](root, args.compiler)
-    (args.work_root / "evidence.json").write_text(json.dumps(evidence, indent=2) + "\n")
-    for name, result in evidence["results"].items():
-        print(json.dumps({"case": name, **result}, sort_keys=True), flush=True)
-    if before != {"application": snapshot(args.application_source), "provider": snapshot(args.provider_package)}:
-        raise RuntimeError("Public witness changed an authoritative input")
-    if compiler["binarySha256"] != sha256(args.compiler):
-        raise RuntimeError("Compiler binary changed during witness")
-    verify(args.compiler_source, args.compiler_manifest, COMPILER_COMMIT)
-    positive = evidence["results"]["read-control"]
-    if (positive["exitCode"] != 0 or positive["diagnostics"] or positive["artifacts"] !=
-            ["executable-operation-package.cbor", "verification-report.cbor"]):
-        raise RuntimeError("Generic read control did not reach package/report success")
-    for name in ("fn-control", "decimal"):
-        negative = evidence["results"][name]
-        if negative["exitCode"] != 2 or negative["artifacts"] or len(negative["diagnostics"]) != 1:
-            raise RuntimeError(f"{name} did not refuse without application artifacts")
-        diagnostic = negative["diagnostics"][0]
-        if (diagnostic.get("kind") != "ApplicationCompilationFailed"
-                or "expected `type`, `enum`, or `intent` declaration" not in diagnostic.get("message", "")
-                or 'fn' not in diagnostic.get("message", "")):
-            raise RuntimeError(f"{name} did not reach the source function parser boundary")
-    print("JIM_BUFFER_DECIMAL_SOURCE_FUNCTION_BOUNDARY_CONFIRMED", flush=True)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/provider-manifest.echo.json b/edict/replace-range-probes/buffer-decoder/evidence/provider-manifest.echo.json
deleted file mode 100644
index 0ce89ee2..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/provider-manifest.echo.json
+++ /dev/null
@@ -1,380 +0,0 @@
-{
-  "apiVersion": "edict.provider-manifest/v1",
-  "providerAbi": "edict:target-provider@1.0.0",
-  "provider": {
-    "coordinate": "echo.edict-provider@1",
-    "digest": "sha256:d5971bc387d873814a60ac46e1fc500c089f0e60c6ac8a232ebb43de139d39e6"
-  },
-  "artifacts": [
-    {
-      "role": "authority-facts.echo-dpo",
-      "artifactKind": "authorityFacts",
-      "resource": {
-        "coordinate": "echo.dpo-authority-facts@1",
-        "digest": "sha256:0347dd3ef916b20314c9d33fbd028432dfb53043fcb333390d8825dce72d7388"
-      },
-      "source": {
-        "kind": "generated",
-        "semanticSource": {
-          "coordinate": "echo.semantic-schema@1",
-          "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852"
-        },
-        "generator": {
-          "coordinate": "echo-wesley-gen.provider-artifact-generator@1",
-          "digest": "sha256:c083c08da330b9d37c7c17b12ce24c5724b5a59d61fc75c8192a53e204e0add5"
-        }
-      }
-    },
-    {
-      "role": "authority-facts.echo-lawpack",
-      "artifactKind": "authorityFacts",
-      "resource": {
-        "coordinate": "echo.dpo-lawpack-authority-facts@1",
-        "digest": "sha256:0e74b34fa901809f3cfe2aacd52f4dea708aa6d8481761193d7e1cd1afeca879"
-      },
-      "source": {
-        "kind": "generated",
-        "semanticSource": {
-          "coordinate": "echo.semantic-schema@1",
-          "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852"
-        },
-        "generator": {
-          "coordinate": "echo-wesley-gen.provider-artifact-generator@1",
-          "digest": "sha256:c083c08da330b9d37c7c17b12ce24c5724b5a59d61fc75c8192a53e204e0add5"
-        }
-      }
-    },
-    {
-      "role": "generated-artifact-profile.echo-dpo-registration",
-      "artifactKind": "generatedArtifactProfile",
-      "resource": {
-        "coordinate": "echo.dpo.registration/v1",
-        "digest": "sha256:ff88be93c26cc533948d8a93601954dc391912d593ca1e96115c846cbf2c5b5d"
-      },
-      "source": {
-        "kind": "generated",
-        "semanticSource": {
-          "coordinate": "echo.semantic-schema@1",
-          "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852"
-        },
-        "generator": {
-          "coordinate": "echo-wesley-gen.provider-artifact-generator@1",
-          "digest": "sha256:c083c08da330b9d37c7c17b12ce24c5724b5a59d61fc75c8192a53e204e0add5"
-        }
-      }
-    },
-    {
-      "role": "lawpack.echo-dpo",
-      "artifactKind": "lawpack",
-      "resource": {
-        "coordinate": "echo.dpo-lawpack@1",
-        "digest": "sha256:8abe773a94945fe1f46573bf4dc166a10ef723f5f5479e27ad03f7c891b77330"
-      },
-      "source": {
-        "kind": "generated",
-        "semanticSource": {
-          "coordinate": "echo.semantic-schema@1",
-          "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852"
-        },
-        "generator": {
-          "coordinate": "echo-wesley-gen.provider-artifact-generator@1",
-          "digest": "sha256:c083c08da330b9d37c7c17b12ce24c5724b5a59d61fc75c8192a53e204e0add5"
-        }
-      }
-    },
-    {
-      "role": "lowerer.echo-dpo",
-      "artifactKind": "lowerer",
-      "resource": {
-        "coordinate": "echo.dpo.lowerer/component@1",
-        "digest": "sha256:4b594a8165079f0a973741b9e27b468cf041f4ad53108fccae641dc35355bd2a"
-      },
-      "source": {
-        "kind": "component",
-        "component": {
-          "coordinate": "echo.dpo.lowerer/component@1",
-          "digest": "sha256:4b594a8165079f0a973741b9e27b468cf041f4ad53108fccae641dc35355bd2a"
-        }
-      }
-    },
-    {
-      "role": "provenance.provider-generation",
-      "artifactKind": "generationProvenance",
-      "resource": {
-        "coordinate": "echo.edict-provider-generation-provenance@1",
-        "digest": "sha256:11a8ef81063f769ccfe431047be3473523fadd49582d6c935b7f7f8d7ccd81d5"
-      },
-      "source": {
-        "kind": "generated",
-        "semanticSource": {
-          "coordinate": "echo.semantic-schema@1",
-          "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852"
-        },
-        "generator": {
-          "coordinate": "echo-wesley-gen.provider-artifact-generator@1",
-          "digest": "sha256:c083c08da330b9d37c7c17b12ce24c5724b5a59d61fc75c8192a53e204e0add5"
-        }
-      }
-    },
-    {
-      "role": "review.provider-generation",
-      "artifactKind": "reviewArtifact",
-      "resource": {
-        "coordinate": "echo.edict-provider-generation-review@1",
-        "digest": "sha256:24836f4170809f343a64dcce095a66765cdb922d652458a658d2f896d7547b78"
-      },
-      "source": {
-        "kind": "generated",
-        "semanticSource": {
-          "coordinate": "echo.semantic-schema@1",
-          "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852"
-        },
-        "generator": {
-          "coordinate": "echo-wesley-gen.provider-artifact-generator@1",
-          "digest": "sha256:c083c08da330b9d37c7c17b12ce24c5724b5a59d61fc75c8192a53e204e0add5"
-        }
-      }
-    },
-    {
-      "role": "schema.echo-provider-artifacts",
-      "artifactKind": "artifactSchema",
-      "resource": {
-        "coordinate": "echo.provider-artifacts.cddl@1",
-        "digest": "sha256:e8b2f078445f1e970bf8e92a33c69bded54a025469791dc3f4a7a418892a3252"
-      },
-      "source": {
-        "kind": "generated",
-        "semanticSource": {
-          "coordinate": "echo.semantic-schema@1",
-          "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852"
-        },
-        "generator": {
-          "coordinate": "echo-wesley-gen.provider-artifact-generator@1",
-          "digest": "sha256:c083c08da330b9d37c7c17b12ce24c5724b5a59d61fc75c8192a53e204e0add5"
-        }
-      }
-    },
-    {
-      "role": "target-profile.echo-dpo",
-      "artifactKind": "targetProfile",
-      "resource": {
-        "coordinate": "echo.dpo@1",
-        "digest": "sha256:2e2494121aecf5e6a2d920f5fb85408825d394765fad41484c416397c920fb04"
-      },
-      "source": {
-        "kind": "generated",
-        "semanticSource": {
-          "coordinate": "echo.semantic-schema@1",
-          "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852"
-        },
-        "generator": {
-          "coordinate": "echo-wesley-gen.provider-artifact-generator@1",
-          "digest": "sha256:c083c08da330b9d37c7c17b12ce24c5724b5a59d61fc75c8192a53e204e0add5"
-        }
-      }
-    },
-    {
-      "role": "verifier.echo-dpo",
-      "artifactKind": "verifier",
-      "resource": {
-        "coordinate": "echo.dpo.verifier/component@1",
-        "digest": "sha256:d0be4d283399aefc45d75b395b3568f9983521ca5543c9dfd23b9495758050ed"
-      },
-      "source": {
-        "kind": "component",
-        "component": {
-          "coordinate": "echo.dpo.verifier/component@1",
-          "digest": "sha256:d0be4d283399aefc45d75b395b3568f9983521ca5543c9dfd23b9495758050ed"
-        }
-      }
-    }
-  ],
-  "schemaBindings": [
-    {
-      "domain": "echo.dpo-lawpack.adapter.echo-dpo@1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "echo-provider-lawpack-target-adapter"
-    },
-    {
-      "domain": "echo.dpo-lawpack.compatibility@1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "echo-provider-lawpack-compatibility"
-    },
-    {
-      "domain": "echo.dpo-lawpack.exports@1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "lawpack-exports"
-    },
-    {
-      "domain": "echo.dpo-lawpack.verifier@1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "echo-provider-lawpack-verifier"
-    },
-    {
-      "domain": "echo.dpo.bundle/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "echo-dpo-bundle"
-    },
-    {
-      "domain": "echo.dpo.cost/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "echo-dpo-cost"
-    },
-    {
-      "domain": "echo.dpo.fixtures/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "echo-provider-conformance-corpus"
-    },
-    {
-      "domain": "echo.dpo.footprint/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "echo-dpo-footprint"
-    },
-    {
-      "domain": "echo.dpo.intrinsics/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "intrinsics-document"
-    },
-    {
-      "domain": "echo.dpo.lowerer/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "echo-dpo-lowerer"
-    },
-    {
-      "domain": "echo.dpo.obstructions/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "echo-dpo-obstructions"
-    },
-    {
-      "domain": "echo.dpo.operation-profiles/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "operation-profiles-document"
-    },
-    {
-      "domain": "echo.dpo.verifier/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "echo-dpo-verifier"
-    },
-    {
-      "domain": "echo.generated-artifact-profile/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "generated-artifact-profile"
-    },
-    {
-      "domain": "echo.generated-artifact/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "generated-artifact"
-    },
-    {
-      "domain": "echo.operation-lowering-configuration/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "echo-operation-lowering-configuration"
-    },
-    {
-      "domain": "echo.operation-package-verifier-report/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "echo-operation-package-verifier-report"
-    },
-    {
-      "domain": "echo.operation-package/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "echo-operation-package"
-    },
-    {
-      "domain": "echo.review-payload/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "review-payload"
-    },
-    {
-      "domain": "echo.span-ir/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "echo-span-ir"
-    },
-    {
-      "domain": "echo.verifier-report/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "verifier-report"
-    },
-    {
-      "domain": "edict.authority-facts/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "authority-facts"
-    },
-    {
-      "domain": "edict.core.module/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "core-module"
-    },
-    {
-      "domain": "edict.lawpack-adapter/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "lawpack-adapter"
-    },
-    {
-      "domain": "edict.lawpack-exports/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "lawpack-exports"
-    },
-    {
-      "domain": "edict.lawpack/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "lawpack-manifest"
-    },
-    {
-      "domain": "edict.lowering-requirements/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "lowering-requirements"
-    },
-    {
-      "domain": "edict.result-projection.artifact/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "result-projection"
-    },
-    {
-      "domain": "edict.source/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "edict-source-bytes"
-    },
-    {
-      "domain": "edict.target-ir.artifact/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "target-ir-artifact"
-    },
-    {
-      "domain": "edict.target-profile/v1",
-      "schemaRole": "schema.echo-provider-artifacts",
-      "format": "selfContainedCddlV1",
-      "rootRule": "target-profile-manifest"
-    }
-  ]
-}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/decimal/ReplaceRange.edict b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/decimal/ReplaceRange.edict
deleted file mode 100644
index 3927ed0e..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/decimal/ReplaceRange.edict
+++ /dev/null
@@ -1,93 +0,0 @@
-package jedit.text.replace_range@1;
-use lawpack jedit.text@1 digest "sha256:2ea164293719d2b03231c4904eb75ddcdf55fd29cc31f4fc5a5319d9ae5e60e7" as text;
-
-// Jim's JSON boundary codec. These are internal scanner values, not intent inputs.
-// A later bounded scanner must obtain each token from the retained Buffer atom.
-type JsonByte = Bytes;
-type DecimalState = variant { Start, Zero, Digits(U64) };
-type DecimalStep = variant { More(DecimalState), End(U64), Invalid, Overflow };
-type DecimalDigit = variant { Digit(U64), NotDigit };
-
-// An End result leaves the delimiter unconsumed for the enclosing JSON scanner.
-// Whitespace terminates a number; canonical-byte policy belongs to that scanner.
-fn isNumberDelimiter(token: JsonByte) -> Bool {
-  return token == b"," || token == b"]" || token == b"}"
-    || token == b" " || token == b"\t" || token == b"\r" || token == b"\n";
-}
-
-fn decimalDigit(token: JsonByte) -> DecimalDigit {
-  return if token == b"0" then DecimalDigit::Digit(0u64)
-    else if token == b"1" then DecimalDigit::Digit(1u64)
-    else if token == b"2" then DecimalDigit::Digit(2u64)
-    else if token == b"3" then DecimalDigit::Digit(3u64)
-    else if token == b"4" then DecimalDigit::Digit(4u64)
-    else if token == b"5" then DecimalDigit::Digit(5u64)
-    else if token == b"6" then DecimalDigit::Digit(6u64)
-    else if token == b"7" then DecimalDigit::Digit(7u64)
-    else if token == b"8" then DecimalDigit::Digit(8u64)
-    else if token == b"9" then DecimalDigit::Digit(9u64)
-    else DecimalDigit::NotDigit;
-}
-
-fn appendScaled(scaled: U64, digit: U64, limit: U64) -> DecimalStep {
-  let sum = checkedAdd(scaled, digit);
-  return if isSome(sum) then
-    if unwrap(sum) <= limit then DecimalStep::More(DecimalState::Digits(unwrap(sum)))
-    else DecimalStep::Overflow
-  else DecimalStep::Overflow;
-}
-
-fn appendDigit(value: U64, digit: U64, limit: U64) -> DecimalStep {
-  let decimalRadix = 10u64;
-  let product = checkedMul(value, decimalRadix);
-  return if isSome(product) then appendScaled(unwrap(product), digit, limit)
-    else DecimalStep::Overflow;
-}
-
-fn startDecimal(token: JsonByte, limit: U64) -> DecimalStep {
-  return match decimalDigit(token) {
-    Digit(value) => if value > limit then DecimalStep::Overflow
-      else if value == 0u64 then DecimalStep::More(DecimalState::Zero)
-      else DecimalStep::More(DecimalState::Digits(value)),
-    NotDigit => DecimalStep::Invalid,
-  };
-}
-
-fn continueDecimal(value: U64, token: JsonByte, limit: U64) -> DecimalStep {
-  return if value == 0u64 then DecimalStep::Invalid
-    else if value > limit then DecimalStep::Overflow
-    else match decimalDigit(token) {
-      Digit(digit) => appendDigit(value, digit, limit),
-      NotDigit => if isNumberDelimiter(token) then DecimalStep::End(value)
-        else DecimalStep::Invalid,
-    };
-}
-
-// canonical_head_id members use limit 255; version uses 18446744073709551615.
-// The enclosing scanner owns these schema limits and starts at Start.
-// Empty token, sign, leading zero, fraction, exponent and non-ASCII byte refuse.
-fn stepJsonUnsigned(state: DecimalState, token: JsonByte, limit: U64) -> DecimalStep {
-  return match state {
-    Start => startDecimal(token, limit),
-    Zero => if isNumberDelimiter(token) then DecimalStep::End(0u64)
-      else DecimalStep::Invalid,
-    Digits(value) => continueDecimal(value, token, limit),
-  };
-}
-
-type Input = { address: text.FactAddress, expected: text.FactBytes };
-intent replaceRange(input: Input) returns text.FactBytes
-  profile text.replaceRange
-  basis input.address.nodeId
-  budget <= text.replaceRangeBudget
-{
-  let actual: text.FactBytes = text.readFact(input.address)
-    else {
-      missing(address) => text.FactMissing,
-      typeMismatch(address) => text.FactMalformed,
-      notAtom(address) => text.FactMalformed,
-      tooLarge(address) => text.FactMalformed,
-    };
-  require actual == input.expected else text.BasisNotCanonical;
-  return actual;
-}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/decimal/stderr.jsonl b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/decimal/stderr.jsonl
deleted file mode 100644
index 015af157..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/decimal/stderr.jsonl
+++ /dev/null
@@ -1,2 +0,0 @@
-{"command":"build","input":{"kind":"stdin"},"kind":"InvalidApplicationSource","message":"Edict source `/tmp/echo-726-runtime/jim-buffer-decoder-reproduction196/decimal/src/ReplaceRange.edict` did not parse: ParseError { kind: Lex, message: \"invalid string escape\", span: Span { start: 861, end: 862 } }","schema":"edict.cli.diagnostic/v1","severity":"error","stage":"cli","type":"diagnostic"}
-{"checked":0,"command":"build","errors":1,"exitCode":2,"schema":"edict.cli.event/v1","status":"error","type":"status"}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/decimal/stdout.jsonl b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/decimal/stdout.jsonl
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/fn-control/ReplaceRange.edict b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/fn-control/ReplaceRange.edict
deleted file mode 100644
index fe87ae1b..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/fn-control/ReplaceRange.edict
+++ /dev/null
@@ -1,20 +0,0 @@
-package jedit.text.replace_range@1;
-use lawpack jedit.text@1 digest "sha256:2ea164293719d2b03231c4904eb75ddcdf55fd29cc31f4fc5a5319d9ae5e60e7" as text;
-fn retainFact(value: text.FactBytes) -> text.FactBytes { return value; }
-
-type Input = { address: text.FactAddress, expected: text.FactBytes };
-intent replaceRange(input: Input) returns text.FactBytes
-  profile text.replaceRange
-  basis input.address.nodeId
-  budget <= text.replaceRangeBudget
-{
-  let actual: text.FactBytes = text.readFact(input.address)
-    else {
-      missing(address) => text.FactMissing,
-      typeMismatch(address) => text.FactMalformed,
-      notAtom(address) => text.FactMalformed,
-      tooLarge(address) => text.FactMalformed,
-    };
-  require actual == input.expected else text.BasisNotCanonical;
-  return actual;
-}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/fn-control/stderr.jsonl b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/fn-control/stderr.jsonl
deleted file mode 100644
index eb0d4ec3..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/fn-control/stderr.jsonl
+++ /dev/null
@@ -1,2 +0,0 @@
-{"command":"build","input":{"kind":"stdin"},"kind":"InvalidApplicationSource","message":"Edict source `/tmp/echo-726-runtime/jim-buffer-decoder-reproduction196/fn-control/src/ReplaceRange.edict` did not parse: ParseError { kind: ExpectedToken, message: \"expected `type`, `enum`, or `intent` declaration, found Ident(\\\"fn\\\")\", span: Span { start: 151, end: 153 } }","schema":"edict.cli.diagnostic/v1","severity":"error","stage":"cli","type":"diagnostic"}
-{"checked":0,"command":"build","errors":1,"exitCode":2,"schema":"edict.cli.event/v1","status":"error","type":"status"}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/fn-control/stdout.jsonl b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/fn-control/stdout.jsonl
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/guard.launch.json b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/guard.launch.json
deleted file mode 100644
index e07fa2b7..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/guard.launch.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
-  "worker": "echo-read-runtime",
-  "image": "echo-read-runtime:red",
-  "lock": "/tmp/echo-validation-host.lock",
-  "inner_lock": "/tmp/echo-validation.lock",
-  "source": "/echo-audit",
-  "outputs": [
-    "/lease-target",
-    "/usr/local/cargo",
-    "/tmp/echo-726-runtime",
-    "all container writable-layer paths",
-    "/dev/shm",
-    "/private/tmp/echo-739-resume/jim-buffer-reproduction196.log"
-  ],
-  "measurements": {
-    "build": 14641243958,
-    "data": 4101269302,
-    "logs": 11301697,
-    "host_free": 709769887744,
-    "vm_free": 674522402816
-  },
-  "build_limit": 21474836480,
-  "data_limit": 4294967296,
-  "log_limit": 134217728,
-  "cpus": 4.0,
-  "memory": 6442450944,
-  "logging": {
-    "Type": "json-file",
-    "Config": {
-      "max-file": "5",
-      "max-size": "20m"
-    }
-  },
-  "timeout_seconds": 600,
-  "guard": "2-second fail-closed monitor; freeze owned process group across the entire size measurement, including cache du; pause container for snapshotter; accept an absent process group only after confirmed owned docker-exec completion; of aggregate writable layers, shared memory, host scratch and logs; no host binds or volumes",
-  "termination": "docker stop/kill owned worker and host docker-exec process group on monitoring failure or limit/timeout",
-  "command": "test ! -e /tmp/echo-726-runtime/buffer-reproduction196-input\nmkdir /tmp/echo-726-runtime/buffer-reproduction196-input\ntar -xf /tmp/echo-726-runtime/buffer-reproduction196-input.tar -C /tmp/echo-726-runtime/buffer-reproduction196-input\ncd /edict-207\nexport CARGO_TARGET_DIR=/lease-target CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=4 CARGO_PROFILE_DEV_DEBUG=0 CARGO_PROFILE_TEST_DEBUG=0\npython3 - <<'INNER'\nfrom pathlib import Path\nimport runpy,hashlib,subprocess\nr=Path('/tmp/echo-726-runtime/buffer-reproduction196-input/edict/replace-range-probes')\ncommon=runpy.run_path(str(r/'leaf-slice/run.py'))\nprint(common['verify_compiler_source'](Path('/edict-207'),r/'buffer-decoder/evidence/compiler-source.json','17397e2aad18a83ffc617d1afd628764501f49cd'),flush=True)\nassert not subprocess.check_output(['git','-C','/edict-207','status','--porcelain'],text=True).strip()\nbinary=Path('/lease-target/debug/edict')\nexpected='e2700698829b03f437c66425ed9878b002ef7a34ac183a39bac4eaf6a758cc6d'\nif True:\n assert '1.96.0-aarch64-unknown-linux-gnu' in subprocess.check_output(['rustup','toolchain','list'],text=True)\n print(subprocess.check_output(['rustc','+1.96.0','--version','--verbose'],text=True),flush=True)\n subprocess.run(['cargo','+1.96.0','clean','-p','edict-cli','-p','edict-syntax'],check=True)\n subprocess.run(['cargo','+1.96.0','build','--locked','-p','edict-cli'],check=True)\nprint('ACTUAL_COMPILER_BINARY',hashlib.sha256(binary.read_bytes()).hexdigest(),flush=True)\nsubprocess.run(['python3',str(r/'buffer-decoder/run.py'),'--compiler',str(binary),'--compiler-sha256',hashlib.sha256(binary.read_bytes()).hexdigest(),'--compiler-source','/edict-207','--compiler-manifest',str(r/'buffer-decoder/evidence/compiler-source.json'),'--application-source',str(r/'buffer-decoder/control'),'--provider-package','/read-provider','--work-root','/tmp/echo-726-runtime/jim-buffer-decoder-reproduction196'],check=True)\nINNER\n"
-}
\ No newline at end of file
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/guard.log b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/guard.log
deleted file mode 100644
index a2e605f3..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/guard.log
+++ /dev/null
@@ -1,20 +0,0 @@
-{'commit': '17397e2aad18a83ffc617d1afd628764501f49cd', 'tree': 'bcfd3112cd8b3d4630738a88761860679b45714b', 'fileCount': 449, 'manifestSha256': '625592ab9dd715349255bece0133378c64b3d4539fb50e437d116c2a4296f016'}
-rustc 1.96.0 (ac68faa20 2026-05-25)
-binary: rustc
-commit-hash: ac68faa20c58cbccd01ee7208bf3b6e93a7d7f96
-commit-date: 2026-05-25
-host: aarch64-unknown-linux-gnu
-release: 1.96.0
-LLVM version: 22.1.2
-
-     Removed 140 files, 343.4MiB total
-   Compiling edict-syntax v0.11.0-alpha.1 (/edict-207/crates/edict-syntax)
-   Compiling edict-provider-schema v0.11.0-alpha.1 (/edict-207/crates/edict-provider-schema)
-   Compiling edict-provider-host-wasmtime v0.11.0-alpha.1 (/edict-207/crates/edict-provider-host-wasmtime)
-   Compiling edict-cli v0.11.0-alpha.1 (/edict-207/crates/edict-cli)
-    Finished `dev` profile [unoptimized] target(s) in 7.44s
-ACTUAL_COMPILER_BINARY 83c70b3fdbb42ac43f0967a0c559c0cc8b66599987774a40412bda4fbc028d36
-{"artifactSha256": {"executable-operation-package.cbor": "afd931700018312d6c0d1e249871313d2c21c0ece1ae41d1f17f2be7af9e5284", "verification-report.cbor": "9114fdd983d456eb83f69969475f558b6e608be23520212a5db5f26bb095d04b"}, "artifacts": ["executable-operation-package.cbor", "verification-report.cbor"], "case": "read-control", "diagnostics": [], "exitCode": 0, "sourceSha256": "4ec3cbf32fd5d98987cbeeaff95d7c9c5ab734dac555e443aac52e8ab02bfbc5", "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61"}
-{"artifactSha256": {}, "artifacts": [], "case": "fn-control", "diagnostics": [{"command": "build", "input": {"kind": "stdin"}, "kind": "InvalidApplicationSource", "message": "Edict source `/tmp/echo-726-runtime/jim-buffer-decoder-reproduction196/fn-control/src/ReplaceRange.edict` did not parse: ParseError { kind: ExpectedToken, message: \"expected `type`, `enum`, or `intent` declaration, found Ident(\\\"fn\\\")\", span: Span { start: 151, end: 153 } }", "schema": "edict.cli.diagnostic/v1", "severity": "error", "stage": "cli", "type": "diagnostic"}], "exitCode": 2, "sourceSha256": "97475b0e6aaf24d3268736efa3312df377b9153b89c8e59f0e2ceb25ce691218", "stderrSha256": "8ce5808f7da7f7457b8cdca7ad00e080f3358a4a35d502d6ac9aee5c83255090", "stdoutSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}
-{"artifactSha256": {}, "artifacts": [], "case": "decimal", "diagnostics": [{"command": "build", "input": {"kind": "stdin"}, "kind": "InvalidApplicationSource", "message": "Edict source `/tmp/echo-726-runtime/jim-buffer-decoder-reproduction196/decimal/src/ReplaceRange.edict` did not parse: ParseError { kind: Lex, message: \"invalid string escape\", span: Span { start: 861, end: 862 } }", "schema": "edict.cli.diagnostic/v1", "severity": "error", "stage": "cli", "type": "diagnostic"}], "exitCode": 2, "sourceSha256": "860712eaae8fad67499967e2475d9a2bef9d072762b3eab1004a3ddf4dba2b94", "stderrSha256": "2c45c51317aa6dffbcd96684a6b288ac9a429c2a19f3672e09c8b85b6ed1adb8", "stdoutSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}
-JIM_BUFFER_DECIMAL_DISTINCT_SOURCE_BOUNDARIES_CONFIRMED
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/guard.result.json b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/guard.result.json
deleted file mode 100644
index 0c9df3b9..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/guard.result.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "measurements": {
-    "build": 14448304197,
-    "data": 4104511557,
-    "logs": 11304883,
-    "host_free": 709664010240,
-    "vm_free": 674522402816
-  },
-  "exit_code": 0
-}
\ No newline at end of file
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/public-build.json b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/public-build.json
deleted file mode 100644
index 47382e4c..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/public-build.json
+++ /dev/null
@@ -1,101 +0,0 @@
-{
-  "compiler": {
-    "commit": "17397e2aad18a83ffc617d1afd628764501f49cd",
-    "tree": "bcfd3112cd8b3d4630738a88761860679b45714b",
-    "fileCount": 449,
-    "manifestSha256": "625592ab9dd715349255bece0133378c64b3d4539fb50e437d116c2a4296f016",
-    "binarySha256": "83c70b3fdbb42ac43f0967a0c559c0cc8b66599987774a40412bda4fbc028d36"
-  },
-  "providerManifestSha256": "5b38ae704a071b88aa0cc2f85020de41cb69e76d037afe3592a4d319e22587c8",
-  "providerFiles": {
-    "components/lowerer.echo-dpo.component.wasm": "4b594a8165079f0a973741b9e27b468cf041f4ad53108fccae641dc35355bd2a",
-    "components/verifier.echo-dpo.component.wasm": "d0be4d283399aefc45d75b395b3568f9983521ca5543c9dfd23b9495758050ed",
-    "generated/evidence/provenance.provider-generation.json": "11a8ef81063f769ccfe431047be3473523fadd49582d6c935b7f7f8d7ccd81d5",
-    "generated/evidence/review.provider-generation.json": "24836f4170809f343a64dcce095a66765cdb922d652458a658d2f896d7547b78",
-    "generated/primary/authority-facts.echo-dpo.cbor": "e2a6a539a7156296c18ff1bc02f80dcabf62b42bb4314d0737527869e43986d6",
-    "generated/primary/authority-facts.echo-lawpack.cbor": "ce1af559551f8b8242c4b290b620c5a28323b9e43f8bc6bb161a191001b6f4b9",
-    "generated/primary/generated-artifact-profile.echo-dpo-registration.cbor": "4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34",
-    "generated/primary/lawpack.echo-dpo.cbor": "8c570362671a0b1cd1a992d8210e4a90ffd153ad06dcdf1e0cb36033cc971e2c",
-    "generated/primary/schema.echo-provider-artifacts.cddl": "e8b2f078445f1e970bf8e92a33c69bded54a025469791dc3f4a7a418892a3252",
-    "generated/primary/target-profile.echo-dpo.cbor": "1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e",
-    "generated/resources/resource.conformance-corpus.cbor": "f1f29d990f83c5af33952a69b16e9c9bbb7c2feb1d3989860b74c9e6c2c19b08",
-    "generated/resources/resource.lawpack-compatibility.cbor": "642945761cb7d60e133008620dc2a6b48fd0f77901b985e02b1d3398fb1411af",
-    "generated/resources/resource.lawpack-exports.cbor": "e80f3597830f30079bae7428cc6fe1ca27e9f2626614284338c5f5c7bfd9f8b8",
-    "generated/resources/resource.lawpack-target-adapter.cbor": "d0cf6a5310c7aa3d5bf291e40221a50a9be676d0e7f9947b71de0c52f03f9a41",
-    "generated/resources/resource.lawpack-verifier.cbor": "a0ca53486f2e1181027cab255792150735a68fc01a93669ab90b58e7c32bd36e",
-    "generated/resources/resource.target-bundle-profile.cbor": "95cc3aab106f0d6d77ec76e88591ee24acac58f4345c031b77cfd1ecf2aa0db8",
-    "generated/resources/resource.target-cost-algebra.cbor": "29cc941cc96ffdb420a24a377146f0e9d5409a89f84cdbb2ad597e78dfde3503",
-    "generated/resources/resource.target-footprint-algebra.cbor": "c08b853b22fa1920cb8971b60a6622e4d8f400c68b8027a9c4f246c5cb4a222c",
-    "generated/resources/resource.target-intrinsics.cbor": "d4080b044ad95d88763f605d25d678dad0d44bbfdc32c212334a962eaf456588",
-    "generated/resources/resource.target-ir.cbor": "f0ead7a5dcb41532d5df9067a9735d7078456b59cc267b3a9f6bb6437431000c",
-    "generated/resources/resource.target-lowerer-contract.cbor": "c4d788a8ae876cfe8c9e9875144014d551d38ff13b4d90bb9dfc46bc562bf280",
-    "generated/resources/resource.target-obstruction-taxonomy.cbor": "5eb85dc3fbb53890f4f5accf6a7a3c03889bd25bf00e7c2a23c43e497652328e",
-    "generated/resources/resource.target-operation-profiles.cbor": "3d560e8df1bfb38e8ba9b70b0a4bc843c848a7900e3af76d8f798db51b6b1077",
-    "generated/resources/resource.target-verifier-contract.cbor": "9cef12fac8190156e152e7c8ab5adeed077bf2bdadf3add2225ce90ab4be8710",
-    "provider-manifest.echo.json": "5b38ae704a071b88aa0cc2f85020de41cb69e76d037afe3592a4d319e22587c8"
-  },
-  "authoredSourceSha256": "9fc1b006c298866463ab83a28fcb1e54769b970970c571f11d0868d79edc6d87",
-  "literalCasesStatus": "not executed",
-  "compositionStatus": "helpers are not connected to a retained-byte scanner",
-  "results": {
-    "read-control": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "4ec3cbf32fd5d98987cbeeaff95d7c9c5ab734dac555e443aac52e8ab02bfbc5",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "afd931700018312d6c0d1e249871313d2c21c0ece1ae41d1f17f2be7af9e5284",
-        "verification-report.cbor": "9114fdd983d456eb83f69969475f558b6e608be23520212a5db5f26bb095d04b"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "fn-control": {
-      "exitCode": 2,
-      "diagnostics": [
-        {
-          "command": "build",
-          "input": {
-            "kind": "stdin"
-          },
-          "kind": "InvalidApplicationSource",
-          "message": "Edict source `/tmp/echo-726-runtime/jim-buffer-decoder-reproduction196/fn-control/src/ReplaceRange.edict` did not parse: ParseError { kind: ExpectedToken, message: \"expected `type`, `enum`, or `intent` declaration, found Ident(\\\"fn\\\")\", span: Span { start: 151, end: 153 } }",
-          "schema": "edict.cli.diagnostic/v1",
-          "severity": "error",
-          "stage": "cli",
-          "type": "diagnostic"
-        }
-      ],
-      "artifacts": [],
-      "sourceSha256": "97475b0e6aaf24d3268736efa3312df377b9153b89c8e59f0e2ceb25ce691218",
-      "artifactSha256": {},
-      "stdoutSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
-      "stderrSha256": "8ce5808f7da7f7457b8cdca7ad00e080f3358a4a35d502d6ac9aee5c83255090"
-    },
-    "decimal": {
-      "exitCode": 2,
-      "diagnostics": [
-        {
-          "command": "build",
-          "input": {
-            "kind": "stdin"
-          },
-          "kind": "InvalidApplicationSource",
-          "message": "Edict source `/tmp/echo-726-runtime/jim-buffer-decoder-reproduction196/decimal/src/ReplaceRange.edict` did not parse: ParseError { kind: Lex, message: \"invalid string escape\", span: Span { start: 861, end: 862 } }",
-          "schema": "edict.cli.diagnostic/v1",
-          "severity": "error",
-          "stage": "cli",
-          "type": "diagnostic"
-        }
-      ],
-      "artifacts": [],
-      "sourceSha256": "860712eaae8fad67499967e2475d9a2bef9d072762b3eab1004a3ddf4dba2b94",
-      "artifactSha256": {},
-      "stdoutSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
-      "stderrSha256": "2c45c51317aa6dffbcd96684a6b288ac9a429c2a19f3672e09c8b85b6ed1adb8"
-    }
-  }
-}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/read-control/ReplaceRange.edict b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/read-control/ReplaceRange.edict
deleted file mode 100644
index 1031dfc9..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/read-control/ReplaceRange.edict
+++ /dev/null
@@ -1,18 +0,0 @@
-package jedit.text.replace_range@1;
-use lawpack jedit.text@1 digest "sha256:2ea164293719d2b03231c4904eb75ddcdf55fd29cc31f4fc5a5319d9ae5e60e7" as text;
-type Input = { address: text.FactAddress, expected: text.FactBytes };
-intent replaceRange(input: Input) returns text.FactBytes
-  profile text.replaceRange
-  basis input.address.nodeId
-  budget <= text.replaceRangeBudget
-{
-  let actual: text.FactBytes = text.readFact(input.address)
-    else {
-      missing(address) => text.FactMissing,
-      typeMismatch(address) => text.FactMalformed,
-      notAtom(address) => text.FactMalformed,
-      tooLarge(address) => text.FactMalformed,
-    };
-  require actual == input.expected else text.BasisNotCanonical;
-  return actual;
-}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/read-control/application/executable-operation-package.cbor b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/read-control/application/executable-operation-package.cbor
deleted file mode 100644
index a14f9ea2..00000000
Binary files a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/read-control/application/executable-operation-package.cbor and /dev/null differ
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/read-control/application/verification-report.cbor b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/read-control/application/verification-report.cbor
deleted file mode 100644
index fb4ef5d0..00000000
Binary files a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/read-control/application/verification-report.cbor and /dev/null differ
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/read-control/stderr.jsonl b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/read-control/stderr.jsonl
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/read-control/stdout.jsonl b/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/read-control/stdout.jsonl
deleted file mode 100644
index a668538e..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/reproduction196/read-control/stdout.jsonl
+++ /dev/null
@@ -1 +0,0 @@
-{"checked":1,"command":"build","errors":0,"exitCode":0,"schema":"edict.cli.event/v1","status":"ok","type":"status"}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/after-cleanup-usage.json b/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/after-cleanup-usage.json
deleted file mode 100644
index a5ff90fc..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/after-cleanup-usage.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "build": 14968038699,
-  "data": 4074673451,
-  "logs": 11298083,
-  "host_free": 709162811392,
-  "vm_free": 673964335104
-}
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/guard.launch.json b/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/guard.launch.json
deleted file mode 100644
index 2fcf115f..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/guard.launch.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
-  "worker": "echo-read-runtime",
-  "image": "echo-read-runtime:red",
-  "lock": "/tmp/echo-validation-host.lock",
-  "inner_lock": "/tmp/echo-validation.lock",
-  "source": "/echo-audit",
-  "outputs": [
-    "/lease-target",
-    "/usr/local/cargo",
-    "/tmp/echo-726-runtime",
-    "all container writable-layer paths",
-    "/dev/shm",
-    "/private/tmp/echo-739-resume/jim-buffer-reproduction.log"
-  ],
-  "measurements": {
-    "build": 14967762459,
-    "data": 4074397211,
-    "logs": 11266512,
-    "host_free": 709436264448,
-    "vm_free": 674182402048
-  },
-  "build_limit": 21474836480,
-  "data_limit": 4294967296,
-  "log_limit": 134217728,
-  "cpus": 4.0,
-  "memory": 6442450944,
-  "logging": {
-    "Type": "json-file",
-    "Config": {
-      "max-file": "5",
-      "max-size": "20m"
-    }
-  },
-  "timeout_seconds": 600,
-  "guard": "2-second fail-closed monitor; freeze owned process group across the entire size measurement, including cache du; pause container for snapshotter; accept an absent process group only after confirmed owned docker-exec completion; of aggregate writable layers, shared memory, host scratch and logs; no host binds or volumes",
-  "termination": "docker stop/kill owned worker and host docker-exec process group on monitoring failure or limit/timeout",
-  "command": "test ! -e /tmp/echo-726-runtime/buffer-reproduction-input\nmkdir /tmp/echo-726-runtime/buffer-reproduction-input\ntar -xf /tmp/echo-726-runtime/buffer-reproduction-input.tar -C /tmp/echo-726-runtime/buffer-reproduction-input\ncd /edict-207\nexport CARGO_TARGET_DIR=/lease-target CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=4 CARGO_PROFILE_DEV_DEBUG=0 CARGO_PROFILE_TEST_DEBUG=0\npython3 - <<'INNER'\nfrom pathlib import Path\nimport runpy,hashlib,subprocess\nr=Path('/tmp/echo-726-runtime/buffer-reproduction-input/edict/replace-range-probes')\ncommon=runpy.run_path(str(r/'leaf-slice/run.py'))\nprint(common['verify_compiler_source'](Path('/edict-207'),r/'buffer-decoder/evidence/compiler-source.json','17397e2aad18a83ffc617d1afd628764501f49cd'),flush=True)\nassert not subprocess.check_output(['git','-C','/edict-207','status','--porcelain'],text=True).strip()\nbinary=Path('/lease-target/debug/edict')\nexpected='e2700698829b03f437c66425ed9878b002ef7a34ac183a39bac4eaf6a758cc6d'\nif not binary.exists() or hashlib.sha256(binary.read_bytes()).hexdigest()!=expected:\n subprocess.run(['cargo','+1.95.0','clean','-p','edict-cli','-p','edict-syntax'],check=True)\n subprocess.run(['cargo','+1.95.0','build','--locked','-p','edict-cli'],check=True)\nprint('ACTUAL_COMPILER_BINARY',hashlib.sha256(binary.read_bytes()).hexdigest(),flush=True)\nsubprocess.run(['python3',str(r/'buffer-decoder/run.py'),'--compiler',str(binary),'--compiler-source','/edict-207','--compiler-manifest',str(r/'buffer-decoder/evidence/compiler-source.json'),'--application-source',str(r/'buffer-decoder/control'),'--provider-package','/read-provider','--work-root','/tmp/echo-726-runtime/jim-buffer-decoder-reproduction'],check=True)\nINNER\n"
-}
\ No newline at end of file
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/guard.log b/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/guard.log
deleted file mode 100644
index a05413ce..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/guard.log
+++ /dev/null
@@ -1,4 +0,0 @@
-{'commit': '17397e2aad18a83ffc617d1afd628764501f49cd', 'tree': 'bcfd3112cd8b3d4630738a88761860679b45714b', 'fileCount': 449, 'manifestSha256': '625592ab9dd715349255bece0133378c64b3d4539fb50e437d116c2a4296f016'}
-info: syncing channel updates for 1.95.0-aarch64-unknown-linux-gnu
-info: latest update on 2026-04-16 for version 1.95.0 (59807616e 2026-04-14)
-info: downloading 3 components
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/observer-record.json b/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/observer-record.json
deleted file mode 100644
index a1c5adb4..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/observer-record.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "observer": "root Echo Edict Jim agent",
-  "evidenceSource": "functions.write_stdin session8441 terminal output",
-  "guard": "guarded-worker-v2.py measured_sizes raised RuntimeError(project budget)",
-  "exitCode": 1,
-  "measurementsAtRefusal": {
-    "build": 15219153753,
-    "data": 4325788505,
-    "logs": 11266897,
-    "host_free": 709395468288,
-    "vm_free": 674182402048
-  },
-  "dataLimit": 4294967296,
-  "compilerTestStarted": false,
-  "workerStopped": true,
-  "qualification": "Observer-authored record of the displayed guard exception; not a raw compiler diagnostic or raw controller stdout file"
-}
\ No newline at end of file
diff --git a/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/partial-toolchain-cleanup.txt b/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/partial-toolchain-cleanup.txt
deleted file mode 100644
index b8131f67..00000000
--- a/edict/replace-range-probes/buffer-decoder/evidence/resource-stop/partial-toolchain-cleanup.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-[
-  {
-    "path": "/usr/local/rustup/toolchains/1.95.0-aarch64-unknown-linux-gnu",
-    "mtime": 1791180435.339878,
-    "bytes": 199361672
-  },
-  {
-    "path": "/usr/local/rustup/downloads/7c070aeba9bbf12073646995a03f36c346bb5f541d0078ba6d9dc2a7adaaf6af",
-    "mtime": 1791180434.8780186,
-    "bytes": 10412640
-  },
-  {
-    "path": "/usr/local/rustup/downloads/0fe3689eeaed603e5ef24572d11597d3edadaefd2cb181674ad621260f2501d2.partial",
-    "mtime": 1791180445.4150162,
-    "bytes": 46322112
-  },
-  {
-    "path": "/usr/local/rustup/downloads/3a21b271b1ff973b94d69b25e7a39992f9fbcae1ab6d9475844a23e6ad3908ac",
-    "mtime": 1791180442.7890167,
-    "bytes": 28233468
-  },
-  {
-    "path": "/usr/local/rustup/tmp/nhqoekhftw1pdi7k_file",
-    "mtime": 1791180444.6051555,
-    "bytes": 32
-  },
-  {
-    "path": "/usr/local/rustup/tmp/7mlm87b4uhm30gts_file",
-    "mtime": 1791180444.606756,
-    "bytes": 1
-  }
-]
-1.90.0-aarch64-unknown-linux-gnu (active, default)
-1.96.0-aarch64-unknown-linux-gnu
-
diff --git a/edict/replace-range-probes/buffer-decoder/run.py b/edict/replace-range-probes/buffer-decoder/run.py
deleted file mode 100644
index fa56c6f1..00000000
--- a/edict/replace-range-probes/buffer-decoder/run.py
+++ /dev/null
@@ -1,98 +0,0 @@
-"""Reproduce the distinct function-parser and decimal-lexer boundaries."""
-
-import argparse
-import json
-from pathlib import Path
-import runpy
-
-
-COMPILER_COMMIT = "17397e2aad18a83ffc617d1afd628764501f49cd"
-HISTORICAL_COMPILER_SHA256 = "e2700698829b03f437c66425ed9878b002ef7a34ac183a39bac4eaf6a758cc6d"
-TRIVIAL_FUNCTION = b"fn retainFact(value: text.FactBytes) -> text.FactBytes { return value; }\n\n"
-
-
-def compiler_digest(value):
-    if len(value) != 64 or any(char not in "0123456789abcdef" for char in value):
-        raise argparse.ArgumentTypeError("compiler SHA-256 must be 64 lowercase hexadecimal digits")
-    return value
-
-
-def main():
-    parser = argparse.ArgumentParser(description=__doc__)
-    for name in ("compiler", "compiler-source", "compiler-manifest", "application-source",
-                 "provider-package", "work-root"):
-        parser.add_argument("--" + name, type=Path, required=True)
-    parser.add_argument("--compiler-sha256", type=compiler_digest,
-                        default=HISTORICAL_COMPILER_SHA256,
-                        help="explicit binary pin from the controlled compiler build; defaults to the historical binary")
-    args = parser.parse_args()
-    if not Path("/.dockerenv").is_file():
-        raise RuntimeError("Run under shared git-locks admission and the guarded Docker lease")
-    if not args.work_root.resolve().is_relative_to(Path("/tmp/echo-726-runtime")):
-        raise RuntimeError("Work must stay inside the declared runtime-data accounting root")
-    common = runpy.run_path(str(Path(__file__).parent.parent / "leaf-slice/run.py"))
-    sha256, snapshot, verify = common["sha256"], common["snapshot"], common["verify_compiler_source"]
-    compiler = verify(args.compiler_source, args.compiler_manifest, COMPILER_COMMIT)
-    compiler["binarySha256"] = sha256(args.compiler)
-    before = {"application": snapshot(args.application_source), "provider": snapshot(args.provider_package)}
-    original = (args.application_source / "src/ReplaceRange.edict").read_bytes()
-    authored = (Path(__file__).parent / "Decimal.edict").read_bytes()
-    package, declarations = authored.split(b"\n", 1)
-    if not original.startswith(package + b"\n") or b"type Input" not in original:
-        raise RuntimeError("Expected the unchanged generic read control's source layout")
-    expected = json.loads((Path(__file__).parent / "evidence/original/public-build.json").read_text())
-    expected_compiler = dict(expected["compiler"], binarySha256=args.compiler_sha256)
-    if compiler != expected_compiler:
-        raise RuntimeError("Compiler source or explicitly pinned binary identity differs")
-    if before["provider"] != expected["providerFiles"]:
-        raise RuntimeError("Provider bytes differ from the retained public witness")
-    if sha256(Path(__file__).parent / "Decimal.edict") != expected["authoredSourceSha256"]:
-        raise RuntimeError("Authored source differs from the retained public witness")
-    if sha256(args.application_source / "src/ReplaceRange.edict") != expected["results"]["read-control"]["sourceSha256"]:
-        raise RuntimeError("Read control differs from the retained public witness")
-    sources = {
-        "read-control": original,
-        "fn-control": original.replace(b"type Input", TRIVIAL_FUNCTION + b"type Input", 1),
-        "decimal": original.replace(b"type Input", declarations + b"\ntype Input", 1),
-    }
-    args.work_root.mkdir()
-    evidence = {"compiler": compiler,
-                "providerManifestSha256": sha256(args.provider_package / "provider-manifest.echo.json"),
-                "providerFiles": before["provider"],
-                "authoredSourceSha256": sha256(Path(__file__).parent / "Decimal.edict"),
-                "literalCasesStatus": "not executed",
-                "compositionStatus": "helpers are not connected to a retained-byte scanner",
-                "results": {}}
-    for name, source in sources.items():
-        root = args.work_root / name
-        common["prepare"](root, args.application_source, args.provider_package, source)
-        evidence["results"][name] = common["build"](root, args.compiler)
-    (args.work_root / "evidence.json").write_text(json.dumps(evidence, indent=2) + "\n")
-    for name, result in evidence["results"].items():
-        print(json.dumps({"case": name, **result}, sort_keys=True), flush=True)
-    if before != {"application": snapshot(args.application_source), "provider": snapshot(args.provider_package)}:
-        raise RuntimeError("Public witness changed an authoritative input")
-    if compiler["binarySha256"] != sha256(args.compiler):
-        raise RuntimeError("Compiler binary changed during witness")
-    verify(args.compiler_source, args.compiler_manifest, COMPILER_COMMIT)
-    positive = evidence["results"]["read-control"]
-    if (positive["exitCode"] != 0 or positive["diagnostics"] or positive["artifacts"] !=
-            ["executable-operation-package.cbor", "verification-report.cbor"]):
-        raise RuntimeError("Generic read control did not reach package/report success")
-    expected_messages = {
-        "fn-control": ("kind: ExpectedToken", "expected `type`, `enum`, or `intent` declaration", "fn"),
-        "decimal": ("kind: Lex", "invalid string escape"),
-    }
-    for name, markers in expected_messages.items():
-        negative = evidence["results"][name]
-        if negative["exitCode"] != 2 or negative["artifacts"] or len(negative["diagnostics"]) != 1:
-            raise RuntimeError(f"{name} did not refuse without application artifacts")
-        diagnostic = negative["diagnostics"][0]
-        if (diagnostic.get("kind") != "InvalidApplicationSource"
-                or any(marker not in diagnostic.get("message", "") for marker in markers)):
-            raise RuntimeError(f"{name} did not reach its retained source boundary")
-    print("JIM_BUFFER_DECIMAL_DISTINCT_SOURCE_BOUNDARIES_CONFIRMED", flush=True)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/edict/replace-range-probes/leaf-slice/LeafSlice.edict b/edict/replace-range-probes/leaf-slice/LeafSlice.edict
deleted file mode 100644
index 63b51745..00000000
--- a/edict/replace-range-probes/leaf-slice/LeafSlice.edict
+++ /dev/null
@@ -1,24 +0,0 @@
-package jedit.text.replace_range@1;
-
-use lawpack jedit.text@1 digest "sha256:95758c1605894672cc9069fde01bb8b6e11842b053102660c9cd4f4d6f34d64e" as text;
-
-type Input = {
-  blobBytes: Bytes,
-  startByte: U64,
-  endByte: U64,
-};
-
-type LeafBytes = {
-  bytes: Bytes,
-};
-
-intent sliceLeaf(input: Input) returns LeafBytes
-  profile text.replaceRange
-  basis none
-  budget <= text.replaceRangeBudget
-  where input.startByte <= input.endByte,
-        input.endByte <= len(input.blobBytes)
-{
-  let bytes = slice(input.blobBytes, input.startByte, input.endByte);
-  return { bytes };
-}
diff --git a/edict/replace-range-probes/leaf-slice/README.md b/edict/replace-range-probes/leaf-slice/README.md
deleted file mode 100644
index 63cdda9f..00000000
--- a/edict/replace-range-probes/leaf-slice/README.md
+++ /dev/null
@@ -1,161 +0,0 @@
-# Authored leaf-byte slicing pressure
-
-`LeafSlice.edict` isolates the byte extraction used by persistent leaf splitting
-in [Jim #296](https://github.com/flyingrobots/jedit/issues/296). It is an authored
-compiler input, not a completed rope operation or a native callback.
-
-The frozen [fact law](../../../contracts/jedit/lawpacks/replace-range-v1/text-schema-v1.json)
-stores a leaf's `blob_id`, `byte_start`, and `byte_length`. The existing
-[`locate_leaf_slice` and `make_leaf_slice`](../../../native/jedit-echo-host/src/rope/tree.rs)
-first check absolute offsets, extract the half-open byte range, validate UTF-8,
-and derive metrics. This source isolates extraction after absolute offsets have
-been obtained. It does not decode facts, validate UTF-8, derive metrics, or
-publish a new leaf.
-
-The proposed generic primitive is `slice(bytes, start, end)`. Offsets are U64;
-the result retains the operand's maximum byte bound and drops any exact-length
-refinement. The source requires `start <= end` and `end <= len(bytes)` before
-evaluation. Invalid inputs must fail ordinary input constraints, without
-clipping, truncation, wrapping, or a host panic. A slice inside a UTF-8 code
-point is still a lawful byte slice; Jim's later UTF-8 validation owns rejection
-as a text operation.
-
-[`cases.json`](cases.json) records literal runtime expectations, including
-empty, full, interior, binary, Unicode, invalid-range, and U64-limit inputs.
-They were not executed by the public compiler witnesses below. The file is a conformance specification, never
-an executable lawpack input or a substitute for the retained 40-case rope
-oracle.
-
-## Current boundary
-
-Source inspection of Edict main `ac63fe679973e8119244471c124cde44dea5984f`
-found no implementation of this primitive. Its closed Bytes prelude currently
-provides comparison and length. Its source compiler also rejects Option types,
-so the first capability uses explicit range proofs instead of relying on an
-unavailable Option result.
-
-The [retained public-build RED](evidence/public-build-red.json) uses the
-already built experimental compiler `2405a550e93e1e97fff640caa44bbd0f65ffff3c`,
-with the unchanged Echo provider from `49e9efb68001dfd78563d18bac9359a87671e431`.
-It does **not** use or replace the frozen application's `3f81f759` compiler pin.
-The witness checks all 440 copied compiler-source files against their Git blob
-identities before and after execution and records the existing binary hash.
-It reuses that binary; this run does not reproduce its compilation.
-
-| Authored input | Public build result |
-| --- | --- |
-| Frozen boundary source | Exit 0; executable package and separate verification report |
-| Leaf source with only the `slice(...)` expression replaced by `input.blobBytes` | Exit 0; executable package and separate verification report |
-| Exact `LeafSlice.edict` | Exit 2; `ApplicationCompilationFailed`, with `TypeCheck` / `UnresolvedFunction`: `pure helper \`slice\` has no compiler context fact`; no application artifacts |
-
-The primary source diagnostic covers bytes 521–575, the call at line 22. The
-following unresolved-binding and return diagnostics are cascading failures.
-The paired control proves the range constraints and output shape compile; the
-new slice expression is the first missing source capability. Neither control
-package was evaluated during this run.
-
-The first harness run incorrectly expected the guarded control to reach a
-provider refusal. Its actual successful build disproved that expectation. The
-harness assertion was corrected, with no source change, and the full paired
-witness passed with `JIM_LEAF_SLICE_SOURCE_BOUNDARY_CONFIRMED`.
-
-## Candidate public build
-
-With Edict [PR #221](https://github.com/flyingrobots/edict/pull/221) at
-`0835f398336ce1c693b5531b262228cd909c0b4b`, the **unchanged** source passes the
-public application-build boundary with the same frozen provider. Both controls
-also pass. The [retained candidate result](evidence/public-build-candidate.json)
-records all source and output hashes. The witness checks all 445 compiler-source
-files and the existing compiler binary before and after the run.
-
-The actual boundary is further than initially expected: the frozen provider
-produces the [executable package](evidence/candidate-artifacts/executable-operation-package.cbor)
-and [verification report](evidence/candidate-artifacts/verification-report.cbor).
-A separate read-only CBOR inspection observed `outcome: accepted`, zero diagnostic
-bytes, the `jedit.text.replace_range@1.sliceLeaf` coordinate, and the explicit
-`core.bytes.slice` call in both retained Core and Target. Its
-[inspection summary](evidence/candidate-report-inspection.json) records those
-observations. This is an inspection of the existing verifier's report, not a
-new independent verification implementation or evidence of evaluator support.
-
-| Retained artifact | Raw SHA-256 |
-| --- | --- |
-| Executable package | `bfacd029cf2dc9247cbcee47d747eca3f8298c7184cac3866eb36f3ab55573c1` |
-| Verification report | `943ac86ea20c40d68881cc8413b926f98ba2a4ee99408e3dcede4eead1e7bb86` |
-
-The first candidate harness expected a provider refusal, so it failed its own
-assertion after recording the successful builds. That was a harness expectation
-mismatch, not a compiler failure. A fresh run with the correct package-boundary
-assertion passed with `JIM_LEAF_SLICE_PACKAGE_BOUNDARY_CONFIRMED` and reproduced
-identical package/report bytes for all three sources. The original source RED
-and both positive controls are preserved.
-
-No evaluator was invoked during these public-build runs. The accepted report
-does not establish runtime availability, metering, refusals, or rope behavior.
-The separate runtime witness below covers the byte primitive.
-
-The frozen `edict/replace-range/` application, lawpack closure, producer pins,
-and artifact locks remain authoritative for the existing pure-boundary witness.
-This development source imports the same published lawpack in an isolated copy.
-It does not repin or regenerate that application.
-
-## Separate generic runtime witness
-
-[Echo PR #746](https://github.com/flyingrobots/echo/pull/746) at
-`bf11732478067e43dda400bab94aa0f6d186b614` consumes the exact retained package
-and report. Its evaluator RED failed on the first interior slice with
-`UnsupportedProgram`. Generic `core.bytes.slice` support then passed all twelve
-literal cases, plus malformed-artifact and exact-budget controls. A test-only
-application-name renaming control preserves outputs and costs; no Jim name
-selects runtime behavior. Those mutated test controls are not new compiler or
-verifier artifacts.
-
-The runtime change passed 40 relevant integration tests, four evaluator unit
-tests, strict Clippy/formatting, and 187 routing assertions in guarded Docker.
-[The exact test source](https://github.com/flyingrobots/echo/blob/bf11732478067e43dda400bab94aa0f6d186b614/crates/warp-core/tests/edict_byte_slice_tests.rs)
-retains literal outputs and bounds. This establishes that generic primitive on
-the named candidate; it does not migrate Jim's frozen evaluator pin, complete
-rope traversal, or admit an edit with Tick/WAL/receipt/recovery evidence.
-
-## Reproduction discipline
-
-Use copied inputs in the existing guarded project Docker worker. Do not build
-another image or use the older probe Dockerfiles as the default recipe: those
-historical recipes bake Cargo output into image layers. Reuse the compiler and
-provider only after identifying their exact source/build coordinates; retain
-outputs outside image layers in the project's bounded owned storage. Follow the
-shared lease, disk, memory, process, and log limits before invocation.
-
-Copy this directory and the unchanged application root into the worker, then
-run the following command inside the guarded lease. The compiler-source root
-must contain the copied `2405a550` tree; the provider root must be the pinned
-`49e9efb` package. Use a fresh `work-root` under the existing accounted directory.
-
-```sh
-python3 "$PROBE_ROOT/run.py" \
-  --compiler "$EDICT_BINARY" \
-  --compiler-source "$EDICT_SOURCE" \
-  --compiler-manifest "$PROBE_ROOT/evidence/compiler-source.json" \
-  --application-source "$APPLICATION_SOURCE" \
-  --provider-package "$PROVIDER_PACKAGE" \
-  --work-root /tmp/echo-726-runtime/jim-leaf-slice-proof
-```
-
-The source manifest is a read-only export of `git ls-tree -r` at `2405a550`,
-not a compiler input. Its retained formatting differs from the original run's
-manifest, so its raw file digest differs; its commit, tree, 440 paths, and blob
-identities are unchanged. Logs and an evidence JSON file remain under the work
-root. The runner's log-size check supplements the mandatory external resource
-guard; it is not a disk quota or permission to run without the guard.
-
-For the candidate build, use the exact `0835f398` compiler source and existing
-binary SHA-256 `a5ffea7b16b641448db4d5dc608bec1539211ab683df3ab78985e12bb1c2fd15`,
-select `evidence/candidate-compiler-source.json`, and add `--boundary package`.
-That manifest has the same formatting qualification as the RED manifest.
-Keep the provider unchanged: its manifest SHA-256 is
-`c5b9fb2fe3a0dc4dad282621a97413225c555be0071f3502b3272952069d42dc`.
-The runner records its actual hash and refuses mutation during the run.
-
-The public source RED, candidate package construction, and separately named
-generic runtime witness are established. Complete rope acceptance and an
-explicit consumer migration remain separate gates.
diff --git a/edict/replace-range-probes/leaf-slice/cases.json b/edict/replace-range-probes/leaf-slice/cases.json
deleted file mode 100644
index 298fb677..00000000
--- a/edict/replace-range-probes/leaf-slice/cases.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  "schema": "jedit.leaf-byte-slice-cases/v1",
-  "operation": "jedit.text.replace_range@1.sliceLeaf",
-  "cases": [
-    {"name": "empty-blob", "blobHex": "", "startByte": "0", "endByte": "0", "bytesHex": ""},
-    {"name": "full-blob", "blobHex": "61626364", "startByte": "0", "endByte": "4", "bytesHex": "61626364"},
-    {"name": "interior", "blobHex": "61626364", "startByte": "1", "endByte": "3", "bytesHex": "6263"},
-    {"name": "empty-interior", "blobHex": "61626364", "startByte": "2", "endByte": "2", "bytesHex": ""},
-    {"name": "empty-at-end", "blobHex": "61626364", "startByte": "4", "endByte": "4", "bytesHex": ""},
-    {"name": "binary-octets", "blobHex": "00017fff80", "startByte": "2", "endByte": "5", "bytesHex": "7fff80"},
-    {"name": "unicode-codepoint", "blobHex": "61f09f98ba62", "startByte": "1", "endByte": "5", "bytesHex": "f09f98ba"},
-    {"name": "inside-codepoint-remains-bytes", "blobHex": "61f09f98ba62", "startByte": "2", "endByte": "4", "bytesHex": "9f98"},
-    {"name": "reversed", "blobHex": "61626364", "startByte": "3", "endByte": "2", "refusal": "input-constraint"},
-    {"name": "end-past-blob", "blobHex": "61626364", "startByte": "1", "endByte": "5", "refusal": "input-constraint"},
-    {"name": "both-past-blob", "blobHex": "61626364", "startByte": "5", "endByte": "5", "refusal": "input-constraint"},
-    {"name": "u64-max", "blobHex": "61626364", "startByte": "0", "endByte": "18446744073709551615", "refusal": "input-constraint"}
-  ]
-}
diff --git a/edict/replace-range-probes/leaf-slice/evidence/candidate-artifacts/executable-operation-package.cbor b/edict/replace-range-probes/leaf-slice/evidence/candidate-artifacts/executable-operation-package.cbor
deleted file mode 100644
index fd9fa8b0..00000000
Binary files a/edict/replace-range-probes/leaf-slice/evidence/candidate-artifacts/executable-operation-package.cbor and /dev/null differ
diff --git a/edict/replace-range-probes/leaf-slice/evidence/candidate-artifacts/verification-report.cbor b/edict/replace-range-probes/leaf-slice/evidence/candidate-artifacts/verification-report.cbor
deleted file mode 100644
index dce05960..00000000
Binary files a/edict/replace-range-probes/leaf-slice/evidence/candidate-artifacts/verification-report.cbor and /dev/null differ
diff --git a/edict/replace-range-probes/leaf-slice/evidence/candidate-compiler-source.json b/edict/replace-range-probes/leaf-slice/evidence/candidate-compiler-source.json
deleted file mode 100644
index 7874a8f8..00000000
--- a/edict/replace-range-probes/leaf-slice/evidence/candidate-compiler-source.json
+++ /dev/null
@@ -1,451 +0,0 @@
-{
-  "commit": "0835f398336ce1c693b5531b262228cd909c0b4b",
-  "tree": "8f984b86c9053a9e570723271babeaaab12e140a",
-  "files": [
-    {"path":".cargo/config.toml","gitBlob":"5592118f6c54bf8b53b16848e04ece896dd56384"},
-    {"path":".github/workflows/auto-release-tag.yml","gitBlob":"87404ceb685191afd496c93494b0bc61e2a59504"},
-    {"path":".github/workflows/ci.yml","gitBlob":"c6c6a17f59b6b96db88e3d4b2775bc64b7fe01f3"},
-    {"path":".github/workflows/release.yml","gitBlob":"2c612fc786998bfa5b11e76ae1185114a7cc535f"},
-    {"path":".gitignore","gitBlob":"30d7faf0fc8b7f010f99280302d4ed269d5da9ba"},
-    {"path":".markdownlint.json","gitBlob":"f3ec2c8dc2fbacc425154a2baedec50c7474aefa"},
-    {"path":"AGENTS.md","gitBlob":"0c48a5794454cf84e20640994a372316efde7bb5"},
-    {"path":"ARCHITECTURE.md","gitBlob":"5b513dd25028092e7e75c8974f1d5f3cc31889ed"},
-    {"path":"CHANGELOG.md","gitBlob":"e25e1b88744ad3972a51bfde03fb24219a009f79"},
-    {"path":"CODE_OF_CONDUCT.md","gitBlob":"784cf2799bcf8d2a69db5f5781359ef7e18a05fc"},
-    {"path":"CONTRIBUTING.md","gitBlob":"9676914060f734dc59eabd9075898dc8170d4d19"},
-    {"path":"Cargo.lock","gitBlob":"bacb208de0583f182379af7b5e078d31b25e2ca5"},
-    {"path":"Cargo.toml","gitBlob":"b2e7106eb78f79230c091492ef21b497bdc9ed19"},
-    {"path":"EDICT.md","gitBlob":"35376134195082d506f0161ba7ecb97efa8b770a"},
-    {"path":"LICENSE","gitBlob":"261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64"},
-    {"path":"NOTICE","gitBlob":"c300687bdd9d931d1f257d291e1cb6ff9d7d3607"},
-    {"path":"README.md","gitBlob":"0812ef9a0c4611bf655dfc67d2ecc3631af9a536"},
-    {"path":"ROADMAP.md","gitBlob":"d0e0135780537afab1d1a3f53808b363b35a63f4"},
-    {"path":"SECURITY.md","gitBlob":"0bcc4e7375442e1334405a2d046df316cee05cd5"},
-    {"path":"crates/edict-cli/Cargo.toml","gitBlob":"e9d844553c395bd312f84e806eb5bac30c5c3a54"},
-    {"path":"crates/edict-cli/src/application_build.rs","gitBlob":"9c56ae6b4dd4eef0b9fe6db40316e100b2ffa699"},
-    {"path":"crates/edict-cli/src/lawpack_build.rs","gitBlob":"55e9579153f34a3d5b139141c9de6640808cd386"},
-    {"path":"crates/edict-cli/src/lawpack_build_windows.rs","gitBlob":"f71d03b368ae83becc1608bbba11cd5f1afa4f07"},
-    {"path":"crates/edict-cli/src/lib.rs","gitBlob":"60883af60cf4b441680952ecce7ef4fcbfeabb97"},
-    {"path":"crates/edict-cli/src/main.rs","gitBlob":"0dd9776642c4090479322111e4164ee7049fb9d0"},
-    {"path":"crates/edict-cli/tests/golden_cli.rs","gitBlob":"9897caad3bcc6fa8bb0f20a1d0e18032285b1fa7"},
-    {"path":"crates/edict-cli/tests/jsonl_cli.rs","gitBlob":"9ed353ca27d073fc7da49d3800c81ba4c58edd5d"},
-    {"path":"crates/edict-cli/tests/lawpack_authoring_cli.rs","gitBlob":"dd7d7bfebf0e051c77d894a55c0204d373b19c63"},
-    {"path":"crates/edict-provider-host-wasmtime/Cargo.toml","gitBlob":"ebeeb941f09012293d9923fe0e6039b2761b328e"},
-    {"path":"crates/edict-provider-host-wasmtime/src/conversion.rs","gitBlob":"62c3cd4a85eb156b8c9a405ef3ea4d8a09b80cc3"},
-    {"path":"crates/edict-provider-host-wasmtime/src/invocation.rs","gitBlob":"a4d6680d289094afebc0f1063abccf706f8149db"},
-    {"path":"crates/edict-provider-host-wasmtime/src/lib.rs","gitBlob":"353ea7394f265219ebdecad56a3070c9e7d2685c"},
-    {"path":"crates/edict-provider-host-wasmtime/src/limits.rs","gitBlob":"9e4d12c1b606d2b180f732db17bfbc78f8e26e3a"},
-    {"path":"crates/edict-provider-host-wasmtime/src/replay.rs","gitBlob":"b8fa7be7c7ee5039793dad4cd0fa6a4f14ce388e"},
-    {"path":"crates/edict-provider-host-wasmtime/tests/invocation.rs","gitBlob":"7a59a3192852a80bc01221ebf3dd1c437bda9508"},
-    {"path":"crates/edict-provider-host-wasmtime/tests/preflight.rs","gitBlob":"a295e7547b0294f0355a85d5b9b8d045c8fceefd"},
-    {"path":"crates/edict-provider-schema/Cargo.toml","gitBlob":"0e74f58acdc054ecce192cb8341afeaddc40deb5"},
-    {"path":"crates/edict-provider-schema/src/contract_pack.rs","gitBlob":"370480d9c606134dd08ee62ae29ef143941e2f54"},
-    {"path":"crates/edict-provider-schema/src/lib.rs","gitBlob":"51f5bee8892c9fb2122cb20022edc4d414759ff7"},
-    {"path":"crates/edict-provider-schema/src/recursive_dispatch.rs","gitBlob":"6d97565b96f941b359d16f7a1c201189968fbeff"},
-    {"path":"crates/edict-provider-schema/src/schema_safety.rs","gitBlob":"a2f605f62a2bfedcb84b68e37db9ff84b1dc3b05"},
-    {"path":"crates/edict-provider-schema/tests/authority_facts_abi.rs","gitBlob":"7dd4d0302805ceecffc2045cdb91e386f8e08517"},
-    {"path":"crates/edict-provider-schema/tests/provider_contract_pack.rs","gitBlob":"a26be8054b39215048825dd8cae7e9bddcfe27c9"},
-    {"path":"crates/edict-provider-schema/tests/registry.rs","gitBlob":"bdd13ec00e441aef9e67ba49f6592ecbc7dcb303"},
-    {"path":"crates/edict-syntax/Cargo.toml","gitBlob":"f55bb23e528af78b1e97b52f9b72cbd876a44ba7"},
-    {"path":"crates/edict-syntax/src/admission.rs","gitBlob":"471430dd13a617bac886fcd44afbf15263e7db3b"},
-    {"path":"crates/edict-syntax/src/ast.rs","gitBlob":"2a5d208a53a82408f8a18d9a13ccb133ec6a7a2e"},
-    {"path":"crates/edict-syntax/src/authority_facts.rs","gitBlob":"644de86d63983bdbfbf1279fdbf1dbdaecc151d5"},
-    {"path":"crates/edict-syntax/src/canonical.rs","gitBlob":"6fb29d50ea4a55eb888a1b9600cdcb31713a6e20"},
-    {"path":"crates/edict-syntax/src/compiler.rs","gitBlob":"ad3efd3e92c23a54a9a279cbfa22b108895af3fb"},
-    {"path":"crates/edict-syntax/src/compiler/byte_length.rs","gitBlob":"0d8d6291064415baee9253d9fe1e11ad87945773"},
-    {"path":"crates/edict-syntax/src/compiler/byte_slice.rs","gitBlob":"3a634d5d6d0fe1d89bb6a8218261326b898a1a2d"},
-    {"path":"crates/edict-syntax/src/compiler/unsigned_subtraction.rs","gitBlob":"c2ef2deda74afb52e4346076a310df341556e1c8"},
-    {"path":"crates/edict-syntax/src/contract_bundle.rs","gitBlob":"9a31645f0e30879d019787e29c21c82eebf58129"},
-    {"path":"crates/edict-syntax/src/core_ir.rs","gitBlob":"119d69b75914db1357030ccc5aecb90448fe8f24"},
-    {"path":"crates/edict-syntax/src/highlight.rs","gitBlob":"28b3f7dcdfe8d4982bdcfb05759f769ccdbffc7f"},
-    {"path":"crates/edict-syntax/src/lawpack.rs","gitBlob":"54f85bda48c960ad0b7bc316d332b379ab5b6ae0"},
-    {"path":"crates/edict-syntax/src/lawpack_adapter.rs","gitBlob":"e425960e2437faa2f9eeb5d089ff507417d39586"},
-    {"path":"crates/edict-syntax/src/lawpack_authoring.rs","gitBlob":"11ff578f458b8a4c8e4df75c0c616e37fa468d49"},
-    {"path":"crates/edict-syntax/src/lib.rs","gitBlob":"7323475cc7f846e11c2d73f4c26a5e581b7e6157"},
-    {"path":"crates/edict-syntax/src/lowerability.rs","gitBlob":"c6a1323fd6a79b0460b43aaf338956c3906a633e"},
-    {"path":"crates/edict-syntax/src/parser.rs","gitBlob":"0b3650e3012e49023ccbb9cc9effe9b5b102f19d"},
-    {"path":"crates/edict-syntax/src/provider.rs","gitBlob":"18fa661d880979c53dd335fb7e68d5445b638d4c"},
-    {"path":"crates/edict-syntax/src/provider_invocation.rs","gitBlob":"2526168f0a6f2d1d9b6181b689ff43e203434122"},
-    {"path":"crates/edict-syntax/src/provider_lowering.rs","gitBlob":"50a4e60b561127cb8c78e3f7c04c6bbaca068e52"},
-    {"path":"crates/edict-syntax/src/result_projection.rs","gitBlob":"79ba246d4c58960fe368eaca4c7d135fe187832a"},
-    {"path":"crates/edict-syntax/src/semantic.rs","gitBlob":"76bd133ef5859bf7722d1987613f7fd84836ab62"},
-    {"path":"crates/edict-syntax/src/target_ir.rs","gitBlob":"c322a874d8a2341ae46a99b1b62eb952f4a49dfe"},
-    {"path":"crates/edict-syntax/src/target_ir/byte_length.rs","gitBlob":"972e6ffa943bc7a7a943d76f0af42b342e3d2aac"},
-    {"path":"crates/edict-syntax/src/target_ir/byte_slice.rs","gitBlob":"62a1c0b9e84a331bb17ab78090cce6d8eb8da486"},
-    {"path":"crates/edict-syntax/src/target_ir/execution_order.rs","gitBlob":"e69a28805dc5e414a64afdaafee34161c217a044"},
-    {"path":"crates/edict-syntax/src/target_ir/totality.rs","gitBlob":"c32fe501838ce3e3979917e0aa1da67bb0cd68da"},
-    {"path":"crates/edict-syntax/src/target_ir/unsigned_subtraction.rs","gitBlob":"b83522bfe9a2b506413b4d306f4bc49f8b053f36"},
-    {"path":"crates/edict-syntax/src/target_profile.rs","gitBlob":"dd514f7380243e795f0655a78aecd06ee3fa2eda"},
-    {"path":"crates/edict-syntax/src/target_profile_contract_resources.rs","gitBlob":"4efd22961c2fd7591440efd6087944ecaf21e991"},
-    {"path":"crates/edict-syntax/src/token.rs","gitBlob":"2768586eea6d42d5df357c4cc62a011ee7f455de"},
-    {"path":"crates/edict-syntax/tests/admission.rs","gitBlob":"57edbc320307c1d6daba85f03d8dc79558d7b849"},
-    {"path":"crates/edict-syntax/tests/authority_facts.rs","gitBlob":"add9d272be6e8eb1cd6fdde2999a5fb452ecd852"},
-    {"path":"crates/edict-syntax/tests/authority_facts_cbor.rs","gitBlob":"7359f047d9f731fee208efb5f69072b612d69547"},
-    {"path":"crates/edict-syntax/tests/byte_length.rs","gitBlob":"50945944e8c2223abcc6b1081322432bc540c017"},
-    {"path":"crates/edict-syntax/tests/byte_slice.rs","gitBlob":"65541ea8ddff550ddb8dfed27f03bf186792e71a"},
-    {"path":"crates/edict-syntax/tests/canonical_encoding.rs","gitBlob":"e4c5d59a88f88193f522eb555359919f7034a264"},
-    {"path":"crates/edict-syntax/tests/common/mod.rs","gitBlob":"89560bfacb3dab031485c2dfa30d7eb325966574"},
-    {"path":"crates/edict-syntax/tests/compiler_spine.rs","gitBlob":"2237318cfc0d4209e8a629e45320e42a4b72dbef"},
-    {"path":"crates/edict-syntax/tests/contract_bundle.rs","gitBlob":"e6a2948335a0efc86d8bbb2e9e2c3d634e53965a"},
-    {"path":"crates/edict-syntax/tests/core_golden_fixtures.rs","gitBlob":"0e0e42d19b52dc0557902dad9e1b85f37edf53f8"},
-    {"path":"crates/edict-syntax/tests/external_action_requests.rs","gitBlob":"3c07be4db0bfc49e67c2d7e1eda0ac0397987a37"},
-    {"path":"crates/edict-syntax/tests/highlighting.rs","gitBlob":"17e6b9ba08c96f0efb6efd440590f0fc917316e2"},
-    {"path":"crates/edict-syntax/tests/lawpack.rs","gitBlob":"a675999ed96309358c8552a9d32781b5eede20dc"},
-    {"path":"crates/edict-syntax/tests/lawpack_authoring.rs","gitBlob":"3a905cbd6d7d2625bc1d7826a6f6f1e991efbab0"},
-    {"path":"crates/edict-syntax/tests/lowerability.rs","gitBlob":"5cfa58f5cbc51cccc7f119caddc1c3fcbc2e4806"},
-    {"path":"crates/edict-syntax/tests/operation_prerequisites.rs","gitBlob":"753659e1a6e7751c455b8518226fa0902157a745"},
-    {"path":"crates/edict-syntax/tests/parse_control_flow.rs","gitBlob":"5245561866d8902c1fbd5ab21f2e34807d568e17"},
-    {"path":"crates/edict-syntax/tests/parse_greeting.rs","gitBlob":"f214d0c17745b8203d562780caa8f37b71c1e62c"},
-    {"path":"crates/edict-syntax/tests/parse_hello.rs","gitBlob":"bf7b1b065277188f4be8754eb11ace94298394ba"},
-    {"path":"crates/edict-syntax/tests/parse_keywords.rs","gitBlob":"78d8a64d785136d42a32655afda3df240c54f884"},
-    {"path":"crates/edict-syntax/tests/parse_loops.rs","gitBlob":"d9ece2fce96fd6835d080055f06955d139c7e0ce"},
-    {"path":"crates/edict-syntax/tests/parse_negative.rs","gitBlob":"17fdb983b8250470368a8f19d3a7bd9680052548"},
-    {"path":"crates/edict-syntax/tests/parse_review_regressions.rs","gitBlob":"560215cfe044a528e190aa1ea7670e52b9365bdf"},
-    {"path":"crates/edict-syntax/tests/parse_variants.rs","gitBlob":"8849f68f5ca1e2b06d0f66496e59b20d1c0fd022"},
-    {"path":"crates/edict-syntax/tests/provider.rs","gitBlob":"7e8a596109b1e1fd3f22b3a0ef82f4755f127291"},
-    {"path":"crates/edict-syntax/tests/provider_invocation.rs","gitBlob":"402647dd6701be65a9e693fd3f5688f26d84988e"},
-    {"path":"crates/edict-syntax/tests/provider_lowering.rs","gitBlob":"411c306f3ab641de9dc2f7aed229767eba9dbd72"},
-    {"path":"crates/edict-syntax/tests/result_projection.rs","gitBlob":"a74dd2a419266cb77d846d83da27f726095660f1"},
-    {"path":"crates/edict-syntax/tests/semantic_validation.rs","gitBlob":"a127988d178c00ed12a0a25f70df6b7fd5e6d931"},
-    {"path":"crates/edict-syntax/tests/target_ir.rs","gitBlob":"928e1cf921dead0b559bd115bb6eef3faaddd37e"},
-    {"path":"crates/edict-syntax/tests/target_ir/ordered.rs","gitBlob":"a1b05db81a97a43ec5a2dc2d9bcc9578bc286f30"},
-    {"path":"crates/edict-syntax/tests/target_profile.rs","gitBlob":"42f1c907f6c60dea1e8a9b4558b56ffd0b3a59ab"},
-    {"path":"crates/edict-syntax/tests/target_profile_contract_resources.rs","gitBlob":"270c180a12dc10fb7e208cc4dc1e202da82c85fb"},
-    {"path":"crates/edict-syntax/tests/target_unsigned_subtraction.rs","gitBlob":"e30d91f896afda48eb3cf11617bccf1f9d160e32"},
-    {"path":"crates/edict-syntax/tests/unsigned_subtraction.rs","gitBlob":"fbd24482fdad4c8ceb4df41302b33595ada337ec"},
-    {"path":"crates/edict/Cargo.toml","gitBlob":"525403f4f36db4040531e4dd747ec2398f9052cd"},
-    {"path":"crates/edict/README.md","gitBlob":"a1ecf50bff3443d25a23fabfa6374d3f0a28ca82"},
-    {"path":"crates/edict/src/lib.rs","gitBlob":"169d820759d6333f27a45ebb712bfcc4f0115107"},
-    {"path":"crates/edict/tests/artifact_models.rs","gitBlob":"b923109c7195ce2c0071dc54179f0746b95329f0"},
-    {"path":"crates/edict/tests/public_surface.rs","gitBlob":"a24c4bc9d9484f540da9b280790896701922968a"},
-    {"path":"deny.toml","gitBlob":"e3f0f54060cead9a0d48b96ed86948d0909c4f78"},
-    {"path":"docs/DESIGN_runtime-neutral-edict-sha-lock-assurance.md","gitBlob":"ea3badf78ebd19545147a93671fdb5f9af4a61ea"},
-    {"path":"docs/GUIDE_edict-assurance-transparency.md","gitBlob":"100321157ec43055c45794f1c161b1e5281ba6b4"},
-    {"path":"docs/README.md","gitBlob":"e21739b842be14d91a17f2508b1a1b629754af01"},
-    {"path":"docs/REQUIREMENTS.md","gitBlob":"52d98fecd60eb04ce55105ae2eb33997248698cb"},
-    {"path":"docs/RETRO_phase1-parser.md","gitBlob":"5cfb7b85ca2f140fc58f9186c47e4635e94a1e6f"},
-    {"path":"docs/SPEC_continuum-admission-v1.md","gitBlob":"0a74a0bfc642337d5d7a85133ce50a0a22caffbd"},
-    {"path":"docs/SPEC_continuum-contract-bundle-v1.md","gitBlob":"65b36bb33a34beb1f246d1f97384631c83ca631e"},
-    {"path":"docs/SPEC_edict-language-v1.md","gitBlob":"1575bc83ae20eec154d09333d59e240162057633"},
-    {"path":"docs/SPEC_edict-lawpack-abi-v1.md","gitBlob":"ea1d801f07ab3677f7a411a1f58a28feda589ec3"},
-    {"path":"docs/SPEC_edict-target-profile-abi-v1.md","gitBlob":"91687bfe45565a21f5f93f6ce9eed84095268691"},
-    {"path":"docs/TECHNICAL_EXPLANATION.md","gitBlob":"d88561c0552c0e75d1ecc2eef6f9afd003e99674"},
-    {"path":"docs/abi/edict-authority-facts.cddl","gitBlob":"e9a6d8685706ae0d8dabda401655234161e94299"},
-    {"path":"docs/abi/edict-common.cddl","gitBlob":"836c11b92425beb6d42b378c0defe6f02d144dd7"},
-    {"path":"docs/abi/edict-core.cddl","gitBlob":"862f02939fcc3858b4a60cb75f9bf149eae8ffda"},
-    {"path":"docs/abi/edict-lawpack-adapter.cddl","gitBlob":"8e887c2e196ba7502470ddb45dc7cfd10116ad6b"},
-    {"path":"docs/abi/edict-lawpack.cddl","gitBlob":"96efd51d437ec785b108b51835e9e8bf87aeab51"},
-    {"path":"docs/abi/edict-result-projection.cddl","gitBlob":"98b5c2e861e7e9b66b7481502287cb041f6e77e6"},
-    {"path":"docs/abi/edict-target-ir.cddl","gitBlob":"98134f277ded1920a3a36e5e3946c51153f2e84d"},
-    {"path":"docs/abi/edict-target-profile.cddl","gitBlob":"746ae03001310f3a83524e5332819dad1a4eea5a"},
-    {"path":"docs/abi/edict-target-provider.wit","gitBlob":"0efa5903a52d38dc61e429619d86322c6c5f1fa0"},
-    {"path":"docs/audit/2026-06-28_code-quality.md","gitBlob":"143cbf4f4491a76a6649e919c6edaba73f0bcf4b"},
-    {"path":"docs/audit/2026-06-28_documentation-quality.md","gitBlob":"656b4fa8dea43306af1818f8622cafd72e82a370"},
-    {"path":"docs/audit/2026-06-28_ship-readiness.md","gitBlob":"b9d34a8693564d0134f550092e7645e5d5137442"},
-    {"path":"docs/design/authority-fact-governance.md","gitBlob":"8531061cf718c47ec791f5712b2f357d92adc9e4"},
-    {"path":"docs/design/canonical-target-ir-v0.11.md","gitBlob":"a46acb84e3523b51e2348c776cfdb63a8b98107a"},
-    {"path":"docs/design/contract-bundle-assembly-v0.11.md","gitBlob":"a364f8ade5445808f87cf0c63ab3484c03ad616a"},
-    {"path":"docs/design/crate-scope-v0.11.md","gitBlob":"92fe92285d02465d84bbe82e29d051fdc461f3a6"},
-    {"path":"docs/design/obstruction-strands-v0.md","gitBlob":"81f70fd688c12798cd23472a4e810191e61eabe2"},
-    {"path":"docs/design/provider-artifact-pipeline-alpha.md","gitBlob":"60eefa7dc160aba986bcd1188b79610ff5e9f299"},
-    {"path":"docs/design/schema-as-sot-codegen.md","gitBlob":"d818e0e3f1fafd1d3aba26cb37c739f3ebe69763"},
-    {"path":"docs/design/v2-obligation-closure.md","gitBlob":"816d22d843a33c6f7e143da4cb45e80679609dc8"},
-    {"path":"docs/releases/v0.1.0-alpha.1.md","gitBlob":"5dd96057ba7f109cf5e5acde16e29d18627f98d3"},
-    {"path":"docs/releases/v0.10.0-alpha.1.md","gitBlob":"363c4e9ed6f5ea5758198c7124681b520098e583"},
-    {"path":"docs/releases/v0.11.0-alpha.1.md","gitBlob":"4612dbb5a1aaf20710bdb199b658ded7ced4ebab"},
-    {"path":"docs/releases/v0.2.0-alpha.1.md","gitBlob":"7302ef93ed5ff9b562d9cec92d49d85a6b789b27"},
-    {"path":"docs/releases/v0.3.0-alpha.1.md","gitBlob":"bf023ba4ca2c38f0120c461781447d58fe239ae0"},
-    {"path":"docs/releases/v0.4.0-alpha.1.md","gitBlob":"769500b59800c02c536b76b0eb850d06d6cd8f58"},
-    {"path":"docs/releases/v0.5.0-alpha.1.md","gitBlob":"7c7354e89846ea816992aaf55d4ad04367d61a10"},
-    {"path":"docs/releases/v0.6.0-alpha.1.md","gitBlob":"3f2a0edfc4bccd9f3c60a7443ef4f8cbcbac1971"},
-    {"path":"docs/releases/v0.7.0-alpha.1.md","gitBlob":"57671d5ef5a6b9f16d1674e0a35ddeb86ff126a8"},
-    {"path":"docs/releases/v0.8.0-alpha.1.md","gitBlob":"12f77bda185c54fbbd136bf0dc7292716ecdfa39"},
-    {"path":"docs/releases/v0.9.0-alpha.1.md","gitBlob":"fa295fcf0967415bb052f238256919b32b3fe6ba"},
-    {"path":"docs/schemas/edict.cli-check-result.v1.schema.json","gitBlob":"eef8cd11f07e06d68b7051efa60ae05f2cfd8a63"},
-    {"path":"docs/schemas/edict.cli-diagnostic.v1.schema.json","gitBlob":"92a2151a76893c598a4191ed6cecd8a0e671613f"},
-    {"path":"docs/schemas/edict.cli-event.v1.schema.json","gitBlob":"705d82a893c2ea91caa91ad6977a9be8646b47bb"},
-    {"path":"docs/schemas/edict.cli-info.v1.schema.json","gitBlob":"2d9a0777b4190b56ff569625275d352d17363afa"},
-    {"path":"docs/schemas/edict.compiler-input.v1.schema.json","gitBlob":"26da3ba0fe85fab4c826ad79f13968ce09c4f29b"},
-    {"path":"docs/schemas/edict.compiler-settings.v1.schema.json","gitBlob":"a3e8ba469895b84ab81724da1075c73141a8dd0c"},
-    {"path":"docs/schemas/edict.projection-core.v1.schema.json","gitBlob":"8c0afe3834256abd1e18efb5f31eae1c4bdf0374"},
-    {"path":"docs/schemas/edict.projection-diagnostics.v1.schema.json","gitBlob":"28cfb0a67dff7b8f879122c74433158dc0a4e5df"},
-    {"path":"docs/schemas/edict.projection-syntax.v1.schema.json","gitBlob":"a85f2e14f536863f5e7b107b1a9f3f10816e6234"},
-    {"path":"docs/schemas/edict.projection-target-ir.v1.schema.json","gitBlob":"8bbb6495ad8800d775d1c08506e85351038d678a"},
-    {"path":"docs/topics/README.md","gitBlob":"99b06d3124c71cb62dfe6faff7604c13063162a7"},
-    {"path":"docs/topics/admission/README.md","gitBlob":"755dcba96c0a428eec18d58a529f3e26d57d118c"},
-    {"path":"docs/topics/admission/test-plan.md","gitBlob":"68ee0a2d2502103285985bf862de9fadf2bac5a0"},
-    {"path":"docs/topics/assurance/README.md","gitBlob":"cf382008f3d3094a5380a687abbf07538e07404d"},
-    {"path":"docs/topics/assurance/test-plan.md","gitBlob":"0ea6c971924db763088577a0a52bbd30bfec814c"},
-    {"path":"docs/topics/authority-facts/README.md","gitBlob":"c5589d2489d6e4a5729c0df2b2655ff281d8d88d"},
-    {"path":"docs/topics/authority-facts/test-plan.md","gitBlob":"e3769edf8309347b23ffa2e8f0901e06feabd654"},
-    {"path":"docs/topics/cli/README.md","gitBlob":"af38946c9ccae8da343877c3861b0f52b6076e1b"},
-    {"path":"docs/topics/cli/test-plan.md","gitBlob":"d72d69ef1d340ffd7057a63dd7bc07e3dfb2c166"},
-    {"path":"docs/topics/compiler-spine/README.md","gitBlob":"8ecdf52fb0d75a7082906916de5fc02812c95a49"},
-    {"path":"docs/topics/compiler-spine/test-plan.md","gitBlob":"99fb5b94194292f12def0924d9d49e61c0dbb3d1"},
-    {"path":"docs/topics/contract-bundles/README.md","gitBlob":"2347499e8da9dd57bb1588faf67fe386c7a70c03"},
-    {"path":"docs/topics/contract-bundles/test-plan.md","gitBlob":"3ae4c7362f90fa89081ab9ff2bf1c3db1a811874"},
-    {"path":"docs/topics/core-ir/README.md","gitBlob":"a8759d0f26569a60590792aadc9ba28d8daea004"},
-    {"path":"docs/topics/core-ir/canonical-encoding.md","gitBlob":"34927c69fb1de10b685294a155fc46bb4ac21628"},
-    {"path":"docs/topics/core-ir/test-plan.md","gitBlob":"00d55085e24a6639b02558ea48af68beea97cb65"},
-    {"path":"docs/topics/developer-tooling/README.md","gitBlob":"8648d3c1bdf4f6b774bc5fec71c71aa8c59b0ce8"},
-    {"path":"docs/topics/developer-tooling/test-plan.md","gitBlob":"9240f717434dfbca08a6366e6d3ebafd4ef2c908"},
-    {"path":"docs/topics/documentation/README.md","gitBlob":"34fa7f4db136c274a88b680f99619d657fda15d5"},
-    {"path":"docs/topics/documentation/test-plan.md","gitBlob":"47964954fbf640211bc30b0dd361c44c9955c488"},
-    {"path":"docs/topics/external-action-requests/README.md","gitBlob":"73aae64e1adb730c00b680d18aea76f64adc23cb"},
-    {"path":"docs/topics/external-action-requests/test-plan.md","gitBlob":"438184fc13353250a0c0976e3c3cc8cba605fa00"},
-    {"path":"docs/topics/fixtures/README.md","gitBlob":"c8b3b196109fb6d4e37d8ffa17635166010075fb"},
-    {"path":"docs/topics/fixtures/test-plan.md","gitBlob":"624357dbc544d365835390d3d3c2f11015b7b82f"},
-    {"path":"docs/topics/lawpack-authoring/README.md","gitBlob":"74bb25cc22e1f88cf4ee952b42313d919339113a"},
-    {"path":"docs/topics/lawpack-authoring/test-plan.md","gitBlob":"d7ad2eacde45dbce3eeb2b1a22c6482134b841ba"},
-    {"path":"docs/topics/lawpacks/README.md","gitBlob":"dedaa524dc55663a44bf8101241ab4b6d4755531"},
-    {"path":"docs/topics/lawpacks/test-plan.md","gitBlob":"f8aa2c7ce40dad2665134956dc95d951d311808f"},
-    {"path":"docs/topics/lowerability/README.md","gitBlob":"fb9519af3539d846dc5bf2915bf5ca86816e46f8"},
-    {"path":"docs/topics/lowerability/test-plan.md","gitBlob":"e0fbff0799ba805c9531097d6b8aeea657e2b815"},
-    {"path":"docs/topics/obstruction-strands/README.md","gitBlob":"a2930645065390cecff8008bfd48b7f034bfcd18"},
-    {"path":"docs/topics/obstruction-strands/test-plan.md","gitBlob":"20c54ffcaa19930a5bc772a49a5f01119054be2d"},
-    {"path":"docs/topics/providers/README.md","gitBlob":"8b5a07fb9c708b753861a4e156b866115f4d687b"},
-    {"path":"docs/topics/providers/architecture.md","gitBlob":"664b38347ccaf37f298d6ac9f19d3423c0277f9e"},
-    {"path":"docs/topics/providers/test-plan.md","gitBlob":"95c55f9e132ca6859fd9df70470973e678ed8d92"},
-    {"path":"docs/topics/public-rust-api/README.md","gitBlob":"c64a1081b7f693b02bd2ea63329f2610bae9d84c"},
-    {"path":"docs/topics/public-rust-api/test-plan.md","gitBlob":"4c3b9e9662afd9edb790ba2b5c57ed5e93df595c"},
-    {"path":"docs/topics/release-process/README.md","gitBlob":"a474ab8b6a4a58c5c73334c9e677be7c20d1837c"},
-    {"path":"docs/topics/release-process/policy.toml","gitBlob":"e40b4f4ec721ae61210ec1bb022a847bcb49fb4a"},
-    {"path":"docs/topics/release-process/runbook.md","gitBlob":"0b6bd8ef44cbfe8c7cdc347273fa74b7c96c4823"},
-    {"path":"docs/topics/release-process/test-plan.md","gitBlob":"61ecded1d2318d7dd74070cd1c6155f353c947e9"},
-    {"path":"docs/topics/result-projections/README.md","gitBlob":"d5c2f85a7681a15dcdc3e35f992a389c50d13461"},
-    {"path":"docs/topics/result-projections/test-plan.md","gitBlob":"9e69d58c88d6a9b7389334a78b994a3449721faa"},
-    {"path":"docs/topics/review-process/README.md","gitBlob":"25190d37dc30110f75ba5d3a41494575ffecc1c3"},
-    {"path":"docs/topics/review-process/policy.toml","gitBlob":"a826ba58aad2e509220b65aa8f96c290b600e094"},
-    {"path":"docs/topics/review-process/test-plan.md","gitBlob":"f1a50aeae47913e4513a8149c1679d9a94c5ef21"},
-    {"path":"docs/topics/rust-standards/README.md","gitBlob":"2fe29258705d117f4d10604a83fd832a8476e303"},
-    {"path":"docs/topics/rust-standards/test-plan.md","gitBlob":"0e0d6b306cd2b58db07a7a5da6a752925fe58764"},
-    {"path":"docs/topics/semantic-validation/README.md","gitBlob":"51cd9761755e7b5879069bf3774eeb487982ca97"},
-    {"path":"docs/topics/semantic-validation/test-plan.md","gitBlob":"b43969d8eb0a884c1663ab761662f9622617bb3b"},
-    {"path":"docs/topics/syntax/README.md","gitBlob":"b2a372bf41b1976567c61f400bf000f33abc20cc"},
-    {"path":"docs/topics/syntax/test-plan.md","gitBlob":"a69efaf12dfe12661fca049b8790b37fa3fb3665"},
-    {"path":"docs/topics/target-ir/README.md","gitBlob":"f904839af7a5136af9430a0efc1f28e0adfa63c7"},
-    {"path":"docs/topics/target-ir/test-plan.md","gitBlob":"cb0b736f4a68effb0d44ca70cc7bc27ae2b4cc37"},
-    {"path":"docs/topics/target-profiles/README.md","gitBlob":"6a88f4d732f8069855b2ed2cb9a8769a117b2f60"},
-    {"path":"docs/topics/target-profiles/test-plan.md","gitBlob":"90084c3f3a1296745469cd86e9b5f2bc928825be"},
-    {"path":"docs/topics/tests/README.md","gitBlob":"4ad079b6a9718e2a8446a6c67ff45735015bef84"},
-    {"path":"docs/topics/tests/test-plan.md","gitBlob":"46bc0572d02a41e86f71c6d46baf5be611a462a6"},
-    {"path":"docs/topics/v2-design/README.md","gitBlob":"b33a07599e43e660aa4def7f119ddd02df6a16de"},
-    {"path":"docs/topics/v2-design/test-plan.md","gitBlob":"f17f96d381f81b20842393f70ff55b9597858b84"},
-    {"path":"editors/README.md","gitBlob":"7a933576262bc58bac197f9264fdbf649dd5e696"},
-    {"path":"editors/vscode/.vscodeignore","gitBlob":"f15b3142e4b8af11d580789a0c82acee3499f571"},
-    {"path":"editors/vscode/README.md","gitBlob":"8b29840ae9ec8f618b7364022329f694d0ed9746"},
-    {"path":"editors/vscode/language-configuration.json","gitBlob":"b7f583841649c9c437785edbfcb70ee24e495c79"},
-    {"path":"editors/vscode/package.json","gitBlob":"cd9e391e7c9afb6f9393fcead118e0e55aadc839"},
-    {"path":"editors/vscode/syntaxes/edict.tmLanguage.json","gitBlob":"5847d8edfdb32d822f0f3950f41d00c947982185"},
-    {"path":"fixtures/README.md","gitBlob":"470e3e0fc3aa00654930ecdef892ee9df8a42c8d"},
-    {"path":"fixtures/authority-facts/canonical/README.md","gitBlob":"28692ce70add5d4f2d4ff5318309c3353924caf9"},
-    {"path":"fixtures/authority-facts/canonical/example-effectful.authority-facts.cbor","gitBlob":"fe2e59a8e2602e02c52094010a130db2637c5227"},
-    {"path":"fixtures/authority-facts/canonical/example-effectful.authority-facts.json","gitBlob":"009faa5d2dc1dcf55cf284dcfd14c0b6405f3e0d"},
-    {"path":"fixtures/authority-facts/canonical/example-effectful.authority-facts.sha256","gitBlob":"a3d68f0a3b3a586e85b6a84cbd884866e662951f"},
-    {"path":"fixtures/bundle/assembly/bounded-hello.bundle-digests.txt","gitBlob":"da5402db7bd41dd88c6152b7799723561130c91e"},
-    {"path":"fixtures/cli/01-source-ok/expected.stdout.jsonl","gitBlob":"e08ccf8fdedd3a73beef5d06c443a1bc60274ce1"},
-    {"path":"fixtures/cli/01-source-ok/request.jsonl","gitBlob":"002fea597e6b93c8468d6972b73cc1344600fa87"},
-    {"path":"fixtures/cli/02-source-parse-rejection/exit","gitBlob":"d00491fd7e5bb6fa28c517a0bb32b8b506539d4d"},
-    {"path":"fixtures/cli/02-source-parse-rejection/expected.stderr.jsonl","gitBlob":"1077b73c9a7c02eae99f737bea7b6ff8c64d04da"},
-    {"path":"fixtures/cli/02-source-parse-rejection/request.jsonl","gitBlob":"dce01f0466bd9384fc6f5cbe2845b6e0bd9a9cfd"},
-    {"path":"fixtures/cli/03-source-semantic-rejection/exit","gitBlob":"d00491fd7e5bb6fa28c517a0bb32b8b506539d4d"},
-    {"path":"fixtures/cli/03-source-semantic-rejection/expected.stderr.jsonl","gitBlob":"5ec447700da52d0b4ce1f75825eb9bffaed4884b"},
-    {"path":"fixtures/cli/03-source-semantic-rejection/request.jsonl","gitBlob":"ddfd529e5448760387961febbd4ce013e49de435"},
-    {"path":"fixtures/cli/04-cli-missing-settings/exit","gitBlob":"0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"},
-    {"path":"fixtures/cli/04-cli-missing-settings/expected.stderr.jsonl","gitBlob":"5060bd2fd773ba9ea3ea6db8c80b86a846bfadbd"},
-    {"path":"fixtures/cli/04-cli-missing-settings/request.jsonl","gitBlob":"8eb12e58d427bd64ccfe339190e05bdccf4c8634"},
-    {"path":"fixtures/cli/05-path-input-ok/expected.stdout.jsonl","gitBlob":"a05fc582efc41b6414e785167b5deeb7532088ef"},
-    {"path":"fixtures/cli/05-path-input-ok/inputs/hello.edict","gitBlob":"39c53bb184a7c10de61da0c637b607eb1d7cc454"},
-    {"path":"fixtures/cli/05-path-input-ok/request.jsonl","gitBlob":"18facaab79dc198134c535df389cba79efe7dce7"},
-    {"path":"fixtures/cli/06-directory-expansion-ok/expected.stdout.jsonl","gitBlob":"ef59591526e2084ddf5057249bbc96ab660cf256"},
-    {"path":"fixtures/cli/06-directory-expansion-ok/inputs/a.edict","gitBlob":"39c53bb184a7c10de61da0c637b607eb1d7cc454"},
-    {"path":"fixtures/cli/06-directory-expansion-ok/inputs/ignore.txt","gitBlob":"ed34ae8da336ff94a67b6125fbd6be730c976d91"},
-    {"path":"fixtures/cli/06-directory-expansion-ok/inputs/nested/b.edict","gitBlob":"39c53bb184a7c10de61da0c637b607eb1d7cc454"},
-    {"path":"fixtures/cli/06-directory-expansion-ok/request.jsonl","gitBlob":"bd9aad14fe79caccacaa6d00ffd32b5e13b3551f"},
-    {"path":"fixtures/cli/07-path-list-ok/expected.stdout.jsonl","gitBlob":"643ecb3e659c10cb98255ec1aced772778e76eb0"},
-    {"path":"fixtures/cli/07-path-list-ok/inputs/first.edict","gitBlob":"39c53bb184a7c10de61da0c637b607eb1d7cc454"},
-    {"path":"fixtures/cli/07-path-list-ok/inputs/second.edict","gitBlob":"39c53bb184a7c10de61da0c637b607eb1d7cc454"},
-    {"path":"fixtures/cli/07-path-list-ok/request.jsonl","gitBlob":"f11265b02c5b7559ced4d975471a78b5bef3ee27"},
-    {"path":"fixtures/cli/08-glob-expansion-ok/expected.stdout.jsonl","gitBlob":"90164a7fce6c51abdadef8f0586d2c56113d9712"},
-    {"path":"fixtures/cli/08-glob-expansion-ok/inputs/x.edict","gitBlob":"39c53bb184a7c10de61da0c637b607eb1d7cc454"},
-    {"path":"fixtures/cli/08-glob-expansion-ok/inputs/y.edict","gitBlob":"39c53bb184a7c10de61da0c637b607eb1d7cc454"},
-    {"path":"fixtures/cli/08-glob-expansion-ok/request.jsonl","gitBlob":"9335acf3a008ab8fb9942b3e22d73c456ed3827e"},
-    {"path":"fixtures/cli/09-shape-source-ok/expected.stdout.jsonl","gitBlob":"ac6f9259502ebfe484e1c07a5f53865888dd8207"},
-    {"path":"fixtures/cli/09-shape-source-ok/request.jsonl","gitBlob":"64c75d9a7b40985bacf0e59a943a16e20419c602"},
-    {"path":"fixtures/cli/10-input-extra-field/exit","gitBlob":"0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"},
-    {"path":"fixtures/cli/10-input-extra-field/expected.stderr.jsonl","gitBlob":"2f5a8fba093b71d15a5b37504ad0352191c8299c"},
-    {"path":"fixtures/cli/10-input-extra-field/request.jsonl","gitBlob":"6052212c652d41f03144a7d3d4018b1cdd18cd09"},
-    {"path":"fixtures/cli/11-input-hybrid-kind/exit","gitBlob":"0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"},
-    {"path":"fixtures/cli/11-input-hybrid-kind/expected.stderr.jsonl","gitBlob":"7b6d2ac0c8afbf5e3991498846c2fc4847ac9453"},
-    {"path":"fixtures/cli/11-input-hybrid-kind/request.jsonl","gitBlob":"b893b640aa6631c77f2a889a807afa31632ac2db"},
-    {"path":"fixtures/cli/12-input-too-large/env.json","gitBlob":"ab0c7f13fc6b22d61fc73da2f1787ff3aa298ecb"},
-    {"path":"fixtures/cli/12-input-too-large/exit","gitBlob":"0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"},
-    {"path":"fixtures/cli/12-input-too-large/expected.stderr.jsonl","gitBlob":"ebda022d79c978d4ff511579512be2c642e3e902"},
-    {"path":"fixtures/cli/12-input-too-large/request.jsonl","gitBlob":"1e2fbb102503356bbcc627f49a5b58590859f170"},
-    {"path":"fixtures/cli/13-input-root-outside/allowed/.gitkeep","gitBlob":"8b137891791fe96927ad78e64b0aad7bded08bdc"},
-    {"path":"fixtures/cli/13-input-root-outside/exit","gitBlob":"0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"},
-    {"path":"fixtures/cli/13-input-root-outside/expected.stderr.jsonl","gitBlob":"9c5b8567a755c9ea2ee6e0168bf96f429185f675"},
-    {"path":"fixtures/cli/13-input-root-outside/outside/outside.edict","gitBlob":"44abebc15811c38cc266007484dd74ae10a26a4d"},
-    {"path":"fixtures/cli/13-input-root-outside/request.jsonl","gitBlob":"116dbbb4b1a80938bc042e41747872cb6da161cd"},
-    {"path":"fixtures/cli/README.md","gitBlob":"9388df4182fedec41c353e85cf9210e88906fa3d"},
-    {"path":"fixtures/core/canonical/README.md","gitBlob":"d9a0ca79557c3623c0b843d9eff4808f94fd7b18"},
-    {"path":"fixtures/core/canonical/bounded-hello.core.cbor","gitBlob":"a0ec54aa1a5e20624192091526445cfd803e6f0c"},
-    {"path":"fixtures/core/canonical/bounded-hello.core.sha256","gitBlob":"86ba062c26a3ad3fd733ccd8c80d7faa7ed62d94"},
-    {"path":"fixtures/core/canonical/statement-branch.core.hex","gitBlob":"c22760cace0e4d146a2fdc8d7c7b50c38497622a"},
-    {"path":"fixtures/core/canonical/statement-branch.core.sha256","gitBlob":"0b62657b192232390479319f0a1c8f601020a58f"},
-    {"path":"fixtures/core/canonical/workspace-snapshot.core.cbor","gitBlob":"58e4f724610861f5b61537bf386a87062e8a57a7"},
-    {"path":"fixtures/core/canonical/workspace-snapshot.core.sha256","gitBlob":"4bcb3e0813cd3f4a7afc7cf311d846f1dfdd0a9d"},
-    {"path":"fixtures/core/schema/accepted/core-fn-body-minimal.fields","gitBlob":"bef3ca412ab0ea97465b8658499ae5e05e1ec760"},
-    {"path":"fixtures/core/schema/accepted/core-intent-minimal.fields","gitBlob":"268b28ce942fed4f139aafe5c7cd50c15a0ee640"},
-    {"path":"fixtures/core/schema/accepted/core-module-minimal.fields","gitBlob":"249ff76349f936c9a5ff6cb65d81de8e80d53de8"},
-    {"path":"fixtures/core/schema/rejected/core-fn-body-effect-node-field.fields","gitBlob":"9af8fa3540b25ec810936bc4dc82e26f6dd0dd48"},
-    {"path":"fixtures/core/schema/rejected/core-intent-unknown-verified-mode.fields","gitBlob":"667ae032ee117f32c1bcbafd21393e406621f517"},
-    {"path":"fixtures/core/schema/rejected/core-module-missing-intents.fields","gitBlob":"17f37c7ac4c199de4eace7f31e6a59b9a6d3a0f6"},
-    {"path":"fixtures/core/schema/rejected/local-ref-missing-alpha-name.fields","gitBlob":"456a89528ffe74d892be40c9c9be4a078ff5c18a"},
-    {"path":"fixtures/lang/bounds/bounded-hello.edict","gitBlob":"e3443a1d3b1c8f0e137ac698b621dd2f3afb673b"},
-    {"path":"fixtures/lang/effects/conditional-blob.edict","gitBlob":"1e4f2ca6112f26d57ee4d20058666ec7cd693b75"},
-    {"path":"fixtures/lang/effects/read-greeting.edict","gitBlob":"5e3838d1547be171e0a0384a7a200f52a2b9d139"},
-    {"path":"fixtures/lang/external-actions/workspace-snapshot.edict","gitBlob":"e54b0fbccad2fd680505f3ee46ca28d39d7e776e"},
-    {"path":"fixtures/lang/operations/explicit-basis-u64.edict","gitBlob":"444d8ca77b9827746df81885f0620dce2d1a3b73"},
-    {"path":"fixtures/lang/tooling/highlight-smoke.edict","gitBlob":"8c2d91084be22e5e1594a42159992aca95c73612"},
-    {"path":"fixtures/lang/types/color-match.edict","gitBlob":"dd98d6de677904f36d7601165a0094d92928e536"},
-    {"path":"fixtures/lawpack/causal-cell/README.md","gitBlob":"52e8cc1e2af8aea86c1090a1b20b5f5ab3e07c06"},
-    {"path":"fixtures/lawpack/causal-cell/adapter.cbor","gitBlob":"3b0c8b1b3a8591a322b6e785d9f963899319310c"},
-    {"path":"fixtures/lawpack/causal-cell/adapter.sha256","gitBlob":"f8231bc941e1fbe02279865a82e183cbeeb0988a"},
-    {"path":"fixtures/lawpack/causal-cell/echo-operation-configuration.cbor","gitBlob":"24527d30d0146b567fda157561ac6a2587cae919"},
-    {"path":"fixtures/lawpack/causal-cell/echo-operation-configuration.sha256","gitBlob":"d293c8a14b1955a3e171703400c4df620c7871a1"},
-    {"path":"fixtures/lawpack/causal-cell/exports.cbor","gitBlob":"384f4839adfe8e5b0f1aa848bfe2aeb1c3f640b6"},
-    {"path":"fixtures/lawpack/causal-cell/exports.sha256","gitBlob":"4f836f6b03497338a1f8eacc55480cbe1a3b49e9"},
-    {"path":"fixtures/lawpack/causal-cell/manifest.cbor","gitBlob":"b9311a236d7898861a0b90b1f30b852b35cef623"},
-    {"path":"fixtures/lawpack/causal-cell/manifest.sha256","gitBlob":"685fd6a6c72fc3100d595d009b6198a81c731a40"},
-    {"path":"fixtures/lawpack/hello-echo/README.md","gitBlob":"79f6612f1f5608a8f7dc4835e5470878cd27f96e"},
-    {"path":"fixtures/lawpack/hello-echo/adapter.cbor","gitBlob":"24e2f546e2b97747b53462a72faaa1d5d85d62f1"},
-    {"path":"fixtures/lawpack/hello-echo/adapter.sha256","gitBlob":"91df491028061e026ecaaeb4e1598e2ac369af44"},
-    {"path":"fixtures/lawpack/hello-echo/create-greeting.core.cbor","gitBlob":"246b6135855c415def0bd89b275f0457752ee563"},
-    {"path":"fixtures/lawpack/hello-echo/create-greeting.core.sha256","gitBlob":"9adc71605e0a275349161809614bd17de97d129c"},
-    {"path":"fixtures/lawpack/hello-echo/create-greeting.edict","gitBlob":"825d50565230bd71d62bfbeb59d0399a89864b4c"},
-    {"path":"fixtures/lawpack/hello-echo/create-greeting.result-projection.cbor","gitBlob":"981cba6e1c7ab6bdae6829116749c4796167e4e6"},
-    {"path":"fixtures/lawpack/hello-echo/create-greeting.result-projection.sha256","gitBlob":"d55e4083771e1d9791f59cf87fd5cc5f1ea3b9f4"},
-    {"path":"fixtures/lawpack/hello-echo/create-greeting.target-ir.cbor","gitBlob":"c8a934cefec17dbab0a43d9be9cebd2533268798"},
-    {"path":"fixtures/lawpack/hello-echo/create-greeting.target-ir.sha256","gitBlob":"20186cbe9482e8a7df7c44fabec13ffd4efbcf36"},
-    {"path":"fixtures/lawpack/hello-echo/echo-operation-configuration.cbor","gitBlob":"84838ab0d8627237232fa5a9b9fa39087bcc5f8a"},
-    {"path":"fixtures/lawpack/hello-echo/echo-operation-configuration.sha256","gitBlob":"0898688f14067560dd22abd04b97f020071fd3e8"},
-    {"path":"fixtures/lawpack/hello-echo/exports.cbor","gitBlob":"0e1220ceed9442a7b35870eeb02fcb65454d8c5c"},
-    {"path":"fixtures/lawpack/hello-echo/exports.sha256","gitBlob":"e1f3e9223de9ce935bc7f60dda3cfa7d12d54fdc"},
-    {"path":"fixtures/lawpack/hello-echo/manifest.cbor","gitBlob":"d715900f03ec454a0ad96e6710f52a46120d0b9d"},
-    {"path":"fixtures/lawpack/hello-echo/manifest.sha256","gitBlob":"20171199b401cecace2dd74e18f3cc1d5c7ed3de"},
-    {"path":"fixtures/lawpack/workspace-patch/README.md","gitBlob":"67cd35f2e0660aa7455de1c197ad821d5438679b"},
-    {"path":"fixtures/lawpack/workspace-patch/adapter.cbor","gitBlob":"2d6f09a7e2fab381b97a05cfad1e692902e878c3"},
-    {"path":"fixtures/lawpack/workspace-patch/adapter.sha256","gitBlob":"d44eb9675e126716e8a5ef3c53fd39ade49d76fb"},
-    {"path":"fixtures/lawpack/workspace-patch/apply-validated-patch.core.cbor","gitBlob":"6a88c127e426288a3e51d4749d5c31d5b0cb60cb"},
-    {"path":"fixtures/lawpack/workspace-patch/apply-validated-patch.core.sha256","gitBlob":"0204b6f1d8b346a67800a7738ee39df49e78571f"},
-    {"path":"fixtures/lawpack/workspace-patch/apply-validated-patch.edict","gitBlob":"6e11a3d022a53a8fb2c20a77e35e29840f5fe086"},
-    {"path":"fixtures/lawpack/workspace-patch/apply-validated-patch.target-ir.cbor","gitBlob":"a6124a995a3cdbb5d39cd0a6e046b329048703aa"},
-    {"path":"fixtures/lawpack/workspace-patch/apply-validated-patch.target-ir.sha256","gitBlob":"f7ac419ce15b32d491e09bddbe7c75f8227f51d8"},
-    {"path":"fixtures/lawpack/workspace-patch/exports.cbor","gitBlob":"3a6fd19dc8059b9fe1bde74fb1da61398b0e80cc"},
-    {"path":"fixtures/lawpack/workspace-patch/exports.sha256","gitBlob":"b301dd883a31fffe324e9306ec90ae2b1ec44520"},
-    {"path":"fixtures/lawpack/workspace-patch/input-schema.cbor","gitBlob":"3045d9b696864fefe111c3eb641b3b68532752d2"},
-    {"path":"fixtures/lawpack/workspace-patch/input-schema.sha256","gitBlob":"9f1284b4f0a2c7f6dbe1915a6113cd13a9700cb8"},
-    {"path":"fixtures/lawpack/workspace-patch/manifest.cbor","gitBlob":"77e56c7525f0e64ab191f0adfeac12b540c87848"},
-    {"path":"fixtures/lawpack/workspace-patch/manifest.sha256","gitBlob":"8316978e68565f29a30a6978d33d907710185857"},
-    {"path":"fixtures/lawpack/workspace-patch/reconciliation-law.cbor","gitBlob":"0736b75f81913fca7ac95c56ec45f66b95aea4cf"},
-    {"path":"fixtures/lawpack/workspace-patch/reconciliation-law.sha256","gitBlob":"de31fc9fda59fa3c29397e5fc48db224e8e1fee7"},
-    {"path":"fixtures/lawpack/workspace-patch/request-profile-configuration.cbor","gitBlob":"5e2870b2f562bafaa73a91a3fc192f5ed39257c7"},
-    {"path":"fixtures/lawpack/workspace-patch/request-profile-configuration.sha256","gitBlob":"4345ae2e39ce3f4d9cfa6b0dddf4ce56d56c035c"},
-    {"path":"fixtures/lawpack/workspace-patch/settlement-schema.cbor","gitBlob":"0a93ac19c51b341602eeba524769147e962d5d60"},
-    {"path":"fixtures/lawpack/workspace-patch/settlement-schema.sha256","gitBlob":"f1bb3fb0313dd6815b4184345194949ec40fe9e1"},
-    {"path":"fixtures/lawpack/workspace-snapshot/README.md","gitBlob":"996bd1d29b28769fff477084d9118d0833ca2970"},
-    {"path":"fixtures/lawpack/workspace-snapshot/adapter.cbor","gitBlob":"9be4ea568b602b56269af505deb809989a3fa8b5"},
-    {"path":"fixtures/lawpack/workspace-snapshot/adapter.sha256","gitBlob":"1e287be0a322e5444dea15fa14bcfc7cf12975c4"},
-    {"path":"fixtures/lawpack/workspace-snapshot/exports.cbor","gitBlob":"33fe04db74775c191d4b7400e1fb2b6393c5a010"},
-    {"path":"fixtures/lawpack/workspace-snapshot/exports.sha256","gitBlob":"e057cac7fc360e6599b7ddab88508aaf0f2f55f8"},
-    {"path":"fixtures/lawpack/workspace-snapshot/input-schema.cbor","gitBlob":"49c849169946e44c8b5f300279dd085bd6b63aeb"},
-    {"path":"fixtures/lawpack/workspace-snapshot/input-schema.sha256","gitBlob":"9dd7bb6e48192e90d19fc346d1705f736b1d85d7"},
-    {"path":"fixtures/lawpack/workspace-snapshot/manifest.cbor","gitBlob":"d4e58e3d4646ca967170a6882f2a617cb8d81390"},
-    {"path":"fixtures/lawpack/workspace-snapshot/manifest.sha256","gitBlob":"0edb311125a89a5816ee3fa0c9b700c9b3bcff3d"},
-    {"path":"fixtures/lawpack/workspace-snapshot/observe-workspace.core.cbor","gitBlob":"a4b249dfb197f1a6b4adc06855f16e4305a1c798"},
-    {"path":"fixtures/lawpack/workspace-snapshot/observe-workspace.core.sha256","gitBlob":"ea6b914d14907d9fd915058e579aff33c954da2c"},
-    {"path":"fixtures/lawpack/workspace-snapshot/observe-workspace.edict","gitBlob":"c2c10f1ef1009796d67061b9722c4db9bb4e031b"},
-    {"path":"fixtures/lawpack/workspace-snapshot/observe-workspace.target-ir.cbor","gitBlob":"bdab1b0c55a34360c7e9ab304af91fe2b1e4afce"},
-    {"path":"fixtures/lawpack/workspace-snapshot/observe-workspace.target-ir.sha256","gitBlob":"7342aaa96221d6c8efa75ead2af5563791ccfeff"},
-    {"path":"fixtures/lawpack/workspace-snapshot/reconciliation-law.cbor","gitBlob":"df55572b350002a3df98ccb3e72dd60c86b9aead"},
-    {"path":"fixtures/lawpack/workspace-snapshot/reconciliation-law.sha256","gitBlob":"957cd04c78c130b07d2cad2fd7e07ae69978be57"},
-    {"path":"fixtures/lawpack/workspace-snapshot/request-profile-configuration.cbor","gitBlob":"708f18918ee1703491a910df82e129e711a4cc46"},
-    {"path":"fixtures/lawpack/workspace-snapshot/request-profile-configuration.sha256","gitBlob":"d9953d9dcaa41c98387226d1980f40b24d2bc3cb"},
-    {"path":"fixtures/lawpack/workspace-snapshot/settlement-schema.cbor","gitBlob":"f01ad68531267666e6bf93bf30a37d5b311c1676"},
-    {"path":"fixtures/lawpack/workspace-snapshot/settlement-schema.sha256","gitBlob":"06fcc0ee2b976a09b3017bd93132a3c51eb1317e"},
-    {"path":"fixtures/obstruction-strands/v0/stale-basis/README.md","gitBlob":"25efbfa04e2e6104c5434f329128333e895e2b0a"},
-    {"path":"fixtures/obstruction-strands/v0/stale-basis/source.edict","gitBlob":"e487b46e81220c50e6f928922dada29f3a21ca6a"},
-    {"path":"fixtures/provider-contracts/v1/README.md","gitBlob":"447692907f9268ce3b6b78c43b7cbbb0417aeadf"},
-    {"path":"fixtures/provider-contracts/v1/edict-provider-contracts.cddl","gitBlob":"07048aeeadb5062eabb89e995713cbc0893b7d7e"},
-    {"path":"fixtures/provider-contracts/v1/manifest.json","gitBlob":"d2c8de5d61049e9f4182c630bf82b138f0f96792"},
-    {"path":"fixtures/providers/README.md","gitBlob":"c26ee60a4930e3e0784c76cb855e48234a5c6b58"},
-    {"path":"fixtures/providers/components/guests/Cargo.lock","gitBlob":"d7858ce7bc67deabb5ff352a24c85a7caa0ef4b0"},
-    {"path":"fixtures/providers/components/guests/Cargo.toml","gitBlob":"450a24aed25dc73661b0ae8adfe2630dfecc9b07"},
-    {"path":"fixtures/providers/components/guests/lowerer/Cargo.toml","gitBlob":"568aa137fa215b6b973fe31e12322530b393b9dc"},
-    {"path":"fixtures/providers/components/guests/lowerer/src/lib.rs","gitBlob":"b39a8a0b18fe9ed7cb90277f793056434afa1318"},
-    {"path":"fixtures/providers/components/guests/verifier/Cargo.toml","gitBlob":"f814f2c8c248bbf03389f5a0936f80cd4dada5b6"},
-    {"path":"fixtures/providers/components/guests/verifier/src/lib.rs","gitBlob":"3f07ffdfd808ff95b206a2c08c2d481ccaf0e165"},
-    {"path":"fixtures/providers/components/instantiation-failure-lowerer.component.wasm","gitBlob":"bd2d7c0d31798d7676aedab0bd0d289fc2053bef"},
-    {"path":"fixtures/providers/components/instantiation-failure-lowerer.wat","gitBlob":"f6f5a70edb80d3a7fa1dee13b34ab5b8b44274d7"},
-    {"path":"fixtures/providers/components/instantiation-fuel-lowerer.component.wasm","gitBlob":"0804d26d3ddb428682ca87ecad03cf0e05ef64af"},
-    {"path":"fixtures/providers/components/instantiation-fuel-lowerer.wat","gitBlob":"80e972463ef593602d27c7d7cec78d87d22ff727"},
-    {"path":"fixtures/providers/components/inventory.json","gitBlob":"45cf2e8e937a17a8ee05dfa8d68e94dcc155e129"},
-    {"path":"fixtures/providers/components/lowerer.component.wasm","gitBlob":"6c1cf123a44284d15b7b1e90f1905ae94e65c158"},
-    {"path":"fixtures/providers/components/malformed-lowerer.component.wasm","gitBlob":"be873af81100dc76ed1f3f1f818a41da45a38e4c"},
-    {"path":"fixtures/providers/components/malformed-lowerer.wat","gitBlob":"1e7bfffe0a0baf230d9fb5766083f82198f4029c"},
-    {"path":"fixtures/providers/components/verifier.component.wasm","gitBlob":"671adbe7931d0a9a5e0c78d459c244d37a135a69"},
-    {"path":"fixtures/providers/echo-generated/provider-manifest.json","gitBlob":"22c8560e7ddecacd5da388e52d3935d7fc1474b9"},
-    {"path":"fixtures/providers/echo-target-profile/README.md","gitBlob":"350c33dcda2d66d2d50e589c58db7c6d7b14a80b"},
-    {"path":"fixtures/providers/echo-target-profile/generated/primary/target-profile.echo-dpo.cbor","gitBlob":"9fa43529b1021dfd8e3a33256c832d4eee6f4a47"},
-    {"path":"fixtures/providers/wit/legacy-target-profile.wit","gitBlob":"ae7d6af764012b16bf06bfa260ccba98a7f04868"},
-    {"path":"fixtures/target-ir/canonical/echo-effectful.target-ir.cbor","gitBlob":"727a80eb37319dbdbea40d7d9b4e37f0d93d8d84"},
-    {"path":"fixtures/target-ir/canonical/echo-effectful.target-ir.sha256","gitBlob":"6d050bb46ac8981ea8e47c7a52371027b941fd89"},
-    {"path":"fixtures/target-ir/canonical/gitwarp-append.target-ir.cbor","gitBlob":"89b46b138a7b90252a4397c0e8b622bceff10a33"},
-    {"path":"fixtures/target-ir/canonical/gitwarp-append.target-ir.sha256","gitBlob":"a59a4ab9d46095d5be1797ed9e60fe841f821bce"},
-    {"path":"fixtures/target-ir/canonical/workspace-snapshot.target-ir.cbor","gitBlob":"1854eeb549b3719fa2b0114867dbece6db1819d4"},
-    {"path":"fixtures/target-ir/canonical/workspace-snapshot.target-ir.sha256","gitBlob":"4d0e501323d415ef9e64c0a3d25bdd57dabfc998"},
-    {"path":"fixtures/target-profile/contract-resources/README.md","gitBlob":"32dcab1dd9376a4eed2c73bb1b1a29255fe3ea05"},
-    {"path":"fixtures/target-profile/contract-resources/canonical-cbor.cbor","gitBlob":"4a95ba3bd9dff190ca5ec9c83262bfa6254a91d3"},
-    {"path":"fixtures/target-profile/contract-resources/canonical-cbor.sha256","gitBlob":"2168df5d4bf77ed2347139dd7c45fd808df8ec7e"},
-    {"path":"fixtures/target-profile/contract-resources/determinism.cbor","gitBlob":"09cd11c36048939961408550763c04fad8241557"},
-    {"path":"fixtures/target-profile/contract-resources/determinism.sha256","gitBlob":"5376d6bfe23bea659463a7e3c56ad1e8afd4095f"},
-    {"path":"fixtures/target-profile/contract-resources/diagnostics.cbor","gitBlob":"c47fa05f463e0da745fbcdf8daf94d70e134eb8d"},
-    {"path":"fixtures/target-profile/contract-resources/diagnostics.sha256","gitBlob":"69613ec4014f27b23245e23fbf7c9447566516b2"},
-    {"path":"fixtures/target-profile/contract-resources/fuel.cbor","gitBlob":"b5a3484ec5b2bf7343c2fcedc67bcb2b63a37104"},
-    {"path":"fixtures/target-profile/contract-resources/fuel.sha256","gitBlob":"6ec1c830358ee35bb12bd04cc1a6edf47fb20997"},
-    {"path":"fixtures/target-profile/contract-resources/wasm-component.cbor","gitBlob":"6344996c283e0d1c332ea3ce597ad4593882a3c5"},
-    {"path":"fixtures/target-profile/contract-resources/wasm-component.sha256","gitBlob":"24bf3e552e4216d8258d2b85c8878af46a176c52"},
-    {"path":"grammars/textmate/README.md","gitBlob":"fc116a669725d4e965d658234d32d779955d5dc8"},
-    {"path":"grammars/textmate/edict.tmLanguage.json","gitBlob":"5847d8edfdb32d822f0f3950f41d00c947982185"},
-    {"path":"grammars/tree-sitter-edict/README.md","gitBlob":"e2992a839d6719f1461db78c4e3f33d2e5ab0c09"},
-    {"path":"grammars/tree-sitter-edict/grammar.js","gitBlob":"a82f5b9d9b78525f17a59272543fdcddd7a0da40"},
-    {"path":"grammars/tree-sitter-edict/queries/highlights.scm","gitBlob":"0f46530b36996d13449901aed4e376a126577cba"},
-    {"path":"grammars/tree-sitter-edict/src/grammar.json","gitBlob":"55df730a06b83c9f622e3ec17845fc9897c7d8c0"},
-    {"path":"grammars/tree-sitter-edict/src/node-types.json","gitBlob":"520f6c4f7b30cd6892dd60faf6d76f3fbaa6a5c7"},
-    {"path":"grammars/tree-sitter-edict/src/parser.c","gitBlob":"81cc4713cb5e05f9aa8dac16da202a864faefee6"},
-    {"path":"grammars/tree-sitter-edict/src/tree_sitter/alloc.h","gitBlob":"1abdd1201578605b8d05a3001f01ebc0d58826d9"},
-    {"path":"grammars/tree-sitter-edict/src/tree_sitter/array.h","gitBlob":"56fc8cd470996ded64a5452be25e26dbd2aa682a"},
-    {"path":"grammars/tree-sitter-edict/src/tree_sitter/parser.h","gitBlob":"858107deb9e4a1ffcd2ed5e6ffe98a5fcab3e1f6"},
-    {"path":"grammars/tree-sitter-edict/test/corpus/current-subset.txt","gitBlob":"732c5eda8e1bf95eef799476296a6ee061eb58eb"},
-    {"path":"grammars/tree-sitter-edict/tree-sitter.json","gitBlob":"97d3fdd498a3bef509c8615d98b9560b527c03cb"},
-    {"path":"scripts/consumer-witnesses/README.md","gitBlob":"2b7d2b9d81f9598fd8df232b3a76bef106ff7ef2"},
-    {"path":"scripts/consumer-witnesses/jedit-state-read.Dockerfile","gitBlob":"7462059be67686090d0097b24b9d14bfbbd4c6f7"},
-    {"path":"scripts/consumer-witnesses/jedit-state-read.Dockerfile.dockerignore","gitBlob":"ee41b3ca0a68fd5eb20e1b777b4b368fd8b44e63"},
-    {"path":"scripts/consumer-witnesses/jedit-state-read.py","gitBlob":"26db295d4eabfc4e57813fc9bf17314c23350777"},
-    {"path":"scripts/consumer-witnesses/run-jedit-state-read.sh","gitBlob":"18cd72bbbdfb17a5ea30a7821d47035071556d10"},
-    {"path":"spec.lock.json","gitBlob":"ef8b02386e0f269a99c1d2121764f70b76e67620"},
-    {"path":"xtask/Cargo.toml","gitBlob":"795c70a5172363bfcd55174b1bc76c9c131d21a3"},
-    {"path":"xtask/src/contract_check.rs","gitBlob":"9e80393accf79936033972fde0f2aa2cf40f1be3"},
-    {"path":"xtask/src/goldens.rs","gitBlob":"713f1f8266d9f6993684ae86db105fcd7d69ee2a"},
-    {"path":"xtask/src/lawpack_goldens.rs","gitBlob":"c499e8581c73313794b83c261937144b3917850a"},
-    {"path":"xtask/src/main.rs","gitBlob":"6c2c06038bb5ecdde60620071b200d8191dc116c"},
-    {"path":"xtask/src/provider_components.rs","gitBlob":"ee9d6a1028f9fbfad879faab4b15a94b996ef6d4"},
-    {"path":"xtask/src/provider_contract_pack.rs","gitBlob":"cf60d89892b7a57cc33300f273d2522a6e8f43f9"},
-    {"path":"xtask/src/provider_dependencies.rs","gitBlob":"c4b0539ed593d2a2777d294090d2a891b13ae628"},
-    {"path":"xtask/src/release_dates.rs","gitBlob":"1c6d7acb872f6d820eab3a30ca580e9c5cfba2ee"},
-    {"path":"xtask/src/release_prep.rs","gitBlob":"01ed64ccbb28c9d1e908b7b800ff58076e5e1a2b"},
-    {"path":"xtask/src/tests.rs","gitBlob":"9a3f6543c2dbae31d53e93d56f781e5d54f74f41"},
-    {"path":"xtask/src/util.rs","gitBlob":"c1bf39e93460c43ffdcfd9a76e0424750cbb9dfd"}
-  ]
-}
diff --git a/edict/replace-range-probes/leaf-slice/evidence/candidate-report-inspection.json b/edict/replace-range-probes/leaf-slice/evidence/candidate-report-inspection.json
deleted file mode 100644
index 227a0df3..00000000
--- a/edict/replace-range-probes/leaf-slice/evidence/candidate-report-inspection.json
+++ /dev/null
@@ -1,70 +0,0 @@
-{
-  "packageCoordinate": "jedit.text.replace_range@1.sliceLeaf",
-  "report": {
-    "outcome": "accepted",
-    "package": {
-      "id": "executable-operation-package.echo",
-      "digest": [
-        "sha256",
-        {
-          "byteLength": 32,
-          "sha256": "b1acdfe0db3286d81604186a3588f595f19aaf21a78209f42a61f90476eba2ab"
-        }
-      ]
-    },
-    "targetIr": {
-      "id": "echo.span-ir/v1",
-      "digest": [
-        "sha256",
-        {
-          "byteLength": 32,
-          "sha256": "78b4e450233527ad0007a95ae2af76ba1cdfbe086b1f19a14291cf7cbd2fd84d"
-        }
-      ]
-    },
-    "apiVersion": "echo.operation-package-verifier-report/v1",
-    "diagnosticAbi": {
-      "id": "edict.diagnostics/v1",
-      "digest": [
-        "sha256",
-        {
-          "byteLength": 32,
-          "sha256": "60f5dfb53db3c4b4cebb44bcaf5689796495b017f0e34e1f30b48f8c292065e4"
-        }
-      ]
-    },
-    "diagnosticBytes": {
-      "byteLength": 0,
-      "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "executableSubject": {
-      "bytes": {
-        "byteLength": 334,
-        "sha256": "a390af915f4493e811cd75322d09968c93f5f09e3d142e8a121cdaad32b65ece"
-      },
-      "reference": {
-        "id": "echo.executable-subject/v1",
-        "digest": [
-          "sha256",
-          {
-            "byteLength": 32,
-            "sha256": "2b6d0f2561348e957e414edf7ad16cdf09b5ba934b5f26112f3c2444b26b4db9"
-          }
-        ]
-      }
-    },
-    "applicationResultProjection": {
-      "id": "jedit.text.replace_range@1.sliceLeaf",
-      "digest": [
-        "sha256",
-        {
-          "byteLength": 32,
-          "sha256": "0f974cde2e2d5e222ff03745fb42e6e6a00c36b2b340887d5e53e45fbc93fb8a"
-        }
-      ]
-    }
-  },
-  "retainedCoreContainsSlice": true,
-  "retainedTargetContainsSlice": true,
-  "runtimeEvaluated": false
-}
diff --git a/edict/replace-range-probes/leaf-slice/evidence/compiler-source.json b/edict/replace-range-probes/leaf-slice/evidence/compiler-source.json
deleted file mode 100644
index d0b18a0d..00000000
--- a/edict/replace-range-probes/leaf-slice/evidence/compiler-source.json
+++ /dev/null
@@ -1,446 +0,0 @@
-{
-  "commit": "2405a550e93e1e97fff640caa44bbd0f65ffff3c",
-  "tree": "257d3e6aa10c2248fdbddaa8e9b3638866396169",
-  "files": [
-    {"path":".cargo/config.toml","gitBlob":"5592118f6c54bf8b53b16848e04ece896dd56384"},
-    {"path":".github/workflows/auto-release-tag.yml","gitBlob":"87404ceb685191afd496c93494b0bc61e2a59504"},
-    {"path":".github/workflows/ci.yml","gitBlob":"c6c6a17f59b6b96db88e3d4b2775bc64b7fe01f3"},
-    {"path":".github/workflows/release.yml","gitBlob":"2c612fc786998bfa5b11e76ae1185114a7cc535f"},
-    {"path":".gitignore","gitBlob":"30d7faf0fc8b7f010f99280302d4ed269d5da9ba"},
-    {"path":".markdownlint.json","gitBlob":"f3ec2c8dc2fbacc425154a2baedec50c7474aefa"},
-    {"path":"AGENTS.md","gitBlob":"0c48a5794454cf84e20640994a372316efde7bb5"},
-    {"path":"ARCHITECTURE.md","gitBlob":"5b513dd25028092e7e75c8974f1d5f3cc31889ed"},
-    {"path":"CHANGELOG.md","gitBlob":"9cc14cfa4891c9ff5167c569bb80567e8f670e0d"},
-    {"path":"CODE_OF_CONDUCT.md","gitBlob":"784cf2799bcf8d2a69db5f5781359ef7e18a05fc"},
-    {"path":"CONTRIBUTING.md","gitBlob":"9676914060f734dc59eabd9075898dc8170d4d19"},
-    {"path":"Cargo.lock","gitBlob":"bacb208de0583f182379af7b5e078d31b25e2ca5"},
-    {"path":"Cargo.toml","gitBlob":"b2e7106eb78f79230c091492ef21b497bdc9ed19"},
-    {"path":"EDICT.md","gitBlob":"35376134195082d506f0161ba7ecb97efa8b770a"},
-    {"path":"LICENSE","gitBlob":"261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64"},
-    {"path":"NOTICE","gitBlob":"c300687bdd9d931d1f257d291e1cb6ff9d7d3607"},
-    {"path":"README.md","gitBlob":"0812ef9a0c4611bf655dfc67d2ecc3631af9a536"},
-    {"path":"ROADMAP.md","gitBlob":"d0e0135780537afab1d1a3f53808b363b35a63f4"},
-    {"path":"SECURITY.md","gitBlob":"0bcc4e7375442e1334405a2d046df316cee05cd5"},
-    {"path":"crates/edict-cli/Cargo.toml","gitBlob":"e9d844553c395bd312f84e806eb5bac30c5c3a54"},
-    {"path":"crates/edict-cli/src/application_build.rs","gitBlob":"9c56ae6b4dd4eef0b9fe6db40316e100b2ffa699"},
-    {"path":"crates/edict-cli/src/lawpack_build.rs","gitBlob":"55e9579153f34a3d5b139141c9de6640808cd386"},
-    {"path":"crates/edict-cli/src/lawpack_build_windows.rs","gitBlob":"f71d03b368ae83becc1608bbba11cd5f1afa4f07"},
-    {"path":"crates/edict-cli/src/lib.rs","gitBlob":"60883af60cf4b441680952ecce7ef4fcbfeabb97"},
-    {"path":"crates/edict-cli/src/main.rs","gitBlob":"0dd9776642c4090479322111e4164ee7049fb9d0"},
-    {"path":"crates/edict-cli/tests/golden_cli.rs","gitBlob":"9897caad3bcc6fa8bb0f20a1d0e18032285b1fa7"},
-    {"path":"crates/edict-cli/tests/jsonl_cli.rs","gitBlob":"9ed353ca27d073fc7da49d3800c81ba4c58edd5d"},
-    {"path":"crates/edict-cli/tests/lawpack_authoring_cli.rs","gitBlob":"dd7d7bfebf0e051c77d894a55c0204d373b19c63"},
-    {"path":"crates/edict-provider-host-wasmtime/Cargo.toml","gitBlob":"ebeeb941f09012293d9923fe0e6039b2761b328e"},
-    {"path":"crates/edict-provider-host-wasmtime/src/conversion.rs","gitBlob":"62c3cd4a85eb156b8c9a405ef3ea4d8a09b80cc3"},
-    {"path":"crates/edict-provider-host-wasmtime/src/invocation.rs","gitBlob":"a4d6680d289094afebc0f1063abccf706f8149db"},
-    {"path":"crates/edict-provider-host-wasmtime/src/lib.rs","gitBlob":"353ea7394f265219ebdecad56a3070c9e7d2685c"},
-    {"path":"crates/edict-provider-host-wasmtime/src/limits.rs","gitBlob":"9e4d12c1b606d2b180f732db17bfbc78f8e26e3a"},
-    {"path":"crates/edict-provider-host-wasmtime/src/replay.rs","gitBlob":"b8fa7be7c7ee5039793dad4cd0fa6a4f14ce388e"},
-    {"path":"crates/edict-provider-host-wasmtime/tests/invocation.rs","gitBlob":"7a59a3192852a80bc01221ebf3dd1c437bda9508"},
-    {"path":"crates/edict-provider-host-wasmtime/tests/preflight.rs","gitBlob":"a295e7547b0294f0355a85d5b9b8d045c8fceefd"},
-    {"path":"crates/edict-provider-schema/Cargo.toml","gitBlob":"0e74f58acdc054ecce192cb8341afeaddc40deb5"},
-    {"path":"crates/edict-provider-schema/src/contract_pack.rs","gitBlob":"370480d9c606134dd08ee62ae29ef143941e2f54"},
-    {"path":"crates/edict-provider-schema/src/lib.rs","gitBlob":"51f5bee8892c9fb2122cb20022edc4d414759ff7"},
-    {"path":"crates/edict-provider-schema/src/recursive_dispatch.rs","gitBlob":"6d97565b96f941b359d16f7a1c201189968fbeff"},
-    {"path":"crates/edict-provider-schema/src/schema_safety.rs","gitBlob":"a2f605f62a2bfedcb84b68e37db9ff84b1dc3b05"},
-    {"path":"crates/edict-provider-schema/tests/authority_facts_abi.rs","gitBlob":"7dd4d0302805ceecffc2045cdb91e386f8e08517"},
-    {"path":"crates/edict-provider-schema/tests/provider_contract_pack.rs","gitBlob":"a26be8054b39215048825dd8cae7e9bddcfe27c9"},
-    {"path":"crates/edict-provider-schema/tests/registry.rs","gitBlob":"bdd13ec00e441aef9e67ba49f6592ecbc7dcb303"},
-    {"path":"crates/edict-syntax/Cargo.toml","gitBlob":"f55bb23e528af78b1e97b52f9b72cbd876a44ba7"},
-    {"path":"crates/edict-syntax/src/admission.rs","gitBlob":"471430dd13a617bac886fcd44afbf15263e7db3b"},
-    {"path":"crates/edict-syntax/src/ast.rs","gitBlob":"2a5d208a53a82408f8a18d9a13ccb133ec6a7a2e"},
-    {"path":"crates/edict-syntax/src/authority_facts.rs","gitBlob":"644de86d63983bdbfbf1279fdbf1dbdaecc151d5"},
-    {"path":"crates/edict-syntax/src/canonical.rs","gitBlob":"6fb29d50ea4a55eb888a1b9600cdcb31713a6e20"},
-    {"path":"crates/edict-syntax/src/compiler.rs","gitBlob":"7d2ef5f503aef28b6878467749200aea99843114"},
-    {"path":"crates/edict-syntax/src/compiler/byte_length.rs","gitBlob":"0d8d6291064415baee9253d9fe1e11ad87945773"},
-    {"path":"crates/edict-syntax/src/compiler/unsigned_subtraction.rs","gitBlob":"e714094b05f69559ec69f1b9b45fb054d06c1919"},
-    {"path":"crates/edict-syntax/src/contract_bundle.rs","gitBlob":"9a31645f0e30879d019787e29c21c82eebf58129"},
-    {"path":"crates/edict-syntax/src/core_ir.rs","gitBlob":"119d69b75914db1357030ccc5aecb90448fe8f24"},
-    {"path":"crates/edict-syntax/src/highlight.rs","gitBlob":"28b3f7dcdfe8d4982bdcfb05759f769ccdbffc7f"},
-    {"path":"crates/edict-syntax/src/lawpack.rs","gitBlob":"54f85bda48c960ad0b7bc316d332b379ab5b6ae0"},
-    {"path":"crates/edict-syntax/src/lawpack_adapter.rs","gitBlob":"e425960e2437faa2f9eeb5d089ff507417d39586"},
-    {"path":"crates/edict-syntax/src/lawpack_authoring.rs","gitBlob":"11ff578f458b8a4c8e4df75c0c616e37fa468d49"},
-    {"path":"crates/edict-syntax/src/lib.rs","gitBlob":"7323475cc7f846e11c2d73f4c26a5e581b7e6157"},
-    {"path":"crates/edict-syntax/src/lowerability.rs","gitBlob":"c6a1323fd6a79b0460b43aaf338956c3906a633e"},
-    {"path":"crates/edict-syntax/src/parser.rs","gitBlob":"0b3650e3012e49023ccbb9cc9effe9b5b102f19d"},
-    {"path":"crates/edict-syntax/src/provider.rs","gitBlob":"18fa661d880979c53dd335fb7e68d5445b638d4c"},
-    {"path":"crates/edict-syntax/src/provider_invocation.rs","gitBlob":"2526168f0a6f2d1d9b6181b689ff43e203434122"},
-    {"path":"crates/edict-syntax/src/provider_lowering.rs","gitBlob":"50a4e60b561127cb8c78e3f7c04c6bbaca068e52"},
-    {"path":"crates/edict-syntax/src/result_projection.rs","gitBlob":"79ba246d4c58960fe368eaca4c7d135fe187832a"},
-    {"path":"crates/edict-syntax/src/semantic.rs","gitBlob":"3314c1ac95904d2b3d92cd67a9d7babad5182123"},
-    {"path":"crates/edict-syntax/src/target_ir.rs","gitBlob":"c6cac206a5e4342ebda323070d3dc18baf68a3ce"},
-    {"path":"crates/edict-syntax/src/target_ir/byte_length.rs","gitBlob":"84e93d15c61936061323485a8408d3f1fbf95f55"},
-    {"path":"crates/edict-syntax/src/target_ir/execution_order.rs","gitBlob":"e69a28805dc5e414a64afdaafee34161c217a044"},
-    {"path":"crates/edict-syntax/src/target_ir/unsigned_subtraction.rs","gitBlob":"2170e31b98dfa7ab48a0441a2355e9824b3fcab6"},
-    {"path":"crates/edict-syntax/src/target_profile.rs","gitBlob":"dd514f7380243e795f0655a78aecd06ee3fa2eda"},
-    {"path":"crates/edict-syntax/src/target_profile_contract_resources.rs","gitBlob":"4efd22961c2fd7591440efd6087944ecaf21e991"},
-    {"path":"crates/edict-syntax/src/token.rs","gitBlob":"2768586eea6d42d5df357c4cc62a011ee7f455de"},
-    {"path":"crates/edict-syntax/tests/admission.rs","gitBlob":"57edbc320307c1d6daba85f03d8dc79558d7b849"},
-    {"path":"crates/edict-syntax/tests/authority_facts.rs","gitBlob":"add9d272be6e8eb1cd6fdde2999a5fb452ecd852"},
-    {"path":"crates/edict-syntax/tests/authority_facts_cbor.rs","gitBlob":"7359f047d9f731fee208efb5f69072b612d69547"},
-    {"path":"crates/edict-syntax/tests/byte_length.rs","gitBlob":"032a62da58ae4ef933ef9dcd92d6510f627ff102"},
-    {"path":"crates/edict-syntax/tests/canonical_encoding.rs","gitBlob":"e4c5d59a88f88193f522eb555359919f7034a264"},
-    {"path":"crates/edict-syntax/tests/common/mod.rs","gitBlob":"89560bfacb3dab031485c2dfa30d7eb325966574"},
-    {"path":"crates/edict-syntax/tests/compiler_spine.rs","gitBlob":"2237318cfc0d4209e8a629e45320e42a4b72dbef"},
-    {"path":"crates/edict-syntax/tests/contract_bundle.rs","gitBlob":"e6a2948335a0efc86d8bbb2e9e2c3d634e53965a"},
-    {"path":"crates/edict-syntax/tests/core_golden_fixtures.rs","gitBlob":"0e0e42d19b52dc0557902dad9e1b85f37edf53f8"},
-    {"path":"crates/edict-syntax/tests/external_action_requests.rs","gitBlob":"3c07be4db0bfc49e67c2d7e1eda0ac0397987a37"},
-    {"path":"crates/edict-syntax/tests/highlighting.rs","gitBlob":"17e6b9ba08c96f0efb6efd440590f0fc917316e2"},
-    {"path":"crates/edict-syntax/tests/lawpack.rs","gitBlob":"a675999ed96309358c8552a9d32781b5eede20dc"},
-    {"path":"crates/edict-syntax/tests/lawpack_authoring.rs","gitBlob":"3a905cbd6d7d2625bc1d7826a6f6f1e991efbab0"},
-    {"path":"crates/edict-syntax/tests/lowerability.rs","gitBlob":"5cfa58f5cbc51cccc7f119caddc1c3fcbc2e4806"},
-    {"path":"crates/edict-syntax/tests/operation_prerequisites.rs","gitBlob":"753659e1a6e7751c455b8518226fa0902157a745"},
-    {"path":"crates/edict-syntax/tests/parse_control_flow.rs","gitBlob":"5245561866d8902c1fbd5ab21f2e34807d568e17"},
-    {"path":"crates/edict-syntax/tests/parse_greeting.rs","gitBlob":"f214d0c17745b8203d562780caa8f37b71c1e62c"},
-    {"path":"crates/edict-syntax/tests/parse_hello.rs","gitBlob":"bf7b1b065277188f4be8754eb11ace94298394ba"},
-    {"path":"crates/edict-syntax/tests/parse_keywords.rs","gitBlob":"78d8a64d785136d42a32655afda3df240c54f884"},
-    {"path":"crates/edict-syntax/tests/parse_loops.rs","gitBlob":"d9ece2fce96fd6835d080055f06955d139c7e0ce"},
-    {"path":"crates/edict-syntax/tests/parse_negative.rs","gitBlob":"17fdb983b8250470368a8f19d3a7bd9680052548"},
-    {"path":"crates/edict-syntax/tests/parse_review_regressions.rs","gitBlob":"560215cfe044a528e190aa1ea7670e52b9365bdf"},
-    {"path":"crates/edict-syntax/tests/parse_variants.rs","gitBlob":"8849f68f5ca1e2b06d0f66496e59b20d1c0fd022"},
-    {"path":"crates/edict-syntax/tests/provider.rs","gitBlob":"7e8a596109b1e1fd3f22b3a0ef82f4755f127291"},
-    {"path":"crates/edict-syntax/tests/provider_invocation.rs","gitBlob":"402647dd6701be65a9e693fd3f5688f26d84988e"},
-    {"path":"crates/edict-syntax/tests/provider_lowering.rs","gitBlob":"411c306f3ab641de9dc2f7aed229767eba9dbd72"},
-    {"path":"crates/edict-syntax/tests/result_projection.rs","gitBlob":"a74dd2a419266cb77d846d83da27f726095660f1"},
-    {"path":"crates/edict-syntax/tests/semantic_validation.rs","gitBlob":"a127988d178c00ed12a0a25f70df6b7fd5e6d931"},
-    {"path":"crates/edict-syntax/tests/target_ir.rs","gitBlob":"928e1cf921dead0b559bd115bb6eef3faaddd37e"},
-    {"path":"crates/edict-syntax/tests/target_ir/ordered.rs","gitBlob":"a1b05db81a97a43ec5a2dc2d9bcc9578bc286f30"},
-    {"path":"crates/edict-syntax/tests/target_profile.rs","gitBlob":"42f1c907f6c60dea1e8a9b4558b56ffd0b3a59ab"},
-    {"path":"crates/edict-syntax/tests/target_profile_contract_resources.rs","gitBlob":"270c180a12dc10fb7e208cc4dc1e202da82c85fb"},
-    {"path":"crates/edict-syntax/tests/target_unsigned_subtraction.rs","gitBlob":"6884e55a45baa4f423056a10b6dea9f8b08fb60f"},
-    {"path":"crates/edict-syntax/tests/unsigned_subtraction.rs","gitBlob":"b4b870cea63f440a52c949529077336a0b58b4ee"},
-    {"path":"crates/edict/Cargo.toml","gitBlob":"525403f4f36db4040531e4dd747ec2398f9052cd"},
-    {"path":"crates/edict/README.md","gitBlob":"a1ecf50bff3443d25a23fabfa6374d3f0a28ca82"},
-    {"path":"crates/edict/src/lib.rs","gitBlob":"169d820759d6333f27a45ebb712bfcc4f0115107"},
-    {"path":"crates/edict/tests/artifact_models.rs","gitBlob":"b923109c7195ce2c0071dc54179f0746b95329f0"},
-    {"path":"crates/edict/tests/public_surface.rs","gitBlob":"a24c4bc9d9484f540da9b280790896701922968a"},
-    {"path":"deny.toml","gitBlob":"e3f0f54060cead9a0d48b96ed86948d0909c4f78"},
-    {"path":"docs/DESIGN_runtime-neutral-edict-sha-lock-assurance.md","gitBlob":"ea3badf78ebd19545147a93671fdb5f9af4a61ea"},
-    {"path":"docs/GUIDE_edict-assurance-transparency.md","gitBlob":"100321157ec43055c45794f1c161b1e5281ba6b4"},
-    {"path":"docs/README.md","gitBlob":"e21739b842be14d91a17f2508b1a1b629754af01"},
-    {"path":"docs/REQUIREMENTS.md","gitBlob":"a00535b05e265bca945229debabd36e2e36016bf"},
-    {"path":"docs/RETRO_phase1-parser.md","gitBlob":"5cfb7b85ca2f140fc58f9186c47e4635e94a1e6f"},
-    {"path":"docs/SPEC_continuum-admission-v1.md","gitBlob":"0a74a0bfc642337d5d7a85133ce50a0a22caffbd"},
-    {"path":"docs/SPEC_continuum-contract-bundle-v1.md","gitBlob":"65b36bb33a34beb1f246d1f97384631c83ca631e"},
-    {"path":"docs/SPEC_edict-language-v1.md","gitBlob":"a8187fa158f8f510a364dc40e5fee2e7c390f675"},
-    {"path":"docs/SPEC_edict-lawpack-abi-v1.md","gitBlob":"ea1d801f07ab3677f7a411a1f58a28feda589ec3"},
-    {"path":"docs/SPEC_edict-target-profile-abi-v1.md","gitBlob":"91687bfe45565a21f5f93f6ce9eed84095268691"},
-    {"path":"docs/TECHNICAL_EXPLANATION.md","gitBlob":"d88561c0552c0e75d1ecc2eef6f9afd003e99674"},
-    {"path":"docs/abi/edict-authority-facts.cddl","gitBlob":"e9a6d8685706ae0d8dabda401655234161e94299"},
-    {"path":"docs/abi/edict-common.cddl","gitBlob":"836c11b92425beb6d42b378c0defe6f02d144dd7"},
-    {"path":"docs/abi/edict-core.cddl","gitBlob":"862f02939fcc3858b4a60cb75f9bf149eae8ffda"},
-    {"path":"docs/abi/edict-lawpack-adapter.cddl","gitBlob":"8e887c2e196ba7502470ddb45dc7cfd10116ad6b"},
-    {"path":"docs/abi/edict-lawpack.cddl","gitBlob":"96efd51d437ec785b108b51835e9e8bf87aeab51"},
-    {"path":"docs/abi/edict-result-projection.cddl","gitBlob":"98b5c2e861e7e9b66b7481502287cb041f6e77e6"},
-    {"path":"docs/abi/edict-target-ir.cddl","gitBlob":"98134f277ded1920a3a36e5e3946c51153f2e84d"},
-    {"path":"docs/abi/edict-target-profile.cddl","gitBlob":"746ae03001310f3a83524e5332819dad1a4eea5a"},
-    {"path":"docs/abi/edict-target-provider.wit","gitBlob":"0efa5903a52d38dc61e429619d86322c6c5f1fa0"},
-    {"path":"docs/audit/2026-06-28_code-quality.md","gitBlob":"143cbf4f4491a76a6649e919c6edaba73f0bcf4b"},
-    {"path":"docs/audit/2026-06-28_documentation-quality.md","gitBlob":"656b4fa8dea43306af1818f8622cafd72e82a370"},
-    {"path":"docs/audit/2026-06-28_ship-readiness.md","gitBlob":"b9d34a8693564d0134f550092e7645e5d5137442"},
-    {"path":"docs/design/authority-fact-governance.md","gitBlob":"8531061cf718c47ec791f5712b2f357d92adc9e4"},
-    {"path":"docs/design/canonical-target-ir-v0.11.md","gitBlob":"a46acb84e3523b51e2348c776cfdb63a8b98107a"},
-    {"path":"docs/design/contract-bundle-assembly-v0.11.md","gitBlob":"a364f8ade5445808f87cf0c63ab3484c03ad616a"},
-    {"path":"docs/design/crate-scope-v0.11.md","gitBlob":"92fe92285d02465d84bbe82e29d051fdc461f3a6"},
-    {"path":"docs/design/obstruction-strands-v0.md","gitBlob":"81f70fd688c12798cd23472a4e810191e61eabe2"},
-    {"path":"docs/design/provider-artifact-pipeline-alpha.md","gitBlob":"60eefa7dc160aba986bcd1188b79610ff5e9f299"},
-    {"path":"docs/design/schema-as-sot-codegen.md","gitBlob":"d818e0e3f1fafd1d3aba26cb37c739f3ebe69763"},
-    {"path":"docs/design/v2-obligation-closure.md","gitBlob":"816d22d843a33c6f7e143da4cb45e80679609dc8"},
-    {"path":"docs/releases/v0.1.0-alpha.1.md","gitBlob":"5dd96057ba7f109cf5e5acde16e29d18627f98d3"},
-    {"path":"docs/releases/v0.10.0-alpha.1.md","gitBlob":"363c4e9ed6f5ea5758198c7124681b520098e583"},
-    {"path":"docs/releases/v0.11.0-alpha.1.md","gitBlob":"4612dbb5a1aaf20710bdb199b658ded7ced4ebab"},
-    {"path":"docs/releases/v0.2.0-alpha.1.md","gitBlob":"7302ef93ed5ff9b562d9cec92d49d85a6b789b27"},
-    {"path":"docs/releases/v0.3.0-alpha.1.md","gitBlob":"bf023ba4ca2c38f0120c461781447d58fe239ae0"},
-    {"path":"docs/releases/v0.4.0-alpha.1.md","gitBlob":"769500b59800c02c536b76b0eb850d06d6cd8f58"},
-    {"path":"docs/releases/v0.5.0-alpha.1.md","gitBlob":"7c7354e89846ea816992aaf55d4ad04367d61a10"},
-    {"path":"docs/releases/v0.6.0-alpha.1.md","gitBlob":"3f2a0edfc4bccd9f3c60a7443ef4f8cbcbac1971"},
-    {"path":"docs/releases/v0.7.0-alpha.1.md","gitBlob":"57671d5ef5a6b9f16d1674e0a35ddeb86ff126a8"},
-    {"path":"docs/releases/v0.8.0-alpha.1.md","gitBlob":"12f77bda185c54fbbd136bf0dc7292716ecdfa39"},
-    {"path":"docs/releases/v0.9.0-alpha.1.md","gitBlob":"fa295fcf0967415bb052f238256919b32b3fe6ba"},
-    {"path":"docs/schemas/edict.cli-check-result.v1.schema.json","gitBlob":"eef8cd11f07e06d68b7051efa60ae05f2cfd8a63"},
-    {"path":"docs/schemas/edict.cli-diagnostic.v1.schema.json","gitBlob":"92a2151a76893c598a4191ed6cecd8a0e671613f"},
-    {"path":"docs/schemas/edict.cli-event.v1.schema.json","gitBlob":"705d82a893c2ea91caa91ad6977a9be8646b47bb"},
-    {"path":"docs/schemas/edict.cli-info.v1.schema.json","gitBlob":"2d9a0777b4190b56ff569625275d352d17363afa"},
-    {"path":"docs/schemas/edict.compiler-input.v1.schema.json","gitBlob":"26da3ba0fe85fab4c826ad79f13968ce09c4f29b"},
-    {"path":"docs/schemas/edict.compiler-settings.v1.schema.json","gitBlob":"a3e8ba469895b84ab81724da1075c73141a8dd0c"},
-    {"path":"docs/schemas/edict.projection-core.v1.schema.json","gitBlob":"8c0afe3834256abd1e18efb5f31eae1c4bdf0374"},
-    {"path":"docs/schemas/edict.projection-diagnostics.v1.schema.json","gitBlob":"28cfb0a67dff7b8f879122c74433158dc0a4e5df"},
-    {"path":"docs/schemas/edict.projection-syntax.v1.schema.json","gitBlob":"a85f2e14f536863f5e7b107b1a9f3f10816e6234"},
-    {"path":"docs/schemas/edict.projection-target-ir.v1.schema.json","gitBlob":"8bbb6495ad8800d775d1c08506e85351038d678a"},
-    {"path":"docs/topics/README.md","gitBlob":"99b06d3124c71cb62dfe6faff7604c13063162a7"},
-    {"path":"docs/topics/admission/README.md","gitBlob":"755dcba96c0a428eec18d58a529f3e26d57d118c"},
-    {"path":"docs/topics/admission/test-plan.md","gitBlob":"68ee0a2d2502103285985bf862de9fadf2bac5a0"},
-    {"path":"docs/topics/assurance/README.md","gitBlob":"cf382008f3d3094a5380a687abbf07538e07404d"},
-    {"path":"docs/topics/assurance/test-plan.md","gitBlob":"0ea6c971924db763088577a0a52bbd30bfec814c"},
-    {"path":"docs/topics/authority-facts/README.md","gitBlob":"c5589d2489d6e4a5729c0df2b2655ff281d8d88d"},
-    {"path":"docs/topics/authority-facts/test-plan.md","gitBlob":"e3769edf8309347b23ffa2e8f0901e06feabd654"},
-    {"path":"docs/topics/cli/README.md","gitBlob":"af38946c9ccae8da343877c3861b0f52b6076e1b"},
-    {"path":"docs/topics/cli/test-plan.md","gitBlob":"d72d69ef1d340ffd7057a63dd7bc07e3dfb2c166"},
-    {"path":"docs/topics/compiler-spine/README.md","gitBlob":"6cc754abfdced28d919d5ae9f9ec4d924afc16d7"},
-    {"path":"docs/topics/compiler-spine/test-plan.md","gitBlob":"8a73925d919a6fb6ee62f713b1603c5f4fe9c179"},
-    {"path":"docs/topics/contract-bundles/README.md","gitBlob":"2347499e8da9dd57bb1588faf67fe386c7a70c03"},
-    {"path":"docs/topics/contract-bundles/test-plan.md","gitBlob":"3ae4c7362f90fa89081ab9ff2bf1c3db1a811874"},
-    {"path":"docs/topics/core-ir/README.md","gitBlob":"a8759d0f26569a60590792aadc9ba28d8daea004"},
-    {"path":"docs/topics/core-ir/canonical-encoding.md","gitBlob":"34927c69fb1de10b685294a155fc46bb4ac21628"},
-    {"path":"docs/topics/core-ir/test-plan.md","gitBlob":"00d55085e24a6639b02558ea48af68beea97cb65"},
-    {"path":"docs/topics/developer-tooling/README.md","gitBlob":"8648d3c1bdf4f6b774bc5fec71c71aa8c59b0ce8"},
-    {"path":"docs/topics/developer-tooling/test-plan.md","gitBlob":"9240f717434dfbca08a6366e6d3ebafd4ef2c908"},
-    {"path":"docs/topics/documentation/README.md","gitBlob":"34fa7f4db136c274a88b680f99619d657fda15d5"},
-    {"path":"docs/topics/documentation/test-plan.md","gitBlob":"47964954fbf640211bc30b0dd361c44c9955c488"},
-    {"path":"docs/topics/external-action-requests/README.md","gitBlob":"73aae64e1adb730c00b680d18aea76f64adc23cb"},
-    {"path":"docs/topics/external-action-requests/test-plan.md","gitBlob":"438184fc13353250a0c0976e3c3cc8cba605fa00"},
-    {"path":"docs/topics/fixtures/README.md","gitBlob":"c8b3b196109fb6d4e37d8ffa17635166010075fb"},
-    {"path":"docs/topics/fixtures/test-plan.md","gitBlob":"624357dbc544d365835390d3d3c2f11015b7b82f"},
-    {"path":"docs/topics/lawpack-authoring/README.md","gitBlob":"74bb25cc22e1f88cf4ee952b42313d919339113a"},
-    {"path":"docs/topics/lawpack-authoring/test-plan.md","gitBlob":"d7ad2eacde45dbce3eeb2b1a22c6482134b841ba"},
-    {"path":"docs/topics/lawpacks/README.md","gitBlob":"dedaa524dc55663a44bf8101241ab4b6d4755531"},
-    {"path":"docs/topics/lawpacks/test-plan.md","gitBlob":"f8aa2c7ce40dad2665134956dc95d951d311808f"},
-    {"path":"docs/topics/lowerability/README.md","gitBlob":"fb9519af3539d846dc5bf2915bf5ca86816e46f8"},
-    {"path":"docs/topics/lowerability/test-plan.md","gitBlob":"e0fbff0799ba805c9531097d6b8aeea657e2b815"},
-    {"path":"docs/topics/obstruction-strands/README.md","gitBlob":"a2930645065390cecff8008bfd48b7f034bfcd18"},
-    {"path":"docs/topics/obstruction-strands/test-plan.md","gitBlob":"20c54ffcaa19930a5bc772a49a5f01119054be2d"},
-    {"path":"docs/topics/providers/README.md","gitBlob":"8b5a07fb9c708b753861a4e156b866115f4d687b"},
-    {"path":"docs/topics/providers/architecture.md","gitBlob":"664b38347ccaf37f298d6ac9f19d3423c0277f9e"},
-    {"path":"docs/topics/providers/test-plan.md","gitBlob":"95c55f9e132ca6859fd9df70470973e678ed8d92"},
-    {"path":"docs/topics/public-rust-api/README.md","gitBlob":"c64a1081b7f693b02bd2ea63329f2610bae9d84c"},
-    {"path":"docs/topics/public-rust-api/test-plan.md","gitBlob":"4c3b9e9662afd9edb790ba2b5c57ed5e93df595c"},
-    {"path":"docs/topics/release-process/README.md","gitBlob":"a474ab8b6a4a58c5c73334c9e677be7c20d1837c"},
-    {"path":"docs/topics/release-process/policy.toml","gitBlob":"e40b4f4ec721ae61210ec1bb022a847bcb49fb4a"},
-    {"path":"docs/topics/release-process/runbook.md","gitBlob":"0b6bd8ef44cbfe8c7cdc347273fa74b7c96c4823"},
-    {"path":"docs/topics/release-process/test-plan.md","gitBlob":"61ecded1d2318d7dd74070cd1c6155f353c947e9"},
-    {"path":"docs/topics/result-projections/README.md","gitBlob":"d5c2f85a7681a15dcdc3e35f992a389c50d13461"},
-    {"path":"docs/topics/result-projections/test-plan.md","gitBlob":"9e69d58c88d6a9b7389334a78b994a3449721faa"},
-    {"path":"docs/topics/review-process/README.md","gitBlob":"25190d37dc30110f75ba5d3a41494575ffecc1c3"},
-    {"path":"docs/topics/review-process/policy.toml","gitBlob":"a826ba58aad2e509220b65aa8f96c290b600e094"},
-    {"path":"docs/topics/review-process/test-plan.md","gitBlob":"f1a50aeae47913e4513a8149c1679d9a94c5ef21"},
-    {"path":"docs/topics/rust-standards/README.md","gitBlob":"2fe29258705d117f4d10604a83fd832a8476e303"},
-    {"path":"docs/topics/rust-standards/test-plan.md","gitBlob":"0e0d6b306cd2b58db07a7a5da6a752925fe58764"},
-    {"path":"docs/topics/semantic-validation/README.md","gitBlob":"51cd9761755e7b5879069bf3774eeb487982ca97"},
-    {"path":"docs/topics/semantic-validation/test-plan.md","gitBlob":"b43969d8eb0a884c1663ab761662f9622617bb3b"},
-    {"path":"docs/topics/syntax/README.md","gitBlob":"b2a372bf41b1976567c61f400bf000f33abc20cc"},
-    {"path":"docs/topics/syntax/test-plan.md","gitBlob":"a69efaf12dfe12661fca049b8790b37fa3fb3665"},
-    {"path":"docs/topics/target-ir/README.md","gitBlob":"3970b7e10985a1f1f0628eb6066a09821bce2856"},
-    {"path":"docs/topics/target-ir/test-plan.md","gitBlob":"c6bed244f422eb39b30b886bfc7bf44f54fad0e6"},
-    {"path":"docs/topics/target-profiles/README.md","gitBlob":"6a88f4d732f8069855b2ed2cb9a8769a117b2f60"},
-    {"path":"docs/topics/target-profiles/test-plan.md","gitBlob":"90084c3f3a1296745469cd86e9b5f2bc928825be"},
-    {"path":"docs/topics/tests/README.md","gitBlob":"4ad079b6a9718e2a8446a6c67ff45735015bef84"},
-    {"path":"docs/topics/tests/test-plan.md","gitBlob":"46bc0572d02a41e86f71c6d46baf5be611a462a6"},
-    {"path":"docs/topics/v2-design/README.md","gitBlob":"b33a07599e43e660aa4def7f119ddd02df6a16de"},
-    {"path":"docs/topics/v2-design/test-plan.md","gitBlob":"f17f96d381f81b20842393f70ff55b9597858b84"},
-    {"path":"editors/README.md","gitBlob":"7a933576262bc58bac197f9264fdbf649dd5e696"},
-    {"path":"editors/vscode/.vscodeignore","gitBlob":"f15b3142e4b8af11d580789a0c82acee3499f571"},
-    {"path":"editors/vscode/README.md","gitBlob":"8b29840ae9ec8f618b7364022329f694d0ed9746"},
-    {"path":"editors/vscode/language-configuration.json","gitBlob":"b7f583841649c9c437785edbfcb70ee24e495c79"},
-    {"path":"editors/vscode/package.json","gitBlob":"cd9e391e7c9afb6f9393fcead118e0e55aadc839"},
-    {"path":"editors/vscode/syntaxes/edict.tmLanguage.json","gitBlob":"5847d8edfdb32d822f0f3950f41d00c947982185"},
-    {"path":"fixtures/README.md","gitBlob":"470e3e0fc3aa00654930ecdef892ee9df8a42c8d"},
-    {"path":"fixtures/authority-facts/canonical/README.md","gitBlob":"28692ce70add5d4f2d4ff5318309c3353924caf9"},
-    {"path":"fixtures/authority-facts/canonical/example-effectful.authority-facts.cbor","gitBlob":"fe2e59a8e2602e02c52094010a130db2637c5227"},
-    {"path":"fixtures/authority-facts/canonical/example-effectful.authority-facts.json","gitBlob":"009faa5d2dc1dcf55cf284dcfd14c0b6405f3e0d"},
-    {"path":"fixtures/authority-facts/canonical/example-effectful.authority-facts.sha256","gitBlob":"a3d68f0a3b3a586e85b6a84cbd884866e662951f"},
-    {"path":"fixtures/bundle/assembly/bounded-hello.bundle-digests.txt","gitBlob":"da5402db7bd41dd88c6152b7799723561130c91e"},
-    {"path":"fixtures/cli/01-source-ok/expected.stdout.jsonl","gitBlob":"e08ccf8fdedd3a73beef5d06c443a1bc60274ce1"},
-    {"path":"fixtures/cli/01-source-ok/request.jsonl","gitBlob":"002fea597e6b93c8468d6972b73cc1344600fa87"},
-    {"path":"fixtures/cli/02-source-parse-rejection/exit","gitBlob":"d00491fd7e5bb6fa28c517a0bb32b8b506539d4d"},
-    {"path":"fixtures/cli/02-source-parse-rejection/expected.stderr.jsonl","gitBlob":"1077b73c9a7c02eae99f737bea7b6ff8c64d04da"},
-    {"path":"fixtures/cli/02-source-parse-rejection/request.jsonl","gitBlob":"dce01f0466bd9384fc6f5cbe2845b6e0bd9a9cfd"},
-    {"path":"fixtures/cli/03-source-semantic-rejection/exit","gitBlob":"d00491fd7e5bb6fa28c517a0bb32b8b506539d4d"},
-    {"path":"fixtures/cli/03-source-semantic-rejection/expected.stderr.jsonl","gitBlob":"5ec447700da52d0b4ce1f75825eb9bffaed4884b"},
-    {"path":"fixtures/cli/03-source-semantic-rejection/request.jsonl","gitBlob":"ddfd529e5448760387961febbd4ce013e49de435"},
-    {"path":"fixtures/cli/04-cli-missing-settings/exit","gitBlob":"0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"},
-    {"path":"fixtures/cli/04-cli-missing-settings/expected.stderr.jsonl","gitBlob":"5060bd2fd773ba9ea3ea6db8c80b86a846bfadbd"},
-    {"path":"fixtures/cli/04-cli-missing-settings/request.jsonl","gitBlob":"8eb12e58d427bd64ccfe339190e05bdccf4c8634"},
-    {"path":"fixtures/cli/05-path-input-ok/expected.stdout.jsonl","gitBlob":"a05fc582efc41b6414e785167b5deeb7532088ef"},
-    {"path":"fixtures/cli/05-path-input-ok/inputs/hello.edict","gitBlob":"39c53bb184a7c10de61da0c637b607eb1d7cc454"},
-    {"path":"fixtures/cli/05-path-input-ok/request.jsonl","gitBlob":"18facaab79dc198134c535df389cba79efe7dce7"},
-    {"path":"fixtures/cli/06-directory-expansion-ok/expected.stdout.jsonl","gitBlob":"ef59591526e2084ddf5057249bbc96ab660cf256"},
-    {"path":"fixtures/cli/06-directory-expansion-ok/inputs/a.edict","gitBlob":"39c53bb184a7c10de61da0c637b607eb1d7cc454"},
-    {"path":"fixtures/cli/06-directory-expansion-ok/inputs/ignore.txt","gitBlob":"ed34ae8da336ff94a67b6125fbd6be730c976d91"},
-    {"path":"fixtures/cli/06-directory-expansion-ok/inputs/nested/b.edict","gitBlob":"39c53bb184a7c10de61da0c637b607eb1d7cc454"},
-    {"path":"fixtures/cli/06-directory-expansion-ok/request.jsonl","gitBlob":"bd9aad14fe79caccacaa6d00ffd32b5e13b3551f"},
-    {"path":"fixtures/cli/07-path-list-ok/expected.stdout.jsonl","gitBlob":"643ecb3e659c10cb98255ec1aced772778e76eb0"},
-    {"path":"fixtures/cli/07-path-list-ok/inputs/first.edict","gitBlob":"39c53bb184a7c10de61da0c637b607eb1d7cc454"},
-    {"path":"fixtures/cli/07-path-list-ok/inputs/second.edict","gitBlob":"39c53bb184a7c10de61da0c637b607eb1d7cc454"},
-    {"path":"fixtures/cli/07-path-list-ok/request.jsonl","gitBlob":"f11265b02c5b7559ced4d975471a78b5bef3ee27"},
-    {"path":"fixtures/cli/08-glob-expansion-ok/expected.stdout.jsonl","gitBlob":"90164a7fce6c51abdadef8f0586d2c56113d9712"},
-    {"path":"fixtures/cli/08-glob-expansion-ok/inputs/x.edict","gitBlob":"39c53bb184a7c10de61da0c637b607eb1d7cc454"},
-    {"path":"fixtures/cli/08-glob-expansion-ok/inputs/y.edict","gitBlob":"39c53bb184a7c10de61da0c637b607eb1d7cc454"},
-    {"path":"fixtures/cli/08-glob-expansion-ok/request.jsonl","gitBlob":"9335acf3a008ab8fb9942b3e22d73c456ed3827e"},
-    {"path":"fixtures/cli/09-shape-source-ok/expected.stdout.jsonl","gitBlob":"ac6f9259502ebfe484e1c07a5f53865888dd8207"},
-    {"path":"fixtures/cli/09-shape-source-ok/request.jsonl","gitBlob":"64c75d9a7b40985bacf0e59a943a16e20419c602"},
-    {"path":"fixtures/cli/10-input-extra-field/exit","gitBlob":"0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"},
-    {"path":"fixtures/cli/10-input-extra-field/expected.stderr.jsonl","gitBlob":"2f5a8fba093b71d15a5b37504ad0352191c8299c"},
-    {"path":"fixtures/cli/10-input-extra-field/request.jsonl","gitBlob":"6052212c652d41f03144a7d3d4018b1cdd18cd09"},
-    {"path":"fixtures/cli/11-input-hybrid-kind/exit","gitBlob":"0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"},
-    {"path":"fixtures/cli/11-input-hybrid-kind/expected.stderr.jsonl","gitBlob":"7b6d2ac0c8afbf5e3991498846c2fc4847ac9453"},
-    {"path":"fixtures/cli/11-input-hybrid-kind/request.jsonl","gitBlob":"b893b640aa6631c77f2a889a807afa31632ac2db"},
-    {"path":"fixtures/cli/12-input-too-large/env.json","gitBlob":"ab0c7f13fc6b22d61fc73da2f1787ff3aa298ecb"},
-    {"path":"fixtures/cli/12-input-too-large/exit","gitBlob":"0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"},
-    {"path":"fixtures/cli/12-input-too-large/expected.stderr.jsonl","gitBlob":"ebda022d79c978d4ff511579512be2c642e3e902"},
-    {"path":"fixtures/cli/12-input-too-large/request.jsonl","gitBlob":"1e2fbb102503356bbcc627f49a5b58590859f170"},
-    {"path":"fixtures/cli/13-input-root-outside/allowed/.gitkeep","gitBlob":"8b137891791fe96927ad78e64b0aad7bded08bdc"},
-    {"path":"fixtures/cli/13-input-root-outside/exit","gitBlob":"0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"},
-    {"path":"fixtures/cli/13-input-root-outside/expected.stderr.jsonl","gitBlob":"9c5b8567a755c9ea2ee6e0168bf96f429185f675"},
-    {"path":"fixtures/cli/13-input-root-outside/outside/outside.edict","gitBlob":"44abebc15811c38cc266007484dd74ae10a26a4d"},
-    {"path":"fixtures/cli/13-input-root-outside/request.jsonl","gitBlob":"116dbbb4b1a80938bc042e41747872cb6da161cd"},
-    {"path":"fixtures/cli/README.md","gitBlob":"9388df4182fedec41c353e85cf9210e88906fa3d"},
-    {"path":"fixtures/core/canonical/README.md","gitBlob":"d9a0ca79557c3623c0b843d9eff4808f94fd7b18"},
-    {"path":"fixtures/core/canonical/bounded-hello.core.cbor","gitBlob":"a0ec54aa1a5e20624192091526445cfd803e6f0c"},
-    {"path":"fixtures/core/canonical/bounded-hello.core.sha256","gitBlob":"86ba062c26a3ad3fd733ccd8c80d7faa7ed62d94"},
-    {"path":"fixtures/core/canonical/statement-branch.core.hex","gitBlob":"c22760cace0e4d146a2fdc8d7c7b50c38497622a"},
-    {"path":"fixtures/core/canonical/statement-branch.core.sha256","gitBlob":"0b62657b192232390479319f0a1c8f601020a58f"},
-    {"path":"fixtures/core/canonical/workspace-snapshot.core.cbor","gitBlob":"58e4f724610861f5b61537bf386a87062e8a57a7"},
-    {"path":"fixtures/core/canonical/workspace-snapshot.core.sha256","gitBlob":"4bcb3e0813cd3f4a7afc7cf311d846f1dfdd0a9d"},
-    {"path":"fixtures/core/schema/accepted/core-fn-body-minimal.fields","gitBlob":"bef3ca412ab0ea97465b8658499ae5e05e1ec760"},
-    {"path":"fixtures/core/schema/accepted/core-intent-minimal.fields","gitBlob":"268b28ce942fed4f139aafe5c7cd50c15a0ee640"},
-    {"path":"fixtures/core/schema/accepted/core-module-minimal.fields","gitBlob":"249ff76349f936c9a5ff6cb65d81de8e80d53de8"},
-    {"path":"fixtures/core/schema/rejected/core-fn-body-effect-node-field.fields","gitBlob":"9af8fa3540b25ec810936bc4dc82e26f6dd0dd48"},
-    {"path":"fixtures/core/schema/rejected/core-intent-unknown-verified-mode.fields","gitBlob":"667ae032ee117f32c1bcbafd21393e406621f517"},
-    {"path":"fixtures/core/schema/rejected/core-module-missing-intents.fields","gitBlob":"17f37c7ac4c199de4eace7f31e6a59b9a6d3a0f6"},
-    {"path":"fixtures/core/schema/rejected/local-ref-missing-alpha-name.fields","gitBlob":"456a89528ffe74d892be40c9c9be4a078ff5c18a"},
-    {"path":"fixtures/lang/bounds/bounded-hello.edict","gitBlob":"e3443a1d3b1c8f0e137ac698b621dd2f3afb673b"},
-    {"path":"fixtures/lang/effects/conditional-blob.edict","gitBlob":"1e4f2ca6112f26d57ee4d20058666ec7cd693b75"},
-    {"path":"fixtures/lang/effects/read-greeting.edict","gitBlob":"5e3838d1547be171e0a0384a7a200f52a2b9d139"},
-    {"path":"fixtures/lang/external-actions/workspace-snapshot.edict","gitBlob":"e54b0fbccad2fd680505f3ee46ca28d39d7e776e"},
-    {"path":"fixtures/lang/operations/explicit-basis-u64.edict","gitBlob":"444d8ca77b9827746df81885f0620dce2d1a3b73"},
-    {"path":"fixtures/lang/tooling/highlight-smoke.edict","gitBlob":"8c2d91084be22e5e1594a42159992aca95c73612"},
-    {"path":"fixtures/lang/types/color-match.edict","gitBlob":"dd98d6de677904f36d7601165a0094d92928e536"},
-    {"path":"fixtures/lawpack/causal-cell/README.md","gitBlob":"52e8cc1e2af8aea86c1090a1b20b5f5ab3e07c06"},
-    {"path":"fixtures/lawpack/causal-cell/adapter.cbor","gitBlob":"3b0c8b1b3a8591a322b6e785d9f963899319310c"},
-    {"path":"fixtures/lawpack/causal-cell/adapter.sha256","gitBlob":"f8231bc941e1fbe02279865a82e183cbeeb0988a"},
-    {"path":"fixtures/lawpack/causal-cell/echo-operation-configuration.cbor","gitBlob":"24527d30d0146b567fda157561ac6a2587cae919"},
-    {"path":"fixtures/lawpack/causal-cell/echo-operation-configuration.sha256","gitBlob":"d293c8a14b1955a3e171703400c4df620c7871a1"},
-    {"path":"fixtures/lawpack/causal-cell/exports.cbor","gitBlob":"384f4839adfe8e5b0f1aa848bfe2aeb1c3f640b6"},
-    {"path":"fixtures/lawpack/causal-cell/exports.sha256","gitBlob":"4f836f6b03497338a1f8eacc55480cbe1a3b49e9"},
-    {"path":"fixtures/lawpack/causal-cell/manifest.cbor","gitBlob":"b9311a236d7898861a0b90b1f30b852b35cef623"},
-    {"path":"fixtures/lawpack/causal-cell/manifest.sha256","gitBlob":"685fd6a6c72fc3100d595d009b6198a81c731a40"},
-    {"path":"fixtures/lawpack/hello-echo/README.md","gitBlob":"79f6612f1f5608a8f7dc4835e5470878cd27f96e"},
-    {"path":"fixtures/lawpack/hello-echo/adapter.cbor","gitBlob":"24e2f546e2b97747b53462a72faaa1d5d85d62f1"},
-    {"path":"fixtures/lawpack/hello-echo/adapter.sha256","gitBlob":"91df491028061e026ecaaeb4e1598e2ac369af44"},
-    {"path":"fixtures/lawpack/hello-echo/create-greeting.core.cbor","gitBlob":"246b6135855c415def0bd89b275f0457752ee563"},
-    {"path":"fixtures/lawpack/hello-echo/create-greeting.core.sha256","gitBlob":"9adc71605e0a275349161809614bd17de97d129c"},
-    {"path":"fixtures/lawpack/hello-echo/create-greeting.edict","gitBlob":"825d50565230bd71d62bfbeb59d0399a89864b4c"},
-    {"path":"fixtures/lawpack/hello-echo/create-greeting.result-projection.cbor","gitBlob":"981cba6e1c7ab6bdae6829116749c4796167e4e6"},
-    {"path":"fixtures/lawpack/hello-echo/create-greeting.result-projection.sha256","gitBlob":"d55e4083771e1d9791f59cf87fd5cc5f1ea3b9f4"},
-    {"path":"fixtures/lawpack/hello-echo/create-greeting.target-ir.cbor","gitBlob":"c8a934cefec17dbab0a43d9be9cebd2533268798"},
-    {"path":"fixtures/lawpack/hello-echo/create-greeting.target-ir.sha256","gitBlob":"20186cbe9482e8a7df7c44fabec13ffd4efbcf36"},
-    {"path":"fixtures/lawpack/hello-echo/echo-operation-configuration.cbor","gitBlob":"84838ab0d8627237232fa5a9b9fa39087bcc5f8a"},
-    {"path":"fixtures/lawpack/hello-echo/echo-operation-configuration.sha256","gitBlob":"0898688f14067560dd22abd04b97f020071fd3e8"},
-    {"path":"fixtures/lawpack/hello-echo/exports.cbor","gitBlob":"0e1220ceed9442a7b35870eeb02fcb65454d8c5c"},
-    {"path":"fixtures/lawpack/hello-echo/exports.sha256","gitBlob":"e1f3e9223de9ce935bc7f60dda3cfa7d12d54fdc"},
-    {"path":"fixtures/lawpack/hello-echo/manifest.cbor","gitBlob":"d715900f03ec454a0ad96e6710f52a46120d0b9d"},
-    {"path":"fixtures/lawpack/hello-echo/manifest.sha256","gitBlob":"20171199b401cecace2dd74e18f3cc1d5c7ed3de"},
-    {"path":"fixtures/lawpack/workspace-patch/README.md","gitBlob":"67cd35f2e0660aa7455de1c197ad821d5438679b"},
-    {"path":"fixtures/lawpack/workspace-patch/adapter.cbor","gitBlob":"2d6f09a7e2fab381b97a05cfad1e692902e878c3"},
-    {"path":"fixtures/lawpack/workspace-patch/adapter.sha256","gitBlob":"d44eb9675e126716e8a5ef3c53fd39ade49d76fb"},
-    {"path":"fixtures/lawpack/workspace-patch/apply-validated-patch.core.cbor","gitBlob":"6a88c127e426288a3e51d4749d5c31d5b0cb60cb"},
-    {"path":"fixtures/lawpack/workspace-patch/apply-validated-patch.core.sha256","gitBlob":"0204b6f1d8b346a67800a7738ee39df49e78571f"},
-    {"path":"fixtures/lawpack/workspace-patch/apply-validated-patch.edict","gitBlob":"6e11a3d022a53a8fb2c20a77e35e29840f5fe086"},
-    {"path":"fixtures/lawpack/workspace-patch/apply-validated-patch.target-ir.cbor","gitBlob":"a6124a995a3cdbb5d39cd0a6e046b329048703aa"},
-    {"path":"fixtures/lawpack/workspace-patch/apply-validated-patch.target-ir.sha256","gitBlob":"f7ac419ce15b32d491e09bddbe7c75f8227f51d8"},
-    {"path":"fixtures/lawpack/workspace-patch/exports.cbor","gitBlob":"3a6fd19dc8059b9fe1bde74fb1da61398b0e80cc"},
-    {"path":"fixtures/lawpack/workspace-patch/exports.sha256","gitBlob":"b301dd883a31fffe324e9306ec90ae2b1ec44520"},
-    {"path":"fixtures/lawpack/workspace-patch/input-schema.cbor","gitBlob":"3045d9b696864fefe111c3eb641b3b68532752d2"},
-    {"path":"fixtures/lawpack/workspace-patch/input-schema.sha256","gitBlob":"9f1284b4f0a2c7f6dbe1915a6113cd13a9700cb8"},
-    {"path":"fixtures/lawpack/workspace-patch/manifest.cbor","gitBlob":"77e56c7525f0e64ab191f0adfeac12b540c87848"},
-    {"path":"fixtures/lawpack/workspace-patch/manifest.sha256","gitBlob":"8316978e68565f29a30a6978d33d907710185857"},
-    {"path":"fixtures/lawpack/workspace-patch/reconciliation-law.cbor","gitBlob":"0736b75f81913fca7ac95c56ec45f66b95aea4cf"},
-    {"path":"fixtures/lawpack/workspace-patch/reconciliation-law.sha256","gitBlob":"de31fc9fda59fa3c29397e5fc48db224e8e1fee7"},
-    {"path":"fixtures/lawpack/workspace-patch/request-profile-configuration.cbor","gitBlob":"5e2870b2f562bafaa73a91a3fc192f5ed39257c7"},
-    {"path":"fixtures/lawpack/workspace-patch/request-profile-configuration.sha256","gitBlob":"4345ae2e39ce3f4d9cfa6b0dddf4ce56d56c035c"},
-    {"path":"fixtures/lawpack/workspace-patch/settlement-schema.cbor","gitBlob":"0a93ac19c51b341602eeba524769147e962d5d60"},
-    {"path":"fixtures/lawpack/workspace-patch/settlement-schema.sha256","gitBlob":"f1bb3fb0313dd6815b4184345194949ec40fe9e1"},
-    {"path":"fixtures/lawpack/workspace-snapshot/README.md","gitBlob":"996bd1d29b28769fff477084d9118d0833ca2970"},
-    {"path":"fixtures/lawpack/workspace-snapshot/adapter.cbor","gitBlob":"9be4ea568b602b56269af505deb809989a3fa8b5"},
-    {"path":"fixtures/lawpack/workspace-snapshot/adapter.sha256","gitBlob":"1e287be0a322e5444dea15fa14bcfc7cf12975c4"},
-    {"path":"fixtures/lawpack/workspace-snapshot/exports.cbor","gitBlob":"33fe04db74775c191d4b7400e1fb2b6393c5a010"},
-    {"path":"fixtures/lawpack/workspace-snapshot/exports.sha256","gitBlob":"e057cac7fc360e6599b7ddab88508aaf0f2f55f8"},
-    {"path":"fixtures/lawpack/workspace-snapshot/input-schema.cbor","gitBlob":"49c849169946e44c8b5f300279dd085bd6b63aeb"},
-    {"path":"fixtures/lawpack/workspace-snapshot/input-schema.sha256","gitBlob":"9dd7bb6e48192e90d19fc346d1705f736b1d85d7"},
-    {"path":"fixtures/lawpack/workspace-snapshot/manifest.cbor","gitBlob":"d4e58e3d4646ca967170a6882f2a617cb8d81390"},
-    {"path":"fixtures/lawpack/workspace-snapshot/manifest.sha256","gitBlob":"0edb311125a89a5816ee3fa0c9b700c9b3bcff3d"},
-    {"path":"fixtures/lawpack/workspace-snapshot/observe-workspace.core.cbor","gitBlob":"a4b249dfb197f1a6b4adc06855f16e4305a1c798"},
-    {"path":"fixtures/lawpack/workspace-snapshot/observe-workspace.core.sha256","gitBlob":"ea6b914d14907d9fd915058e579aff33c954da2c"},
-    {"path":"fixtures/lawpack/workspace-snapshot/observe-workspace.edict","gitBlob":"c2c10f1ef1009796d67061b9722c4db9bb4e031b"},
-    {"path":"fixtures/lawpack/workspace-snapshot/observe-workspace.target-ir.cbor","gitBlob":"bdab1b0c55a34360c7e9ab304af91fe2b1e4afce"},
-    {"path":"fixtures/lawpack/workspace-snapshot/observe-workspace.target-ir.sha256","gitBlob":"7342aaa96221d6c8efa75ead2af5563791ccfeff"},
-    {"path":"fixtures/lawpack/workspace-snapshot/reconciliation-law.cbor","gitBlob":"df55572b350002a3df98ccb3e72dd60c86b9aead"},
-    {"path":"fixtures/lawpack/workspace-snapshot/reconciliation-law.sha256","gitBlob":"957cd04c78c130b07d2cad2fd7e07ae69978be57"},
-    {"path":"fixtures/lawpack/workspace-snapshot/request-profile-configuration.cbor","gitBlob":"708f18918ee1703491a910df82e129e711a4cc46"},
-    {"path":"fixtures/lawpack/workspace-snapshot/request-profile-configuration.sha256","gitBlob":"d9953d9dcaa41c98387226d1980f40b24d2bc3cb"},
-    {"path":"fixtures/lawpack/workspace-snapshot/settlement-schema.cbor","gitBlob":"f01ad68531267666e6bf93bf30a37d5b311c1676"},
-    {"path":"fixtures/lawpack/workspace-snapshot/settlement-schema.sha256","gitBlob":"06fcc0ee2b976a09b3017bd93132a3c51eb1317e"},
-    {"path":"fixtures/obstruction-strands/v0/stale-basis/README.md","gitBlob":"25efbfa04e2e6104c5434f329128333e895e2b0a"},
-    {"path":"fixtures/obstruction-strands/v0/stale-basis/source.edict","gitBlob":"e487b46e81220c50e6f928922dada29f3a21ca6a"},
-    {"path":"fixtures/provider-contracts/v1/README.md","gitBlob":"447692907f9268ce3b6b78c43b7cbbb0417aeadf"},
-    {"path":"fixtures/provider-contracts/v1/edict-provider-contracts.cddl","gitBlob":"07048aeeadb5062eabb89e995713cbc0893b7d7e"},
-    {"path":"fixtures/provider-contracts/v1/manifest.json","gitBlob":"d2c8de5d61049e9f4182c630bf82b138f0f96792"},
-    {"path":"fixtures/providers/README.md","gitBlob":"c26ee60a4930e3e0784c76cb855e48234a5c6b58"},
-    {"path":"fixtures/providers/components/guests/Cargo.lock","gitBlob":"d7858ce7bc67deabb5ff352a24c85a7caa0ef4b0"},
-    {"path":"fixtures/providers/components/guests/Cargo.toml","gitBlob":"450a24aed25dc73661b0ae8adfe2630dfecc9b07"},
-    {"path":"fixtures/providers/components/guests/lowerer/Cargo.toml","gitBlob":"568aa137fa215b6b973fe31e12322530b393b9dc"},
-    {"path":"fixtures/providers/components/guests/lowerer/src/lib.rs","gitBlob":"b39a8a0b18fe9ed7cb90277f793056434afa1318"},
-    {"path":"fixtures/providers/components/guests/verifier/Cargo.toml","gitBlob":"f814f2c8c248bbf03389f5a0936f80cd4dada5b6"},
-    {"path":"fixtures/providers/components/guests/verifier/src/lib.rs","gitBlob":"3f07ffdfd808ff95b206a2c08c2d481ccaf0e165"},
-    {"path":"fixtures/providers/components/instantiation-failure-lowerer.component.wasm","gitBlob":"bd2d7c0d31798d7676aedab0bd0d289fc2053bef"},
-    {"path":"fixtures/providers/components/instantiation-failure-lowerer.wat","gitBlob":"f6f5a70edb80d3a7fa1dee13b34ab5b8b44274d7"},
-    {"path":"fixtures/providers/components/instantiation-fuel-lowerer.component.wasm","gitBlob":"0804d26d3ddb428682ca87ecad03cf0e05ef64af"},
-    {"path":"fixtures/providers/components/instantiation-fuel-lowerer.wat","gitBlob":"80e972463ef593602d27c7d7cec78d87d22ff727"},
-    {"path":"fixtures/providers/components/inventory.json","gitBlob":"45cf2e8e937a17a8ee05dfa8d68e94dcc155e129"},
-    {"path":"fixtures/providers/components/lowerer.component.wasm","gitBlob":"6c1cf123a44284d15b7b1e90f1905ae94e65c158"},
-    {"path":"fixtures/providers/components/malformed-lowerer.component.wasm","gitBlob":"be873af81100dc76ed1f3f1f818a41da45a38e4c"},
-    {"path":"fixtures/providers/components/malformed-lowerer.wat","gitBlob":"1e7bfffe0a0baf230d9fb5766083f82198f4029c"},
-    {"path":"fixtures/providers/components/verifier.component.wasm","gitBlob":"671adbe7931d0a9a5e0c78d459c244d37a135a69"},
-    {"path":"fixtures/providers/echo-generated/provider-manifest.json","gitBlob":"22c8560e7ddecacd5da388e52d3935d7fc1474b9"},
-    {"path":"fixtures/providers/echo-target-profile/README.md","gitBlob":"350c33dcda2d66d2d50e589c58db7c6d7b14a80b"},
-    {"path":"fixtures/providers/echo-target-profile/generated/primary/target-profile.echo-dpo.cbor","gitBlob":"9fa43529b1021dfd8e3a33256c832d4eee6f4a47"},
-    {"path":"fixtures/providers/wit/legacy-target-profile.wit","gitBlob":"ae7d6af764012b16bf06bfa260ccba98a7f04868"},
-    {"path":"fixtures/target-ir/canonical/echo-effectful.target-ir.cbor","gitBlob":"727a80eb37319dbdbea40d7d9b4e37f0d93d8d84"},
-    {"path":"fixtures/target-ir/canonical/echo-effectful.target-ir.sha256","gitBlob":"6d050bb46ac8981ea8e47c7a52371027b941fd89"},
-    {"path":"fixtures/target-ir/canonical/gitwarp-append.target-ir.cbor","gitBlob":"89b46b138a7b90252a4397c0e8b622bceff10a33"},
-    {"path":"fixtures/target-ir/canonical/gitwarp-append.target-ir.sha256","gitBlob":"a59a4ab9d46095d5be1797ed9e60fe841f821bce"},
-    {"path":"fixtures/target-ir/canonical/workspace-snapshot.target-ir.cbor","gitBlob":"1854eeb549b3719fa2b0114867dbece6db1819d4"},
-    {"path":"fixtures/target-ir/canonical/workspace-snapshot.target-ir.sha256","gitBlob":"4d0e501323d415ef9e64c0a3d25bdd57dabfc998"},
-    {"path":"fixtures/target-profile/contract-resources/README.md","gitBlob":"32dcab1dd9376a4eed2c73bb1b1a29255fe3ea05"},
-    {"path":"fixtures/target-profile/contract-resources/canonical-cbor.cbor","gitBlob":"4a95ba3bd9dff190ca5ec9c83262bfa6254a91d3"},
-    {"path":"fixtures/target-profile/contract-resources/canonical-cbor.sha256","gitBlob":"2168df5d4bf77ed2347139dd7c45fd808df8ec7e"},
-    {"path":"fixtures/target-profile/contract-resources/determinism.cbor","gitBlob":"09cd11c36048939961408550763c04fad8241557"},
-    {"path":"fixtures/target-profile/contract-resources/determinism.sha256","gitBlob":"5376d6bfe23bea659463a7e3c56ad1e8afd4095f"},
-    {"path":"fixtures/target-profile/contract-resources/diagnostics.cbor","gitBlob":"c47fa05f463e0da745fbcdf8daf94d70e134eb8d"},
-    {"path":"fixtures/target-profile/contract-resources/diagnostics.sha256","gitBlob":"69613ec4014f27b23245e23fbf7c9447566516b2"},
-    {"path":"fixtures/target-profile/contract-resources/fuel.cbor","gitBlob":"b5a3484ec5b2bf7343c2fcedc67bcb2b63a37104"},
-    {"path":"fixtures/target-profile/contract-resources/fuel.sha256","gitBlob":"6ec1c830358ee35bb12bd04cc1a6edf47fb20997"},
-    {"path":"fixtures/target-profile/contract-resources/wasm-component.cbor","gitBlob":"6344996c283e0d1c332ea3ce597ad4593882a3c5"},
-    {"path":"fixtures/target-profile/contract-resources/wasm-component.sha256","gitBlob":"24bf3e552e4216d8258d2b85c8878af46a176c52"},
-    {"path":"grammars/textmate/README.md","gitBlob":"fc116a669725d4e965d658234d32d779955d5dc8"},
-    {"path":"grammars/textmate/edict.tmLanguage.json","gitBlob":"5847d8edfdb32d822f0f3950f41d00c947982185"},
-    {"path":"grammars/tree-sitter-edict/README.md","gitBlob":"e2992a839d6719f1461db78c4e3f33d2e5ab0c09"},
-    {"path":"grammars/tree-sitter-edict/grammar.js","gitBlob":"a82f5b9d9b78525f17a59272543fdcddd7a0da40"},
-    {"path":"grammars/tree-sitter-edict/queries/highlights.scm","gitBlob":"0f46530b36996d13449901aed4e376a126577cba"},
-    {"path":"grammars/tree-sitter-edict/src/grammar.json","gitBlob":"55df730a06b83c9f622e3ec17845fc9897c7d8c0"},
-    {"path":"grammars/tree-sitter-edict/src/node-types.json","gitBlob":"520f6c4f7b30cd6892dd60faf6d76f3fbaa6a5c7"},
-    {"path":"grammars/tree-sitter-edict/src/parser.c","gitBlob":"81cc4713cb5e05f9aa8dac16da202a864faefee6"},
-    {"path":"grammars/tree-sitter-edict/src/tree_sitter/alloc.h","gitBlob":"1abdd1201578605b8d05a3001f01ebc0d58826d9"},
-    {"path":"grammars/tree-sitter-edict/src/tree_sitter/array.h","gitBlob":"56fc8cd470996ded64a5452be25e26dbd2aa682a"},
-    {"path":"grammars/tree-sitter-edict/src/tree_sitter/parser.h","gitBlob":"858107deb9e4a1ffcd2ed5e6ffe98a5fcab3e1f6"},
-    {"path":"grammars/tree-sitter-edict/test/corpus/current-subset.txt","gitBlob":"732c5eda8e1bf95eef799476296a6ee061eb58eb"},
-    {"path":"grammars/tree-sitter-edict/tree-sitter.json","gitBlob":"97d3fdd498a3bef509c8615d98b9560b527c03cb"},
-    {"path":"scripts/consumer-witnesses/README.md","gitBlob":"262ba30223afa1a3782b17dd5272a02b40a541fb"},
-    {"path":"scripts/consumer-witnesses/jedit-state-read.Dockerfile","gitBlob":"b76948f9b5d337f3681d645cceb56e32f8e9c69f"},
-    {"path":"scripts/consumer-witnesses/jedit-state-read.Dockerfile.dockerignore","gitBlob":"ee41b3ca0a68fd5eb20e1b777b4b368fd8b44e63"},
-    {"path":"scripts/consumer-witnesses/jedit-state-read.py","gitBlob":"26db295d4eabfc4e57813fc9bf17314c23350777"},
-    {"path":"spec.lock.json","gitBlob":"ef8b02386e0f269a99c1d2121764f70b76e67620"},
-    {"path":"xtask/Cargo.toml","gitBlob":"795c70a5172363bfcd55174b1bc76c9c131d21a3"},
-    {"path":"xtask/src/contract_check.rs","gitBlob":"9e80393accf79936033972fde0f2aa2cf40f1be3"},
-    {"path":"xtask/src/goldens.rs","gitBlob":"713f1f8266d9f6993684ae86db105fcd7d69ee2a"},
-    {"path":"xtask/src/lawpack_goldens.rs","gitBlob":"c499e8581c73313794b83c261937144b3917850a"},
-    {"path":"xtask/src/main.rs","gitBlob":"6c2c06038bb5ecdde60620071b200d8191dc116c"},
-    {"path":"xtask/src/provider_components.rs","gitBlob":"ee9d6a1028f9fbfad879faab4b15a94b996ef6d4"},
-    {"path":"xtask/src/provider_contract_pack.rs","gitBlob":"cf60d89892b7a57cc33300f273d2522a6e8f43f9"},
-    {"path":"xtask/src/provider_dependencies.rs","gitBlob":"c4b0539ed593d2a2777d294090d2a891b13ae628"},
-    {"path":"xtask/src/release_dates.rs","gitBlob":"1c6d7acb872f6d820eab3a30ca580e9c5cfba2ee"},
-    {"path":"xtask/src/release_prep.rs","gitBlob":"01ed64ccbb28c9d1e908b7b800ff58076e5e1a2b"},
-    {"path":"xtask/src/tests.rs","gitBlob":"9a3f6543c2dbae31d53e93d56f781e5d54f74f41"},
-    {"path":"xtask/src/util.rs","gitBlob":"c1bf39e93460c43ffdcfd9a76e0424750cbb9dfd"}
-  ]
-}
diff --git a/edict/replace-range-probes/leaf-slice/evidence/public-build-candidate.json b/edict/replace-range-probes/leaf-slice/evidence/public-build-candidate.json
deleted file mode 100644
index 7dd105f4..00000000
--- a/edict/replace-range-probes/leaf-slice/evidence/public-build-candidate.json
+++ /dev/null
@@ -1,57 +0,0 @@
-{
-  "compiler": {
-    "commit": "0835f398336ce1c693b5531b262228cd909c0b4b",
-    "tree": "8f984b86c9053a9e570723271babeaaab12e140a",
-    "fileCount": 445,
-    "manifestSha256": "522c6decea5a96058f1dda96e1e5d2632a70d49c6b193a658c3464048cd8e41f",
-    "binarySha256": "a5ffea7b16b641448db4d5dc608bec1539211ab683df3ab78985e12bb1c2fd15"
-  },
-  "providerManifestSha256": "c5b9fb2fe3a0dc4dad282621a97413225c555be0071f3502b3272952069d42dc",
-  "results": {
-    "baseline": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "51797e77062585a9f59083ee8a1da3faaf486ef7691e1b62203369a9d9356ee0",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "1860ab8a6cb9a4bfd63a1db99d1c2bc00aa53dae52a9d1998295654379a95d85",
-        "verification-report.cbor": "d96e5d21eecbc1e5bbf6ce76ab438d55cc8e74f6843121d4ffb0f4343e648267"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "guard-control": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "066f7f3858f31bfd2ddc8490470942ae56da2f9a461399a872f7f158b1bc9774",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "361888511419c3689c92d0e4fab0ca5bbd9196ad827fc212f2e7a1a3394f2e74",
-        "verification-report.cbor": "5580f1247b900a862eaf6b6c3eccc87bc23bbd53e40fde0bdc1f66826c5966c2"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "slice": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "81ffc0dae8c5d8900badf66b1ca4b8cac92378935702374785f2b20781e6934c",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "bfacd029cf2dc9247cbcee47d747eca3f8298c7184cac3866eb36f3ab55573c1",
-        "verification-report.cbor": "943ac86ea20c40d68881cc8413b926f98ba2a4ee99408e3dcede4eead1e7bb86"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    }
-  }
-}
diff --git a/edict/replace-range-probes/leaf-slice/evidence/public-build-red.json b/edict/replace-range-probes/leaf-slice/evidence/public-build-red.json
deleted file mode 100644
index 1245f6c9..00000000
--- a/edict/replace-range-probes/leaf-slice/evidence/public-build-red.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
-  "compiler": {
-    "commit": "2405a550e93e1e97fff640caa44bbd0f65ffff3c",
-    "tree": "257d3e6aa10c2248fdbddaa8e9b3638866396169",
-    "fileCount": 440,
-    "manifestSha256": "9cc2cb4f711ef4038091559587099bbe65d6c54c8316c3e373752d0783b25173",
-    "binarySha256": "3b082d61c8cd23b0f917efb55c4eebd54e75c0df5d31c72f90ad856853678bf5"
-  },
-  "results": {
-    "baseline": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "51797e77062585a9f59083ee8a1da3faaf486ef7691e1b62203369a9d9356ee0",
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "guard-control": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "066f7f3858f31bfd2ddc8490470942ae56da2f9a461399a872f7f158b1bc9774",
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "slice": {
-      "exitCode": 2,
-      "diagnostics": [
-        {
-          "command": "build",
-          "input": {
-            "kind": "stdin"
-          },
-          "kind": "ApplicationCompilationFailed",
-          "message": "Edict application did not compile to Core: [CompilerError { stage: TypeCheck, kind: UnresolvedFunction, message: \"pure helper `slice` has no compiler context fact\", span: Span { start: 521, end: 575 } }, CompilerError { stage: TypeCheck, kind: UnresolvedType, message: \"record shorthand `bytes` has no typed binding\", span: Span { start: 588, end: 593 } }, CompilerError { stage: TypeCheck, kind: TypeMismatch, message: \"return value does not match declared output type\", span: Span { start: 291, end: 598 } }, CompilerError { stage: TypeCheck, kind: TypeMismatch, message: \"intent body must return a value\", span: Span { start: 291, end: 598 } }]",
-          "schema": "edict.cli.diagnostic/v1",
-          "severity": "error",
-          "stage": "cli",
-          "type": "diagnostic"
-        }
-      ],
-      "artifacts": [],
-      "sourceSha256": "81ffc0dae8c5d8900badf66b1ca4b8cac92378935702374785f2b20781e6934c",
-      "stdoutSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
-      "stderrSha256": "6181544d23ab4e8bf02f3719bfbe9a86a9f851490995eb23983d55af61525e64"
-    }
-  }
-}
diff --git a/edict/replace-range-probes/leaf-slice/run.py b/edict/replace-range-probes/leaf-slice/run.py
deleted file mode 100644
index 98bab443..00000000
--- a/edict/replace-range-probes/leaf-slice/run.py
+++ /dev/null
@@ -1,141 +0,0 @@
-"""Exercise authored byte slicing at the public compiler build boundary."""
-
-import argparse
-import hashlib
-import json
-from pathlib import Path
-import shutil
-import subprocess
-
-
-COMPILER_COMMIT = "2405a550e93e1e97fff640caa44bbd0f65ffff3c"
-CANDIDATE_COMPILER_COMMIT = "0835f398336ce1c693b5531b262228cd909c0b4b"
-SOURCE_EXPRESSION = "slice(input.blobBytes, input.startByte, input.endByte)"
-MAX_LOG_BYTES = 1024 * 1024
-
-
-def sha256(path):
-    return hashlib.sha256(path.read_bytes()).hexdigest()
-
-
-def snapshot(root):
-    return {str(path.relative_to(root)): sha256(path)
-            for path in sorted(root.rglob("*")) if path.is_file()}
-
-
-def verify_compiler_source(root, manifest_path, expected_commit):
-    manifest = json.loads(manifest_path.read_text())
-    if manifest["commit"] != expected_commit:
-        raise RuntimeError("The witness requires its explicit experimental compiler pin")
-    for entry in manifest["files"]:
-        relative = Path(entry["path"])
-        if relative.is_absolute() or ".." in relative.parts:
-            raise RuntimeError("Compiler source manifest contains an unsafe path")
-        data = (root / relative).read_bytes()
-        blob = hashlib.sha1(b"blob " + str(len(data)).encode() + b"\0" + data).hexdigest()
-        if blob != entry["gitBlob"]:
-            raise RuntimeError(f"Compiler source differs at {relative}")
-    return {"commit": manifest["commit"], "tree": manifest["tree"],
-            "fileCount": len(manifest["files"]),
-            "manifestSha256": sha256(manifest_path)}
-
-
-def prepare(root, application_source, provider_source, source):
-    root.mkdir()
-    shutil.copy2(application_source / "edict.application.json", root)
-    shutil.copytree(application_source / "vendor", root / "vendor")
-    (root / "src").mkdir()
-    (root / "src/ReplaceRange.edict").write_bytes(source)
-    shutil.copytree(provider_source, root / ".build/echo-provider")
-
-
-def build(root, compiler):
-    request = {"schema": "edict.compiler.settings/v1", "type": "compilerSettings",
-               "operation": "build", "application": "edict.application.json"}
-    stdout_path, stderr_path = root / "stdout.jsonl", root / "stderr.jsonl"
-    with stdout_path.open("wb") as stdout, stderr_path.open("wb") as stderr:
-        result = subprocess.run([str(compiler)], cwd=root,
-                                input=(json.dumps(request) + "\n").encode(),
-                                stdout=stdout, stderr=stderr, timeout=120, check=False)
-    events = []
-    for path in (stdout_path, stderr_path):
-        if path.stat().st_size > MAX_LOG_BYTES:
-            raise RuntimeError("Compiler output exceeded witness log ceiling")
-        events.extend(json.loads(line) for line in path.read_text().splitlines())
-    statuses = [event for event in events if event.get("type") == "status"]
-    if len(statuses) != 1 or statuses[0].get("exitCode") != result.returncode:
-        raise RuntimeError(f"Invalid compiler status stream: {events}")
-    diagnostics = [event for event in events if event.get("type") == "diagnostic"]
-    output = root / ".build/application"
-    artifacts = sorted(str(path.relative_to(output)) for path in output.rglob("*")
-                       if path.is_file()) if output.exists() else []
-    return {"exitCode": result.returncode, "diagnostics": diagnostics,
-            "artifacts": artifacts, "sourceSha256": sha256(root / "src/ReplaceRange.edict"),
-            "artifactSha256": {name: sha256(output / name) for name in artifacts},
-            "stdoutSha256": sha256(stdout_path), "stderrSha256": sha256(stderr_path)}
-
-
-def main():
-    parser = argparse.ArgumentParser(description=__doc__)
-    for name in ("compiler", "compiler-source", "compiler-manifest", "application-source",
-                 "provider-package", "work-root"):
-        parser.add_argument("--" + name, type=Path, required=True)
-    parser.add_argument("--boundary", choices=("source", "package"), default="source")
-    args = parser.parse_args()
-    if not Path("/.dockerenv").is_file():
-        raise RuntimeError("Run only under the shared guarded Docker-worker lease")
-    if not args.work_root.resolve().is_relative_to(Path("/tmp/echo-726-runtime")):
-        raise RuntimeError("Work must stay inside the declared runtime-data accounting root")
-    args.work_root.mkdir()
-    expected_commit = COMPILER_COMMIT if args.boundary == "source" else CANDIDATE_COMPILER_COMMIT
-    compiler_identity = verify_compiler_source(args.compiler_source, args.compiler_manifest,
-                                               expected_commit)
-    compiler_identity["binarySha256"] = sha256(args.compiler)
-    before = {"application": snapshot(args.application_source),
-              "provider": snapshot(args.provider_package)}
-    source = (Path(__file__).parent / "LeafSlice.edict").read_bytes()
-    if source.count(SOURCE_EXPRESSION.encode()) != 1:
-        raise RuntimeError("Expected one exact authored slice expression")
-    sources = {
-        "baseline": (args.application_source / "src/ReplaceRange.edict").read_bytes(),
-        "guard-control": source.replace(SOURCE_EXPRESSION.encode(), b"input.blobBytes"),
-        "slice": source,
-    }
-    evidence = {"compiler": compiler_identity,
-                "providerManifestSha256": sha256(args.provider_package / "provider-manifest.echo.json"),
-                "results": {}}
-    for name, authored in sources.items():
-        root = args.work_root / name
-        prepare(root, args.application_source, args.provider_package, authored)
-        evidence["results"][name] = build(root, args.compiler)
-    (args.work_root / "evidence.json").write_text(json.dumps(evidence, indent=2) + "\n")
-    for name, result in evidence["results"].items():
-        print(json.dumps({"case": name, **result}, sort_keys=True), flush=True)
-    if before != {"application": snapshot(args.application_source),
-                  "provider": snapshot(args.provider_package)}:
-        raise RuntimeError("Witness changed an authoritative input")
-    if compiler_identity["binarySha256"] != sha256(args.compiler):
-        raise RuntimeError("Compiler binary changed during the witness")
-    verify_compiler_source(args.compiler_source, args.compiler_manifest, expected_commit)
-    for name in ("baseline", "guard-control"):
-        result = evidence["results"][name]
-        if result["exitCode"] != 0 or result["diagnostics"] or not result["artifacts"]:
-            raise RuntimeError(f"{name} positive control did not build")
-    result = evidence["results"]["slice"]
-    if args.boundary == "package":
-        if (result["exitCode"] != 0 or result["diagnostics"]
-                or result["artifacts"] != ["executable-operation-package.cbor", "verification-report.cbor"]):
-            raise RuntimeError("Slice did not reach the expected package build boundary")
-        print("JIM_LEAF_SLICE_PACKAGE_BOUNDARY_CONFIRMED", flush=True)
-        return
-    if result["exitCode"] != 2 or result["artifacts"]:
-        raise RuntimeError("Slice must refuse without application artifacts")
-    refusal = evidence["results"]["slice"]["diagnostics"]
-    if (len(refusal) != 1 or refusal[0].get("kind") != "ApplicationCompilationFailed"
-            or "pure helper `slice` has no compiler context fact" not in refusal[0].get("message", "")):
-        raise RuntimeError("Slice did not produce the expected source refusal")
-    print("JIM_LEAF_SLICE_SOURCE_BOUNDARY_CONFIRMED", flush=True)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/edict/replace-range-probes/node-atom-read/Dockerfile b/edict/replace-range-probes/node-atom-read/Dockerfile
deleted file mode 100644
index 679dc849..00000000
--- a/edict/replace-range-probes/node-atom-read/Dockerfile
+++ /dev/null
@@ -1,24 +0,0 @@
-FROM rust:1.95.0-bookworm AS compiler
-RUN apt-get update && apt-get install -y --no-install-recommends python3 \
-    && rm -rf /var/lib/apt/lists/*
-WORKDIR /edict
-RUN git init && git remote add origin https://github.com/flyingrobots/edict.git \
-    && git fetch --depth=1 origin 2405a550e93e1e97fff640caa44bbd0f65ffff3c \
-    && git archive FETCH_HEAD | tar -x
-RUN cargo build --locked -p edict-cli
-WORKDIR /echo-source
-RUN git init && git remote add origin https://github.com/flyingrobots/echo.git \
-    && git fetch --depth=1 origin 49e9efb68001dfd78563d18bac9359a87671e431 \
-    && git archive FETCH_HEAD schemas/edict-provider/package/v1 | tar -x
-
-FROM rust:1.90.0-bookworm AS provider
-WORKDIR /echo
-RUN git init && git remote add origin https://github.com/flyingrobots/echo.git \
-    && git fetch --depth=1 origin 84ccbcec0640f2c7d0565464fd55655007689b42 \
-    && git archive FETCH_HEAD | tar -x
-RUN cargo run --locked -p echo-wesley-gen --example ordered_publication_witness -- /ordered-provider
-
-FROM compiler AS witness
-COPY --from=provider /ordered-provider /ordered-provider
-COPY edict/replace-range-probes/node-atom-read /probe
-CMD ["python3", "/probe/run.py"]
diff --git a/edict/replace-range-probes/node-atom-read/Dockerfile.dockerignore b/edict/replace-range-probes/node-atom-read/Dockerfile.dockerignore
deleted file mode 100644
index 7c923dc8..00000000
--- a/edict/replace-range-probes/node-atom-read/Dockerfile.dockerignore
+++ /dev/null
@@ -1,5 +0,0 @@
-**
-!edict/
-!edict/replace-range-probes/
-!edict/replace-range-probes/node-atom-read/
-!edict/replace-range-probes/node-atom-read/**
diff --git a/edict/replace-range-probes/node-atom-read/README.md b/edict/replace-range-probes/node-atom-read/README.md
deleted file mode 100644
index 2eb63885..00000000
--- a/edict/replace-range-probes/node-atom-read/README.md
+++ /dev/null
@@ -1,67 +0,0 @@
-# Node atom read and guard probe
-
-This is authored consumer evidence for
-[Echo #740](https://github.com/flyingrobots/echo/issues/740),
-[Jedit #296](https://github.com/flyingrobots/jedit/issues/296), and
-[PR #302](https://github.com/flyingrobots/jedit/pull/302). It reproduces an
-unsupported provider boundary. **It does not implement reads or ReplaceRange.**
-The frozen application and producer pins under `edict/replace-range/` remain
-unchanged.
-
-The source requests the opaque atom bytes at an explicit address, compares
-them with expected bytes, then returns them. The proposed address contains
-32-byte WARP, node, and expected atom-type IDs. Four named failure arms cover
-missing data, wrong atom type, non-atom attachments, and the byte bound. The
-exported type uses Edict's canonical `Record<...>` syntax with sorted fields.
-The output is bounded to 1 MiB.
-
-`echo.dpo@1.node-atom-read` and its failure coordinates are **proposed** target
-contracts. Echo does not implement them. The pure provider configuration is
-retained deliberately to identify its refusal boundary; it must not be treated
-as permission for stateful execution. The experimental `echo.span-ir/v2`
-selection binds the pinned Edict CDDL bytes, not a released semantic profile.
-
-## Reproduce
-
-From the repository root, with no host repository mounted into Docker:
-
-```sh
-docker build -f edict/replace-range-probes/node-atom-read/Dockerfile \
-  -t jedit-node-atom-read-boundary .
-docker run --rm jedit-node-atom-read-boundary
-```
-
-The Dockerfile fetches exact revisions:
-
-- Edict `2405a550e93e1e97fff640caa44bbd0f65ffff3c` supplies ordered Target IR.
-- Echo `49e9efb68001dfd78563d18bac9359a87671e431` supplies the old provider control.
-- Echo `84ccbcec0640f2c7d0565464fd55655007689b42` supplies the public generator
-  example that assembles and digest-admits an ordered-schema provider candidate.
-
-The witness uses the public lawpack/application JSONL build API. It checks:
-
-1. The lawpack builds and its generated digest equals the authored import.
-2. The old provider refuses ordered IR at `InvalidProviderInvocation`, naming
-   `ArtifactSchemaMismatch` and `06-target-ir`.
-3. Changing only the provider to the ordered-schema candidate reaches
-   `ProviderLowererRefused`, naming `UnsupportedSemantics` and
-   `core.echo-pure-operation`.
-4. Neither refusal publishes application outputs; the authored body is unchanged.
-
-Success prints `JEDIT_NODE_ATOM_READ_PROVIDER_BOUNDARY_CONFIRMED`. That means
-the limitation was reproduced, not that an executable read package was emitted.
-The harness neither fabricates intermediate artifacts nor substitutes a native
-read implementation.
-
-## What remains
-
-Echo #740 owns explicit read-capable provider configuration, independent
-verification, real bounded evaluation over graph storage, basis/aperture
-enforcement, ordered guards, typed failures, and deterministic accounting.
-No ordinary caller-provided bytes may stand in for an authorized read view.
-
-Jim owns fact decoding. Its canonical Buffer head is a field inside an encoded
-fact, not the entire atom payload. Returning raw bytes does not supply that head
-without the application-owned decoding step. Rope operations, staged writes,
-admission, oracle agreement, Tick/WAL/receipts, and recovery remain the parent
-issues' requirements.
diff --git a/edict/replace-range-probes/node-atom-read/edict.application.json b/edict/replace-range-probes/node-atom-read/edict.application.json
deleted file mode 100644
index 9bad89fb..00000000
--- a/edict/replace-range-probes/node-atom-read/edict.application.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-  "schema": "edict.application/v1",
-  "coordinate": "jedit.text.replace_range@1",
-  "sources": [
-    "src/ReplaceRange.edict"
-  ],
-  "lawpacks": [
-    {
-      "manifest": "vendor/atom-read/manifest.cbor",
-      "exports": "vendor/atom-read/exports.cbor",
-      "adapter": "vendor/atom-read/adapter.cbor",
-      "targetConfiguration": "vendor/atom-read/echo-operation-configuration.cbor"
-    }
-  ],
-  "target": {
-    "profile": "echo.dpo@1",
-    "providerPackage": ".build/echo-provider"
-  },
-  "outputDirectory": ".build/application"
-}
diff --git a/edict/replace-range-probes/node-atom-read/edict.lawpack.json b/edict/replace-range-probes/node-atom-read/edict.lawpack.json
deleted file mode 100644
index d74d67de..00000000
--- a/edict/replace-range-probes/node-atom-read/edict.lawpack.json
+++ /dev/null
@@ -1,183 +0,0 @@
-{
-  "schema": "edict.lawpack-build/v1",
-  "outputDirectory": "vendor/atom-read",
-  "lawpack": {
-    "schema": "edict.lawpack-authoring/v1",
-    "id": "jedit.text",
-    "version": "1",
-    "acceptedCoreAbi": [
-      "edict.core/v1"
-    ],
-    "dependencies": [],
-    "exportsCoordinate": "jedit.text.exports/v1",
-    "exports": {
-      "types": [
-        {
-          "coordinate": "jedit.text@1.FactAddress",
-          "definition": "Record,typeId:Bytes,warpId:Bytes>"
-        },
-        {
-          "coordinate": "jedit.text@1.FactBytes",
-          "definition": "Bytes"
-        },
-        {
-          "coordinate": "jedit.text@1.ObstructionDetail",
-          "definition": "String"
-        }
-      ],
-      "constants": [],
-      "pureFunctions": [],
-      "effects": [
-        {
-          "coordinate": "jedit.text@1.readFact",
-          "typeParameters": [],
-          "inputType": "jedit.text@1.FactAddress",
-          "outputType": "jedit.text@1.FactBytes",
-          "executionClass": "runtime",
-          "effectKindHint": "read",
-          "footprintObligation": "jedit.text@1.replaceRangeFootprint",
-          "costObligation": "jedit.text@1.replaceRangeBudget",
-          "effectFailures": {
-            "missing": {
-              "authorityClass": "resourceFault",
-              "payloadType": "jedit.text@1.FactAddress"
-            },
-            "typeMismatch": {
-              "authorityClass": "integrityFault",
-              "payloadType": "jedit.text@1.FactAddress"
-            },
-            "notAtom": {
-              "authorityClass": "integrityFault",
-              "payloadType": "jedit.text@1.FactAddress"
-            },
-            "tooLarge": {
-              "authorityClass": "integrityFault",
-              "payloadType": "jedit.text@1.FactAddress"
-            }
-          },
-          "guardSupport": true
-        }
-      ],
-      "obstructions": [
-        {
-          "coordinate": "jedit.text@1.BasisNotCanonical",
-          "authorityClass": "domainMappable",
-          "payloadSchema": "jedit.text@1.ObstructionDetail"
-        },
-        {
-          "coordinate": "jedit.text@1.FactMissing",
-          "authorityClass": "resourceFault",
-          "payloadSchema": "jedit.text@1.ObstructionDetail"
-        },
-        {
-          "coordinate": "jedit.text@1.FactMalformed",
-          "authorityClass": "integrityFault",
-          "payloadSchema": "jedit.text@1.ObstructionDetail"
-        }
-      ],
-      "operationProfiles": {
-        "jedit.text@1.replaceRange": {
-          "opticTemplate": {
-            "opticKind": "affectReintegration",
-            "boundaryKind": "affect",
-            "supportPolicy": "jedit.text@1.basisBoundSupport",
-            "lossDisposition": "jedit.text@1.lossless",
-            "basisTemplate": "jedit.text@1.exactHeadBasis",
-            "apertureRequirement": {
-              "kind": "abstractFootprintObligation",
-              "reference": "jedit.text@1.replaceRangeFootprint"
-            }
-          },
-          "effectPredicate": "jedit.text@1.replaceRangeEffects"
-        }
-      }
-    },
-    "targetAdapters": [
-      {
-        "coordinate": "jedit.text.echo-adapter/v1",
-        "output": "adapter.cbor",
-        "acceptedTargetProfile": {
-          "id": "echo.dpo@1",
-          "digest": "sha256:2e2494121aecf5e6a2d920f5fb85408825d394765fad41484c416397c920fb04"
-        },
-        "acceptedTargetIr": {
-          "id": "echo.span-ir/v2",
-          "digest": "sha256:123e7f805dc5e831e88befec4cd49ec02c39858b6f3990da8a73b50c6086ae39"
-        },
-        "operationProfiles": {
-          "jedit.text@1.replaceRange": {
-            "core": "continuum.profile.read-only/v1",
-            "semanticEffects": [
-              "jedit.text@1.readFact"
-            ],
-            "budgetObligation": "jedit.text@1.replaceRangeBudget",
-            "targetConfiguration": {
-              "local": "echo-config"
-            }
-          }
-        },
-        "effectImplementations": {
-          "jedit.text@1.readFact": {
-            "targetIntrinsic": "echo.dpo@1.node-atom-read",
-            "targetConfiguration": {
-              "local": "echo-config"
-            },
-            "writeClass": "read",
-            "footprintObligation": "jedit.text@1.replaceRangeFootprint",
-            "costObligation": "jedit.text@1.replaceRangeBudget",
-            "failureMappings": {
-              "missing": "echo.atom-missing/v1",
-              "typeMismatch": "echo.atom-type-mismatch/v1",
-              "notAtom": "echo.atom-required/v1",
-              "tooLarge": "echo.atom-byte-bound-exceeded/v1"
-            }
-          }
-        },
-        "budgets": {
-          "jedit.text@1.replaceRangeBudget": {
-            "maxSteps": 1048576,
-            "maxAllocatedBytes": 16777216,
-            "maxOutputBytes": 8388608
-          }
-        }
-      }
-    ],
-    "verifier": {
-      "class": "declarative",
-      "ruleset": {
-        "local": "verifier-rules"
-      }
-    },
-    "compatibility": {
-      "id": "jedit.text.compatibility/v1",
-      "digest": "sha256:2adf83f798205f52636ad64ca45178f33a8e1cc663874f8a6113484c945e3052"
-    },
-    "conformanceFixtureCorpus": {
-      "id": "jedit.text.ReplaceRange.oracle@1",
-      "digest": "sha256:b9b4707dd5e07897cbe7af36d88928401887e6af5d167d1a88a8d6181b4dbb0e"
-    },
-    "localResources": [
-      {
-        "name": "echo-config",
-        "coordinate": "echo.operation-lowering-configuration/v1",
-        "output": "echo-operation-configuration.cbor",
-        "value": {
-          "apiVersion": "echo.operation-lowering-configuration/v1",
-          "programKind": "compiler-produced-bounded-pure/v1"
-        }
-      },
-      {
-        "name": "verifier-rules",
-        "coordinate": "jedit.text.verifier-rules/v1",
-        "output": "verifier-rules.cbor",
-        "value": {
-          "schema": "jedit.text.schema@1",
-          "schemaDigest": "sha256:f49b0ff6c9c7010d3a72b46734d47832853f496739a083edc41dddec3431bac7",
-          "oracleIsExecutableInput": false,
-          "runtimeOntology": "generic-bounded-graph"
-        }
-      }
-    ]
-  },
-  "dependencyBundles": []
-}
diff --git a/edict/replace-range-probes/node-atom-read/run.py b/edict/replace-range-probes/node-atom-read/run.py
deleted file mode 100644
index 12af67b7..00000000
--- a/edict/replace-range-probes/node-atom-read/run.py
+++ /dev/null
@@ -1,82 +0,0 @@
-"""Reproduce the raw atom read/guard boundary through the public Edict CLI."""
-
-import hashlib
-import json
-from pathlib import Path
-import shutil
-import subprocess
-import tempfile
-
-
-def build(root, document, expected_kind=None, required_details=()):
-    request = {
-        "schema": "edict.compiler.settings/v1",
-        "type": "compilerSettings",
-        "operation": "build",
-        document: f"edict.{document}.json",
-    }
-    result = subprocess.run(
-        ["/edict/target/debug/edict"], cwd=root,
-        input=json.dumps(request) + "\n", text=True, capture_output=True,
-        timeout=120, check=False,
-    )
-    events = [json.loads(line) for stream in (result.stdout, result.stderr)
-              for line in stream.splitlines()]
-    diagnostics = [event for event in events if event.get("type") == "diagnostic"]
-    statuses = [event for event in events if event.get("type") == "status"]
-    expected_code = 0 if expected_kind is None else 2
-    if (result.returncode != expected_code or len(statuses) != 1
-            or statuses[0].get("exitCode") != expected_code):
-        raise RuntimeError(f"Unexpected public build result: {result}")
-    if expected_kind is None:
-        if diagnostics:
-            raise RuntimeError(f"Lawpack build produced diagnostics: {diagnostics}")
-    elif (len(diagnostics) != 1 or diagnostics[0].get("kind") != expected_kind
-          or any(detail not in diagnostics[0].get("message", "")
-                 for detail in required_details)):
-        raise RuntimeError(f"Unexpected refusal boundary: {diagnostics}")
-    if document == "application":
-        output = root / ".build/application"
-        if output.exists() and any(output.rglob("*")):
-            raise RuntimeError("Refused build published application artifacts")
-    for event in events:
-        print(json.dumps(event, sort_keys=True), flush=True)
-
-
-def main():
-    if not Path("/.dockerenv").is_file():
-        raise RuntimeError("Run with the COPY-based node-atom-read Dockerfile")
-    source = Path("/probe")
-    definition = json.loads((source / "edict.lawpack.json").read_text())
-    selection = definition["lawpack"]["targetAdapters"][0]["acceptedTargetIr"]
-    schema = Path("/edict/docs/abi/edict-target-ir.cddl").read_bytes()
-    if selection != {
-        "id": "echo.span-ir/v2",
-        "digest": "sha256:" + hashlib.sha256(schema).hexdigest(),
-    }:
-        raise RuntimeError("Probe does not select the pinned experimental IR contract")
-    with tempfile.TemporaryDirectory(prefix="jedit-atom-read-") as scratch:
-        root = Path(scratch)
-        for document in ("edict.lawpack.json", "edict.application.json"):
-            shutil.copyfile(source / document, root / document)
-        shutil.copytree(source / "src", root / "src")
-        build(root, "lawpack")
-        digest = (root / "vendor/atom-read/manifest.sha256").read_text().strip()
-        authored = (root / "src/ReplaceRange.edict").read_text()
-        if authored.count(f'digest "{digest}"') != 1:
-            raise RuntimeError("Authored lawpack import does not match generated bytes")
-        provider = root / ".build/echo-provider"
-        shutil.copytree("/echo-source/schemas/edict-provider/package/v1", provider)
-        build(root, "application", "InvalidProviderInvocation",
-              ("ArtifactSchemaMismatch", "06-target-ir"))
-        shutil.rmtree(provider)
-        shutil.copytree("/ordered-provider", provider)
-        build(root, "application", "ProviderLowererRefused",
-              ("UnsupportedSemantics", "core.echo-pure-operation"))
-        if (root / "src/ReplaceRange.edict").read_text() != authored:
-            raise RuntimeError("Witness changed the authored operation")
-    print("JEDIT_NODE_ATOM_READ_PROVIDER_BOUNDARY_CONFIRMED", flush=True)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/edict/replace-range-probes/node-atom-read/src/ReplaceRange.edict b/edict/replace-range-probes/node-atom-read/src/ReplaceRange.edict
deleted file mode 100644
index dd33b7f7..00000000
--- a/edict/replace-range-probes/node-atom-read/src/ReplaceRange.edict
+++ /dev/null
@@ -1,18 +0,0 @@
-package jedit.text.replace_range@1;
-use lawpack jedit.text@1 digest "sha256:add46dc12d57a1df57847d501092b2d91dceab011d8781a747ed39437b01737e" as text;
-type Input = { address: text.FactAddress, expected: text.FactBytes };
-intent replaceRange(input: Input) returns text.FactBytes
-  profile text.replaceRange
-  basis input.address.nodeId
-  budget <= text.replaceRangeBudget
-{
-  let actual: text.FactBytes = text.readFact(input.address)
-    else {
-      missing(address) => text.FactMissing,
-      typeMismatch(address) => text.FactMalformed,
-      notAtom(address) => text.FactMalformed,
-      tooLarge(address) => text.FactMalformed,
-    };
-  require actual == input.expected else text.BasisNotCanonical;
-  return actual;
-}
diff --git a/edict/replace-range-probes/range-assembly/README.md b/edict/replace-range-probes/range-assembly/README.md
deleted file mode 100644
index 4d4d97bf..00000000
--- a/edict/replace-range-probes/range-assembly/README.md
+++ /dev/null
@@ -1,149 +0,0 @@
-# Authored range-fragment assembly pressure
-
-`RangeAssembly.edict` isolates one append step of Jim's native range reader:
-[`plan_replace_with_reason`](../../../native/jedit-echo-host/src/rope/replace.rs)
-reads current range bytes at line 176 and compares them with replacement bytes
-for the no-op decision. [`read_range_bytes`](../../../native/jedit-echo-host/src/rope/window.rs)
-at line 136 calls `collect_range`, which visits left before right and appends
-each selected leaf slice with `output.extend_from_slice(slice)` at line 244.
-These source coordinates are inspected at Jim `0cd880224fafcd1f26f78552e7b34ad170ae6a04`.
-
-The authored operation receives two already selected fragments and joins them
-in order with `+`. Each fragment has an eight-byte probe aperture, making the
-sixteen-byte summed output bound explicit and testable with literal data.
-Those small apertures are specimen bounds, not the application's rope limits.
-This is raw byte concatenation: it does not interpret UTF-8, classify no-op,
-traverse nodes, prove range length, fold a collection, join tree references,
-or publish facts. Those semantics remain Jim-owned authored work under
-[Jim #296](https://github.com/flyingrobots/jedit/issues/296) and draft PR #302.
-
-[`cases.json`](cases.json) specifies ten literal outputs and two input-type
-refusals. These are future runtime conformance expectations, not executed
-results, executable lawpack input, or the full rope oracle. Empty input has
-its literal identity result; reversed fragment order changes the expected
-bytes; invalid UTF-8 stays bytes. The full-aperture case requires the sum of
-both static bounds, not either operand's bound alone.
-
-## Compiler boundary
-
-Inspection of Edict `ac836e5c42a5c47b0dab30cfb0b09848cca73215` found source `+`
-dispatched to `check_string_concat`, which rejects non-String operands. The
-[public compiler probe](evidence/public-build-red.json) confirms the source
-failure below. GitHub merge `0f38fce33c2b8c0cad7bd8aeba110a34c9166a2d` and this
-compiler have the identical source tree `dadd4703a9905a37ff366c7134aea5cfe351e2fd`.
-The witness explicitly names the built compiler, not a substituted frozen pin.
-
-Two controls replace only the addition expression with `input.firstFragment`
-or `input.secondFragment`. They retain both input fields and the declared
-sixteen-byte output bound, so their actual build outcomes distinguish missing
-byte concatenation from basic field/projection/type-bound failures. The frozen
-boundary application is a third positive control.
-
-| Input | Public result |
-| --- | --- |
-| Frozen boundary source | Exit 0, package and separate report |
-| First-fragment-only control | Exit 0, package and separate report |
-| Second-fragment-only control | Exit 0, package and separate report |
-| Exact `RangeAssembly.edict` | Exit 2, `ApplicationCompilationFailed` with `TypeCheck/TypeMismatch`; no application artifacts |
-
-The primary diagnostic is `string concatenation requires string operands`,
-covering source bytes 430–472 at line 19. Later shorthand/return diagnostics are
-cascades. [Raw assembly diagnostics](evidence/assembly-stderr.jsonl) and all
-control streams are retained unchanged. The successful paired witness ends with
-`JIM_RANGE_ASSEMBLY_SOURCE_BOUNDARY_CONFIRMED`. No runtime case was executed.
-
-The guarded worker rebuilt Edict with Rust 1.95.0 from the verified 446-file
-source manifest, reproducing binary SHA-256
-`a937e6f150f73fa20e9868c84adee0a8270cc62130d4aef18e5b891ec268fee2`.
-The frozen provider remains Echo `49e9efb68001dfd78563d18bac9359a87671e431`,
-manifest SHA-256
-`c5b9fb2fe3a0dc4dad282621a97413225c555be0071f3502b3272952069d42dc`.
-Source, binary, application, and provider identities were checked before and
-after the public builds. One earlier preflight stopped before compilation
-because the preserved `/edict/target` symlink appeared as an untracked file;
-its destination was verified as the existing shared target before proceeding.
-That setup stop is not the source RED.
-
-The unchanged published lawpack provides the profile and budget. The frozen
-application root, producer pins, closure, and artifact locks are authoritative
-for their existing witness and are not migrated by this development source.
-
-## Candidate package boundary
-
-The unchanged authored source and all three controls also built with
-[Edict's bounded-byte concatenation candidate](https://github.com/flyingrobots/edict/issues/222)
-`01dc5abb9a8a74f8fd8b0e0a6d1041d0adb86d6e`. The
-[retained public result](evidence/candidate/public-build.json) records exit 0,
-no diagnostics, and an executable package plus separate verification report
-for each source. This advances the source/compiler/package boundary; it does
-not execute byte concatenation or any of the twelve runtime expectations.
-
-The candidate's 449 tracked source files and Git identity were verified before
-and after the builds against the [original SHA-256 manifest](evidence/candidate/compiler-source-sha256.json).
-Its tree is `74e571125a1da6ac5b2eac80944e343811708d51`; CLI SHA-256 is
-`e2700698829b03f437c66425ed9878b002ef7a34ac183a39bac4eaf6a758cc6d`.
-The [portable Git-blob manifest](evidence/candidate/compiler-source.json)
-derives from the same exact commit and was checked against that original
-manifest. The frozen provider manifest remains `c5b9fb2fe3a0dc4dad282621a97413225c555be0071f3502b3272952069d42dc`.
-
-Exact assembly artifacts are retained unchanged:
-
-- [Executable package](evidence/candidate/assembly/application/executable-operation-package.cbor):
-  SHA-256 `e889d4680435139fe76f45762f0529c090afcf3d73ef7d17f787d44a49bda534`.
-- [Verification report](evidence/candidate/assembly/application/verification-report.cbor):
-  SHA-256 `7eec90854e0663aa2346ec5005ff7d05eeb50fc2229b32b407dda3cfa0280077`.
-
-The candidate directory also retains each control's package/report, all raw
-compiler streams, the [guard output](evidence/candidate/guard.log),
-[completion measurements](evidence/candidate/guard.result.json), and the
-unchanged admission/release event records. The original RED above is preserved.
-The application manifest, producer pins, source closure, and artifact locks remain unchanged.
-The [portable runner replay](evidence/candidate/portable-public-build.json)
-reproduced all four complete public result records, including identical source,
-stream, package and report hashes. Its [guard log](evidence/candidate/portable-guard.log)
-ends with `JIM_RANGE_ASSEMBLY_PACKAGE_BOUNDARY_CONFIRMED`; the
-[completion receipt](evidence/candidate/portable-guard.result.json) records exit 0.
-This checks the checked-in harness's package mode without replacing the
-original observational replay.
-
-Full traversal, no-op classification, rope consequences and admitted execution
-remain open under #296.
-
-## Reproduction discipline
-
-Use copied inputs, the existing compiler and frozen provider package, the
-shared Docker worker and Cargo target, workstation git-locks admission,
-native locks, and the mandatory fail-closed disk/process guard. Record exact
-compiler source and binary identities before a build. Keep generated apps,
-artifacts, and streams under the owned bounded runtime-data directory. Do not
-use historical build-in-image recipes or create another image, worker, or
-cache. The twelve runtime expectations require separate generic evaluator
-execution of the successfully built candidate package.
-
-Copy both this directory and the unchanged sibling `leaf-slice/run.py`; the
-runner reuses that file's public-build and identity helpers. Provide the frozen
-application root and provider package as read-only copied inputs, then invoke
-inside the admitted guarded worker:
-
-```sh
-python3 "$PROBE_ROOT/range-assembly/run.py" \
-  --compiler "$EDICT_BINARY" \
-  --compiler-source "$EDICT_SOURCE" \
-  --compiler-manifest "$PROBE_ROOT/range-assembly/evidence/compiler-source.json" \
-  --application-source "$APPLICATION_SOURCE" \
-  --provider-package "$PROVIDER_PACKAGE" \
-  --work-root /tmp/echo-726-runtime/jim-range-assembly-proof
-```
-
-The default `--boundary source` preserves the original RED assertion and its
-compiler identity. To reproduce the candidate package witness, use the exact
-candidate compiler binary/source, add `--boundary package`, and select
-`evidence/candidate/compiler-source.json` as the compiler manifest. Both modes
-retain the same source and controls; package mode requires the actual package
-and separate report without claiming runtime support.
-
-The source manifest is read-only provenance, not executable compiler input.
-Use a fresh work-root; retain unique evidence and recycle only owned disposable
-copies after export. The runner's stream-size check does not replace the external
-disk/process guard. The retained results establish their named compiler boundaries, not
-byte-concatenation runtime support or complete `ReplaceRange` behavior.
diff --git a/edict/replace-range-probes/range-assembly/RangeAssembly.edict b/edict/replace-range-probes/range-assembly/RangeAssembly.edict
deleted file mode 100644
index f8905c8a..00000000
--- a/edict/replace-range-probes/range-assembly/RangeAssembly.edict
+++ /dev/null
@@ -1,21 +0,0 @@
-package jedit.text.replace_range@1;
-
-use lawpack jedit.text@1 digest "sha256:95758c1605894672cc9069fde01bb8b6e11842b053102660c9cd4f4d6f34d64e" as text;
-
-type Input = {
-  firstFragment: Bytes,
-  secondFragment: Bytes,
-};
-
-type RangeBytes = {
-  bytes: Bytes,
-};
-
-intent assembleRange(input: Input) returns RangeBytes
-  profile text.replaceRange
-  basis none
-  budget <= text.replaceRangeBudget
-{
-  let bytes = input.firstFragment + input.secondFragment;
-  return { bytes };
-}
diff --git a/edict/replace-range-probes/range-assembly/cases.json b/edict/replace-range-probes/range-assembly/cases.json
deleted file mode 100644
index ee8bcf9a..00000000
--- a/edict/replace-range-probes/range-assembly/cases.json
+++ /dev/null
@@ -1,78 +0,0 @@
-{
-  "schema": "jedit.range-fragment-assembly-cases/v1",
-  "operation": "jedit.text.replace_range@1.assembleRange",
-  "cases": [
-    {
-      "name": "both-empty",
-      "firstHex": "",
-      "secondHex": "",
-      "bytesHex": ""
-    },
-    {
-      "name": "first-empty",
-      "firstHex": "",
-      "secondHex": "6162",
-      "bytesHex": "6162"
-    },
-    {
-      "name": "second-empty",
-      "firstHex": "6162",
-      "secondHex": "",
-      "bytesHex": "6162"
-    },
-    {
-      "name": "in-order",
-      "firstHex": "61626364",
-      "secondHex": "65666768",
-      "bytesHex": "6162636465666768"
-    },
-    {
-      "name": "different-order",
-      "firstHex": "65666768",
-      "secondHex": "61626364",
-      "bytesHex": "6566676861626364"
-    },
-    {
-      "name": "binary-octets",
-      "firstHex": "00ff",
-      "secondHex": "807f",
-      "bytesHex": "00ff807f"
-    },
-    {
-      "name": "codepoint-fragments",
-      "firstHex": "f09f",
-      "secondHex": "98ba",
-      "bytesHex": "f09f98ba"
-    },
-    {
-      "name": "incomplete-codepoint-remains-bytes",
-      "firstHex": "f0",
-      "secondHex": "9f",
-      "bytesHex": "f09f"
-    },
-    {
-      "name": "full-apertures",
-      "firstHex": "0001020304050607",
-      "secondHex": "08090a0b0c0d0e0f",
-      "bytesHex": "000102030405060708090a0b0c0d0e0f"
-    },
-    {
-      "name": "repeated-bytes-preserved",
-      "firstHex": "ff00ff",
-      "secondHex": "ff00ff",
-      "bytesHex": "ff00ffff00ff"
-    },
-    {
-      "name": "first-over-bound",
-      "firstHex": "000102030405060708",
-      "secondHex": "",
-      "refusal": "input-type"
-    },
-    {
-      "name": "second-over-bound",
-      "firstHex": "",
-      "secondHex": "000102030405060708",
-      "refusal": "input-type"
-    }
-  ]
-}
diff --git a/edict/replace-range-probes/range-assembly/evidence/assembly-stderr.jsonl b/edict/replace-range-probes/range-assembly/evidence/assembly-stderr.jsonl
deleted file mode 100644
index 8ae2e3aa..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/assembly-stderr.jsonl
+++ /dev/null
@@ -1,2 +0,0 @@
-{"command":"build","input":{"kind":"stdin"},"kind":"ApplicationCompilationFailed","message":"Edict application did not compile to Core: [CompilerError { stage: TypeCheck, kind: TypeMismatch, message: \"string concatenation requires string operands\", span: Span { start: 430, end: 472 } }, CompilerError { stage: TypeCheck, kind: UnresolvedType, message: \"record shorthand `bytes` has no typed binding\", span: Span { start: 485, end: 490 } }, CompilerError { stage: TypeCheck, kind: TypeMismatch, message: \"return value does not match declared output type\", span: Span { start: 283, end: 495 } }, CompilerError { stage: TypeCheck, kind: TypeMismatch, message: \"intent body must return a value\", span: Span { start: 283, end: 495 } }]","schema":"edict.cli.diagnostic/v1","severity":"error","stage":"cli","type":"diagnostic"}
-{"checked":0,"command":"build","errors":1,"exitCode":2,"schema":"edict.cli.event/v1","status":"error","type":"status"}
diff --git a/edict/replace-range-probes/range-assembly/evidence/assembly-stdout.jsonl b/edict/replace-range-probes/range-assembly/evidence/assembly-stdout.jsonl
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/range-assembly/evidence/baseline-stderr.jsonl b/edict/replace-range-probes/range-assembly/evidence/baseline-stderr.jsonl
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/range-assembly/evidence/baseline-stdout.jsonl b/edict/replace-range-probes/range-assembly/evidence/baseline-stdout.jsonl
deleted file mode 100644
index a668538e..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/baseline-stdout.jsonl
+++ /dev/null
@@ -1 +0,0 @@
-{"checked":1,"command":"build","errors":0,"exitCode":0,"schema":"edict.cli.event/v1","status":"ok","type":"status"}
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/assembly/application/executable-operation-package.cbor b/edict/replace-range-probes/range-assembly/evidence/candidate/assembly/application/executable-operation-package.cbor
deleted file mode 100644
index 27b20864..00000000
Binary files a/edict/replace-range-probes/range-assembly/evidence/candidate/assembly/application/executable-operation-package.cbor and /dev/null differ
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/assembly/application/verification-report.cbor b/edict/replace-range-probes/range-assembly/evidence/candidate/assembly/application/verification-report.cbor
deleted file mode 100644
index 6f3a5a61..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/assembly/application/verification-report.cbor
+++ /dev/null
@@ -1,3 +0,0 @@
-¨goutcomehacceptedgpackage¢bidx!executable-operation-package.echofdigest‚fsha256X íH
-3*�_„÷B^F«̨†È @àH[ˆû¡æàA_htargetIr¢bidoecho.span-ir/v1fdigest‚fsha256X �è•|ø‹x`ç&9 ¤ðh~ÇHÌ¢ô¸`$7®³japiVersionx)echo.operation-package-verifier-report/v1mdiagnosticAbi¢bidtedict.diagnostics/v1fdigest‚fsha256X (ýr©‚#9‚ÊL)Û±²Ô0b9g«;m¹×þæhæ¹odiagnosticBytes@qexecutableSubject¢ebytesYR¤gpackage¢bidx!executable-operation-package.echofdigest‚fsha256X íH
-3*�_„÷B^F«̨†È @àH[ˆû¡æàA_htargetIr¢bidoecho.span-ir/v1fdigest‚fsha256X �è•|ø‹x`ç&9 ¤ðh~ÇHÌ¢ô¸`$7®³japiVersionxecho.executable-subject/v1xapplicationResultProjection¢bidx(jedit.text.replace_range@1.assembleRangefdigest‚fsha256X ¸{¡��ò„(�²0è_FPº8â2‚šÕŽŠkü¿å••ireference¢bidxecho.executable-subject/v1fdigest‚fsha256X cøžv­UÏìGÒÌmŠÛrY`HùŠ}t'ÙƒR`gèòxapplicationResultProjection¢bidx(jedit.text.replace_range@1.assembleRangefdigest‚fsha256X ¸{¡��ò„(�²0è_FPº8â2‚šÕŽŠkü¿å••
\ No newline at end of file
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/assembly/stderr.jsonl b/edict/replace-range-probes/range-assembly/evidence/candidate/assembly/stderr.jsonl
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/assembly/stdout.jsonl b/edict/replace-range-probes/range-assembly/evidence/candidate/assembly/stdout.jsonl
deleted file mode 100644
index a668538e..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/assembly/stdout.jsonl
+++ /dev/null
@@ -1 +0,0 @@
-{"checked":1,"command":"build","errors":0,"exitCode":0,"schema":"edict.cli.event/v1","status":"ok","type":"status"}
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/baseline/application/executable-operation-package.cbor b/edict/replace-range-probes/range-assembly/evidence/candidate/baseline/application/executable-operation-package.cbor
deleted file mode 100644
index 8e13c184..00000000
Binary files a/edict/replace-range-probes/range-assembly/evidence/candidate/baseline/application/executable-operation-package.cbor and /dev/null differ
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/baseline/application/verification-report.cbor b/edict/replace-range-probes/range-assembly/evidence/candidate/baseline/application/verification-report.cbor
deleted file mode 100644
index c34f2faf..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/baseline/application/verification-report.cbor
+++ /dev/null
@@ -1 +0,0 @@
-¨goutcomehacceptedgpackage¢bidx!executable-operation-package.echofdigest‚fsha256X ¹-<@‡ŠŸË§v‹æ|�ºPÏu‚3�üÝXqA[htargetIr¢bidoecho.span-ir/v1fdigest‚fsha256X ,×ÕçÓ¿–‰æn{Àx$d6öâ>Ø9`™ÊŽ$çŸùjapiVersionx)echo.operation-package-verifier-report/v1mdiagnosticAbi¢bidtedict.diagnostics/v1fdigest‚fsha256X (ýr©‚#9‚ÊL)Û±²Ô0b9g«;m¹×þæhæ¹odiagnosticBytes@qexecutableSubject¢ebytesYQ¤gpackage¢bidx!executable-operation-package.echofdigest‚fsha256X ¹-<@‡ŠŸË§v‹æ|�ºPÏu‚3�üÝXqA[htargetIr¢bidoecho.span-ir/v1fdigest‚fsha256X ,×ÕçÓ¿–‰æn{Àx$d6öâ>Ø9`™ÊŽ$çŸùjapiVersionxecho.executable-subject/v1xapplicationResultProjection¢bidx'jedit.text.replace_range@1.replaceRangefdigest‚fsha256X øº 5~^ÕN†÷Rê‚äT­GÁýèÇÜ*ë¦ireference¢bidxecho.executable-subject/v1fdigest‚fsha256X “ÑÂîk—˜d�'ïoû°Ä&¯Ø†3#ÔR`_¼;ͬËxapplicationResultProjection¢bidx'jedit.text.replace_range@1.replaceRangefdigest‚fsha256X øº 5~^ÕN†÷Rê‚äT­GÁýèÇÜ*ë¦
\ No newline at end of file
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/baseline/stderr.jsonl b/edict/replace-range-probes/range-assembly/evidence/candidate/baseline/stderr.jsonl
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/baseline/stdout.jsonl b/edict/replace-range-probes/range-assembly/evidence/candidate/baseline/stdout.jsonl
deleted file mode 100644
index a668538e..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/baseline/stdout.jsonl
+++ /dev/null
@@ -1 +0,0 @@
-{"checked":1,"command":"build","errors":0,"exitCode":0,"schema":"edict.cli.event/v1","status":"ok","type":"status"}
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/compiler-source-sha256.json b/edict/replace-range-probes/range-assembly/evidence/candidate/compiler-source-sha256.json
deleted file mode 100644
index 9bc9f80a..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/compiler-source-sha256.json
+++ /dev/null
@@ -1,454 +0,0 @@
-{
-  "revision": "01dc5abb9a8a74f8fd8b0e0a6d1041d0adb86d6e",
-  "files": {
-    ".cargo/config.toml": "c185a2b859850d94af015a9672c1568e1ef73b12612d820f596ef967b835f637",
-    ".github/workflows/auto-release-tag.yml": "8f9769cc8ebd110cd9887562368b17b7cf640ea70487ab9e329b5efa4ad34aea",
-    ".github/workflows/ci.yml": "21fb0536c7ceb84136baa7f60e636df7f59739943c1a67692a789ee4598d19e1",
-    ".github/workflows/release.yml": "eece9419c92837bc90bb645ed00c19b4c4d7e05e9737b9dddb4bf4e750903eb7",
-    ".gitignore": "4a2b3d736804960e55dba16b8e00bc85084195608e4b9b3877859e745f4ddca1",
-    ".markdownlint.json": "d56624af462cadbbd8f8b2cfebec943cd2a34fe82c3f7eb517f3d63bb3d21a7e",
-    "AGENTS.md": "c43bd85432ee58d57041a389533c9531d26267af3e260346cf53a75932bd5c50",
-    "ARCHITECTURE.md": "7b476013a54a2b0ca2faf9b8c41a28d8042bd66999b385dea90e7fc1f6bab116",
-    "CHANGELOG.md": "35c1e5fb285701a09f0cf6794b4becf9b446a274287c7d7051ffa12023f3bfba",
-    "CODE_OF_CONDUCT.md": "46e5940b4f1f0f259b1c0ca3c5aa73e2804ea916370f70dff742f4978020e810",
-    "CONTRIBUTING.md": "cbf1a4cbab1891a55f86baf7aba1726aa496fe0d54e6ec91c3c5c66981242527",
-    "Cargo.lock": "668623d1ad8e50c2e2dd28fabacefccf852d8f234b1029bdf72943b0a7e47eaf",
-    "Cargo.toml": "59e341299663a5c63c48cf2752c25e4cfce724c1ead492258569d8261f4ab731",
-    "EDICT.md": "8117c4c7dc611490e3913afadd9e7dab9353fb6eb0ab1c35eac345bcaf7546c6",
-    "LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
-    "NOTICE": "7acbac1eec94174678c6517ec3d0c087774176afe7ecc10dad13f006437d33da",
-    "README.md": "e94fb534ff7ce849c2e10ac7ea527b89dda9b2ead35e1ce7b582b1d077a52e27",
-    "ROADMAP.md": "12657f335e177d42c7f424657ff02488e4856568028ed7dc3b0adc99745da7bc",
-    "SECURITY.md": "b9f33ffbdc334812c53a7ab91c5ee20174fab455de5cf8b06adc151c57d46386",
-    "crates/edict-cli/Cargo.toml": "97bd5d56fb3d5a8b9ae92e10a33e1ee2a91ed4f7b07567e997cc4c074e0a6057",
-    "crates/edict-cli/src/application_build.rs": "0f3684e93fe79949e5bf7cee1f94e1f5044841b689ba7a8c1f963847a78179d7",
-    "crates/edict-cli/src/lawpack_build.rs": "ec63d3fef595ae4f9267e01fc1fa729e8b0f283e8c8f850dd26ee837bbeb7348",
-    "crates/edict-cli/src/lawpack_build_windows.rs": "f8df381586aeeb0ae9809cccff1fe00249b13117b681583fe16124017aada96c",
-    "crates/edict-cli/src/lib.rs": "5861d6e444dbb0c0583c5ce265ff0262915600978162bc9c15e5ca35ae42cbc0",
-    "crates/edict-cli/src/main.rs": "3605ed96c2c23b0a49108a466dc3622af1164c45702ddcc6de1714bda033c1a7",
-    "crates/edict-cli/tests/golden_cli.rs": "601ce4fbe45719fb465c3ba53f15745a3d6f6a4fb70c901b4edaf76b1ace6b1e",
-    "crates/edict-cli/tests/jsonl_cli.rs": "9b6b84b2c5c95c90148d3b370b84b95901a76332d64e75288e3f4a7c8e77336f",
-    "crates/edict-cli/tests/lawpack_authoring_cli.rs": "00a7a4c68262fcafdde1e4284c3f0f46bb5f5e508eefff42a2ae4b0cc49dc690",
-    "crates/edict-provider-host-wasmtime/Cargo.toml": "1c32708d174e52a50f26705907042a0912d393781d9f4fb3a04f31c4656eef90",
-    "crates/edict-provider-host-wasmtime/src/conversion.rs": "3cdf3773fd80ec49e34ff162212df79c0f0b41e4a9747e8cb3ab9e3fbde2c2d1",
-    "crates/edict-provider-host-wasmtime/src/invocation.rs": "517cd7631a172a948cdb86a69a91f43c43b4b2752939272e2ede05ddab36ff54",
-    "crates/edict-provider-host-wasmtime/src/lib.rs": "87dab846338d6e53e47ba6d818a6b7c8b321537c62cc4970076b89851b18f3aa",
-    "crates/edict-provider-host-wasmtime/src/limits.rs": "b8395e16dde588f75375e6ff635650aa25607ae63c024f0d05eae46c561bfb19",
-    "crates/edict-provider-host-wasmtime/src/replay.rs": "91d55f288cc84021bee48a1b10581c2bedcd56c95c7bf071a627a9a38b68940b",
-    "crates/edict-provider-host-wasmtime/tests/invocation.rs": "18fb18970d51ec3e105bfc9a3907044962e88681a6d7971b3e56e0480c278845",
-    "crates/edict-provider-host-wasmtime/tests/preflight.rs": "3de8dffbbcc26c3efa06aa7e8a9d281d874ea1365269552caf46d3d54ce18dee",
-    "crates/edict-provider-schema/Cargo.toml": "04e9de090fe8a0ef20237b3c0dac6a846fc04653399b49c45934cae64dbc444d",
-    "crates/edict-provider-schema/src/contract_pack.rs": "4ba5aa93fa6c82a0df6f82708cffbe7f1ea0690f1cb315ad9ea76318e87af8e5",
-    "crates/edict-provider-schema/src/lib.rs": "77391e3c7e0785c771f4dbb5c1618934fba82940b11dfafa5148dc4fa9b1b742",
-    "crates/edict-provider-schema/src/recursive_dispatch.rs": "2aff6c1350b3c93d7f5c75377462c860b44c5aaaa390e21e0ad3e58f255adf14",
-    "crates/edict-provider-schema/src/schema_safety.rs": "715d59a014750e4785c6127b73d301f92a3f2e59e63e296adc94315c92810702",
-    "crates/edict-provider-schema/tests/authority_facts_abi.rs": "877a5487f2c6e38cb2dc358cf66cbd40975076da2ce628ef0642e99971c7c7a3",
-    "crates/edict-provider-schema/tests/provider_contract_pack.rs": "2c45670654fd3171f75c935e0bcc2bcabf07d3c4d021145d52b45d735e942094",
-    "crates/edict-provider-schema/tests/registry.rs": "dc774cfc6f4f09af239831ae116f4cb55b764d8a863f121cde9762eb8e72b37b",
-    "crates/edict-syntax/Cargo.toml": "12058f9ae36c1b2ab78d683f56eb1e41af8c8185dcbf3c993ef097acd097283d",
-    "crates/edict-syntax/src/admission.rs": "5cd08a9c05a5c9be22d9720b137d25dec019efdf23c41289010e5f107cb93f45",
-    "crates/edict-syntax/src/ast.rs": "27770c7eda15838e99f7b790727b7d3a1ad93a22804b3d50054fdbc9eb95d827",
-    "crates/edict-syntax/src/authority_facts.rs": "3beea380b1f617a452e7a66e508ebdaa1262ede41c60381cfb96c2544f50de13",
-    "crates/edict-syntax/src/canonical.rs": "f0e1e60b272ff1b623aa6e018f8e3d1def4c90d1f0f66b0aba82d5ab2397ce42",
-    "crates/edict-syntax/src/compiler.rs": "0f1a1f9e14b7eb910838e08dfc6e67f71184b708d082a0bfaef9334f6e5a5f67",
-    "crates/edict-syntax/src/compiler/byte_concat.rs": "2f608fcd0c7f797f587cc0efb356be06437cfb372feb1d8b4516840d2e261ef4",
-    "crates/edict-syntax/src/compiler/byte_length.rs": "088b3a62ee8debd9512758ab2d670abcb5b0f04f9dacfe130b70a65567af1421",
-    "crates/edict-syntax/src/compiler/byte_slice.rs": "375297492ff393f6d132034c24c34aaa86e81d615f7b0a7c0d54ed9196fe7749",
-    "crates/edict-syntax/src/compiler/unsigned_subtraction.rs": "89f0b8275549e639a133b7466125811d7205ab320ab0ba6f1e30d11f5015c925",
-    "crates/edict-syntax/src/contract_bundle.rs": "4796496d79f7a3d9fb17afed1d79e54873007b84fe690706af66e127dd1c33f7",
-    "crates/edict-syntax/src/core_ir.rs": "0426224018a6990b60217739250f6f60232badd76df420e83d35bc7ee99cf533",
-    "crates/edict-syntax/src/highlight.rs": "98d63bbc547c44f01e7f6e665071c707352e94e6a1da9427db6ca9bd34c64c1a",
-    "crates/edict-syntax/src/lawpack.rs": "f85fb5b23be638f87cbc13ab9dcd63cecbfd3c6c8546f0c681eabb0a747a6d14",
-    "crates/edict-syntax/src/lawpack_adapter.rs": "3e535a54e09d14f204347e8e6c5d76fbde421fdd83d0f81ab96aa34254778261",
-    "crates/edict-syntax/src/lawpack_authoring.rs": "d841eb54a05de902dec2d5c051bc6bb1fc63fb860bd90c329d6d651c6defa864",
-    "crates/edict-syntax/src/lib.rs": "a61378d8f1747d2cad3b08999fed72f39643acbea262cafee993ff0a8cf95cca",
-    "crates/edict-syntax/src/lowerability.rs": "bbe4a2c194fdbf3ecaac891a0283bc565c29a50da7b88add56a84bf7f8d38612",
-    "crates/edict-syntax/src/parser.rs": "7000c9597582f9d4e40acd35c22c9a3ae11c60f98e06ca87166faa5674044c4d",
-    "crates/edict-syntax/src/provider.rs": "1664029ea4a946ef4583a89679936e6b617af4cb7f85ddf172d6d021e15f53dc",
-    "crates/edict-syntax/src/provider_invocation.rs": "41705963f052c64fbca5223d932c50f81bf475758a45ec60ce43388039b72420",
-    "crates/edict-syntax/src/provider_lowering.rs": "2d9db78159a0fed1edd39293eb245a9af723991654d5ee8b2b9b4bedb4ce3829",
-    "crates/edict-syntax/src/result_projection.rs": "3ebc8d04690127e713a3068adda28eadaa273e00efdb3b25c3d493aa9c31e3e9",
-    "crates/edict-syntax/src/semantic.rs": "c62ab97f2f23cdc90373b3e7b96d897776fbecf4f2a05a5e0cbcabf6a4521402",
-    "crates/edict-syntax/src/target_ir.rs": "f3efc95f75ab5a4cb85020a8ada65e7de224829c66ad44f18570ca4d015100ff",
-    "crates/edict-syntax/src/target_ir/byte_concat.rs": "212f25d55f29609a4f27990c3c8b635a88234908aee96a895079c31826a9e480",
-    "crates/edict-syntax/src/target_ir/byte_length.rs": "eccde25dc6bc2afa0bbe94ae295fe808853cb0020afd9c5b26601f2fb81f0339",
-    "crates/edict-syntax/src/target_ir/byte_slice.rs": "aa670da555ab42224fc1a5771589a9a4e08c62eea2707a7a8bcc932432d59da6",
-    "crates/edict-syntax/src/target_ir/execution_order.rs": "36351597b015491712c1cc2a3372a9d9a67c76c94d7f162aa04fadcbfde48495",
-    "crates/edict-syntax/src/target_ir/totality.rs": "b838eb8eb45bb8fe4f44a939e68b628ece8eb7be8de24c054c9ae162236abe07",
-    "crates/edict-syntax/src/target_ir/unsigned_subtraction.rs": "61263d52c0aa531f43a7962c673a7178d9325ea92ef37a159ad0979cf2b287e0",
-    "crates/edict-syntax/src/target_profile.rs": "904baf82f4f1a59287eef88e5f6cc5f14f6f5426be01625840c5bc5557d28775",
-    "crates/edict-syntax/src/target_profile_contract_resources.rs": "4307121aafc4081a744ae9a51457cddc2ac7a020bd528513a41c8a815825867d",
-    "crates/edict-syntax/src/token.rs": "fd89e2f658c1e4b1c4f3135ad377898755296343e899b12260a0880519e00f66",
-    "crates/edict-syntax/tests/admission.rs": "1bcea2e01578ccbcda98751a995dfa52d013ee10caa612f41e450ba713376f3b",
-    "crates/edict-syntax/tests/authority_facts.rs": "d3ccb5d407694ef040c8f6e8de4cac37d0c6c2a26ae29261b10cd754c01a9be3",
-    "crates/edict-syntax/tests/authority_facts_cbor.rs": "07fafcb7e611b260b4040098dfeaf6d1f1ca172ec2726f4eb084fd4c503070fb",
-    "crates/edict-syntax/tests/byte_concat.rs": "830ee7cd2bee0e2235a9b2dcd6af968a8e88fb9b3f7af34d5b26163a294e90fc",
-    "crates/edict-syntax/tests/byte_length.rs": "4ee3ff7844377d59f3461b20bbf8fb1e44824faba8a3768c901eba9ffe4f1694",
-    "crates/edict-syntax/tests/byte_slice.rs": "d479160e1fc462223fddc60ee2faf504487231480ff68a136cb5597535170e4d",
-    "crates/edict-syntax/tests/canonical_encoding.rs": "2e81d33a525c01708f0329e0117128fd9d969b785dbd6539919ef9179a251d9b",
-    "crates/edict-syntax/tests/common/mod.rs": "e4ab06daed846140ea87e5b5bc53094bec8e9121d63e209fa2f9cc7f8c8c56e4",
-    "crates/edict-syntax/tests/compiler_spine.rs": "bb27dcfce0c09a713b4841dd25276b2e5eb6cfefbf6612678c32b40e4c1169f2",
-    "crates/edict-syntax/tests/contract_bundle.rs": "652e4270f9ff90cb207a5e52d2863ea3077e1cb8e6ab753603a2784614da2985",
-    "crates/edict-syntax/tests/core_golden_fixtures.rs": "65bd63e543bbb9a6c9f9ea494d16690231355410e5dc9fce331ea5fa8667252c",
-    "crates/edict-syntax/tests/core_graph_depth.rs": "1ac9a0bbb6df7ef4a084a4b352384f397724bc2c105057de85c6c568d5158d92",
-    "crates/edict-syntax/tests/external_action_requests.rs": "351b65ef2e335120513e2f525c33c4b5ffc4920b5df71615a299c40c6dda981d",
-    "crates/edict-syntax/tests/highlighting.rs": "4a66ba0da9b05e10665230ad3f1151f07b5990a51a1b33a07ba2c408c49a67c0",
-    "crates/edict-syntax/tests/lawpack.rs": "06eb48d7e28a04eff94d2726f725209e980d04240bc6fa181f13cbefb838535e",
-    "crates/edict-syntax/tests/lawpack_authoring.rs": "0eabfad59ac99d18b50a5efa7f2c9bc763dbd1cb593719b568b2747947b8f18a",
-    "crates/edict-syntax/tests/lowerability.rs": "25654daf28c4543551fbc698c177a8b36a2b23ebe3792d51f59fca64a3a6dd5c",
-    "crates/edict-syntax/tests/operation_prerequisites.rs": "5d1762ded6d5132b72aba8973e45b1d1c13918fcc7a3bb9841432d4d5b5461dc",
-    "crates/edict-syntax/tests/parse_control_flow.rs": "5568c5d9616830cec8905811672738dd373e981b96e6f2fa7059ab9b2b125da9",
-    "crates/edict-syntax/tests/parse_greeting.rs": "12892d5a25393afcd7a3d13addb840c2ef478e96ea0896690c4bfdcdb08cf7cc",
-    "crates/edict-syntax/tests/parse_hello.rs": "3ff047d05d54f03538e4448427756c577adf19bb1d6b016ea885c2453f3ee9b4",
-    "crates/edict-syntax/tests/parse_keywords.rs": "e9bcd4f76a6254fa5bd2c38dad65818540fad013e8e1de4056ab8ef9136fc859",
-    "crates/edict-syntax/tests/parse_loops.rs": "909e08d646a6cf85f6cd9bc0a46ff6bf87c7d3fd0e67b5198313b8e46093ea9f",
-    "crates/edict-syntax/tests/parse_negative.rs": "3f6d3417192c7bac2da4117827e37024ee78af4766f906c93a49fb68be018901",
-    "crates/edict-syntax/tests/parse_review_regressions.rs": "5c2e5b24f64f72e8c5f0faad2e0bf87810b7e7c4d07a5f065d528bb2fff98974",
-    "crates/edict-syntax/tests/parse_variants.rs": "91a011215e0a058cc99546930f9f0dbb0eab5763f6efebc1bc3c3a3ba0071500",
-    "crates/edict-syntax/tests/provider.rs": "cf23cf7eaa0e7e5225220333091db869e4041f9362724e1bf436067cb0005d75",
-    "crates/edict-syntax/tests/provider_invocation.rs": "2bcd5c801ddc2c9104db7dd5f59375b7c34a28a70f0f3a24331c78b3123cc5b4",
-    "crates/edict-syntax/tests/provider_lowering.rs": "5db0737afd40d8d405dc49dc68d9190a91feaba02cff827c8e7c7587626d49fd",
-    "crates/edict-syntax/tests/result_projection.rs": "fb1a22dba15c177d8b65aae4ad46173c0345e84b9f87ba92d3c725bf6f901601",
-    "crates/edict-syntax/tests/semantic_validation.rs": "8176193d9abc9bab7cf36bf026059a64cfc95cb7d7126b0862ddd1336ee2f1ab",
-    "crates/edict-syntax/tests/target_ir.rs": "293d463a72a0770383fe43fa332cfa67d537ca3dc87ab1d9020f41960ccdb820",
-    "crates/edict-syntax/tests/target_ir/ordered.rs": "db4e7eb38ad4d2e04a5a63b94d6c21e8c2fd901a88f4c40a1130a1c1eb94f61b",
-    "crates/edict-syntax/tests/target_profile.rs": "78c360c9f16b97698338a9759cdfc60d61b700d6a486be7547b428d1cfdd525a",
-    "crates/edict-syntax/tests/target_profile_contract_resources.rs": "07947308744e307877bc1cc91bfd69c24f4d6752e1c8091fd31e68fc6b121211",
-    "crates/edict-syntax/tests/target_unsigned_subtraction.rs": "3905adb9dadfe23e93343bded17445b16a783771929d776c5e0fb4a166461c72",
-    "crates/edict-syntax/tests/unsigned_subtraction.rs": "4a33ebb4cfc854a16cff8f9eeb1465d871857d9dc9ce60604acc192a5f254627",
-    "crates/edict/Cargo.toml": "7ef565369c0108d463d9804fc494298cc80a5833aa26273bbf9abad328e342ef",
-    "crates/edict/README.md": "a4c923bf99c34bf42775286c73de35a8bf023e9105ff3f6827c67a0cde2193c5",
-    "crates/edict/src/lib.rs": "29962d09fd96bee5b9b7059a46732a7d8e965716185c1efc383ab68720b5b973",
-    "crates/edict/tests/artifact_models.rs": "4c635858a21e4e939f0c41c17da8ef874379191c13141ccb862b15ba6e9d3814",
-    "crates/edict/tests/public_surface.rs": "b6b2f9aa3c48be671ebb452ec5ee14d59c29b55184ee274f85b50f7477d77e6d",
-    "deny.toml": "b140f4619f9705b58bbdd9f82a82e3ca2c3c410545b2087940751e6a407ef6dd",
-    "docs/DESIGN_runtime-neutral-edict-sha-lock-assurance.md": "ec8cd6cb513a259458d932d0ed684a1773759ed4dbe2d5f3e561addc9b92b2ae",
-    "docs/GUIDE_edict-assurance-transparency.md": "30e26b75cfc7f4873ba0679a60c6611ce80cf5b206787488115630a3c49505f0",
-    "docs/README.md": "1d45afb7244c51e06130ca222b150d8777c4d93e79b05562dec111f1a359d79a",
-    "docs/REQUIREMENTS.md": "be8ca1f6c7f45f0d495d97e7a1e889a7f05fbd97a09515923eb34be80b1079b3",
-    "docs/RETRO_phase1-parser.md": "f88d661fc50ac6c62595d4db73214ba92adf180e59d6dbc3ce8a7c353a62946d",
-    "docs/SPEC_continuum-admission-v1.md": "32eaa3ae802b47c041cd5b289a9ce59cb5456a971b803794a2d0913a3a08295d",
-    "docs/SPEC_continuum-contract-bundle-v1.md": "01a899ce5b2b901b5b5dd8e7794ea4540926bef6eeade03775111f3fd0773ede",
-    "docs/SPEC_edict-language-v1.md": "a3e1f99eaf97e59628d59719db3921c4814814144b66211c6ea9bcf5e95489d2",
-    "docs/SPEC_edict-lawpack-abi-v1.md": "a2a1816167df73365f309228012abf33374861afb857ce71538a4ff760b83831",
-    "docs/SPEC_edict-target-profile-abi-v1.md": "b659e8139469ebb94ccb93cfac1300591e6ad5e02142bd0bbe6fc3f6d8af5d01",
-    "docs/TECHNICAL_EXPLANATION.md": "25b837b0639c340d871f86e4e6830c2572f6dffb7a405e12620cf6db014ac1f0",
-    "docs/abi/edict-authority-facts.cddl": "1b01189e5e95c583f5c07820b1572bb00ad75d87b9246079ff039e4897a49595",
-    "docs/abi/edict-common.cddl": "cce1c85f1a64e0b87098781cf606c5f251d09e1a851c50386fee6ef09b7844a1",
-    "docs/abi/edict-core.cddl": "07cf44011a58ecb29e849e81a3f2e33712299d06f5060bfab4737be48d22ac13",
-    "docs/abi/edict-lawpack-adapter.cddl": "3db613aa72379b50ad5ccd931e791fc2b6334e3c3ae4d4385ded0eda607948ca",
-    "docs/abi/edict-lawpack.cddl": "2e42f18af14089b5d3faaf2eef76b1412f828ca77dfd5df5c22fcf7abd222fb8",
-    "docs/abi/edict-result-projection.cddl": "5194be961826186ad678d8962e1453334b162d44c1eee443fed3079395554df4",
-    "docs/abi/edict-target-ir.cddl": "123e7f805dc5e831e88befec4cd49ec02c39858b6f3990da8a73b50c6086ae39",
-    "docs/abi/edict-target-profile.cddl": "a465b1214232de00029b8d6fa11747dc187f43c4901511e358adc45f04d54d7b",
-    "docs/abi/edict-target-provider.wit": "2971fe44def7e51d5271dfc0f04f3088aa58754cffdc847681a587605aac749e",
-    "docs/audit/2026-06-28_code-quality.md": "de796db9655ba262a27d940ff5aae9bdfce1e5932e913cfcd88b1c2fc012b9e4",
-    "docs/audit/2026-06-28_documentation-quality.md": "583d5f7ed077ae1dc7d76c675a35956a687e81d94490d942991532b8e84410a5",
-    "docs/audit/2026-06-28_ship-readiness.md": "a236c18ef7f1051ff68dcce11d4f5a2e4d31cc2be2d4ffc95afb03494d5d3204",
-    "docs/design/authority-fact-governance.md": "27fa454182a1366b2a85d467b323201ccf6e7ad0b0fd72c60af768ec4c0ce192",
-    "docs/design/canonical-target-ir-v0.11.md": "19bd1166f6d236946b0b98800c7a4000f862a395bab8273906360bc03c23f4d3",
-    "docs/design/contract-bundle-assembly-v0.11.md": "62752f8a85b2eec0ee27e65fd3fae7b895d5eca70856386dde69fbcc608ae736",
-    "docs/design/crate-scope-v0.11.md": "fbe735625d79951f7dfa1d500595d5257e48b4f89d67b8030a29cd791d6b59bf",
-    "docs/design/obstruction-strands-v0.md": "33bee298c20b64b09fdf6a09f9de369abb17a5a840993c2e1c624c5c7ea73b2b",
-    "docs/design/provider-artifact-pipeline-alpha.md": "d03b04b3b54be6f030336eed0745d7bdf7a3fdb27e46ae2715a1a2ce1c929e44",
-    "docs/design/schema-as-sot-codegen.md": "92072da960c24424784fdcc3c8a437d5ac7bdd9391d249af22c89db05a6bdf0c",
-    "docs/design/v2-obligation-closure.md": "8e0927734597a64f30451831f3a3aeda661242b3622de3d81b8a9cec723b5bfd",
-    "docs/releases/v0.1.0-alpha.1.md": "45edbd919f16d6a8e83364f6932b230e5021a4fe22efa4637a07411ed6c0fdb5",
-    "docs/releases/v0.10.0-alpha.1.md": "a5e587e70ed7b5c061153c98cd3712811518d9f5a4d6a9cd7fb3a4a83afffb42",
-    "docs/releases/v0.11.0-alpha.1.md": "52d21f35a92db8bc3cea9f065a93ef27db19a38ee2d54ae707a9e96b843e5f55",
-    "docs/releases/v0.2.0-alpha.1.md": "7bf1f65a05f647155ec5e649f40128da16dbf9073dc1e50416127470366644ae",
-    "docs/releases/v0.3.0-alpha.1.md": "9b4feca3ec64332a613b21bb9d712c09b1d2a516bec2e5a44add9532a76672ec",
-    "docs/releases/v0.4.0-alpha.1.md": "55bacd3162c6ff5ff82bf8a2823ab10d118d7371ed5299d7351ffe916d55394a",
-    "docs/releases/v0.5.0-alpha.1.md": "fd8585076e7b8bdb9c3ab863785a4c8a7febe9547e06def7c29f97fd239aa5a8",
-    "docs/releases/v0.6.0-alpha.1.md": "b8827f5c16c65b09bf13c9d2fb9354e969d52f668d3cd7681f488e2f135dd2a5",
-    "docs/releases/v0.7.0-alpha.1.md": "25848f2d35e31dd685553fd2b5e6cdd651be8864e49c902c73e1833b5287506e",
-    "docs/releases/v0.8.0-alpha.1.md": "c3c98f5461b74d72f83fdf2d65bf5fbdb54dad18825bbbb3cdf364769d395aa2",
-    "docs/releases/v0.9.0-alpha.1.md": "f41dadaa36ed8e48ca9a4ae5ae68e6898ca2a3eee2e677a5995448295eda5063",
-    "docs/schemas/edict.cli-check-result.v1.schema.json": "36547692662d017c57f2812598c19e64da3f19410ccb9e6c14386ae8714d0972",
-    "docs/schemas/edict.cli-diagnostic.v1.schema.json": "918d72cdf5356930959ccd590034653fc735b1b9aad9a4891d91c739420d4cb7",
-    "docs/schemas/edict.cli-event.v1.schema.json": "7294ae819dfd5e657f0ec677f5c945520c9e4e7c929b81a73c9cf79b49ff3767",
-    "docs/schemas/edict.cli-info.v1.schema.json": "8ccd6fa256b9cf5c7448480e884b202d2ed7eee2a427ad7f7f64cda3f79d847d",
-    "docs/schemas/edict.compiler-input.v1.schema.json": "478995c3d92ec08ad3a5d3ec8441592bfd87d5918ce6e5c023d7a658f19499f4",
-    "docs/schemas/edict.compiler-settings.v1.schema.json": "8dc2c56e77feedbbb407b653c838939ac7b31eb758b4964bb85a5a6c4febfd4f",
-    "docs/schemas/edict.projection-core.v1.schema.json": "3bb8ba3316e3ecd16513715fe0d0832b140aad98a20a7b4a44a698981f9c942d",
-    "docs/schemas/edict.projection-diagnostics.v1.schema.json": "5ef5f91600829158b74768f48e1dfe85b433313197c7db21f36e4e514052a4db",
-    "docs/schemas/edict.projection-syntax.v1.schema.json": "b235d88786554f2cec390193ae961b4579cc08a7379e0330070dcd46667ad655",
-    "docs/schemas/edict.projection-target-ir.v1.schema.json": "adcdff6d97e228dccb59219a8ad65da376208984201e9a23e257601f9ee51545",
-    "docs/topics/README.md": "f8b9d8b6cff5df545180d31d307295507db3d6fe61c6591af1bd9007995ed384",
-    "docs/topics/admission/README.md": "4d4dd43243a8ebe9b93bdaa9da3cbc22ef0e740039ac9319cd49777866c86a43",
-    "docs/topics/admission/test-plan.md": "ca413dbccca92fb5526502127034d51d815d141234172b82428bf167aaf9b056",
-    "docs/topics/assurance/README.md": "a9f4d173dad1bd5bf6d904166da7dcbbe57a02792d4f11b3bb5eff8c55a768f4",
-    "docs/topics/assurance/test-plan.md": "a80bb51c7c3492037c71a74ac865c96da03b95f39cc382da15261ae210a3f584",
-    "docs/topics/authority-facts/README.md": "499dd2e23d6f934cc8c443bafe9c580fb2196c87f7e5030fe8742528fd769e20",
-    "docs/topics/authority-facts/test-plan.md": "1acb5c38dfe610ab3660313b1fd19eae32f45fbd9896190f1474a212bcf7ca9f",
-    "docs/topics/cli/README.md": "72a05856737cb6f22285966fdde3e59d1770d43d45e155d41a41202f6b525525",
-    "docs/topics/cli/test-plan.md": "fc012a6cc4421053d606bed6ea6a083f9ffdd6bfc479483d1f315de25c1d2867",
-    "docs/topics/compiler-spine/README.md": "c0a1d9f9323d77365af089bcc3bbcc46d6aa9f020e087ea7d545af52f9104df1",
-    "docs/topics/compiler-spine/test-plan.md": "99c33b257107884c1b77b964682eb16cb4f44ced10dc3c77fc2b173d3c530ada",
-    "docs/topics/contract-bundles/README.md": "1f083c59ec1bf06350b0e3553cc359f48cbfe96a5fe112376ad853c2057a673e",
-    "docs/topics/contract-bundles/test-plan.md": "90c6bdd9dfd353ac6b884c8a77892aca88bc3da054f9fb7261b9e066a7effcc9",
-    "docs/topics/core-ir/README.md": "fafc02e14a18b4c93f2a2f598256227a11e2847161be6cd9c474cf39461ef632",
-    "docs/topics/core-ir/canonical-encoding.md": "0e798dda2d8ca6e30c5b8a03c0d891cd0828b32fab77ec7fd765bf4c4ed41368",
-    "docs/topics/core-ir/test-plan.md": "d61b97ebfbfeb04e83ac9533b78c819580d3fa1c15300ac00b13c64f4382e2c9",
-    "docs/topics/developer-tooling/README.md": "982186d3f43a9e2fcd107b997212a2783c2894f20c8c3e72ee602a575bc2b627",
-    "docs/topics/developer-tooling/test-plan.md": "ec2f8f8d708d9c4da72e718ae5ab21f982de1bfaf5ed0ec3a11f91ab24625094",
-    "docs/topics/documentation/README.md": "37e6fb6bf67035459646e8ae03a9aad74a8e2ee97f746aae2e852dd05da1a1e5",
-    "docs/topics/documentation/test-plan.md": "e6a75f6160f27f7aea8f224ab830bbf05298f9241ff90f6c3311d989e82fc45e",
-    "docs/topics/external-action-requests/README.md": "0dade9953c656da44dd0cdfc747181c087aca4190a886a35a35c4dc8b07c8d7d",
-    "docs/topics/external-action-requests/test-plan.md": "7a53705e10776768bc9aa8b9c2fc625cfad4a7f6f74f41e18dab7e512f1399ff",
-    "docs/topics/fixtures/README.md": "79079486ffeca402ccf9e67b2a9c5d848efb4d9109887cdd2bb711678a3730e3",
-    "docs/topics/fixtures/test-plan.md": "261248e06c2da1840039b990258dfd1bcf7db5748e38fa169f4067916c52f348",
-    "docs/topics/lawpack-authoring/README.md": "ff55f321cd12899d63c0968841dcfbdfffaafb4c03d457ccd51a3dffabc73881",
-    "docs/topics/lawpack-authoring/test-plan.md": "56693e41a6fd25c6aa92065225f610bab767ba109689425cd385b57484422112",
-    "docs/topics/lawpacks/README.md": "22b8560e228f4608cd77f8de057a21fb618a6b10c7e7636691d4682d06e7b409",
-    "docs/topics/lawpacks/test-plan.md": "574f246ce5c7c815e8f9f5fa56270ed1361df32ccc7570d3f9c3eafffcc1b321",
-    "docs/topics/lowerability/README.md": "0272cd674d01c80f26d77fb01d2f9a1471cca71dc496afa1d539bb419b280573",
-    "docs/topics/lowerability/test-plan.md": "9cfca95e5d4212e84d93a6d2875a96d9bfd8d34edbfb41f2be83791b470dc6ae",
-    "docs/topics/obstruction-strands/README.md": "bdbc56030383f514ce09aa1c3a38fc62ae2ba23985c26af1c0b4f2f0c21a69a9",
-    "docs/topics/obstruction-strands/test-plan.md": "9f6d5086d1808bdea1bf50bb7547b7f9949ecf5240a2137080f306372dbc918a",
-    "docs/topics/providers/README.md": "7d93a17892e4995c7e2fb5813f0d3113f03778f6bd62ea09fbe4373d52ce95ab",
-    "docs/topics/providers/architecture.md": "87a1f565ed08a3b83996e990ca403b3720ce850bba65d126790809b62572fb16",
-    "docs/topics/providers/test-plan.md": "839d25b278debf152468729c0eccec3d1b2829883781f624425814bcaeddc978",
-    "docs/topics/public-rust-api/README.md": "5452ae2c536ddace20e83f1f5aaa33921634efa468745d43331608b12d15acda",
-    "docs/topics/public-rust-api/test-plan.md": "4529a6bc909a2d98b76c415b7e03aa5f1eea0da04f65f309cac10d6403c504a4",
-    "docs/topics/release-process/README.md": "04276147621f5ef8daa09e3d2921d8f7b8ede4b1190bdfbe9642989c0e224383",
-    "docs/topics/release-process/policy.toml": "203a7da2e6b327ca5664c4abbc813cf42ef9cf608cb105344944bc3241e81cff",
-    "docs/topics/release-process/runbook.md": "900f89932c5664d64f27f2ad5ecf5bda4e59e216770c8bab8ddc456a0ae4cd39",
-    "docs/topics/release-process/test-plan.md": "d4401f8b6819c9128dd09f7761f2fff5fca52b3fe82daa3ed922bb98f0c2f44f",
-    "docs/topics/result-projections/README.md": "0c845ca6e2c94c3af767edce3e4734a57a90542cd22759425fe4a950d0c13316",
-    "docs/topics/result-projections/test-plan.md": "9c7b9003189f6be6c67232281d7559152f49bc29b144b6bf0a4f20c5f351bb0a",
-    "docs/topics/review-process/README.md": "ad39e621572f4a472627cce3054909de645b6d5f882d88596f58cda073f13b88",
-    "docs/topics/review-process/policy.toml": "4ef2212a5c0843061ac64c0e568728ccc9ed1fc5091179177865ac21a8f55be3",
-    "docs/topics/review-process/test-plan.md": "387fb196d75b41096efd8e01d078f8ae946e46e23504d2798263074bced0aac5",
-    "docs/topics/rust-standards/README.md": "458ac52d1f35c2a2dc6a7b8904538d3f7db01b5c0e6986232440b797c1a167ed",
-    "docs/topics/rust-standards/test-plan.md": "9ca0677387942cd93c4fd2ff2196ee58303988e04d343990d623662f1d05d2f6",
-    "docs/topics/semantic-validation/README.md": "d39c0a87fb27d4c628345cf7dc84936ad49b5c87d7c3b318d234c1bcc0423054",
-    "docs/topics/semantic-validation/test-plan.md": "5b419c5c96760709cb889aa7f00aeea54b1eb14bed6d7f1ebf8250688326de47",
-    "docs/topics/syntax/README.md": "60ab4d64ddecf3757155b837c048eb2906023c8b324b41c7e43258b154b3388e",
-    "docs/topics/syntax/test-plan.md": "11ce0ebab9bb67eb67571404812e1a2ce141d8c2a3aaf6a760f40dfc47d91f33",
-    "docs/topics/target-ir/README.md": "0115bca1607aad12517b0c9339d87ede338d67cafd6e5c1b7c01380c98ae807f",
-    "docs/topics/target-ir/test-plan.md": "1904169bb88b7738eb3414b1db71b8d6a5e09ebbc668162e58e8e1f2aea852d8",
-    "docs/topics/target-profiles/README.md": "b42a301c561d9ea6fd7455263762752c89393d6c48d518180969a1b5211d3978",
-    "docs/topics/target-profiles/test-plan.md": "523f92ed32ae20f1a319e6eb5b21d2d18dffcd23aa4dbd83288ecc59a96ec86f",
-    "docs/topics/tests/README.md": "756221e24179a044b9d46c98e7340c01f2608a64388fffa0666d81a868a3236d",
-    "docs/topics/tests/test-plan.md": "58b750304af182e5033e2a4e0decee1fd2ce08aa99626272d131f13548280993",
-    "docs/topics/v2-design/README.md": "bbeb46d1ca9745e0809340f42166220d0911a6728230bdf24bab2dcc06705956",
-    "docs/topics/v2-design/test-plan.md": "6484de0febe1c061e0da0cdfbf07c59d849f9aa1a5419e62e248e2a15ec887c7",
-    "editors/README.md": "6fe19fe526c03268e29e45034fa6194883211dcc492b917d666f0c8af875e0e4",
-    "editors/vscode/.vscodeignore": "350c3f2808c5afc7de666c9a1b52c8fcf6f17c56d473c2e9f2f350174badd40a",
-    "editors/vscode/README.md": "05910adb7ad6ebfe78777324b7429cc275f0c954ce39ea87d74ddc17753a06b8",
-    "editors/vscode/language-configuration.json": "c48833f0c475f5f47b24ea3f50224ab93e91c5cf4be948a3ed1d45e6c3ff695b",
-    "editors/vscode/package.json": "d78a1cbdba4fa4ba3924ff9091918885d945b0e0320287ad6853502165d2fdb5",
-    "editors/vscode/syntaxes/edict.tmLanguage.json": "3384038419ccd7300453255e07a4c2fd8b6bc357fb83ee9eabe7a9ea3c1a8c21",
-    "fixtures/README.md": "f5b662bbe9cb2e771948945ce375aa451aa64c27a24bf21ff7714c92ffd97fd8",
-    "fixtures/authority-facts/canonical/README.md": "cae609cf8e98447c47e8e88c72e92b8a8c3a8d7f633ceb8e2e679e9a22142d04",
-    "fixtures/authority-facts/canonical/example-effectful.authority-facts.cbor": "d5ef9ae4c3ed7ad9ea6d82e0ddd79b2d4f2f1b231f084a009299f2c37a738074",
-    "fixtures/authority-facts/canonical/example-effectful.authority-facts.json": "16971188ce3f09095b890131b5c57c82eed608fb28495dba1c89b2c96e3397d4",
-    "fixtures/authority-facts/canonical/example-effectful.authority-facts.sha256": "54164d1d71430a87cfda496a9b5dc0885e7a9d7b4e66630e183d099432b15f74",
-    "fixtures/bundle/assembly/bounded-hello.bundle-digests.txt": "bd8d2d2a03e2a6b32911c7eee4eb1bdd390efb7011b95b34974d52a400e47cbd",
-    "fixtures/cli/01-source-ok/expected.stdout.jsonl": "d283f2ee7e143a6b60b803a627e2dee90f339241cd63bef1229c1a8e315fd274",
-    "fixtures/cli/01-source-ok/request.jsonl": "49a53d641de070134b686e545f2929d067ec7af4396c3a6702216cc1e9d3782a",
-    "fixtures/cli/02-source-parse-rejection/exit": "4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865",
-    "fixtures/cli/02-source-parse-rejection/expected.stderr.jsonl": "1c104870ac2bac548fb272e3672227b1ac8d85eb480637b9a09c4a2d31bbc654",
-    "fixtures/cli/02-source-parse-rejection/request.jsonl": "086cb795184703d2fc0eb07f7f425961bf2348aaa1e4e1af9dee2ed0d1971ab3",
-    "fixtures/cli/03-source-semantic-rejection/exit": "4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865",
-    "fixtures/cli/03-source-semantic-rejection/expected.stderr.jsonl": "90125d225064524dc65ceb0f5b90b8713c345aa4af0152c5b476fc389eb2e449",
-    "fixtures/cli/03-source-semantic-rejection/request.jsonl": "6e24d2bae9ba37e25177830b2b5c6b983adad8276835dcd6c226d11518e9f7d7",
-    "fixtures/cli/04-cli-missing-settings/exit": "53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3",
-    "fixtures/cli/04-cli-missing-settings/expected.stderr.jsonl": "29572d578b44c71f8b6f78b0932dc14997be05cc9881e43ff1255a36347cc6f2",
-    "fixtures/cli/04-cli-missing-settings/request.jsonl": "9e5abbd3690d9a7af8a9b57ef7282596aef168d453be14314a6f89d6d11a82f2",
-    "fixtures/cli/05-path-input-ok/expected.stdout.jsonl": "68d4ad7ce44ec648cfbb4157a47e64a96a9005f6ae7ce3c718bd27abb8a04ac9",
-    "fixtures/cli/05-path-input-ok/inputs/hello.edict": "459640d110280d466496c4b74ab33fb2d1b499421d0cf069a6271c80c6a8bfa9",
-    "fixtures/cli/05-path-input-ok/request.jsonl": "8ec7682d92d628d12ab42b7dd7f271246001ba6e8c253be8818658905e88ae07",
-    "fixtures/cli/06-directory-expansion-ok/expected.stdout.jsonl": "ad161bbc118eeffd176dd4a4012f4f7eff179e9099a550d72baa690897b6884b",
-    "fixtures/cli/06-directory-expansion-ok/inputs/a.edict": "459640d110280d466496c4b74ab33fb2d1b499421d0cf069a6271c80c6a8bfa9",
-    "fixtures/cli/06-directory-expansion-ok/inputs/ignore.txt": "4c434d1d1573ce9a0ee2770f8668f7ea9d3a432625abc3f9c9370f84a2a5b4c2",
-    "fixtures/cli/06-directory-expansion-ok/inputs/nested/b.edict": "459640d110280d466496c4b74ab33fb2d1b499421d0cf069a6271c80c6a8bfa9",
-    "fixtures/cli/06-directory-expansion-ok/request.jsonl": "17831d76d91e32f7f18bfaf3a9cb4c069419d96be7d50be5641c8a22101b4522",
-    "fixtures/cli/07-path-list-ok/expected.stdout.jsonl": "b406e74333b798f86b73a87f3f528ecd7651cabf21f642e7b49120a12d2b5c49",
-    "fixtures/cli/07-path-list-ok/inputs/first.edict": "459640d110280d466496c4b74ab33fb2d1b499421d0cf069a6271c80c6a8bfa9",
-    "fixtures/cli/07-path-list-ok/inputs/second.edict": "459640d110280d466496c4b74ab33fb2d1b499421d0cf069a6271c80c6a8bfa9",
-    "fixtures/cli/07-path-list-ok/request.jsonl": "99a931efb17b128401f9e7c2efcff07d58ef424939d675a5f5fb2fa01b2ffd82",
-    "fixtures/cli/08-glob-expansion-ok/expected.stdout.jsonl": "1becf0452a9dbecc53d7b89f06ec62903c21cbe034c2dec0c5e2413641d8ebba",
-    "fixtures/cli/08-glob-expansion-ok/inputs/x.edict": "459640d110280d466496c4b74ab33fb2d1b499421d0cf069a6271c80c6a8bfa9",
-    "fixtures/cli/08-glob-expansion-ok/inputs/y.edict": "459640d110280d466496c4b74ab33fb2d1b499421d0cf069a6271c80c6a8bfa9",
-    "fixtures/cli/08-glob-expansion-ok/request.jsonl": "460c88f3012149a427fa33c187fbb4c540cbb5a04ac1bb962df9d842b9e19681",
-    "fixtures/cli/09-shape-source-ok/expected.stdout.jsonl": "ced445625029b147a51d44dedfa4e1de45bb4d118547dd3b35f8e231aebb897d",
-    "fixtures/cli/09-shape-source-ok/request.jsonl": "7c61374ae76501e1ec541ae00cb9ffcf0f573e8e891494622639738ab56e669a",
-    "fixtures/cli/10-input-extra-field/exit": "53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3",
-    "fixtures/cli/10-input-extra-field/expected.stderr.jsonl": "72b2e4740ce4f08c37716f7134bb4bbd6404e1a87b7767a27f73543c6b89df75",
-    "fixtures/cli/10-input-extra-field/request.jsonl": "1f0687ce65f17e71f7d0c85da8c9032abf9d137ca188d47a569639387d6b93d7",
-    "fixtures/cli/11-input-hybrid-kind/exit": "53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3",
-    "fixtures/cli/11-input-hybrid-kind/expected.stderr.jsonl": "7228a6f4b15cc3e2c814bc9d2a5c71505445da120c6643d8cc462d374c3debb3",
-    "fixtures/cli/11-input-hybrid-kind/request.jsonl": "2237ebf045c7eba20756f21b64df67257cf81c0f89f9a408ed828b7cf08db3b2",
-    "fixtures/cli/12-input-too-large/env.json": "959ceca4ff72c2d041c96a0976e7d9359564ad7e08f0015fd5683d2b61914c2a",
-    "fixtures/cli/12-input-too-large/exit": "53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3",
-    "fixtures/cli/12-input-too-large/expected.stderr.jsonl": "41a0b8447fa06b80587334650e4ab6eb7049301bf5613926bd17d1d6845e39be",
-    "fixtures/cli/12-input-too-large/request.jsonl": "beffabf8d4dfd383a2f1f3e6d2a36cd9e10dc9da39d348056bf73b4c6eab8d26",
-    "fixtures/cli/13-input-root-outside/allowed/.gitkeep": "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b",
-    "fixtures/cli/13-input-root-outside/exit": "53c234e5e8472b6ac51c1ae1cab3fe06fad053beb8ebfd8977b010655bfdd3c3",
-    "fixtures/cli/13-input-root-outside/expected.stderr.jsonl": "c52a20d7c9c59096b93931060f4daa8903d76a07de450745b0380d20099357ae",
-    "fixtures/cli/13-input-root-outside/outside/outside.edict": "856152b284b005af913b8aa037e68e9abfeb2c068e21ca644c09646c41180e0a",
-    "fixtures/cli/13-input-root-outside/request.jsonl": "aa6bec1d8ca29503be3937b16d807d0dbdb419ca1699bd069758341260e4f094",
-    "fixtures/cli/README.md": "43699191655d06e2120651e05824fae33a49193cd8c6a9f86556d33b094c56d9",
-    "fixtures/core/canonical/README.md": "2be0425a72900ad00c18b03cd7dcd01c7ae2ed021d30752e8ee36b3ed238008e",
-    "fixtures/core/canonical/bounded-hello.core.cbor": "66c0b4e91baaa68a95d84e389539fbd4c1013aa1cf12157f3eb0f09cb4297331",
-    "fixtures/core/canonical/bounded-hello.core.sha256": "cb888280d435adb2c3139145c6937179e0e3f89b45b701471a279d277b0e01fc",
-    "fixtures/core/canonical/statement-branch.core.hex": "32c4ee079fd92bb70d278338d76a12de9e822c8023794e5319f6241e04f81580",
-    "fixtures/core/canonical/statement-branch.core.sha256": "e3b20f92dcf8c502f85d9906a6b7ed84da348384f5900ce8a4d7772eb89c301e",
-    "fixtures/core/canonical/workspace-snapshot.core.cbor": "d026d06daa6b9b6180f0273f275b350ff0a9d19d69116b35eb1b5959a943d7ef",
-    "fixtures/core/canonical/workspace-snapshot.core.sha256": "eeda93c7fc42a3ceb496285243016d1171b14b08827ca31bc2afc0c39e97af10",
-    "fixtures/core/schema/accepted/core-fn-body-minimal.fields": "7878a67508fc3c430ee1e2467139383bab65baf3b792ac2695223e95f163b774",
-    "fixtures/core/schema/accepted/core-intent-minimal.fields": "6b8e17aa243289cd55e0974bec0d3a8f37918804e04e85e678d5405519a88ea8",
-    "fixtures/core/schema/accepted/core-module-minimal.fields": "2abb412e1cd98b085f9ea2122ca616bb425b29551669376b8f6d720c874fac02",
-    "fixtures/core/schema/rejected/core-fn-body-effect-node-field.fields": "af63e1ac9f50f5eb2cda472163a14d2de9d3741e8af336b8f36e20a67fc047c8",
-    "fixtures/core/schema/rejected/core-intent-unknown-verified-mode.fields": "a9447cecad7deee7ecd3938fe8a68991072a6c4ae5fc4bb02e1d83ae3f8cc2d4",
-    "fixtures/core/schema/rejected/core-module-missing-intents.fields": "1a78fead2c7b8dd9674c718ba21a053c673ea9c47228a1167864335c5f2abc91",
-    "fixtures/core/schema/rejected/local-ref-missing-alpha-name.fields": "8ee072e0337146e0418cf56212c7de898bfc7152fe8ec1b779c10585911fc87e",
-    "fixtures/lang/bounds/bounded-hello.edict": "c03b747de8c642f6c64e83cca82736b70445c2919b57ac5f4cf5ee42aa63305d",
-    "fixtures/lang/effects/conditional-blob.edict": "7e03df8e17288d90df94ba39922847e48ee35f34ed9feac802747d599ebbffc8",
-    "fixtures/lang/effects/read-greeting.edict": "2fa8822ba5d99aebeffedeb85537868c8b55ebe472a7de08e7b849f57262122b",
-    "fixtures/lang/external-actions/workspace-snapshot.edict": "4d5098f0c836db135981348f45eef9c537752ae495911b2709e1c7775f4c876e",
-    "fixtures/lang/operations/explicit-basis-u64.edict": "261e30f6e76684acfc9b112d1fe2439770deb2e6dc04659492cbb29a91e7d4b4",
-    "fixtures/lang/tooling/highlight-smoke.edict": "9d1f0f8314b60aab75e148e2ef3cda9c083d3748018d2ceb1c575cf8628f592e",
-    "fixtures/lang/types/color-match.edict": "82ce21d9a500f4f10249102f363762998b9841d4b016771b04ad29cc18735987",
-    "fixtures/lawpack/causal-cell/README.md": "9d2f2fe3a6949a8bcd3b7d5e66e9af428fce7b1837e0ae3835645c2da602ef55",
-    "fixtures/lawpack/causal-cell/adapter.cbor": "9ff972460a34a566ebc2d9fd34853468ec6c7378a642f9026767f0d16a841ca3",
-    "fixtures/lawpack/causal-cell/adapter.sha256": "8b50d9ac114a6cb6d8ea20bec9dc7bdd9837661070db92ca5d73adbd4c0983cf",
-    "fixtures/lawpack/causal-cell/echo-operation-configuration.cbor": "c3101946866fcc4c353f212e649aef1a367fe6b4155859486f71a3e4b2b8d89a",
-    "fixtures/lawpack/causal-cell/echo-operation-configuration.sha256": "4eb0e0c5e2a600adcdd34f7f7c97d8111318876a474fe00a368e1fb78bb35cbb",
-    "fixtures/lawpack/causal-cell/exports.cbor": "acd2912e8746bd0389b8782793fdc8549f5b8f9070ad25592bb293bee814f3e3",
-    "fixtures/lawpack/causal-cell/exports.sha256": "03eab6548701dd258759440e54ad42a898b691a80b768f63f6110a056c39ca42",
-    "fixtures/lawpack/causal-cell/manifest.cbor": "d38f1012fc3d111e501903dd39820a61149e59bd13b09377ec37670cfeab7761",
-    "fixtures/lawpack/causal-cell/manifest.sha256": "817105062c5e6691880bcf0e4cc3698ee720b33f811f9671a3f85ae6d144f1f6",
-    "fixtures/lawpack/hello-echo/README.md": "2f83ca775b06ceff1a1df5fc6b8ca22c7cd37c8f4b1db671ac52acf80a34760c",
-    "fixtures/lawpack/hello-echo/adapter.cbor": "5ca8fecd2127d6ea5aff28fefdd2711ac9a92460247668bc57ea651c313d393e",
-    "fixtures/lawpack/hello-echo/adapter.sha256": "4de4924c943bfbf8f14427d1bf7cdf047e9a7b9f3f395067bae655785b6a4eb8",
-    "fixtures/lawpack/hello-echo/create-greeting.core.cbor": "bbf7e69a9146d5dbffb7f7e234830821bbc38070159ff0821c1dbf191ddebeca",
-    "fixtures/lawpack/hello-echo/create-greeting.core.sha256": "88cfe6dc6a54cc32a0be81f79a9ad7d8e4f51a1b1117df70b8e08007814de850",
-    "fixtures/lawpack/hello-echo/create-greeting.edict": "3bc0abfbaa561d4b5c08a0cc7effe8ad1a9101b5792cc4a7a5a8dcaf020acca2",
-    "fixtures/lawpack/hello-echo/create-greeting.result-projection.cbor": "adcd5863f896276b633d1954924849851e38a482b4fed2a600314c7e9625b35f",
-    "fixtures/lawpack/hello-echo/create-greeting.result-projection.sha256": "cb06288e8b212ac10e765309271a0088f2b2ab4bf952dea54f41a3e3bf5449dc",
-    "fixtures/lawpack/hello-echo/create-greeting.target-ir.cbor": "4ee7334328d505c54b7c61a6b1a966bd39805e273208bfe56289ea4ac60cf205",
-    "fixtures/lawpack/hello-echo/create-greeting.target-ir.sha256": "3f4af5f826a0d887b4c5e72b0d9808b04938223285352ad5b44fa5e90239c2bf",
-    "fixtures/lawpack/hello-echo/echo-operation-configuration.cbor": "fa8eb9bc27f729d33a87e70a23a0b4ac15eb5302306e2aa2664fe74415ba9d91",
-    "fixtures/lawpack/hello-echo/echo-operation-configuration.sha256": "18ac8912c9ee4577441518ebcceb15b06b3564590cd61586434d0b9bcae657fa",
-    "fixtures/lawpack/hello-echo/exports.cbor": "542cfff96f940ae83b6444b6eae1735e491b36f07b259cb2c1f6fd6642cfa1f8",
-    "fixtures/lawpack/hello-echo/exports.sha256": "918bece8922d623158172d78a24923abb6271f37e943b177de55ea83fc45f755",
-    "fixtures/lawpack/hello-echo/manifest.cbor": "1ad4ff3dbe1fa7293f542b4b82e3726a18008f53bfb137e58592d2f815cbc857",
-    "fixtures/lawpack/hello-echo/manifest.sha256": "69aea9344dc5dc4322ee05ba1ddbaad8906f6765c8b0f98c8d0c0ecad6d25477",
-    "fixtures/lawpack/workspace-patch/README.md": "a467e07814c52766583c608c683ebcb55d1f784e3b27b49da3c3f3d0cd81c331",
-    "fixtures/lawpack/workspace-patch/adapter.cbor": "2d9ddd3d8b00896b6bdb2f7dd3d6d06c11905b0858a1a56a2b71eb0c511cdd86",
-    "fixtures/lawpack/workspace-patch/adapter.sha256": "54353255601a3a3cfbb925de17bec3d0b2e16754865b9394d1470e5c43833d5b",
-    "fixtures/lawpack/workspace-patch/apply-validated-patch.core.cbor": "d7d11106b50d2c63606accbec221067afe86d0bb72098f9ef074d6e01e4e87ad",
-    "fixtures/lawpack/workspace-patch/apply-validated-patch.core.sha256": "124f6f036c6b5d7029a4cee9a9176d95c798643654c41c60e9653220abeba37d",
-    "fixtures/lawpack/workspace-patch/apply-validated-patch.edict": "eaaa47ab28f011938eb12dce7cda5ceb8af4bc5fa7128d72114f50652849ba1d",
-    "fixtures/lawpack/workspace-patch/apply-validated-patch.target-ir.cbor": "fc1d262af3da243b50a65ab4b726f049c0b3820f39d997b81eca7d7ffad2dbf5",
-    "fixtures/lawpack/workspace-patch/apply-validated-patch.target-ir.sha256": "5863b4b0538094c005db4294e2e73a3ef2a31f1d9277c92e5b9f35cf374a4295",
-    "fixtures/lawpack/workspace-patch/exports.cbor": "6c2c162d038bab0ebbf353b81f64f0f9cdfa569a953d99f9a1dc8288f2f97bbb",
-    "fixtures/lawpack/workspace-patch/exports.sha256": "145c439ceeed642e2497a4a1f77cadc80d7581d019ae9dc55f52653d685e62b6",
-    "fixtures/lawpack/workspace-patch/input-schema.cbor": "d691aae9de3a6473602c691b62eea441475efbffac9874c518c4702dee20f2c4",
-    "fixtures/lawpack/workspace-patch/input-schema.sha256": "8ce51f680414aee6726519ee97dde0c456ef982dc16216d9efe7ffc258d4f4e5",
-    "fixtures/lawpack/workspace-patch/manifest.cbor": "96900d03412a204547779707f404db2518640962856f99fc05efca5d704abd2b",
-    "fixtures/lawpack/workspace-patch/manifest.sha256": "d4bc64cd59615534c04b759620ff43c43a3462a7531a2ec557de814fa340ea97",
-    "fixtures/lawpack/workspace-patch/reconciliation-law.cbor": "776377f8d2c7c282af179aee48787913bcac053d293947143064be2fe13965a4",
-    "fixtures/lawpack/workspace-patch/reconciliation-law.sha256": "7620adc1e00d1d8449bac8d53671d87afa61228294196f84dc3d328419d9fd7e",
-    "fixtures/lawpack/workspace-patch/request-profile-configuration.cbor": "ef4bc2665b9867392c37e0378532a1410434f8fdb66e5d198b5882a74816481a",
-    "fixtures/lawpack/workspace-patch/request-profile-configuration.sha256": "9da854a686d5c76998a7516dc121985de895441e727b435cb7b3a237cd40d9fe",
-    "fixtures/lawpack/workspace-patch/settlement-schema.cbor": "d2aa24697b9fdfca6f8bdff244c99dbcb08ca128308507044057ad3836cfa017",
-    "fixtures/lawpack/workspace-patch/settlement-schema.sha256": "67f58bf6eb1df74f660304499ec49a97bd13d7fa1f71e6f3437157789e01ebdf",
-    "fixtures/lawpack/workspace-snapshot/README.md": "37ebb6d1ffa4e45197c986b823e3aaba20255123dc8111a2ffca5d4b7a85b566",
-    "fixtures/lawpack/workspace-snapshot/adapter.cbor": "0b06dae097530b5c6e5246a998320170a9612f55c8099711c08a388fa050c0aa",
-    "fixtures/lawpack/workspace-snapshot/adapter.sha256": "a00af1e62a1ade6e226ae1572cc8e2542e1e8256b8a2c377167bede46ccb99c0",
-    "fixtures/lawpack/workspace-snapshot/exports.cbor": "788ba1741529248ca4cd902cf56a529d79ac30d0cdd2122c8a631cd626c27059",
-    "fixtures/lawpack/workspace-snapshot/exports.sha256": "49c890f3a194283109b211875646e558584e27c0c0cf51ecc5d442fb667947c7",
-    "fixtures/lawpack/workspace-snapshot/input-schema.cbor": "bbbff7ff8ee3aff2d80a2ecdf67cc5d61b56a9dec6feb3f913369d80a35809a0",
-    "fixtures/lawpack/workspace-snapshot/input-schema.sha256": "b85d50e4a42a610fe1869c0ef97d17e6f6154c043d560fa35b83a8c4150c1658",
-    "fixtures/lawpack/workspace-snapshot/manifest.cbor": "de562334ed0ad8b868af7c7f2664a0e27adbed5633b20f8f78191d52891c8583",
-    "fixtures/lawpack/workspace-snapshot/manifest.sha256": "54d24bac38ebcbf1474f70b6d53ed68ed73e3fb4b3ebb85f7bf2963c3b8004fc",
-    "fixtures/lawpack/workspace-snapshot/observe-workspace.core.cbor": "86fa2cf6ed6edf12a92ca4bbf7d576f2a5eab32c2ff9a84a12ca25e7b843e3f6",
-    "fixtures/lawpack/workspace-snapshot/observe-workspace.core.sha256": "bba1e6ebcab0430e459f31ebe82004aae33a5ab32219b9f51a80416b6e6b7fbc",
-    "fixtures/lawpack/workspace-snapshot/observe-workspace.edict": "da2c10b6ca53a43ec0fda6a74a1a9296c533f42ee50b4ff8eaaa7d57f4b17289",
-    "fixtures/lawpack/workspace-snapshot/observe-workspace.target-ir.cbor": "9fc28d791ef91a2e7cecfca9244f1bf3826665d715ebaf00f73ef5f782ea82a9",
-    "fixtures/lawpack/workspace-snapshot/observe-workspace.target-ir.sha256": "dfbee2c71b5dfef18ddf840ab6913769cf8d85b233bdbba851feb1013a4d61b8",
-    "fixtures/lawpack/workspace-snapshot/reconciliation-law.cbor": "c6c3ec51e17ce74b3fd779b41f8d4a686a43df9f164b7381abda56b0f4f45d12",
-    "fixtures/lawpack/workspace-snapshot/reconciliation-law.sha256": "910723163a789e058922e914ba37540dc49aec320f58680218bfef0e45b90036",
-    "fixtures/lawpack/workspace-snapshot/request-profile-configuration.cbor": "61314a4f79e8ad572feb2a6f5479d45da11430f2ad902ed8cf1f7ff5d2211007",
-    "fixtures/lawpack/workspace-snapshot/request-profile-configuration.sha256": "e11e858751fb2e39205a605d7aa9a9512c8ff06b788cfbc0c5a98aa53e671bf6",
-    "fixtures/lawpack/workspace-snapshot/settlement-schema.cbor": "6689e3b655d25cbbbfdf7b75d52039db614d3d408677181afbbc5e7e02e0e2bd",
-    "fixtures/lawpack/workspace-snapshot/settlement-schema.sha256": "4775b7c7fc507035788dc3bf5fcdbe488c522114f128ca09f87ac3a28dc16e6b",
-    "fixtures/obstruction-strands/v0/stale-basis/README.md": "6d53a559e38c214f3850b848526fee8f1d83b38be376d284bf2ffe2d5f7ba723",
-    "fixtures/obstruction-strands/v0/stale-basis/source.edict": "fb36a7017af8f8f5735ea0b62f788caab1f7cd56bfb5f9f3a0509b7664b92d85",
-    "fixtures/provider-contracts/v1/README.md": "ce3c381dd6dab67c092b288d36558b331a7066ba2fed21d53c56d600db59502b",
-    "fixtures/provider-contracts/v1/edict-provider-contracts.cddl": "82273f3ea016a421c881f15b0fd451802205903ac9177bac8accbf3173f66d2c",
-    "fixtures/provider-contracts/v1/manifest.json": "6303668861667a30418870ef25e5f169017905ae1f9d261451ba298120afdd9d",
-    "fixtures/providers/README.md": "7178ed08686953bf7a3c03c4761c637808ac259b279b2fc3e0fbec9183fa60e2",
-    "fixtures/providers/components/guests/Cargo.lock": "85a7e30f09abcd23033599b6426b419d35c1b2ddacb69331967587b0c55745c0",
-    "fixtures/providers/components/guests/Cargo.toml": "3d78e0001225560207cbe97a9f6f12f71dcc8b4f1f7a06a85e7092209f4dc0d0",
-    "fixtures/providers/components/guests/lowerer/Cargo.toml": "62689501ef19bcfed24ca965e6dea0c301e76640907bdb5a2048847844e4691c",
-    "fixtures/providers/components/guests/lowerer/src/lib.rs": "76d83548c76ac6d3a1c20a24b4dbe1c8843a0facdbbf0c05015e858f05c5be7b",
-    "fixtures/providers/components/guests/verifier/Cargo.toml": "0fcdd68f536887afab601c04e252445f9393fc89d7b020db60da5deb5ffe3afd",
-    "fixtures/providers/components/guests/verifier/src/lib.rs": "426f45e8617caf5974a6e13a5cfec36e620f84f99338e3e1f5aab3407937055f",
-    "fixtures/providers/components/instantiation-failure-lowerer.component.wasm": "4ca29c3c16f1c0c3c3d80d5fa877cd853d41b9a84d5f30dbb11e2387f81b6e7c",
-    "fixtures/providers/components/instantiation-failure-lowerer.wat": "add5541aad2743d9ff16d0fed5326a9c528859b2616c34c0ab89319bd39118ba",
-    "fixtures/providers/components/instantiation-fuel-lowerer.component.wasm": "6511898df2801170b40323038ef642e32d57c9a9e3f0fd97b616cd2873031bdd",
-    "fixtures/providers/components/instantiation-fuel-lowerer.wat": "cb6ed1588c48274a6de4c36aa5f28c0315b37e89590ff1cab7f50d4e8041541d",
-    "fixtures/providers/components/inventory.json": "6d5d19359134e3e8cb701bd9df8c80e38dc56ac2f9ab928b88e755f80e7ea96f",
-    "fixtures/providers/components/lowerer.component.wasm": "0d16533735fa00f90bdb55f82495e1888802f4c857b35a5b3931429f24143885",
-    "fixtures/providers/components/malformed-lowerer.component.wasm": "dfcd171918373d18b9dff16778e98b7618eeb4ac85976dd7134b9e201562f41b",
-    "fixtures/providers/components/malformed-lowerer.wat": "b8044e5caa50bcc3a80e8b7af2eaab29d3a0d51d62725458909e1bfdf42241b6",
-    "fixtures/providers/components/verifier.component.wasm": "e889007a621d05820261eeb9fd69ce555f5761dbdbf82c6e9f55220ea529776d",
-    "fixtures/providers/echo-generated/provider-manifest.json": "96974d26f39f6cfccfe91bf499b59bdff50bc103cbaff8d1fbf7e4252c916ca5",
-    "fixtures/providers/echo-target-profile/README.md": "c9041ceeb1210ce520167b12fe9e8b6caff0c5fac87177aa6cf5b4c51d6b0721",
-    "fixtures/providers/echo-target-profile/generated/primary/target-profile.echo-dpo.cbor": "1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e",
-    "fixtures/providers/wit/legacy-target-profile.wit": "9db5841289178228f2583927f02fe40a2cf71bfd0a9ea4e664ccb358506a6d57",
-    "fixtures/target-ir/canonical/echo-effectful.target-ir.cbor": "7a60cd64823eeb9801abcc887bb4deaa0ed4af0ca378dc84d142b3df650702bb",
-    "fixtures/target-ir/canonical/echo-effectful.target-ir.sha256": "522e896587f5eeeabb0b3680584a230b2521b97675c40152b43c7c7c94370483",
-    "fixtures/target-ir/canonical/gitwarp-append.target-ir.cbor": "49259a149d2fe02856059a7683a9a3a02fcec84ca6937b2401a08f6536391735",
-    "fixtures/target-ir/canonical/gitwarp-append.target-ir.sha256": "930af94de85ffe09f75afea9e112ac659062ec2c6b62af166a3ccd6e3a9daacb",
-    "fixtures/target-ir/canonical/workspace-snapshot.target-ir.cbor": "1c4a8bafa1fdaa681a028f5bff381904b613f951ad3a65dfaecf16a4aedfeba4",
-    "fixtures/target-ir/canonical/workspace-snapshot.target-ir.sha256": "218b558b825a1fa59d52e816bb74fbd3a0d359a5437a8263c8562fed381b08d6",
-    "fixtures/target-profile/contract-resources/README.md": "ceba47e8308c06e484aec1c30d9e4aef8ee7886d0cab13f860894e4bc62fc7dc",
-    "fixtures/target-profile/contract-resources/canonical-cbor.cbor": "8306e4f08c1e4e7d29ab22bcf55c324312712aac3eeeb675857ced57c3e48bdc",
-    "fixtures/target-profile/contract-resources/canonical-cbor.sha256": "1571de5dddfaa963952eb89b1e40e9749f5e92668645c221ff8d92c515af8e19",
-    "fixtures/target-profile/contract-resources/determinism.cbor": "84073f5c1734b625e16799048e28458d43e0a10befdae56a79d906f5e37ef76a",
-    "fixtures/target-profile/contract-resources/determinism.sha256": "bd9465934a18f73def0c38c75358440f84ec98d39d3b688ce44cdcd5c280e72e",
-    "fixtures/target-profile/contract-resources/diagnostics.cbor": "e465a28f1170fe478db5ff65d96a1fdbfbbcb95d327e6965021c252437991e4b",
-    "fixtures/target-profile/contract-resources/diagnostics.sha256": "e3cf575631bc142ae67786269211383352bb869a9690b8c5190669788bedddb7",
-    "fixtures/target-profile/contract-resources/fuel.cbor": "c712c2d831cc8e731bdc1dfb8ea536f4630f38f0b0e0c6448b2df57176d3d0bd",
-    "fixtures/target-profile/contract-resources/fuel.sha256": "afa42a66b0df107eab464a08e5c358639edb4ca9b72f77d8abf21a165d4e293e",
-    "fixtures/target-profile/contract-resources/wasm-component.cbor": "cd09d702db1d10be825e72effe35627bec56963cb3d78601b69478c58787e34d",
-    "fixtures/target-profile/contract-resources/wasm-component.sha256": "1f960c0ae125ad146775c3f40d4fe7402b7fbfc619195968d019d4213149bcb2",
-    "grammars/textmate/README.md": "d68a6d01eb366626b7b66e72b210e0ccfd0de961e7dcf67bf23ca11d24683791",
-    "grammars/textmate/edict.tmLanguage.json": "3384038419ccd7300453255e07a4c2fd8b6bc357fb83ee9eabe7a9ea3c1a8c21",
-    "grammars/tree-sitter-edict/README.md": "d01a9a5d0823ff83bd7eae709796d2ba9f60827258e83f4acc61a8f67cd166be",
-    "grammars/tree-sitter-edict/grammar.js": "648d883aeeb95276e50b83cbeb11c478ba494671a883c4156ea185cd9e1fb689",
-    "grammars/tree-sitter-edict/queries/highlights.scm": "c5eebabd4ecfab6d61e1a81e534be40e678313e7f62de45a012b363184051883",
-    "grammars/tree-sitter-edict/src/grammar.json": "ec1d17ccdab6c8c7a1b3d819f80ceb63e5fef4217b51771a19ff1b292a960172",
-    "grammars/tree-sitter-edict/src/node-types.json": "a79d4870fcb31450660570279de5cbb0571ec9751565eb70e663a08e78857f2c",
-    "grammars/tree-sitter-edict/src/parser.c": "db53b6f1984be6857920a3b669fd02ac5a61ab4c4adc297cd13d1a698200d67a",
-    "grammars/tree-sitter-edict/src/tree_sitter/alloc.h": "b29c1c9fb7cc82f58c84b376df1297d6e2737a1d655fd356db0859e3c29c2fea",
-    "grammars/tree-sitter-edict/src/tree_sitter/array.h": "31e60a1bff6f715afacce03b5b70efe42b58371b4f9595dd4af52a577ff9608c",
-    "grammars/tree-sitter-edict/src/tree_sitter/parser.h": "180b893c8734778fd32f372dfbc27bd6ad1cd2221f26150b31256ff6716320d2",
-    "grammars/tree-sitter-edict/test/corpus/current-subset.txt": "0ece2b4025504030e241bf7dc86e100d90de01ecf47be7187c69fc109402616e",
-    "grammars/tree-sitter-edict/tree-sitter.json": "ffd900f458d520c326b084c950c0683da5110326dfef664d2845671e9e0ba1c2",
-    "scripts/consumer-witnesses/README.md": "97bb29ed4ba509f5c52c6d3fc4862d0bfd2e6f1098f31441a9c6d10a0058e107",
-    "scripts/consumer-witnesses/jedit-state-read.Dockerfile": "33ab296609d366955e95bdfafdac88d8fd89c334a95392e0d840757372682a04",
-    "scripts/consumer-witnesses/jedit-state-read.Dockerfile.dockerignore": "e4281aa8c5c9399a71fc801b3f39f1d639d12ddc5e36a7bf4df684366d2a92b9",
-    "scripts/consumer-witnesses/jedit-state-read.py": "30933061c52eb82a511bc290c367c003129ac1853e717595ce1976fd9b6da015",
-    "scripts/consumer-witnesses/run-jedit-state-read.sh": "3fb7e4d9f91b8ea2506916dc70968cfc61cb481ea67a7780c44c8dc442523482",
-    "spec.lock.json": "0d44a0f5d8fbd77e198edd776a7d9b9bc4babae1c820b10e340c2bfda772fd0f",
-    "xtask/Cargo.toml": "127c5b19d72856e62c9e19766035af7122f76b12d41dbbcf2ad0c48a95291d31",
-    "xtask/src/contract_check.rs": "aefa5117e7bc547c85c67bef5f67756ff9f676314ea3d245be7f63e949d4f13d",
-    "xtask/src/goldens.rs": "33d10989d188149517bc5f1a59632da00a27f85299f4b209f99803d650d7022d",
-    "xtask/src/lawpack_goldens.rs": "9555cdfd2624ca4dc7ddf2143562096fce7f4ef56c617809764b231bf8b5a0f6",
-    "xtask/src/main.rs": "b634296a41c26dcc5f4c2d5308437a089c7e0bc4ac1c244c2641c5ae70074ecb",
-    "xtask/src/provider_components.rs": "db291c46e24c38e1955c9f4077b135a74d08ae5ed9aef05e4ef771c1e7aaf500",
-    "xtask/src/provider_contract_pack.rs": "2d9d14184b63d0253732225442483da51c70ccdb6092efd2e7705b74f4986479",
-    "xtask/src/provider_dependencies.rs": "aa2236f057acda35445c429d4fd3a37c0606cc477f898354a292952b744f2415",
-    "xtask/src/release_dates.rs": "733a1d6915e4a897308f458f080f576f023f071183b263ce4dbe2302297471cb",
-    "xtask/src/release_prep.rs": "a0c335406b15c86314dd0c00e3a0b8ff5e14b47d92b5f5b1dc763ceb48759520",
-    "xtask/src/tests.rs": "3ea68d101e9cbcce69ce5067ecd034a58a809af703d6ddece9455cfd16abc02d",
-    "xtask/src/util.rs": "9fd9d75981d0e38dc4cfd87090a96f3665435c5d010607508c848f759b749539"
-  }
-}
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/compiler-source.json b/edict/replace-range-probes/range-assembly/evidence/candidate/compiler-source.json
deleted file mode 100644
index 3ef03a8f..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/compiler-source.json
+++ /dev/null
@@ -1,1802 +0,0 @@
-{
-  "commit": "01dc5abb9a8a74f8fd8b0e0a6d1041d0adb86d6e",
-  "tree": "74e571125a1da6ac5b2eac80944e343811708d51",
-  "files": [
-    {
-      "path": ".cargo/config.toml",
-      "gitBlob": "5592118f6c54bf8b53b16848e04ece896dd56384"
-    },
-    {
-      "path": ".github/workflows/auto-release-tag.yml",
-      "gitBlob": "87404ceb685191afd496c93494b0bc61e2a59504"
-    },
-    {
-      "path": ".github/workflows/ci.yml",
-      "gitBlob": "c6c6a17f59b6b96db88e3d4b2775bc64b7fe01f3"
-    },
-    {
-      "path": ".github/workflows/release.yml",
-      "gitBlob": "2c612fc786998bfa5b11e76ae1185114a7cc535f"
-    },
-    {
-      "path": ".gitignore",
-      "gitBlob": "30d7faf0fc8b7f010f99280302d4ed269d5da9ba"
-    },
-    {
-      "path": ".markdownlint.json",
-      "gitBlob": "f3ec2c8dc2fbacc425154a2baedec50c7474aefa"
-    },
-    {
-      "path": "AGENTS.md",
-      "gitBlob": "0c48a5794454cf84e20640994a372316efde7bb5"
-    },
-    {
-      "path": "ARCHITECTURE.md",
-      "gitBlob": "5b513dd25028092e7e75c8974f1d5f3cc31889ed"
-    },
-    {
-      "path": "CHANGELOG.md",
-      "gitBlob": "cd40892f0f2ed2e5667c65e274f9a1ead1619990"
-    },
-    {
-      "path": "CODE_OF_CONDUCT.md",
-      "gitBlob": "784cf2799bcf8d2a69db5f5781359ef7e18a05fc"
-    },
-    {
-      "path": "CONTRIBUTING.md",
-      "gitBlob": "9676914060f734dc59eabd9075898dc8170d4d19"
-    },
-    {
-      "path": "Cargo.lock",
-      "gitBlob": "bacb208de0583f182379af7b5e078d31b25e2ca5"
-    },
-    {
-      "path": "Cargo.toml",
-      "gitBlob": "b2e7106eb78f79230c091492ef21b497bdc9ed19"
-    },
-    {
-      "path": "EDICT.md",
-      "gitBlob": "35376134195082d506f0161ba7ecb97efa8b770a"
-    },
-    {
-      "path": "LICENSE",
-      "gitBlob": "261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64"
-    },
-    {
-      "path": "NOTICE",
-      "gitBlob": "c300687bdd9d931d1f257d291e1cb6ff9d7d3607"
-    },
-    {
-      "path": "README.md",
-      "gitBlob": "0812ef9a0c4611bf655dfc67d2ecc3631af9a536"
-    },
-    {
-      "path": "ROADMAP.md",
-      "gitBlob": "d0e0135780537afab1d1a3f53808b363b35a63f4"
-    },
-    {
-      "path": "SECURITY.md",
-      "gitBlob": "0bcc4e7375442e1334405a2d046df316cee05cd5"
-    },
-    {
-      "path": "crates/edict-cli/Cargo.toml",
-      "gitBlob": "e9d844553c395bd312f84e806eb5bac30c5c3a54"
-    },
-    {
-      "path": "crates/edict-cli/src/application_build.rs",
-      "gitBlob": "9c56ae6b4dd4eef0b9fe6db40316e100b2ffa699"
-    },
-    {
-      "path": "crates/edict-cli/src/lawpack_build.rs",
-      "gitBlob": "55e9579153f34a3d5b139141c9de6640808cd386"
-    },
-    {
-      "path": "crates/edict-cli/src/lawpack_build_windows.rs",
-      "gitBlob": "f71d03b368ae83becc1608bbba11cd5f1afa4f07"
-    },
-    {
-      "path": "crates/edict-cli/src/lib.rs",
-      "gitBlob": "60883af60cf4b441680952ecce7ef4fcbfeabb97"
-    },
-    {
-      "path": "crates/edict-cli/src/main.rs",
-      "gitBlob": "0dd9776642c4090479322111e4164ee7049fb9d0"
-    },
-    {
-      "path": "crates/edict-cli/tests/golden_cli.rs",
-      "gitBlob": "9897caad3bcc6fa8bb0f20a1d0e18032285b1fa7"
-    },
-    {
-      "path": "crates/edict-cli/tests/jsonl_cli.rs",
-      "gitBlob": "9ed353ca27d073fc7da49d3800c81ba4c58edd5d"
-    },
-    {
-      "path": "crates/edict-cli/tests/lawpack_authoring_cli.rs",
-      "gitBlob": "dd7d7bfebf0e051c77d894a55c0204d373b19c63"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/Cargo.toml",
-      "gitBlob": "ebeeb941f09012293d9923fe0e6039b2761b328e"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/conversion.rs",
-      "gitBlob": "62c3cd4a85eb156b8c9a405ef3ea4d8a09b80cc3"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/invocation.rs",
-      "gitBlob": "a4d6680d289094afebc0f1063abccf706f8149db"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/lib.rs",
-      "gitBlob": "353ea7394f265219ebdecad56a3070c9e7d2685c"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/limits.rs",
-      "gitBlob": "9e4d12c1b606d2b180f732db17bfbc78f8e26e3a"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/replay.rs",
-      "gitBlob": "b8fa7be7c7ee5039793dad4cd0fa6a4f14ce388e"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/tests/invocation.rs",
-      "gitBlob": "7a59a3192852a80bc01221ebf3dd1c437bda9508"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/tests/preflight.rs",
-      "gitBlob": "a295e7547b0294f0355a85d5b9b8d045c8fceefd"
-    },
-    {
-      "path": "crates/edict-provider-schema/Cargo.toml",
-      "gitBlob": "0e74f58acdc054ecce192cb8341afeaddc40deb5"
-    },
-    {
-      "path": "crates/edict-provider-schema/src/contract_pack.rs",
-      "gitBlob": "370480d9c606134dd08ee62ae29ef143941e2f54"
-    },
-    {
-      "path": "crates/edict-provider-schema/src/lib.rs",
-      "gitBlob": "51f5bee8892c9fb2122cb20022edc4d414759ff7"
-    },
-    {
-      "path": "crates/edict-provider-schema/src/recursive_dispatch.rs",
-      "gitBlob": "6d97565b96f941b359d16f7a1c201189968fbeff"
-    },
-    {
-      "path": "crates/edict-provider-schema/src/schema_safety.rs",
-      "gitBlob": "a2f605f62a2bfedcb84b68e37db9ff84b1dc3b05"
-    },
-    {
-      "path": "crates/edict-provider-schema/tests/authority_facts_abi.rs",
-      "gitBlob": "7dd4d0302805ceecffc2045cdb91e386f8e08517"
-    },
-    {
-      "path": "crates/edict-provider-schema/tests/provider_contract_pack.rs",
-      "gitBlob": "a26be8054b39215048825dd8cae7e9bddcfe27c9"
-    },
-    {
-      "path": "crates/edict-provider-schema/tests/registry.rs",
-      "gitBlob": "bdd13ec00e441aef9e67ba49f6592ecbc7dcb303"
-    },
-    {
-      "path": "crates/edict-syntax/Cargo.toml",
-      "gitBlob": "f55bb23e528af78b1e97b52f9b72cbd876a44ba7"
-    },
-    {
-      "path": "crates/edict-syntax/src/admission.rs",
-      "gitBlob": "471430dd13a617bac886fcd44afbf15263e7db3b"
-    },
-    {
-      "path": "crates/edict-syntax/src/ast.rs",
-      "gitBlob": "2a5d208a53a82408f8a18d9a13ccb133ec6a7a2e"
-    },
-    {
-      "path": "crates/edict-syntax/src/authority_facts.rs",
-      "gitBlob": "644de86d63983bdbfbf1279fdbf1dbdaecc151d5"
-    },
-    {
-      "path": "crates/edict-syntax/src/canonical.rs",
-      "gitBlob": "6fb29d50ea4a55eb888a1b9600cdcb31713a6e20"
-    },
-    {
-      "path": "crates/edict-syntax/src/compiler.rs",
-      "gitBlob": "d9661e2605f23f503a8fdf4471462cc0b9bad4c1"
-    },
-    {
-      "path": "crates/edict-syntax/src/compiler/byte_concat.rs",
-      "gitBlob": "185d11c0ae20931cd2737774a34cac92b13d6712"
-    },
-    {
-      "path": "crates/edict-syntax/src/compiler/byte_length.rs",
-      "gitBlob": "0d8d6291064415baee9253d9fe1e11ad87945773"
-    },
-    {
-      "path": "crates/edict-syntax/src/compiler/byte_slice.rs",
-      "gitBlob": "84385fffdf4e38e21285e1fde252e9185a3a76fa"
-    },
-    {
-      "path": "crates/edict-syntax/src/compiler/unsigned_subtraction.rs",
-      "gitBlob": "c2ef2deda74afb52e4346076a310df341556e1c8"
-    },
-    {
-      "path": "crates/edict-syntax/src/contract_bundle.rs",
-      "gitBlob": "9a31645f0e30879d019787e29c21c82eebf58129"
-    },
-    {
-      "path": "crates/edict-syntax/src/core_ir.rs",
-      "gitBlob": "4c6f350b325d13a27947687dd1f4114edf6d548d"
-    },
-    {
-      "path": "crates/edict-syntax/src/highlight.rs",
-      "gitBlob": "28b3f7dcdfe8d4982bdcfb05759f769ccdbffc7f"
-    },
-    {
-      "path": "crates/edict-syntax/src/lawpack.rs",
-      "gitBlob": "54f85bda48c960ad0b7bc316d332b379ab5b6ae0"
-    },
-    {
-      "path": "crates/edict-syntax/src/lawpack_adapter.rs",
-      "gitBlob": "e425960e2437faa2f9eeb5d089ff507417d39586"
-    },
-    {
-      "path": "crates/edict-syntax/src/lawpack_authoring.rs",
-      "gitBlob": "11ff578f458b8a4c8e4df75c0c616e37fa468d49"
-    },
-    {
-      "path": "crates/edict-syntax/src/lib.rs",
-      "gitBlob": "7323475cc7f846e11c2d73f4c26a5e581b7e6157"
-    },
-    {
-      "path": "crates/edict-syntax/src/lowerability.rs",
-      "gitBlob": "c6a1323fd6a79b0460b43aaf338956c3906a633e"
-    },
-    {
-      "path": "crates/edict-syntax/src/parser.rs",
-      "gitBlob": "0b3650e3012e49023ccbb9cc9effe9b5b102f19d"
-    },
-    {
-      "path": "crates/edict-syntax/src/provider.rs",
-      "gitBlob": "18fa661d880979c53dd335fb7e68d5445b638d4c"
-    },
-    {
-      "path": "crates/edict-syntax/src/provider_invocation.rs",
-      "gitBlob": "2526168f0a6f2d1d9b6181b689ff43e203434122"
-    },
-    {
-      "path": "crates/edict-syntax/src/provider_lowering.rs",
-      "gitBlob": "50a4e60b561127cb8c78e3f7c04c6bbaca068e52"
-    },
-    {
-      "path": "crates/edict-syntax/src/result_projection.rs",
-      "gitBlob": "79ba246d4c58960fe368eaca4c7d135fe187832a"
-    },
-    {
-      "path": "crates/edict-syntax/src/semantic.rs",
-      "gitBlob": "76bd133ef5859bf7722d1987613f7fd84836ab62"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir.rs",
-      "gitBlob": "9dd759a18ea3a171837baa50e88c67987c84da13"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/byte_concat.rs",
-      "gitBlob": "bff3a35e1d3183813ffb1e69655934f65f2c9131"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/byte_length.rs",
-      "gitBlob": "972e6ffa943bc7a7a943d76f0af42b342e3d2aac"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/byte_slice.rs",
-      "gitBlob": "62a1c0b9e84a331bb17ab78090cce6d8eb8da486"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/execution_order.rs",
-      "gitBlob": "e69a28805dc5e414a64afdaafee34161c217a044"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/totality.rs",
-      "gitBlob": "a4fb9573d59e1a4bb9d7c250402c5b7e1da0a8c3"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/unsigned_subtraction.rs",
-      "gitBlob": "b83522bfe9a2b506413b4d306f4bc49f8b053f36"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_profile.rs",
-      "gitBlob": "dd514f7380243e795f0655a78aecd06ee3fa2eda"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_profile_contract_resources.rs",
-      "gitBlob": "4efd22961c2fd7591440efd6087944ecaf21e991"
-    },
-    {
-      "path": "crates/edict-syntax/src/token.rs",
-      "gitBlob": "2768586eea6d42d5df357c4cc62a011ee7f455de"
-    },
-    {
-      "path": "crates/edict-syntax/tests/admission.rs",
-      "gitBlob": "57edbc320307c1d6daba85f03d8dc79558d7b849"
-    },
-    {
-      "path": "crates/edict-syntax/tests/authority_facts.rs",
-      "gitBlob": "add9d272be6e8eb1cd6fdde2999a5fb452ecd852"
-    },
-    {
-      "path": "crates/edict-syntax/tests/authority_facts_cbor.rs",
-      "gitBlob": "7359f047d9f731fee208efb5f69072b612d69547"
-    },
-    {
-      "path": "crates/edict-syntax/tests/byte_concat.rs",
-      "gitBlob": "72da10e53a2e84f4a23217122b54dd9eac76338f"
-    },
-    {
-      "path": "crates/edict-syntax/tests/byte_length.rs",
-      "gitBlob": "50945944e8c2223abcc6b1081322432bc540c017"
-    },
-    {
-      "path": "crates/edict-syntax/tests/byte_slice.rs",
-      "gitBlob": "99aae98ac1637a95532cdd833463210bbaa5a5be"
-    },
-    {
-      "path": "crates/edict-syntax/tests/canonical_encoding.rs",
-      "gitBlob": "e4c5d59a88f88193f522eb555359919f7034a264"
-    },
-    {
-      "path": "crates/edict-syntax/tests/common/mod.rs",
-      "gitBlob": "89560bfacb3dab031485c2dfa30d7eb325966574"
-    },
-    {
-      "path": "crates/edict-syntax/tests/compiler_spine.rs",
-      "gitBlob": "2237318cfc0d4209e8a629e45320e42a4b72dbef"
-    },
-    {
-      "path": "crates/edict-syntax/tests/contract_bundle.rs",
-      "gitBlob": "e6a2948335a0efc86d8bbb2e9e2c3d634e53965a"
-    },
-    {
-      "path": "crates/edict-syntax/tests/core_golden_fixtures.rs",
-      "gitBlob": "0e0e42d19b52dc0557902dad9e1b85f37edf53f8"
-    },
-    {
-      "path": "crates/edict-syntax/tests/core_graph_depth.rs",
-      "gitBlob": "1d95462ad2426d29b5974e6bb56ab8c125a92837"
-    },
-    {
-      "path": "crates/edict-syntax/tests/external_action_requests.rs",
-      "gitBlob": "20aac8c03325ea0cdab8f4f54660cb980b4667c4"
-    },
-    {
-      "path": "crates/edict-syntax/tests/highlighting.rs",
-      "gitBlob": "17e6b9ba08c96f0efb6efd440590f0fc917316e2"
-    },
-    {
-      "path": "crates/edict-syntax/tests/lawpack.rs",
-      "gitBlob": "a675999ed96309358c8552a9d32781b5eede20dc"
-    },
-    {
-      "path": "crates/edict-syntax/tests/lawpack_authoring.rs",
-      "gitBlob": "3a905cbd6d7d2625bc1d7826a6f6f1e991efbab0"
-    },
-    {
-      "path": "crates/edict-syntax/tests/lowerability.rs",
-      "gitBlob": "5cfa58f5cbc51cccc7f119caddc1c3fcbc2e4806"
-    },
-    {
-      "path": "crates/edict-syntax/tests/operation_prerequisites.rs",
-      "gitBlob": "753659e1a6e7751c455b8518226fa0902157a745"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_control_flow.rs",
-      "gitBlob": "5245561866d8902c1fbd5ab21f2e34807d568e17"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_greeting.rs",
-      "gitBlob": "f214d0c17745b8203d562780caa8f37b71c1e62c"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_hello.rs",
-      "gitBlob": "bf7b1b065277188f4be8754eb11ace94298394ba"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_keywords.rs",
-      "gitBlob": "78d8a64d785136d42a32655afda3df240c54f884"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_loops.rs",
-      "gitBlob": "d9ece2fce96fd6835d080055f06955d139c7e0ce"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_negative.rs",
-      "gitBlob": "17fdb983b8250470368a8f19d3a7bd9680052548"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_review_regressions.rs",
-      "gitBlob": "560215cfe044a528e190aa1ea7670e52b9365bdf"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_variants.rs",
-      "gitBlob": "8849f68f5ca1e2b06d0f66496e59b20d1c0fd022"
-    },
-    {
-      "path": "crates/edict-syntax/tests/provider.rs",
-      "gitBlob": "7e8a596109b1e1fd3f22b3a0ef82f4755f127291"
-    },
-    {
-      "path": "crates/edict-syntax/tests/provider_invocation.rs",
-      "gitBlob": "402647dd6701be65a9e693fd3f5688f26d84988e"
-    },
-    {
-      "path": "crates/edict-syntax/tests/provider_lowering.rs",
-      "gitBlob": "411c306f3ab641de9dc2f7aed229767eba9dbd72"
-    },
-    {
-      "path": "crates/edict-syntax/tests/result_projection.rs",
-      "gitBlob": "a74dd2a419266cb77d846d83da27f726095660f1"
-    },
-    {
-      "path": "crates/edict-syntax/tests/semantic_validation.rs",
-      "gitBlob": "a127988d178c00ed12a0a25f70df6b7fd5e6d931"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_ir.rs",
-      "gitBlob": "928e1cf921dead0b559bd115bb6eef3faaddd37e"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_ir/ordered.rs",
-      "gitBlob": "a1b05db81a97a43ec5a2dc2d9bcc9578bc286f30"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_profile.rs",
-      "gitBlob": "42f1c907f6c60dea1e8a9b4558b56ffd0b3a59ab"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_profile_contract_resources.rs",
-      "gitBlob": "270c180a12dc10fb7e208cc4dc1e202da82c85fb"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_unsigned_subtraction.rs",
-      "gitBlob": "e30d91f896afda48eb3cf11617bccf1f9d160e32"
-    },
-    {
-      "path": "crates/edict-syntax/tests/unsigned_subtraction.rs",
-      "gitBlob": "fbd24482fdad4c8ceb4df41302b33595ada337ec"
-    },
-    {
-      "path": "crates/edict/Cargo.toml",
-      "gitBlob": "525403f4f36db4040531e4dd747ec2398f9052cd"
-    },
-    {
-      "path": "crates/edict/README.md",
-      "gitBlob": "a1ecf50bff3443d25a23fabfa6374d3f0a28ca82"
-    },
-    {
-      "path": "crates/edict/src/lib.rs",
-      "gitBlob": "169d820759d6333f27a45ebb712bfcc4f0115107"
-    },
-    {
-      "path": "crates/edict/tests/artifact_models.rs",
-      "gitBlob": "b923109c7195ce2c0071dc54179f0746b95329f0"
-    },
-    {
-      "path": "crates/edict/tests/public_surface.rs",
-      "gitBlob": "a24c4bc9d9484f540da9b280790896701922968a"
-    },
-    {
-      "path": "deny.toml",
-      "gitBlob": "e3f0f54060cead9a0d48b96ed86948d0909c4f78"
-    },
-    {
-      "path": "docs/DESIGN_runtime-neutral-edict-sha-lock-assurance.md",
-      "gitBlob": "ea3badf78ebd19545147a93671fdb5f9af4a61ea"
-    },
-    {
-      "path": "docs/GUIDE_edict-assurance-transparency.md",
-      "gitBlob": "100321157ec43055c45794f1c161b1e5281ba6b4"
-    },
-    {
-      "path": "docs/README.md",
-      "gitBlob": "e21739b842be14d91a17f2508b1a1b629754af01"
-    },
-    {
-      "path": "docs/REQUIREMENTS.md",
-      "gitBlob": "fd69cf5b3f57af39cda8bcf7f94ff21666a34636"
-    },
-    {
-      "path": "docs/RETRO_phase1-parser.md",
-      "gitBlob": "5cfb7b85ca2f140fc58f9186c47e4635e94a1e6f"
-    },
-    {
-      "path": "docs/SPEC_continuum-admission-v1.md",
-      "gitBlob": "0a74a0bfc642337d5d7a85133ce50a0a22caffbd"
-    },
-    {
-      "path": "docs/SPEC_continuum-contract-bundle-v1.md",
-      "gitBlob": "65b36bb33a34beb1f246d1f97384631c83ca631e"
-    },
-    {
-      "path": "docs/SPEC_edict-language-v1.md",
-      "gitBlob": "e137ddc947f8ca3e057ea618c0cdf103096130b3"
-    },
-    {
-      "path": "docs/SPEC_edict-lawpack-abi-v1.md",
-      "gitBlob": "ea1d801f07ab3677f7a411a1f58a28feda589ec3"
-    },
-    {
-      "path": "docs/SPEC_edict-target-profile-abi-v1.md",
-      "gitBlob": "91687bfe45565a21f5f93f6ce9eed84095268691"
-    },
-    {
-      "path": "docs/TECHNICAL_EXPLANATION.md",
-      "gitBlob": "d88561c0552c0e75d1ecc2eef6f9afd003e99674"
-    },
-    {
-      "path": "docs/abi/edict-authority-facts.cddl",
-      "gitBlob": "e9a6d8685706ae0d8dabda401655234161e94299"
-    },
-    {
-      "path": "docs/abi/edict-common.cddl",
-      "gitBlob": "836c11b92425beb6d42b378c0defe6f02d144dd7"
-    },
-    {
-      "path": "docs/abi/edict-core.cddl",
-      "gitBlob": "862f02939fcc3858b4a60cb75f9bf149eae8ffda"
-    },
-    {
-      "path": "docs/abi/edict-lawpack-adapter.cddl",
-      "gitBlob": "8e887c2e196ba7502470ddb45dc7cfd10116ad6b"
-    },
-    {
-      "path": "docs/abi/edict-lawpack.cddl",
-      "gitBlob": "96efd51d437ec785b108b51835e9e8bf87aeab51"
-    },
-    {
-      "path": "docs/abi/edict-result-projection.cddl",
-      "gitBlob": "98b5c2e861e7e9b66b7481502287cb041f6e77e6"
-    },
-    {
-      "path": "docs/abi/edict-target-ir.cddl",
-      "gitBlob": "98134f277ded1920a3a36e5e3946c51153f2e84d"
-    },
-    {
-      "path": "docs/abi/edict-target-profile.cddl",
-      "gitBlob": "746ae03001310f3a83524e5332819dad1a4eea5a"
-    },
-    {
-      "path": "docs/abi/edict-target-provider.wit",
-      "gitBlob": "0efa5903a52d38dc61e429619d86322c6c5f1fa0"
-    },
-    {
-      "path": "docs/audit/2026-06-28_code-quality.md",
-      "gitBlob": "143cbf4f4491a76a6649e919c6edaba73f0bcf4b"
-    },
-    {
-      "path": "docs/audit/2026-06-28_documentation-quality.md",
-      "gitBlob": "656b4fa8dea43306af1818f8622cafd72e82a370"
-    },
-    {
-      "path": "docs/audit/2026-06-28_ship-readiness.md",
-      "gitBlob": "b9d34a8693564d0134f550092e7645e5d5137442"
-    },
-    {
-      "path": "docs/design/authority-fact-governance.md",
-      "gitBlob": "8531061cf718c47ec791f5712b2f357d92adc9e4"
-    },
-    {
-      "path": "docs/design/canonical-target-ir-v0.11.md",
-      "gitBlob": "a46acb84e3523b51e2348c776cfdb63a8b98107a"
-    },
-    {
-      "path": "docs/design/contract-bundle-assembly-v0.11.md",
-      "gitBlob": "a364f8ade5445808f87cf0c63ab3484c03ad616a"
-    },
-    {
-      "path": "docs/design/crate-scope-v0.11.md",
-      "gitBlob": "92fe92285d02465d84bbe82e29d051fdc461f3a6"
-    },
-    {
-      "path": "docs/design/obstruction-strands-v0.md",
-      "gitBlob": "81f70fd688c12798cd23472a4e810191e61eabe2"
-    },
-    {
-      "path": "docs/design/provider-artifact-pipeline-alpha.md",
-      "gitBlob": "60eefa7dc160aba986bcd1188b79610ff5e9f299"
-    },
-    {
-      "path": "docs/design/schema-as-sot-codegen.md",
-      "gitBlob": "d818e0e3f1fafd1d3aba26cb37c739f3ebe69763"
-    },
-    {
-      "path": "docs/design/v2-obligation-closure.md",
-      "gitBlob": "816d22d843a33c6f7e143da4cb45e80679609dc8"
-    },
-    {
-      "path": "docs/releases/v0.1.0-alpha.1.md",
-      "gitBlob": "5dd96057ba7f109cf5e5acde16e29d18627f98d3"
-    },
-    {
-      "path": "docs/releases/v0.10.0-alpha.1.md",
-      "gitBlob": "363c4e9ed6f5ea5758198c7124681b520098e583"
-    },
-    {
-      "path": "docs/releases/v0.11.0-alpha.1.md",
-      "gitBlob": "4612dbb5a1aaf20710bdb199b658ded7ced4ebab"
-    },
-    {
-      "path": "docs/releases/v0.2.0-alpha.1.md",
-      "gitBlob": "7302ef93ed5ff9b562d9cec92d49d85a6b789b27"
-    },
-    {
-      "path": "docs/releases/v0.3.0-alpha.1.md",
-      "gitBlob": "bf023ba4ca2c38f0120c461781447d58fe239ae0"
-    },
-    {
-      "path": "docs/releases/v0.4.0-alpha.1.md",
-      "gitBlob": "769500b59800c02c536b76b0eb850d06d6cd8f58"
-    },
-    {
-      "path": "docs/releases/v0.5.0-alpha.1.md",
-      "gitBlob": "7c7354e89846ea816992aaf55d4ad04367d61a10"
-    },
-    {
-      "path": "docs/releases/v0.6.0-alpha.1.md",
-      "gitBlob": "3f2a0edfc4bccd9f3c60a7443ef4f8cbcbac1971"
-    },
-    {
-      "path": "docs/releases/v0.7.0-alpha.1.md",
-      "gitBlob": "57671d5ef5a6b9f16d1674e0a35ddeb86ff126a8"
-    },
-    {
-      "path": "docs/releases/v0.8.0-alpha.1.md",
-      "gitBlob": "12f77bda185c54fbbd136bf0dc7292716ecdfa39"
-    },
-    {
-      "path": "docs/releases/v0.9.0-alpha.1.md",
-      "gitBlob": "fa295fcf0967415bb052f238256919b32b3fe6ba"
-    },
-    {
-      "path": "docs/schemas/edict.cli-check-result.v1.schema.json",
-      "gitBlob": "eef8cd11f07e06d68b7051efa60ae05f2cfd8a63"
-    },
-    {
-      "path": "docs/schemas/edict.cli-diagnostic.v1.schema.json",
-      "gitBlob": "92a2151a76893c598a4191ed6cecd8a0e671613f"
-    },
-    {
-      "path": "docs/schemas/edict.cli-event.v1.schema.json",
-      "gitBlob": "705d82a893c2ea91caa91ad6977a9be8646b47bb"
-    },
-    {
-      "path": "docs/schemas/edict.cli-info.v1.schema.json",
-      "gitBlob": "2d9a0777b4190b56ff569625275d352d17363afa"
-    },
-    {
-      "path": "docs/schemas/edict.compiler-input.v1.schema.json",
-      "gitBlob": "26da3ba0fe85fab4c826ad79f13968ce09c4f29b"
-    },
-    {
-      "path": "docs/schemas/edict.compiler-settings.v1.schema.json",
-      "gitBlob": "a3e8ba469895b84ab81724da1075c73141a8dd0c"
-    },
-    {
-      "path": "docs/schemas/edict.projection-core.v1.schema.json",
-      "gitBlob": "8c0afe3834256abd1e18efb5f31eae1c4bdf0374"
-    },
-    {
-      "path": "docs/schemas/edict.projection-diagnostics.v1.schema.json",
-      "gitBlob": "28cfb0a67dff7b8f879122c74433158dc0a4e5df"
-    },
-    {
-      "path": "docs/schemas/edict.projection-syntax.v1.schema.json",
-      "gitBlob": "a85f2e14f536863f5e7b107b1a9f3f10816e6234"
-    },
-    {
-      "path": "docs/schemas/edict.projection-target-ir.v1.schema.json",
-      "gitBlob": "8bbb6495ad8800d775d1c08506e85351038d678a"
-    },
-    {
-      "path": "docs/topics/README.md",
-      "gitBlob": "99b06d3124c71cb62dfe6faff7604c13063162a7"
-    },
-    {
-      "path": "docs/topics/admission/README.md",
-      "gitBlob": "755dcba96c0a428eec18d58a529f3e26d57d118c"
-    },
-    {
-      "path": "docs/topics/admission/test-plan.md",
-      "gitBlob": "68ee0a2d2502103285985bf862de9fadf2bac5a0"
-    },
-    {
-      "path": "docs/topics/assurance/README.md",
-      "gitBlob": "cf382008f3d3094a5380a687abbf07538e07404d"
-    },
-    {
-      "path": "docs/topics/assurance/test-plan.md",
-      "gitBlob": "0ea6c971924db763088577a0a52bbd30bfec814c"
-    },
-    {
-      "path": "docs/topics/authority-facts/README.md",
-      "gitBlob": "c5589d2489d6e4a5729c0df2b2655ff281d8d88d"
-    },
-    {
-      "path": "docs/topics/authority-facts/test-plan.md",
-      "gitBlob": "e3769edf8309347b23ffa2e8f0901e06feabd654"
-    },
-    {
-      "path": "docs/topics/cli/README.md",
-      "gitBlob": "af38946c9ccae8da343877c3861b0f52b6076e1b"
-    },
-    {
-      "path": "docs/topics/cli/test-plan.md",
-      "gitBlob": "d72d69ef1d340ffd7057a63dd7bc07e3dfb2c166"
-    },
-    {
-      "path": "docs/topics/compiler-spine/README.md",
-      "gitBlob": "740a1433877b7bdcf233e5f3e178ff263471c0b2"
-    },
-    {
-      "path": "docs/topics/compiler-spine/test-plan.md",
-      "gitBlob": "ccf687876fc30b04de11db9dc86ea41afae87641"
-    },
-    {
-      "path": "docs/topics/contract-bundles/README.md",
-      "gitBlob": "2347499e8da9dd57bb1588faf67fe386c7a70c03"
-    },
-    {
-      "path": "docs/topics/contract-bundles/test-plan.md",
-      "gitBlob": "3ae4c7362f90fa89081ab9ff2bf1c3db1a811874"
-    },
-    {
-      "path": "docs/topics/core-ir/README.md",
-      "gitBlob": "d747a18d1f53de2b29473ada7a06b819c77cd162"
-    },
-    {
-      "path": "docs/topics/core-ir/canonical-encoding.md",
-      "gitBlob": "34927c69fb1de10b685294a155fc46bb4ac21628"
-    },
-    {
-      "path": "docs/topics/core-ir/test-plan.md",
-      "gitBlob": "0f80304a4dd6b160c78674b73605bdbbb7e11066"
-    },
-    {
-      "path": "docs/topics/developer-tooling/README.md",
-      "gitBlob": "8648d3c1bdf4f6b774bc5fec71c71aa8c59b0ce8"
-    },
-    {
-      "path": "docs/topics/developer-tooling/test-plan.md",
-      "gitBlob": "9240f717434dfbca08a6366e6d3ebafd4ef2c908"
-    },
-    {
-      "path": "docs/topics/documentation/README.md",
-      "gitBlob": "34fa7f4db136c274a88b680f99619d657fda15d5"
-    },
-    {
-      "path": "docs/topics/documentation/test-plan.md",
-      "gitBlob": "47964954fbf640211bc30b0dd361c44c9955c488"
-    },
-    {
-      "path": "docs/topics/external-action-requests/README.md",
-      "gitBlob": "45bc73e469919d3eff6e7eddbe9baa0383c7d91b"
-    },
-    {
-      "path": "docs/topics/external-action-requests/test-plan.md",
-      "gitBlob": "38e7e53827d223c031d414f4ecd63720eb78eae0"
-    },
-    {
-      "path": "docs/topics/fixtures/README.md",
-      "gitBlob": "c8b3b196109fb6d4e37d8ffa17635166010075fb"
-    },
-    {
-      "path": "docs/topics/fixtures/test-plan.md",
-      "gitBlob": "624357dbc544d365835390d3d3c2f11015b7b82f"
-    },
-    {
-      "path": "docs/topics/lawpack-authoring/README.md",
-      "gitBlob": "74bb25cc22e1f88cf4ee952b42313d919339113a"
-    },
-    {
-      "path": "docs/topics/lawpack-authoring/test-plan.md",
-      "gitBlob": "d7ad2eacde45dbce3eeb2b1a22c6482134b841ba"
-    },
-    {
-      "path": "docs/topics/lawpacks/README.md",
-      "gitBlob": "dedaa524dc55663a44bf8101241ab4b6d4755531"
-    },
-    {
-      "path": "docs/topics/lawpacks/test-plan.md",
-      "gitBlob": "f8aa2c7ce40dad2665134956dc95d951d311808f"
-    },
-    {
-      "path": "docs/topics/lowerability/README.md",
-      "gitBlob": "fb9519af3539d846dc5bf2915bf5ca86816e46f8"
-    },
-    {
-      "path": "docs/topics/lowerability/test-plan.md",
-      "gitBlob": "e0fbff0799ba805c9531097d6b8aeea657e2b815"
-    },
-    {
-      "path": "docs/topics/obstruction-strands/README.md",
-      "gitBlob": "a2930645065390cecff8008bfd48b7f034bfcd18"
-    },
-    {
-      "path": "docs/topics/obstruction-strands/test-plan.md",
-      "gitBlob": "20c54ffcaa19930a5bc772a49a5f01119054be2d"
-    },
-    {
-      "path": "docs/topics/providers/README.md",
-      "gitBlob": "8b5a07fb9c708b753861a4e156b866115f4d687b"
-    },
-    {
-      "path": "docs/topics/providers/architecture.md",
-      "gitBlob": "664b38347ccaf37f298d6ac9f19d3423c0277f9e"
-    },
-    {
-      "path": "docs/topics/providers/test-plan.md",
-      "gitBlob": "95c55f9e132ca6859fd9df70470973e678ed8d92"
-    },
-    {
-      "path": "docs/topics/public-rust-api/README.md",
-      "gitBlob": "c64a1081b7f693b02bd2ea63329f2610bae9d84c"
-    },
-    {
-      "path": "docs/topics/public-rust-api/test-plan.md",
-      "gitBlob": "4c3b9e9662afd9edb790ba2b5c57ed5e93df595c"
-    },
-    {
-      "path": "docs/topics/release-process/README.md",
-      "gitBlob": "a474ab8b6a4a58c5c73334c9e677be7c20d1837c"
-    },
-    {
-      "path": "docs/topics/release-process/policy.toml",
-      "gitBlob": "e40b4f4ec721ae61210ec1bb022a847bcb49fb4a"
-    },
-    {
-      "path": "docs/topics/release-process/runbook.md",
-      "gitBlob": "0b6bd8ef44cbfe8c7cdc347273fa74b7c96c4823"
-    },
-    {
-      "path": "docs/topics/release-process/test-plan.md",
-      "gitBlob": "61ecded1d2318d7dd74070cd1c6155f353c947e9"
-    },
-    {
-      "path": "docs/topics/result-projections/README.md",
-      "gitBlob": "d5c2f85a7681a15dcdc3e35f992a389c50d13461"
-    },
-    {
-      "path": "docs/topics/result-projections/test-plan.md",
-      "gitBlob": "9e69d58c88d6a9b7389334a78b994a3449721faa"
-    },
-    {
-      "path": "docs/topics/review-process/README.md",
-      "gitBlob": "25190d37dc30110f75ba5d3a41494575ffecc1c3"
-    },
-    {
-      "path": "docs/topics/review-process/policy.toml",
-      "gitBlob": "a826ba58aad2e509220b65aa8f96c290b600e094"
-    },
-    {
-      "path": "docs/topics/review-process/test-plan.md",
-      "gitBlob": "f1a50aeae47913e4513a8149c1679d9a94c5ef21"
-    },
-    {
-      "path": "docs/topics/rust-standards/README.md",
-      "gitBlob": "2fe29258705d117f4d10604a83fd832a8476e303"
-    },
-    {
-      "path": "docs/topics/rust-standards/test-plan.md",
-      "gitBlob": "0e0d6b306cd2b58db07a7a5da6a752925fe58764"
-    },
-    {
-      "path": "docs/topics/semantic-validation/README.md",
-      "gitBlob": "51cd9761755e7b5879069bf3774eeb487982ca97"
-    },
-    {
-      "path": "docs/topics/semantic-validation/test-plan.md",
-      "gitBlob": "b43969d8eb0a884c1663ab761662f9622617bb3b"
-    },
-    {
-      "path": "docs/topics/syntax/README.md",
-      "gitBlob": "b2a372bf41b1976567c61f400bf000f33abc20cc"
-    },
-    {
-      "path": "docs/topics/syntax/test-plan.md",
-      "gitBlob": "a69efaf12dfe12661fca049b8790b37fa3fb3665"
-    },
-    {
-      "path": "docs/topics/target-ir/README.md",
-      "gitBlob": "93b73c18871d68b5ee5290ccbf52cf7f720a88c8"
-    },
-    {
-      "path": "docs/topics/target-ir/test-plan.md",
-      "gitBlob": "124306f0b893100e389ff55fe3ffb66d30f7332a"
-    },
-    {
-      "path": "docs/topics/target-profiles/README.md",
-      "gitBlob": "6a88f4d732f8069855b2ed2cb9a8769a117b2f60"
-    },
-    {
-      "path": "docs/topics/target-profiles/test-plan.md",
-      "gitBlob": "90084c3f3a1296745469cd86e9b5f2bc928825be"
-    },
-    {
-      "path": "docs/topics/tests/README.md",
-      "gitBlob": "4ad079b6a9718e2a8446a6c67ff45735015bef84"
-    },
-    {
-      "path": "docs/topics/tests/test-plan.md",
-      "gitBlob": "46bc0572d02a41e86f71c6d46baf5be611a462a6"
-    },
-    {
-      "path": "docs/topics/v2-design/README.md",
-      "gitBlob": "b33a07599e43e660aa4def7f119ddd02df6a16de"
-    },
-    {
-      "path": "docs/topics/v2-design/test-plan.md",
-      "gitBlob": "f17f96d381f81b20842393f70ff55b9597858b84"
-    },
-    {
-      "path": "editors/README.md",
-      "gitBlob": "7a933576262bc58bac197f9264fdbf649dd5e696"
-    },
-    {
-      "path": "editors/vscode/.vscodeignore",
-      "gitBlob": "f15b3142e4b8af11d580789a0c82acee3499f571"
-    },
-    {
-      "path": "editors/vscode/README.md",
-      "gitBlob": "8b29840ae9ec8f618b7364022329f694d0ed9746"
-    },
-    {
-      "path": "editors/vscode/language-configuration.json",
-      "gitBlob": "b7f583841649c9c437785edbfcb70ee24e495c79"
-    },
-    {
-      "path": "editors/vscode/package.json",
-      "gitBlob": "cd9e391e7c9afb6f9393fcead118e0e55aadc839"
-    },
-    {
-      "path": "editors/vscode/syntaxes/edict.tmLanguage.json",
-      "gitBlob": "5847d8edfdb32d822f0f3950f41d00c947982185"
-    },
-    {
-      "path": "fixtures/README.md",
-      "gitBlob": "470e3e0fc3aa00654930ecdef892ee9df8a42c8d"
-    },
-    {
-      "path": "fixtures/authority-facts/canonical/README.md",
-      "gitBlob": "28692ce70add5d4f2d4ff5318309c3353924caf9"
-    },
-    {
-      "path": "fixtures/authority-facts/canonical/example-effectful.authority-facts.cbor",
-      "gitBlob": "fe2e59a8e2602e02c52094010a130db2637c5227"
-    },
-    {
-      "path": "fixtures/authority-facts/canonical/example-effectful.authority-facts.json",
-      "gitBlob": "009faa5d2dc1dcf55cf284dcfd14c0b6405f3e0d"
-    },
-    {
-      "path": "fixtures/authority-facts/canonical/example-effectful.authority-facts.sha256",
-      "gitBlob": "a3d68f0a3b3a586e85b6a84cbd884866e662951f"
-    },
-    {
-      "path": "fixtures/bundle/assembly/bounded-hello.bundle-digests.txt",
-      "gitBlob": "da5402db7bd41dd88c6152b7799723561130c91e"
-    },
-    {
-      "path": "fixtures/cli/01-source-ok/expected.stdout.jsonl",
-      "gitBlob": "e08ccf8fdedd3a73beef5d06c443a1bc60274ce1"
-    },
-    {
-      "path": "fixtures/cli/01-source-ok/request.jsonl",
-      "gitBlob": "002fea597e6b93c8468d6972b73cc1344600fa87"
-    },
-    {
-      "path": "fixtures/cli/02-source-parse-rejection/exit",
-      "gitBlob": "d00491fd7e5bb6fa28c517a0bb32b8b506539d4d"
-    },
-    {
-      "path": "fixtures/cli/02-source-parse-rejection/expected.stderr.jsonl",
-      "gitBlob": "1077b73c9a7c02eae99f737bea7b6ff8c64d04da"
-    },
-    {
-      "path": "fixtures/cli/02-source-parse-rejection/request.jsonl",
-      "gitBlob": "dce01f0466bd9384fc6f5cbe2845b6e0bd9a9cfd"
-    },
-    {
-      "path": "fixtures/cli/03-source-semantic-rejection/exit",
-      "gitBlob": "d00491fd7e5bb6fa28c517a0bb32b8b506539d4d"
-    },
-    {
-      "path": "fixtures/cli/03-source-semantic-rejection/expected.stderr.jsonl",
-      "gitBlob": "5ec447700da52d0b4ce1f75825eb9bffaed4884b"
-    },
-    {
-      "path": "fixtures/cli/03-source-semantic-rejection/request.jsonl",
-      "gitBlob": "ddfd529e5448760387961febbd4ce013e49de435"
-    },
-    {
-      "path": "fixtures/cli/04-cli-missing-settings/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/04-cli-missing-settings/expected.stderr.jsonl",
-      "gitBlob": "5060bd2fd773ba9ea3ea6db8c80b86a846bfadbd"
-    },
-    {
-      "path": "fixtures/cli/04-cli-missing-settings/request.jsonl",
-      "gitBlob": "8eb12e58d427bd64ccfe339190e05bdccf4c8634"
-    },
-    {
-      "path": "fixtures/cli/05-path-input-ok/expected.stdout.jsonl",
-      "gitBlob": "a05fc582efc41b6414e785167b5deeb7532088ef"
-    },
-    {
-      "path": "fixtures/cli/05-path-input-ok/inputs/hello.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/05-path-input-ok/request.jsonl",
-      "gitBlob": "18facaab79dc198134c535df389cba79efe7dce7"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/expected.stdout.jsonl",
-      "gitBlob": "ef59591526e2084ddf5057249bbc96ab660cf256"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/inputs/a.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/inputs/ignore.txt",
-      "gitBlob": "ed34ae8da336ff94a67b6125fbd6be730c976d91"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/inputs/nested/b.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/request.jsonl",
-      "gitBlob": "bd9aad14fe79caccacaa6d00ffd32b5e13b3551f"
-    },
-    {
-      "path": "fixtures/cli/07-path-list-ok/expected.stdout.jsonl",
-      "gitBlob": "643ecb3e659c10cb98255ec1aced772778e76eb0"
-    },
-    {
-      "path": "fixtures/cli/07-path-list-ok/inputs/first.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/07-path-list-ok/inputs/second.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/07-path-list-ok/request.jsonl",
-      "gitBlob": "f11265b02c5b7559ced4d975471a78b5bef3ee27"
-    },
-    {
-      "path": "fixtures/cli/08-glob-expansion-ok/expected.stdout.jsonl",
-      "gitBlob": "90164a7fce6c51abdadef8f0586d2c56113d9712"
-    },
-    {
-      "path": "fixtures/cli/08-glob-expansion-ok/inputs/x.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/08-glob-expansion-ok/inputs/y.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/08-glob-expansion-ok/request.jsonl",
-      "gitBlob": "9335acf3a008ab8fb9942b3e22d73c456ed3827e"
-    },
-    {
-      "path": "fixtures/cli/09-shape-source-ok/expected.stdout.jsonl",
-      "gitBlob": "ac6f9259502ebfe484e1c07a5f53865888dd8207"
-    },
-    {
-      "path": "fixtures/cli/09-shape-source-ok/request.jsonl",
-      "gitBlob": "64c75d9a7b40985bacf0e59a943a16e20419c602"
-    },
-    {
-      "path": "fixtures/cli/10-input-extra-field/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/10-input-extra-field/expected.stderr.jsonl",
-      "gitBlob": "2f5a8fba093b71d15a5b37504ad0352191c8299c"
-    },
-    {
-      "path": "fixtures/cli/10-input-extra-field/request.jsonl",
-      "gitBlob": "6052212c652d41f03144a7d3d4018b1cdd18cd09"
-    },
-    {
-      "path": "fixtures/cli/11-input-hybrid-kind/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/11-input-hybrid-kind/expected.stderr.jsonl",
-      "gitBlob": "7b6d2ac0c8afbf5e3991498846c2fc4847ac9453"
-    },
-    {
-      "path": "fixtures/cli/11-input-hybrid-kind/request.jsonl",
-      "gitBlob": "b893b640aa6631c77f2a889a807afa31632ac2db"
-    },
-    {
-      "path": "fixtures/cli/12-input-too-large/env.json",
-      "gitBlob": "ab0c7f13fc6b22d61fc73da2f1787ff3aa298ecb"
-    },
-    {
-      "path": "fixtures/cli/12-input-too-large/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/12-input-too-large/expected.stderr.jsonl",
-      "gitBlob": "ebda022d79c978d4ff511579512be2c642e3e902"
-    },
-    {
-      "path": "fixtures/cli/12-input-too-large/request.jsonl",
-      "gitBlob": "1e2fbb102503356bbcc627f49a5b58590859f170"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/allowed/.gitkeep",
-      "gitBlob": "8b137891791fe96927ad78e64b0aad7bded08bdc"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/expected.stderr.jsonl",
-      "gitBlob": "9c5b8567a755c9ea2ee6e0168bf96f429185f675"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/outside/outside.edict",
-      "gitBlob": "44abebc15811c38cc266007484dd74ae10a26a4d"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/request.jsonl",
-      "gitBlob": "116dbbb4b1a80938bc042e41747872cb6da161cd"
-    },
-    {
-      "path": "fixtures/cli/README.md",
-      "gitBlob": "9388df4182fedec41c353e85cf9210e88906fa3d"
-    },
-    {
-      "path": "fixtures/core/canonical/README.md",
-      "gitBlob": "d9a0ca79557c3623c0b843d9eff4808f94fd7b18"
-    },
-    {
-      "path": "fixtures/core/canonical/bounded-hello.core.cbor",
-      "gitBlob": "a0ec54aa1a5e20624192091526445cfd803e6f0c"
-    },
-    {
-      "path": "fixtures/core/canonical/bounded-hello.core.sha256",
-      "gitBlob": "86ba062c26a3ad3fd733ccd8c80d7faa7ed62d94"
-    },
-    {
-      "path": "fixtures/core/canonical/statement-branch.core.hex",
-      "gitBlob": "c22760cace0e4d146a2fdc8d7c7b50c38497622a"
-    },
-    {
-      "path": "fixtures/core/canonical/statement-branch.core.sha256",
-      "gitBlob": "0b62657b192232390479319f0a1c8f601020a58f"
-    },
-    {
-      "path": "fixtures/core/canonical/workspace-snapshot.core.cbor",
-      "gitBlob": "58e4f724610861f5b61537bf386a87062e8a57a7"
-    },
-    {
-      "path": "fixtures/core/canonical/workspace-snapshot.core.sha256",
-      "gitBlob": "4bcb3e0813cd3f4a7afc7cf311d846f1dfdd0a9d"
-    },
-    {
-      "path": "fixtures/core/schema/accepted/core-fn-body-minimal.fields",
-      "gitBlob": "bef3ca412ab0ea97465b8658499ae5e05e1ec760"
-    },
-    {
-      "path": "fixtures/core/schema/accepted/core-intent-minimal.fields",
-      "gitBlob": "268b28ce942fed4f139aafe5c7cd50c15a0ee640"
-    },
-    {
-      "path": "fixtures/core/schema/accepted/core-module-minimal.fields",
-      "gitBlob": "249ff76349f936c9a5ff6cb65d81de8e80d53de8"
-    },
-    {
-      "path": "fixtures/core/schema/rejected/core-fn-body-effect-node-field.fields",
-      "gitBlob": "9af8fa3540b25ec810936bc4dc82e26f6dd0dd48"
-    },
-    {
-      "path": "fixtures/core/schema/rejected/core-intent-unknown-verified-mode.fields",
-      "gitBlob": "667ae032ee117f32c1bcbafd21393e406621f517"
-    },
-    {
-      "path": "fixtures/core/schema/rejected/core-module-missing-intents.fields",
-      "gitBlob": "17f37c7ac4c199de4eace7f31e6a59b9a6d3a0f6"
-    },
-    {
-      "path": "fixtures/core/schema/rejected/local-ref-missing-alpha-name.fields",
-      "gitBlob": "456a89528ffe74d892be40c9c9be4a078ff5c18a"
-    },
-    {
-      "path": "fixtures/lang/bounds/bounded-hello.edict",
-      "gitBlob": "e3443a1d3b1c8f0e137ac698b621dd2f3afb673b"
-    },
-    {
-      "path": "fixtures/lang/effects/conditional-blob.edict",
-      "gitBlob": "1e4f2ca6112f26d57ee4d20058666ec7cd693b75"
-    },
-    {
-      "path": "fixtures/lang/effects/read-greeting.edict",
-      "gitBlob": "5e3838d1547be171e0a0384a7a200f52a2b9d139"
-    },
-    {
-      "path": "fixtures/lang/external-actions/workspace-snapshot.edict",
-      "gitBlob": "e54b0fbccad2fd680505f3ee46ca28d39d7e776e"
-    },
-    {
-      "path": "fixtures/lang/operations/explicit-basis-u64.edict",
-      "gitBlob": "444d8ca77b9827746df81885f0620dce2d1a3b73"
-    },
-    {
-      "path": "fixtures/lang/tooling/highlight-smoke.edict",
-      "gitBlob": "8c2d91084be22e5e1594a42159992aca95c73612"
-    },
-    {
-      "path": "fixtures/lang/types/color-match.edict",
-      "gitBlob": "dd98d6de677904f36d7601165a0094d92928e536"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/README.md",
-      "gitBlob": "52e8cc1e2af8aea86c1090a1b20b5f5ab3e07c06"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/adapter.cbor",
-      "gitBlob": "3b0c8b1b3a8591a322b6e785d9f963899319310c"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/adapter.sha256",
-      "gitBlob": "f8231bc941e1fbe02279865a82e183cbeeb0988a"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/echo-operation-configuration.cbor",
-      "gitBlob": "24527d30d0146b567fda157561ac6a2587cae919"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/echo-operation-configuration.sha256",
-      "gitBlob": "d293c8a14b1955a3e171703400c4df620c7871a1"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/exports.cbor",
-      "gitBlob": "384f4839adfe8e5b0f1aa848bfe2aeb1c3f640b6"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/exports.sha256",
-      "gitBlob": "4f836f6b03497338a1f8eacc55480cbe1a3b49e9"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/manifest.cbor",
-      "gitBlob": "b9311a236d7898861a0b90b1f30b852b35cef623"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/manifest.sha256",
-      "gitBlob": "685fd6a6c72fc3100d595d009b6198a81c731a40"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/README.md",
-      "gitBlob": "79f6612f1f5608a8f7dc4835e5470878cd27f96e"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/adapter.cbor",
-      "gitBlob": "24e2f546e2b97747b53462a72faaa1d5d85d62f1"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/adapter.sha256",
-      "gitBlob": "91df491028061e026ecaaeb4e1598e2ac369af44"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.core.cbor",
-      "gitBlob": "246b6135855c415def0bd89b275f0457752ee563"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.core.sha256",
-      "gitBlob": "9adc71605e0a275349161809614bd17de97d129c"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.edict",
-      "gitBlob": "825d50565230bd71d62bfbeb59d0399a89864b4c"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.result-projection.cbor",
-      "gitBlob": "981cba6e1c7ab6bdae6829116749c4796167e4e6"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.result-projection.sha256",
-      "gitBlob": "d55e4083771e1d9791f59cf87fd5cc5f1ea3b9f4"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.target-ir.cbor",
-      "gitBlob": "c8a934cefec17dbab0a43d9be9cebd2533268798"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.target-ir.sha256",
-      "gitBlob": "20186cbe9482e8a7df7c44fabec13ffd4efbcf36"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/echo-operation-configuration.cbor",
-      "gitBlob": "84838ab0d8627237232fa5a9b9fa39087bcc5f8a"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/echo-operation-configuration.sha256",
-      "gitBlob": "0898688f14067560dd22abd04b97f020071fd3e8"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/exports.cbor",
-      "gitBlob": "0e1220ceed9442a7b35870eeb02fcb65454d8c5c"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/exports.sha256",
-      "gitBlob": "e1f3e9223de9ce935bc7f60dda3cfa7d12d54fdc"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/manifest.cbor",
-      "gitBlob": "d715900f03ec454a0ad96e6710f52a46120d0b9d"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/manifest.sha256",
-      "gitBlob": "20171199b401cecace2dd74e18f3cc1d5c7ed3de"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/README.md",
-      "gitBlob": "67cd35f2e0660aa7455de1c197ad821d5438679b"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/adapter.cbor",
-      "gitBlob": "2d6f09a7e2fab381b97a05cfad1e692902e878c3"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/adapter.sha256",
-      "gitBlob": "d44eb9675e126716e8a5ef3c53fd39ade49d76fb"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.core.cbor",
-      "gitBlob": "6a88c127e426288a3e51d4749d5c31d5b0cb60cb"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.core.sha256",
-      "gitBlob": "0204b6f1d8b346a67800a7738ee39df49e78571f"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.edict",
-      "gitBlob": "6e11a3d022a53a8fb2c20a77e35e29840f5fe086"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.target-ir.cbor",
-      "gitBlob": "a6124a995a3cdbb5d39cd0a6e046b329048703aa"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.target-ir.sha256",
-      "gitBlob": "f7ac419ce15b32d491e09bddbe7c75f8227f51d8"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/exports.cbor",
-      "gitBlob": "3a6fd19dc8059b9fe1bde74fb1da61398b0e80cc"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/exports.sha256",
-      "gitBlob": "b301dd883a31fffe324e9306ec90ae2b1ec44520"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/input-schema.cbor",
-      "gitBlob": "3045d9b696864fefe111c3eb641b3b68532752d2"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/input-schema.sha256",
-      "gitBlob": "9f1284b4f0a2c7f6dbe1915a6113cd13a9700cb8"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/manifest.cbor",
-      "gitBlob": "77e56c7525f0e64ab191f0adfeac12b540c87848"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/manifest.sha256",
-      "gitBlob": "8316978e68565f29a30a6978d33d907710185857"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/reconciliation-law.cbor",
-      "gitBlob": "0736b75f81913fca7ac95c56ec45f66b95aea4cf"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/reconciliation-law.sha256",
-      "gitBlob": "de31fc9fda59fa3c29397e5fc48db224e8e1fee7"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/request-profile-configuration.cbor",
-      "gitBlob": "5e2870b2f562bafaa73a91a3fc192f5ed39257c7"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/request-profile-configuration.sha256",
-      "gitBlob": "4345ae2e39ce3f4d9cfa6b0dddf4ce56d56c035c"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/settlement-schema.cbor",
-      "gitBlob": "0a93ac19c51b341602eeba524769147e962d5d60"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/settlement-schema.sha256",
-      "gitBlob": "f1bb3fb0313dd6815b4184345194949ec40fe9e1"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/README.md",
-      "gitBlob": "996bd1d29b28769fff477084d9118d0833ca2970"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/adapter.cbor",
-      "gitBlob": "9be4ea568b602b56269af505deb809989a3fa8b5"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/adapter.sha256",
-      "gitBlob": "1e287be0a322e5444dea15fa14bcfc7cf12975c4"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/exports.cbor",
-      "gitBlob": "33fe04db74775c191d4b7400e1fb2b6393c5a010"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/exports.sha256",
-      "gitBlob": "e057cac7fc360e6599b7ddab88508aaf0f2f55f8"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/input-schema.cbor",
-      "gitBlob": "49c849169946e44c8b5f300279dd085bd6b63aeb"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/input-schema.sha256",
-      "gitBlob": "9dd7bb6e48192e90d19fc346d1705f736b1d85d7"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/manifest.cbor",
-      "gitBlob": "d4e58e3d4646ca967170a6882f2a617cb8d81390"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/manifest.sha256",
-      "gitBlob": "0edb311125a89a5816ee3fa0c9b700c9b3bcff3d"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.core.cbor",
-      "gitBlob": "a4b249dfb197f1a6b4adc06855f16e4305a1c798"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.core.sha256",
-      "gitBlob": "ea6b914d14907d9fd915058e579aff33c954da2c"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.edict",
-      "gitBlob": "c2c10f1ef1009796d67061b9722c4db9bb4e031b"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.target-ir.cbor",
-      "gitBlob": "bdab1b0c55a34360c7e9ab304af91fe2b1e4afce"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.target-ir.sha256",
-      "gitBlob": "7342aaa96221d6c8efa75ead2af5563791ccfeff"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/reconciliation-law.cbor",
-      "gitBlob": "df55572b350002a3df98ccb3e72dd60c86b9aead"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/reconciliation-law.sha256",
-      "gitBlob": "957cd04c78c130b07d2cad2fd7e07ae69978be57"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/request-profile-configuration.cbor",
-      "gitBlob": "708f18918ee1703491a910df82e129e711a4cc46"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/request-profile-configuration.sha256",
-      "gitBlob": "d9953d9dcaa41c98387226d1980f40b24d2bc3cb"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/settlement-schema.cbor",
-      "gitBlob": "f01ad68531267666e6bf93bf30a37d5b311c1676"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/settlement-schema.sha256",
-      "gitBlob": "06fcc0ee2b976a09b3017bd93132a3c51eb1317e"
-    },
-    {
-      "path": "fixtures/obstruction-strands/v0/stale-basis/README.md",
-      "gitBlob": "25efbfa04e2e6104c5434f329128333e895e2b0a"
-    },
-    {
-      "path": "fixtures/obstruction-strands/v0/stale-basis/source.edict",
-      "gitBlob": "e487b46e81220c50e6f928922dada29f3a21ca6a"
-    },
-    {
-      "path": "fixtures/provider-contracts/v1/README.md",
-      "gitBlob": "447692907f9268ce3b6b78c43b7cbbb0417aeadf"
-    },
-    {
-      "path": "fixtures/provider-contracts/v1/edict-provider-contracts.cddl",
-      "gitBlob": "07048aeeadb5062eabb89e995713cbc0893b7d7e"
-    },
-    {
-      "path": "fixtures/provider-contracts/v1/manifest.json",
-      "gitBlob": "d2c8de5d61049e9f4182c630bf82b138f0f96792"
-    },
-    {
-      "path": "fixtures/providers/README.md",
-      "gitBlob": "c26ee60a4930e3e0784c76cb855e48234a5c6b58"
-    },
-    {
-      "path": "fixtures/providers/components/guests/Cargo.lock",
-      "gitBlob": "d7858ce7bc67deabb5ff352a24c85a7caa0ef4b0"
-    },
-    {
-      "path": "fixtures/providers/components/guests/Cargo.toml",
-      "gitBlob": "450a24aed25dc73661b0ae8adfe2630dfecc9b07"
-    },
-    {
-      "path": "fixtures/providers/components/guests/lowerer/Cargo.toml",
-      "gitBlob": "568aa137fa215b6b973fe31e12322530b393b9dc"
-    },
-    {
-      "path": "fixtures/providers/components/guests/lowerer/src/lib.rs",
-      "gitBlob": "b39a8a0b18fe9ed7cb90277f793056434afa1318"
-    },
-    {
-      "path": "fixtures/providers/components/guests/verifier/Cargo.toml",
-      "gitBlob": "f814f2c8c248bbf03389f5a0936f80cd4dada5b6"
-    },
-    {
-      "path": "fixtures/providers/components/guests/verifier/src/lib.rs",
-      "gitBlob": "3f07ffdfd808ff95b206a2c08c2d481ccaf0e165"
-    },
-    {
-      "path": "fixtures/providers/components/instantiation-failure-lowerer.component.wasm",
-      "gitBlob": "bd2d7c0d31798d7676aedab0bd0d289fc2053bef"
-    },
-    {
-      "path": "fixtures/providers/components/instantiation-failure-lowerer.wat",
-      "gitBlob": "f6f5a70edb80d3a7fa1dee13b34ab5b8b44274d7"
-    },
-    {
-      "path": "fixtures/providers/components/instantiation-fuel-lowerer.component.wasm",
-      "gitBlob": "0804d26d3ddb428682ca87ecad03cf0e05ef64af"
-    },
-    {
-      "path": "fixtures/providers/components/instantiation-fuel-lowerer.wat",
-      "gitBlob": "80e972463ef593602d27c7d7cec78d87d22ff727"
-    },
-    {
-      "path": "fixtures/providers/components/inventory.json",
-      "gitBlob": "45cf2e8e937a17a8ee05dfa8d68e94dcc155e129"
-    },
-    {
-      "path": "fixtures/providers/components/lowerer.component.wasm",
-      "gitBlob": "6c1cf123a44284d15b7b1e90f1905ae94e65c158"
-    },
-    {
-      "path": "fixtures/providers/components/malformed-lowerer.component.wasm",
-      "gitBlob": "be873af81100dc76ed1f3f1f818a41da45a38e4c"
-    },
-    {
-      "path": "fixtures/providers/components/malformed-lowerer.wat",
-      "gitBlob": "1e7bfffe0a0baf230d9fb5766083f82198f4029c"
-    },
-    {
-      "path": "fixtures/providers/components/verifier.component.wasm",
-      "gitBlob": "671adbe7931d0a9a5e0c78d459c244d37a135a69"
-    },
-    {
-      "path": "fixtures/providers/echo-generated/provider-manifest.json",
-      "gitBlob": "22c8560e7ddecacd5da388e52d3935d7fc1474b9"
-    },
-    {
-      "path": "fixtures/providers/echo-target-profile/README.md",
-      "gitBlob": "350c33dcda2d66d2d50e589c58db7c6d7b14a80b"
-    },
-    {
-      "path": "fixtures/providers/echo-target-profile/generated/primary/target-profile.echo-dpo.cbor",
-      "gitBlob": "9fa43529b1021dfd8e3a33256c832d4eee6f4a47"
-    },
-    {
-      "path": "fixtures/providers/wit/legacy-target-profile.wit",
-      "gitBlob": "ae7d6af764012b16bf06bfa260ccba98a7f04868"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/echo-effectful.target-ir.cbor",
-      "gitBlob": "727a80eb37319dbdbea40d7d9b4e37f0d93d8d84"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/echo-effectful.target-ir.sha256",
-      "gitBlob": "6d050bb46ac8981ea8e47c7a52371027b941fd89"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/gitwarp-append.target-ir.cbor",
-      "gitBlob": "89b46b138a7b90252a4397c0e8b622bceff10a33"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/gitwarp-append.target-ir.sha256",
-      "gitBlob": "a59a4ab9d46095d5be1797ed9e60fe841f821bce"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/workspace-snapshot.target-ir.cbor",
-      "gitBlob": "1854eeb549b3719fa2b0114867dbece6db1819d4"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/workspace-snapshot.target-ir.sha256",
-      "gitBlob": "4d0e501323d415ef9e64c0a3d25bdd57dabfc998"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/README.md",
-      "gitBlob": "32dcab1dd9376a4eed2c73bb1b1a29255fe3ea05"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/canonical-cbor.cbor",
-      "gitBlob": "4a95ba3bd9dff190ca5ec9c83262bfa6254a91d3"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/canonical-cbor.sha256",
-      "gitBlob": "2168df5d4bf77ed2347139dd7c45fd808df8ec7e"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/determinism.cbor",
-      "gitBlob": "09cd11c36048939961408550763c04fad8241557"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/determinism.sha256",
-      "gitBlob": "5376d6bfe23bea659463a7e3c56ad1e8afd4095f"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/diagnostics.cbor",
-      "gitBlob": "c47fa05f463e0da745fbcdf8daf94d70e134eb8d"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/diagnostics.sha256",
-      "gitBlob": "69613ec4014f27b23245e23fbf7c9447566516b2"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/fuel.cbor",
-      "gitBlob": "b5a3484ec5b2bf7343c2fcedc67bcb2b63a37104"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/fuel.sha256",
-      "gitBlob": "6ec1c830358ee35bb12bd04cc1a6edf47fb20997"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/wasm-component.cbor",
-      "gitBlob": "6344996c283e0d1c332ea3ce597ad4593882a3c5"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/wasm-component.sha256",
-      "gitBlob": "24bf3e552e4216d8258d2b85c8878af46a176c52"
-    },
-    {
-      "path": "grammars/textmate/README.md",
-      "gitBlob": "fc116a669725d4e965d658234d32d779955d5dc8"
-    },
-    {
-      "path": "grammars/textmate/edict.tmLanguage.json",
-      "gitBlob": "5847d8edfdb32d822f0f3950f41d00c947982185"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/README.md",
-      "gitBlob": "e2992a839d6719f1461db78c4e3f33d2e5ab0c09"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/grammar.js",
-      "gitBlob": "a82f5b9d9b78525f17a59272543fdcddd7a0da40"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/queries/highlights.scm",
-      "gitBlob": "0f46530b36996d13449901aed4e376a126577cba"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/grammar.json",
-      "gitBlob": "55df730a06b83c9f622e3ec17845fc9897c7d8c0"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/node-types.json",
-      "gitBlob": "520f6c4f7b30cd6892dd60faf6d76f3fbaa6a5c7"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/parser.c",
-      "gitBlob": "81cc4713cb5e05f9aa8dac16da202a864faefee6"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/tree_sitter/alloc.h",
-      "gitBlob": "1abdd1201578605b8d05a3001f01ebc0d58826d9"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/tree_sitter/array.h",
-      "gitBlob": "56fc8cd470996ded64a5452be25e26dbd2aa682a"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/tree_sitter/parser.h",
-      "gitBlob": "858107deb9e4a1ffcd2ed5e6ffe98a5fcab3e1f6"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/test/corpus/current-subset.txt",
-      "gitBlob": "732c5eda8e1bf95eef799476296a6ee061eb58eb"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/tree-sitter.json",
-      "gitBlob": "97d3fdd498a3bef509c8615d98b9560b527c03cb"
-    },
-    {
-      "path": "scripts/consumer-witnesses/README.md",
-      "gitBlob": "2b7d2b9d81f9598fd8df232b3a76bef106ff7ef2"
-    },
-    {
-      "path": "scripts/consumer-witnesses/jedit-state-read.Dockerfile",
-      "gitBlob": "7462059be67686090d0097b24b9d14bfbbd4c6f7"
-    },
-    {
-      "path": "scripts/consumer-witnesses/jedit-state-read.Dockerfile.dockerignore",
-      "gitBlob": "ee41b3ca0a68fd5eb20e1b777b4b368fd8b44e63"
-    },
-    {
-      "path": "scripts/consumer-witnesses/jedit-state-read.py",
-      "gitBlob": "26db295d4eabfc4e57813fc9bf17314c23350777"
-    },
-    {
-      "path": "scripts/consumer-witnesses/run-jedit-state-read.sh",
-      "gitBlob": "18cd72bbbdfb17a5ea30a7821d47035071556d10"
-    },
-    {
-      "path": "spec.lock.json",
-      "gitBlob": "ef8b02386e0f269a99c1d2121764f70b76e67620"
-    },
-    {
-      "path": "xtask/Cargo.toml",
-      "gitBlob": "795c70a5172363bfcd55174b1bc76c9c131d21a3"
-    },
-    {
-      "path": "xtask/src/contract_check.rs",
-      "gitBlob": "9e80393accf79936033972fde0f2aa2cf40f1be3"
-    },
-    {
-      "path": "xtask/src/goldens.rs",
-      "gitBlob": "713f1f8266d9f6993684ae86db105fcd7d69ee2a"
-    },
-    {
-      "path": "xtask/src/lawpack_goldens.rs",
-      "gitBlob": "c499e8581c73313794b83c261937144b3917850a"
-    },
-    {
-      "path": "xtask/src/main.rs",
-      "gitBlob": "6c2c06038bb5ecdde60620071b200d8191dc116c"
-    },
-    {
-      "path": "xtask/src/provider_components.rs",
-      "gitBlob": "ee9d6a1028f9fbfad879faab4b15a94b996ef6d4"
-    },
-    {
-      "path": "xtask/src/provider_contract_pack.rs",
-      "gitBlob": "cf60d89892b7a57cc33300f273d2522a6e8f43f9"
-    },
-    {
-      "path": "xtask/src/provider_dependencies.rs",
-      "gitBlob": "c4b0539ed593d2a2777d294090d2a891b13ae628"
-    },
-    {
-      "path": "xtask/src/release_dates.rs",
-      "gitBlob": "1c6d7acb872f6d820eab3a30ca580e9c5cfba2ee"
-    },
-    {
-      "path": "xtask/src/release_prep.rs",
-      "gitBlob": "01ed64ccbb28c9d1e908b7b800ff58076e5e1a2b"
-    },
-    {
-      "path": "xtask/src/tests.rs",
-      "gitBlob": "9a3f6543c2dbae31d53e93d56f781e5d54f74f41"
-    },
-    {
-      "path": "xtask/src/util.rs",
-      "gitBlob": "c1bf39e93460c43ffdcfd9a76e0424750cbb9dfd"
-    }
-  ]
-}
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/first-control/application/executable-operation-package.cbor b/edict/replace-range-probes/range-assembly/evidence/candidate/first-control/application/executable-operation-package.cbor
deleted file mode 100644
index 0b860cf3..00000000
Binary files a/edict/replace-range-probes/range-assembly/evidence/candidate/first-control/application/executable-operation-package.cbor and /dev/null differ
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/first-control/application/verification-report.cbor b/edict/replace-range-probes/range-assembly/evidence/candidate/first-control/application/verification-report.cbor
deleted file mode 100644
index d3afb3f9..00000000
Binary files a/edict/replace-range-probes/range-assembly/evidence/candidate/first-control/application/verification-report.cbor and /dev/null differ
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/first-control/stderr.jsonl b/edict/replace-range-probes/range-assembly/evidence/candidate/first-control/stderr.jsonl
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/first-control/stdout.jsonl b/edict/replace-range-probes/range-assembly/evidence/candidate/first-control/stdout.jsonl
deleted file mode 100644
index a668538e..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/first-control/stdout.jsonl
+++ /dev/null
@@ -1 +0,0 @@
-{"checked":1,"command":"build","errors":0,"exitCode":0,"schema":"edict.cli.event/v1","status":"ok","type":"status"}
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/git-locks-receipt.jsonl b/edict/replace-range-probes/range-assembly/evidence/candidate/git-locks-receipt.jsonl
deleted file mode 100644
index 64b0a110..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/git-locks-receipt.jsonl
+++ /dev/null
@@ -1,2 +0,0 @@
-{"event":"claimed","job":"80747C0A-6071-48B4-AD6C-A901D092CD12","holder":"jim-edict-authoring","note":"Jim RangeAssembly exact source candidate compiler public replay","claimed":1791162935,"expires":1791163835,"paths":["host/docker/echo-read-runtime/","host/heavy-work"],"record":"09627a715eea26c0ac88988e4b6d392ac4492232","acquisition":"1791162935-84725-3066529233"}
-{"event":"released","job":"80747C0A-6071-48B4-AD6C-A901D092CD12","paths":2}
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/guard.log b/edict/replace-range-probes/range-assembly/evidence/candidate/guard.log
deleted file mode 100644
index f1ca3e7e..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/guard.log
+++ /dev/null
@@ -1,5 +0,0 @@
-{"artifactSha256": {"executable-operation-package.cbor": "1860ab8a6cb9a4bfd63a1db99d1c2bc00aa53dae52a9d1998295654379a95d85", "verification-report.cbor": "d96e5d21eecbc1e5bbf6ce76ab438d55cc8e74f6843121d4ffb0f4343e648267"}, "artifacts": ["executable-operation-package.cbor", "verification-report.cbor"], "case": "baseline", "diagnostics": [], "exitCode": 0, "sourceSha256": "51797e77062585a9f59083ee8a1da3faaf486ef7691e1b62203369a9d9356ee0", "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61"}
-{"artifactSha256": {"executable-operation-package.cbor": "d950cebad1bb978e24dfa736efab302eb0f5c96135cb32f27ad8781d6ace6b51", "verification-report.cbor": "412fb923e3dbd3f070624446ae953920058e08eda5fdc94f201d9b475842c803"}, "artifacts": ["executable-operation-package.cbor", "verification-report.cbor"], "case": "first-control", "diagnostics": [], "exitCode": 0, "sourceSha256": "fa207e40f734fce99c581efbc5159a276c95e7b399d3acce854829ace05c6d2e", "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61"}
-{"artifactSha256": {"executable-operation-package.cbor": "e75c18f7265ea8fd7390e2e2d4ff49047323e99a07602d80442659d636fd61f4", "verification-report.cbor": "463a47e58e00390937c565413305b4ec553928b86aae2979fbcbf631b55961d9"}, "artifacts": ["executable-operation-package.cbor", "verification-report.cbor"], "case": "second-control", "diagnostics": [], "exitCode": 0, "sourceSha256": "b7bdfce283a977bf2a04ec95d278138a9fbcaeb3e5eedefb909b6d617b1cf8c0", "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61"}
-{"artifactSha256": {"executable-operation-package.cbor": "e889d4680435139fe76f45762f0529c090afcf3d73ef7d17f787d44a49bda534", "verification-report.cbor": "7eec90854e0663aa2346ec5005ff7d05eeb50fc2229b32b407dda3cfa0280077"}, "artifacts": ["executable-operation-package.cbor", "verification-report.cbor"], "case": "assembly", "diagnostics": [], "exitCode": 0, "sourceSha256": "8e8d2703759fb30cb49b73650ba8ddfd637d68b33b86145661bfca3033c968fc", "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61"}
-JIM_RANGE_ASSEMBLY_CANDIDATE_OBSERVED package-and-report-produced
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/guard.result.json b/edict/replace-range-probes/range-assembly/evidence/candidate/guard.result.json
deleted file mode 100644
index 1a395a0b..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/guard.result.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "measurements": {
-    "build": 7053634163,
-    "data": 2900191859,
-    "logs": 8645095,
-    "host_free": 718933827584,
-    "vm_free": 684305022976
-  },
-  "exit_code": 0
-}
\ No newline at end of file
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/portable-git-locks-receipt.jsonl b/edict/replace-range-probes/range-assembly/evidence/candidate/portable-git-locks-receipt.jsonl
deleted file mode 100644
index 756508a7..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/portable-git-locks-receipt.jsonl
+++ /dev/null
@@ -1,2 +0,0 @@
-{"event":"claimed","job":"A26105DF-83F3-425C-9B47-9AF022715D45","holder":"jim-edict-authoring","note":"Replay portable RangeAssembly package harness and preserve exact evidence","claimed":1791163732,"expires":1791164632,"paths":["host/docker/echo-read-runtime/","host/heavy-work"],"record":"70633e7bdf3697cf733b40aec3f88e420104b419","acquisition":"1791163732-09781-0278023995"}
-{"event":"released","job":"A26105DF-83F3-425C-9B47-9AF022715D45","paths":2}
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/portable-guard.log b/edict/replace-range-probes/range-assembly/evidence/candidate/portable-guard.log
deleted file mode 100644
index a0427953..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/portable-guard.log
+++ /dev/null
@@ -1,5 +0,0 @@
-{"artifactSha256": {"executable-operation-package.cbor": "1860ab8a6cb9a4bfd63a1db99d1c2bc00aa53dae52a9d1998295654379a95d85", "verification-report.cbor": "d96e5d21eecbc1e5bbf6ce76ab438d55cc8e74f6843121d4ffb0f4343e648267"}, "artifacts": ["executable-operation-package.cbor", "verification-report.cbor"], "case": "baseline", "diagnostics": [], "exitCode": 0, "sourceSha256": "51797e77062585a9f59083ee8a1da3faaf486ef7691e1b62203369a9d9356ee0", "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61"}
-{"artifactSha256": {"executable-operation-package.cbor": "d950cebad1bb978e24dfa736efab302eb0f5c96135cb32f27ad8781d6ace6b51", "verification-report.cbor": "412fb923e3dbd3f070624446ae953920058e08eda5fdc94f201d9b475842c803"}, "artifacts": ["executable-operation-package.cbor", "verification-report.cbor"], "case": "first-control", "diagnostics": [], "exitCode": 0, "sourceSha256": "fa207e40f734fce99c581efbc5159a276c95e7b399d3acce854829ace05c6d2e", "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61"}
-{"artifactSha256": {"executable-operation-package.cbor": "e75c18f7265ea8fd7390e2e2d4ff49047323e99a07602d80442659d636fd61f4", "verification-report.cbor": "463a47e58e00390937c565413305b4ec553928b86aae2979fbcbf631b55961d9"}, "artifacts": ["executable-operation-package.cbor", "verification-report.cbor"], "case": "second-control", "diagnostics": [], "exitCode": 0, "sourceSha256": "b7bdfce283a977bf2a04ec95d278138a9fbcaeb3e5eedefb909b6d617b1cf8c0", "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61"}
-{"artifactSha256": {"executable-operation-package.cbor": "e889d4680435139fe76f45762f0529c090afcf3d73ef7d17f787d44a49bda534", "verification-report.cbor": "7eec90854e0663aa2346ec5005ff7d05eeb50fc2229b32b407dda3cfa0280077"}, "artifacts": ["executable-operation-package.cbor", "verification-report.cbor"], "case": "assembly", "diagnostics": [], "exitCode": 0, "sourceSha256": "8e8d2703759fb30cb49b73650ba8ddfd637d68b33b86145661bfca3033c968fc", "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61"}
-JIM_RANGE_ASSEMBLY_PACKAGE_BOUNDARY_CONFIRMED
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/portable-guard.result.json b/edict/replace-range-probes/range-assembly/evidence/candidate/portable-guard.result.json
deleted file mode 100644
index a13a0edc..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/portable-guard.result.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "measurements": {
-    "build": 7060787839,
-    "data": 2904236671,
-    "logs": 8950064,
-    "host_free": 718894419968,
-    "vm_free": 683224801280
-  },
-  "exit_code": 0
-}
\ No newline at end of file
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/portable-public-build.json b/edict/replace-range-probes/range-assembly/evidence/candidate/portable-public-build.json
deleted file mode 100644
index f23fd1cf..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/portable-public-build.json
+++ /dev/null
@@ -1,72 +0,0 @@
-{
-  "compiler": {
-    "commit": "01dc5abb9a8a74f8fd8b0e0a6d1041d0adb86d6e",
-    "tree": "74e571125a1da6ac5b2eac80944e343811708d51",
-    "fileCount": 449,
-    "manifestSha256": "bce253363396aad59ed3a7e51634ab1cc357c80972fc8e1ebad3a004fff3de11",
-    "binarySha256": "e2700698829b03f437c66425ed9878b002ef7a34ac183a39bac4eaf6a758cc6d"
-  },
-  "providerManifestSha256": "c5b9fb2fe3a0dc4dad282621a97413225c555be0071f3502b3272952069d42dc",
-  "results": {
-    "baseline": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "51797e77062585a9f59083ee8a1da3faaf486ef7691e1b62203369a9d9356ee0",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "1860ab8a6cb9a4bfd63a1db99d1c2bc00aa53dae52a9d1998295654379a95d85",
-        "verification-report.cbor": "d96e5d21eecbc1e5bbf6ce76ab438d55cc8e74f6843121d4ffb0f4343e648267"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "first-control": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "fa207e40f734fce99c581efbc5159a276c95e7b399d3acce854829ace05c6d2e",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "d950cebad1bb978e24dfa736efab302eb0f5c96135cb32f27ad8781d6ace6b51",
-        "verification-report.cbor": "412fb923e3dbd3f070624446ae953920058e08eda5fdc94f201d9b475842c803"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "second-control": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "b7bdfce283a977bf2a04ec95d278138a9fbcaeb3e5eedefb909b6d617b1cf8c0",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "e75c18f7265ea8fd7390e2e2d4ff49047323e99a07602d80442659d636fd61f4",
-        "verification-report.cbor": "463a47e58e00390937c565413305b4ec553928b86aae2979fbcbf631b55961d9"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "assembly": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "8e8d2703759fb30cb49b73650ba8ddfd637d68b33b86145661bfca3033c968fc",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "e889d4680435139fe76f45762f0529c090afcf3d73ef7d17f787d44a49bda534",
-        "verification-report.cbor": "7eec90854e0663aa2346ec5005ff7d05eeb50fc2229b32b407dda3cfa0280077"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    }
-  }
-}
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/public-build.json b/edict/replace-range-probes/range-assembly/evidence/candidate/public-build.json
deleted file mode 100644
index 0f239271..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/public-build.json
+++ /dev/null
@@ -1,75 +0,0 @@
-{
-  "compiler": {
-    "commit": "01dc5abb9a8a74f8fd8b0e0a6d1041d0adb86d6e",
-    "tree": "74e571125a1da6ac5b2eac80944e343811708d51",
-    "fileCount": 449,
-    "manifestSha256": "22e4cc00473d2ccd3db80fe1f1de2ed8377f8a976df1fd05117eac649e77c529",
-    "binarySha256": "e2700698829b03f437c66425ed9878b002ef7a34ac183a39bac4eaf6a758cc6d"
-  },
-  "jimSourceCommit": "e9ac7433c12d995743c109fd3cf6bcec46f9bca7",
-  "providerManifestSha256": "c5b9fb2fe3a0dc4dad282621a97413225c555be0071f3502b3272952069d42dc",
-  "boundary": "Public compiler build and provider package/report only; runtime not exercised.",
-  "results": {
-    "baseline": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "51797e77062585a9f59083ee8a1da3faaf486ef7691e1b62203369a9d9356ee0",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "1860ab8a6cb9a4bfd63a1db99d1c2bc00aa53dae52a9d1998295654379a95d85",
-        "verification-report.cbor": "d96e5d21eecbc1e5bbf6ce76ab438d55cc8e74f6843121d4ffb0f4343e648267"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "first-control": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "fa207e40f734fce99c581efbc5159a276c95e7b399d3acce854829ace05c6d2e",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "d950cebad1bb978e24dfa736efab302eb0f5c96135cb32f27ad8781d6ace6b51",
-        "verification-report.cbor": "412fb923e3dbd3f070624446ae953920058e08eda5fdc94f201d9b475842c803"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "second-control": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "b7bdfce283a977bf2a04ec95d278138a9fbcaeb3e5eedefb909b6d617b1cf8c0",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "e75c18f7265ea8fd7390e2e2d4ff49047323e99a07602d80442659d636fd61f4",
-        "verification-report.cbor": "463a47e58e00390937c565413305b4ec553928b86aae2979fbcbf631b55961d9"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "assembly": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "8e8d2703759fb30cb49b73650ba8ddfd637d68b33b86145661bfca3033c968fc",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "e889d4680435139fe76f45762f0529c090afcf3d73ef7d17f787d44a49bda534",
-        "verification-report.cbor": "7eec90854e0663aa2346ec5005ff7d05eeb50fc2229b32b407dda3cfa0280077"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    }
-  },
-  "assemblyOutcome": "package-and-report-produced"
-}
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/second-control/application/executable-operation-package.cbor b/edict/replace-range-probes/range-assembly/evidence/candidate/second-control/application/executable-operation-package.cbor
deleted file mode 100644
index e42ff61b..00000000
Binary files a/edict/replace-range-probes/range-assembly/evidence/candidate/second-control/application/executable-operation-package.cbor and /dev/null differ
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/second-control/application/verification-report.cbor b/edict/replace-range-probes/range-assembly/evidence/candidate/second-control/application/verification-report.cbor
deleted file mode 100644
index 65cb7a56..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/second-control/application/verification-report.cbor
+++ /dev/null
@@ -1 +0,0 @@
-¨goutcomehacceptedgpackage¢bidx!executable-operation-package.echofdigest‚fsha256X G_€õwc$e<)¦œD€?°f¿™²f)sÚ¹5å�[htargetIr¢bidoecho.span-ir/v1fdigest‚fsha256X ÊÊ eU	OôL¦ƒÍ퀕o%wŸRÚ8CŠÌb‘]njapiVersionx)echo.operation-package-verifier-report/v1mdiagnosticAbi¢bidtedict.diagnostics/v1fdigest‚fsha256X (ýr©‚#9‚ÊL)Û±²Ô0b9g«;m¹×þæhæ¹odiagnosticBytes@qexecutableSubject¢ebytesYR¤gpackage¢bidx!executable-operation-package.echofdigest‚fsha256X G_€õwc$e<)¦œD€?°f¿™²f)sÚ¹5å�[htargetIr¢bidoecho.span-ir/v1fdigest‚fsha256X ÊÊ eU	OôL¦ƒÍ퀕o%wŸRÚ8CŠÌb‘]njapiVersionxecho.executable-subject/v1xapplicationResultProjection¢bidx(jedit.text.replace_range@1.assembleRangefdigest‚fsha256X ¸{¡��ò„(�²0è_FPº8â2‚šÕŽŠkü¿å••ireference¢bidxecho.executable-subject/v1fdigest‚fsha256X nÕ¯äRÑUn×Û Æz™I»2ÝÚF¾€¸ª€±(¼ÃÈ¡xapplicationResultProjection¢bidx(jedit.text.replace_range@1.assembleRangefdigest‚fsha256X ¸{¡��ò„(�²0è_FPº8â2‚šÕŽŠkü¿å••
\ No newline at end of file
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/second-control/stderr.jsonl b/edict/replace-range-probes/range-assembly/evidence/candidate/second-control/stderr.jsonl
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/range-assembly/evidence/candidate/second-control/stdout.jsonl b/edict/replace-range-probes/range-assembly/evidence/candidate/second-control/stdout.jsonl
deleted file mode 100644
index a668538e..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/candidate/second-control/stdout.jsonl
+++ /dev/null
@@ -1 +0,0 @@
-{"checked":1,"command":"build","errors":0,"exitCode":0,"schema":"edict.cli.event/v1","status":"ok","type":"status"}
diff --git a/edict/replace-range-probes/range-assembly/evidence/compiler-source.json b/edict/replace-range-probes/range-assembly/evidence/compiler-source.json
deleted file mode 100644
index ed4a8f2c..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/compiler-source.json
+++ /dev/null
@@ -1,1790 +0,0 @@
-{
-  "commit": "ac836e5c42a5c47b0dab30cfb0b09848cca73215",
-  "tree": "dadd4703a9905a37ff366c7134aea5cfe351e2fd",
-  "files": [
-    {
-      "path": ".cargo/config.toml",
-      "gitBlob": "5592118f6c54bf8b53b16848e04ece896dd56384"
-    },
-    {
-      "path": ".github/workflows/auto-release-tag.yml",
-      "gitBlob": "87404ceb685191afd496c93494b0bc61e2a59504"
-    },
-    {
-      "path": ".github/workflows/ci.yml",
-      "gitBlob": "c6c6a17f59b6b96db88e3d4b2775bc64b7fe01f3"
-    },
-    {
-      "path": ".github/workflows/release.yml",
-      "gitBlob": "2c612fc786998bfa5b11e76ae1185114a7cc535f"
-    },
-    {
-      "path": ".gitignore",
-      "gitBlob": "30d7faf0fc8b7f010f99280302d4ed269d5da9ba"
-    },
-    {
-      "path": ".markdownlint.json",
-      "gitBlob": "f3ec2c8dc2fbacc425154a2baedec50c7474aefa"
-    },
-    {
-      "path": "AGENTS.md",
-      "gitBlob": "0c48a5794454cf84e20640994a372316efde7bb5"
-    },
-    {
-      "path": "ARCHITECTURE.md",
-      "gitBlob": "5b513dd25028092e7e75c8974f1d5f3cc31889ed"
-    },
-    {
-      "path": "CHANGELOG.md",
-      "gitBlob": "10a05a5561d05b79d087c2b660271e08d799771b"
-    },
-    {
-      "path": "CODE_OF_CONDUCT.md",
-      "gitBlob": "784cf2799bcf8d2a69db5f5781359ef7e18a05fc"
-    },
-    {
-      "path": "CONTRIBUTING.md",
-      "gitBlob": "9676914060f734dc59eabd9075898dc8170d4d19"
-    },
-    {
-      "path": "Cargo.lock",
-      "gitBlob": "bacb208de0583f182379af7b5e078d31b25e2ca5"
-    },
-    {
-      "path": "Cargo.toml",
-      "gitBlob": "b2e7106eb78f79230c091492ef21b497bdc9ed19"
-    },
-    {
-      "path": "EDICT.md",
-      "gitBlob": "35376134195082d506f0161ba7ecb97efa8b770a"
-    },
-    {
-      "path": "LICENSE",
-      "gitBlob": "261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64"
-    },
-    {
-      "path": "NOTICE",
-      "gitBlob": "c300687bdd9d931d1f257d291e1cb6ff9d7d3607"
-    },
-    {
-      "path": "README.md",
-      "gitBlob": "0812ef9a0c4611bf655dfc67d2ecc3631af9a536"
-    },
-    {
-      "path": "ROADMAP.md",
-      "gitBlob": "d0e0135780537afab1d1a3f53808b363b35a63f4"
-    },
-    {
-      "path": "SECURITY.md",
-      "gitBlob": "0bcc4e7375442e1334405a2d046df316cee05cd5"
-    },
-    {
-      "path": "crates/edict-cli/Cargo.toml",
-      "gitBlob": "e9d844553c395bd312f84e806eb5bac30c5c3a54"
-    },
-    {
-      "path": "crates/edict-cli/src/application_build.rs",
-      "gitBlob": "9c56ae6b4dd4eef0b9fe6db40316e100b2ffa699"
-    },
-    {
-      "path": "crates/edict-cli/src/lawpack_build.rs",
-      "gitBlob": "55e9579153f34a3d5b139141c9de6640808cd386"
-    },
-    {
-      "path": "crates/edict-cli/src/lawpack_build_windows.rs",
-      "gitBlob": "f71d03b368ae83becc1608bbba11cd5f1afa4f07"
-    },
-    {
-      "path": "crates/edict-cli/src/lib.rs",
-      "gitBlob": "60883af60cf4b441680952ecce7ef4fcbfeabb97"
-    },
-    {
-      "path": "crates/edict-cli/src/main.rs",
-      "gitBlob": "0dd9776642c4090479322111e4164ee7049fb9d0"
-    },
-    {
-      "path": "crates/edict-cli/tests/golden_cli.rs",
-      "gitBlob": "9897caad3bcc6fa8bb0f20a1d0e18032285b1fa7"
-    },
-    {
-      "path": "crates/edict-cli/tests/jsonl_cli.rs",
-      "gitBlob": "9ed353ca27d073fc7da49d3800c81ba4c58edd5d"
-    },
-    {
-      "path": "crates/edict-cli/tests/lawpack_authoring_cli.rs",
-      "gitBlob": "dd7d7bfebf0e051c77d894a55c0204d373b19c63"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/Cargo.toml",
-      "gitBlob": "ebeeb941f09012293d9923fe0e6039b2761b328e"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/conversion.rs",
-      "gitBlob": "62c3cd4a85eb156b8c9a405ef3ea4d8a09b80cc3"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/invocation.rs",
-      "gitBlob": "a4d6680d289094afebc0f1063abccf706f8149db"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/lib.rs",
-      "gitBlob": "353ea7394f265219ebdecad56a3070c9e7d2685c"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/limits.rs",
-      "gitBlob": "9e4d12c1b606d2b180f732db17bfbc78f8e26e3a"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/src/replay.rs",
-      "gitBlob": "b8fa7be7c7ee5039793dad4cd0fa6a4f14ce388e"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/tests/invocation.rs",
-      "gitBlob": "7a59a3192852a80bc01221ebf3dd1c437bda9508"
-    },
-    {
-      "path": "crates/edict-provider-host-wasmtime/tests/preflight.rs",
-      "gitBlob": "a295e7547b0294f0355a85d5b9b8d045c8fceefd"
-    },
-    {
-      "path": "crates/edict-provider-schema/Cargo.toml",
-      "gitBlob": "0e74f58acdc054ecce192cb8341afeaddc40deb5"
-    },
-    {
-      "path": "crates/edict-provider-schema/src/contract_pack.rs",
-      "gitBlob": "370480d9c606134dd08ee62ae29ef143941e2f54"
-    },
-    {
-      "path": "crates/edict-provider-schema/src/lib.rs",
-      "gitBlob": "51f5bee8892c9fb2122cb20022edc4d414759ff7"
-    },
-    {
-      "path": "crates/edict-provider-schema/src/recursive_dispatch.rs",
-      "gitBlob": "6d97565b96f941b359d16f7a1c201189968fbeff"
-    },
-    {
-      "path": "crates/edict-provider-schema/src/schema_safety.rs",
-      "gitBlob": "a2f605f62a2bfedcb84b68e37db9ff84b1dc3b05"
-    },
-    {
-      "path": "crates/edict-provider-schema/tests/authority_facts_abi.rs",
-      "gitBlob": "7dd4d0302805ceecffc2045cdb91e386f8e08517"
-    },
-    {
-      "path": "crates/edict-provider-schema/tests/provider_contract_pack.rs",
-      "gitBlob": "a26be8054b39215048825dd8cae7e9bddcfe27c9"
-    },
-    {
-      "path": "crates/edict-provider-schema/tests/registry.rs",
-      "gitBlob": "bdd13ec00e441aef9e67ba49f6592ecbc7dcb303"
-    },
-    {
-      "path": "crates/edict-syntax/Cargo.toml",
-      "gitBlob": "f55bb23e528af78b1e97b52f9b72cbd876a44ba7"
-    },
-    {
-      "path": "crates/edict-syntax/src/admission.rs",
-      "gitBlob": "471430dd13a617bac886fcd44afbf15263e7db3b"
-    },
-    {
-      "path": "crates/edict-syntax/src/ast.rs",
-      "gitBlob": "2a5d208a53a82408f8a18d9a13ccb133ec6a7a2e"
-    },
-    {
-      "path": "crates/edict-syntax/src/authority_facts.rs",
-      "gitBlob": "644de86d63983bdbfbf1279fdbf1dbdaecc151d5"
-    },
-    {
-      "path": "crates/edict-syntax/src/canonical.rs",
-      "gitBlob": "6fb29d50ea4a55eb888a1b9600cdcb31713a6e20"
-    },
-    {
-      "path": "crates/edict-syntax/src/compiler.rs",
-      "gitBlob": "ad3efd3e92c23a54a9a279cbfa22b108895af3fb"
-    },
-    {
-      "path": "crates/edict-syntax/src/compiler/byte_length.rs",
-      "gitBlob": "0d8d6291064415baee9253d9fe1e11ad87945773"
-    },
-    {
-      "path": "crates/edict-syntax/src/compiler/byte_slice.rs",
-      "gitBlob": "84385fffdf4e38e21285e1fde252e9185a3a76fa"
-    },
-    {
-      "path": "crates/edict-syntax/src/compiler/unsigned_subtraction.rs",
-      "gitBlob": "c2ef2deda74afb52e4346076a310df341556e1c8"
-    },
-    {
-      "path": "crates/edict-syntax/src/contract_bundle.rs",
-      "gitBlob": "9a31645f0e30879d019787e29c21c82eebf58129"
-    },
-    {
-      "path": "crates/edict-syntax/src/core_ir.rs",
-      "gitBlob": "4c6f350b325d13a27947687dd1f4114edf6d548d"
-    },
-    {
-      "path": "crates/edict-syntax/src/highlight.rs",
-      "gitBlob": "28b3f7dcdfe8d4982bdcfb05759f769ccdbffc7f"
-    },
-    {
-      "path": "crates/edict-syntax/src/lawpack.rs",
-      "gitBlob": "54f85bda48c960ad0b7bc316d332b379ab5b6ae0"
-    },
-    {
-      "path": "crates/edict-syntax/src/lawpack_adapter.rs",
-      "gitBlob": "e425960e2437faa2f9eeb5d089ff507417d39586"
-    },
-    {
-      "path": "crates/edict-syntax/src/lawpack_authoring.rs",
-      "gitBlob": "11ff578f458b8a4c8e4df75c0c616e37fa468d49"
-    },
-    {
-      "path": "crates/edict-syntax/src/lib.rs",
-      "gitBlob": "7323475cc7f846e11c2d73f4c26a5e581b7e6157"
-    },
-    {
-      "path": "crates/edict-syntax/src/lowerability.rs",
-      "gitBlob": "c6a1323fd6a79b0460b43aaf338956c3906a633e"
-    },
-    {
-      "path": "crates/edict-syntax/src/parser.rs",
-      "gitBlob": "0b3650e3012e49023ccbb9cc9effe9b5b102f19d"
-    },
-    {
-      "path": "crates/edict-syntax/src/provider.rs",
-      "gitBlob": "18fa661d880979c53dd335fb7e68d5445b638d4c"
-    },
-    {
-      "path": "crates/edict-syntax/src/provider_invocation.rs",
-      "gitBlob": "2526168f0a6f2d1d9b6181b689ff43e203434122"
-    },
-    {
-      "path": "crates/edict-syntax/src/provider_lowering.rs",
-      "gitBlob": "50a4e60b561127cb8c78e3f7c04c6bbaca068e52"
-    },
-    {
-      "path": "crates/edict-syntax/src/result_projection.rs",
-      "gitBlob": "79ba246d4c58960fe368eaca4c7d135fe187832a"
-    },
-    {
-      "path": "crates/edict-syntax/src/semantic.rs",
-      "gitBlob": "76bd133ef5859bf7722d1987613f7fd84836ab62"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir.rs",
-      "gitBlob": "c322a874d8a2341ae46a99b1b62eb952f4a49dfe"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/byte_length.rs",
-      "gitBlob": "972e6ffa943bc7a7a943d76f0af42b342e3d2aac"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/byte_slice.rs",
-      "gitBlob": "62a1c0b9e84a331bb17ab78090cce6d8eb8da486"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/execution_order.rs",
-      "gitBlob": "e69a28805dc5e414a64afdaafee34161c217a044"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/totality.rs",
-      "gitBlob": "a4fb9573d59e1a4bb9d7c250402c5b7e1da0a8c3"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_ir/unsigned_subtraction.rs",
-      "gitBlob": "b83522bfe9a2b506413b4d306f4bc49f8b053f36"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_profile.rs",
-      "gitBlob": "dd514f7380243e795f0655a78aecd06ee3fa2eda"
-    },
-    {
-      "path": "crates/edict-syntax/src/target_profile_contract_resources.rs",
-      "gitBlob": "4efd22961c2fd7591440efd6087944ecaf21e991"
-    },
-    {
-      "path": "crates/edict-syntax/src/token.rs",
-      "gitBlob": "2768586eea6d42d5df357c4cc62a011ee7f455de"
-    },
-    {
-      "path": "crates/edict-syntax/tests/admission.rs",
-      "gitBlob": "57edbc320307c1d6daba85f03d8dc79558d7b849"
-    },
-    {
-      "path": "crates/edict-syntax/tests/authority_facts.rs",
-      "gitBlob": "add9d272be6e8eb1cd6fdde2999a5fb452ecd852"
-    },
-    {
-      "path": "crates/edict-syntax/tests/authority_facts_cbor.rs",
-      "gitBlob": "7359f047d9f731fee208efb5f69072b612d69547"
-    },
-    {
-      "path": "crates/edict-syntax/tests/byte_length.rs",
-      "gitBlob": "50945944e8c2223abcc6b1081322432bc540c017"
-    },
-    {
-      "path": "crates/edict-syntax/tests/byte_slice.rs",
-      "gitBlob": "99aae98ac1637a95532cdd833463210bbaa5a5be"
-    },
-    {
-      "path": "crates/edict-syntax/tests/canonical_encoding.rs",
-      "gitBlob": "e4c5d59a88f88193f522eb555359919f7034a264"
-    },
-    {
-      "path": "crates/edict-syntax/tests/common/mod.rs",
-      "gitBlob": "89560bfacb3dab031485c2dfa30d7eb325966574"
-    },
-    {
-      "path": "crates/edict-syntax/tests/compiler_spine.rs",
-      "gitBlob": "2237318cfc0d4209e8a629e45320e42a4b72dbef"
-    },
-    {
-      "path": "crates/edict-syntax/tests/contract_bundle.rs",
-      "gitBlob": "e6a2948335a0efc86d8bbb2e9e2c3d634e53965a"
-    },
-    {
-      "path": "crates/edict-syntax/tests/core_golden_fixtures.rs",
-      "gitBlob": "0e0e42d19b52dc0557902dad9e1b85f37edf53f8"
-    },
-    {
-      "path": "crates/edict-syntax/tests/core_graph_depth.rs",
-      "gitBlob": "1d95462ad2426d29b5974e6bb56ab8c125a92837"
-    },
-    {
-      "path": "crates/edict-syntax/tests/external_action_requests.rs",
-      "gitBlob": "20aac8c03325ea0cdab8f4f54660cb980b4667c4"
-    },
-    {
-      "path": "crates/edict-syntax/tests/highlighting.rs",
-      "gitBlob": "17e6b9ba08c96f0efb6efd440590f0fc917316e2"
-    },
-    {
-      "path": "crates/edict-syntax/tests/lawpack.rs",
-      "gitBlob": "a675999ed96309358c8552a9d32781b5eede20dc"
-    },
-    {
-      "path": "crates/edict-syntax/tests/lawpack_authoring.rs",
-      "gitBlob": "3a905cbd6d7d2625bc1d7826a6f6f1e991efbab0"
-    },
-    {
-      "path": "crates/edict-syntax/tests/lowerability.rs",
-      "gitBlob": "5cfa58f5cbc51cccc7f119caddc1c3fcbc2e4806"
-    },
-    {
-      "path": "crates/edict-syntax/tests/operation_prerequisites.rs",
-      "gitBlob": "753659e1a6e7751c455b8518226fa0902157a745"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_control_flow.rs",
-      "gitBlob": "5245561866d8902c1fbd5ab21f2e34807d568e17"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_greeting.rs",
-      "gitBlob": "f214d0c17745b8203d562780caa8f37b71c1e62c"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_hello.rs",
-      "gitBlob": "bf7b1b065277188f4be8754eb11ace94298394ba"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_keywords.rs",
-      "gitBlob": "78d8a64d785136d42a32655afda3df240c54f884"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_loops.rs",
-      "gitBlob": "d9ece2fce96fd6835d080055f06955d139c7e0ce"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_negative.rs",
-      "gitBlob": "17fdb983b8250470368a8f19d3a7bd9680052548"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_review_regressions.rs",
-      "gitBlob": "560215cfe044a528e190aa1ea7670e52b9365bdf"
-    },
-    {
-      "path": "crates/edict-syntax/tests/parse_variants.rs",
-      "gitBlob": "8849f68f5ca1e2b06d0f66496e59b20d1c0fd022"
-    },
-    {
-      "path": "crates/edict-syntax/tests/provider.rs",
-      "gitBlob": "7e8a596109b1e1fd3f22b3a0ef82f4755f127291"
-    },
-    {
-      "path": "crates/edict-syntax/tests/provider_invocation.rs",
-      "gitBlob": "402647dd6701be65a9e693fd3f5688f26d84988e"
-    },
-    {
-      "path": "crates/edict-syntax/tests/provider_lowering.rs",
-      "gitBlob": "411c306f3ab641de9dc2f7aed229767eba9dbd72"
-    },
-    {
-      "path": "crates/edict-syntax/tests/result_projection.rs",
-      "gitBlob": "a74dd2a419266cb77d846d83da27f726095660f1"
-    },
-    {
-      "path": "crates/edict-syntax/tests/semantic_validation.rs",
-      "gitBlob": "a127988d178c00ed12a0a25f70df6b7fd5e6d931"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_ir.rs",
-      "gitBlob": "928e1cf921dead0b559bd115bb6eef3faaddd37e"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_ir/ordered.rs",
-      "gitBlob": "a1b05db81a97a43ec5a2dc2d9bcc9578bc286f30"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_profile.rs",
-      "gitBlob": "42f1c907f6c60dea1e8a9b4558b56ffd0b3a59ab"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_profile_contract_resources.rs",
-      "gitBlob": "270c180a12dc10fb7e208cc4dc1e202da82c85fb"
-    },
-    {
-      "path": "crates/edict-syntax/tests/target_unsigned_subtraction.rs",
-      "gitBlob": "e30d91f896afda48eb3cf11617bccf1f9d160e32"
-    },
-    {
-      "path": "crates/edict-syntax/tests/unsigned_subtraction.rs",
-      "gitBlob": "fbd24482fdad4c8ceb4df41302b33595ada337ec"
-    },
-    {
-      "path": "crates/edict/Cargo.toml",
-      "gitBlob": "525403f4f36db4040531e4dd747ec2398f9052cd"
-    },
-    {
-      "path": "crates/edict/README.md",
-      "gitBlob": "a1ecf50bff3443d25a23fabfa6374d3f0a28ca82"
-    },
-    {
-      "path": "crates/edict/src/lib.rs",
-      "gitBlob": "169d820759d6333f27a45ebb712bfcc4f0115107"
-    },
-    {
-      "path": "crates/edict/tests/artifact_models.rs",
-      "gitBlob": "b923109c7195ce2c0071dc54179f0746b95329f0"
-    },
-    {
-      "path": "crates/edict/tests/public_surface.rs",
-      "gitBlob": "a24c4bc9d9484f540da9b280790896701922968a"
-    },
-    {
-      "path": "deny.toml",
-      "gitBlob": "e3f0f54060cead9a0d48b96ed86948d0909c4f78"
-    },
-    {
-      "path": "docs/DESIGN_runtime-neutral-edict-sha-lock-assurance.md",
-      "gitBlob": "ea3badf78ebd19545147a93671fdb5f9af4a61ea"
-    },
-    {
-      "path": "docs/GUIDE_edict-assurance-transparency.md",
-      "gitBlob": "100321157ec43055c45794f1c161b1e5281ba6b4"
-    },
-    {
-      "path": "docs/README.md",
-      "gitBlob": "e21739b842be14d91a17f2508b1a1b629754af01"
-    },
-    {
-      "path": "docs/REQUIREMENTS.md",
-      "gitBlob": "52d98fecd60eb04ce55105ae2eb33997248698cb"
-    },
-    {
-      "path": "docs/RETRO_phase1-parser.md",
-      "gitBlob": "5cfb7b85ca2f140fc58f9186c47e4635e94a1e6f"
-    },
-    {
-      "path": "docs/SPEC_continuum-admission-v1.md",
-      "gitBlob": "0a74a0bfc642337d5d7a85133ce50a0a22caffbd"
-    },
-    {
-      "path": "docs/SPEC_continuum-contract-bundle-v1.md",
-      "gitBlob": "65b36bb33a34beb1f246d1f97384631c83ca631e"
-    },
-    {
-      "path": "docs/SPEC_edict-language-v1.md",
-      "gitBlob": "37ac2382f6ed09b314e64cce819a4de8c6fb7321"
-    },
-    {
-      "path": "docs/SPEC_edict-lawpack-abi-v1.md",
-      "gitBlob": "ea1d801f07ab3677f7a411a1f58a28feda589ec3"
-    },
-    {
-      "path": "docs/SPEC_edict-target-profile-abi-v1.md",
-      "gitBlob": "91687bfe45565a21f5f93f6ce9eed84095268691"
-    },
-    {
-      "path": "docs/TECHNICAL_EXPLANATION.md",
-      "gitBlob": "d88561c0552c0e75d1ecc2eef6f9afd003e99674"
-    },
-    {
-      "path": "docs/abi/edict-authority-facts.cddl",
-      "gitBlob": "e9a6d8685706ae0d8dabda401655234161e94299"
-    },
-    {
-      "path": "docs/abi/edict-common.cddl",
-      "gitBlob": "836c11b92425beb6d42b378c0defe6f02d144dd7"
-    },
-    {
-      "path": "docs/abi/edict-core.cddl",
-      "gitBlob": "862f02939fcc3858b4a60cb75f9bf149eae8ffda"
-    },
-    {
-      "path": "docs/abi/edict-lawpack-adapter.cddl",
-      "gitBlob": "8e887c2e196ba7502470ddb45dc7cfd10116ad6b"
-    },
-    {
-      "path": "docs/abi/edict-lawpack.cddl",
-      "gitBlob": "96efd51d437ec785b108b51835e9e8bf87aeab51"
-    },
-    {
-      "path": "docs/abi/edict-result-projection.cddl",
-      "gitBlob": "98b5c2e861e7e9b66b7481502287cb041f6e77e6"
-    },
-    {
-      "path": "docs/abi/edict-target-ir.cddl",
-      "gitBlob": "98134f277ded1920a3a36e5e3946c51153f2e84d"
-    },
-    {
-      "path": "docs/abi/edict-target-profile.cddl",
-      "gitBlob": "746ae03001310f3a83524e5332819dad1a4eea5a"
-    },
-    {
-      "path": "docs/abi/edict-target-provider.wit",
-      "gitBlob": "0efa5903a52d38dc61e429619d86322c6c5f1fa0"
-    },
-    {
-      "path": "docs/audit/2026-06-28_code-quality.md",
-      "gitBlob": "143cbf4f4491a76a6649e919c6edaba73f0bcf4b"
-    },
-    {
-      "path": "docs/audit/2026-06-28_documentation-quality.md",
-      "gitBlob": "656b4fa8dea43306af1818f8622cafd72e82a370"
-    },
-    {
-      "path": "docs/audit/2026-06-28_ship-readiness.md",
-      "gitBlob": "b9d34a8693564d0134f550092e7645e5d5137442"
-    },
-    {
-      "path": "docs/design/authority-fact-governance.md",
-      "gitBlob": "8531061cf718c47ec791f5712b2f357d92adc9e4"
-    },
-    {
-      "path": "docs/design/canonical-target-ir-v0.11.md",
-      "gitBlob": "a46acb84e3523b51e2348c776cfdb63a8b98107a"
-    },
-    {
-      "path": "docs/design/contract-bundle-assembly-v0.11.md",
-      "gitBlob": "a364f8ade5445808f87cf0c63ab3484c03ad616a"
-    },
-    {
-      "path": "docs/design/crate-scope-v0.11.md",
-      "gitBlob": "92fe92285d02465d84bbe82e29d051fdc461f3a6"
-    },
-    {
-      "path": "docs/design/obstruction-strands-v0.md",
-      "gitBlob": "81f70fd688c12798cd23472a4e810191e61eabe2"
-    },
-    {
-      "path": "docs/design/provider-artifact-pipeline-alpha.md",
-      "gitBlob": "60eefa7dc160aba986bcd1188b79610ff5e9f299"
-    },
-    {
-      "path": "docs/design/schema-as-sot-codegen.md",
-      "gitBlob": "d818e0e3f1fafd1d3aba26cb37c739f3ebe69763"
-    },
-    {
-      "path": "docs/design/v2-obligation-closure.md",
-      "gitBlob": "816d22d843a33c6f7e143da4cb45e80679609dc8"
-    },
-    {
-      "path": "docs/releases/v0.1.0-alpha.1.md",
-      "gitBlob": "5dd96057ba7f109cf5e5acde16e29d18627f98d3"
-    },
-    {
-      "path": "docs/releases/v0.10.0-alpha.1.md",
-      "gitBlob": "363c4e9ed6f5ea5758198c7124681b520098e583"
-    },
-    {
-      "path": "docs/releases/v0.11.0-alpha.1.md",
-      "gitBlob": "4612dbb5a1aaf20710bdb199b658ded7ced4ebab"
-    },
-    {
-      "path": "docs/releases/v0.2.0-alpha.1.md",
-      "gitBlob": "7302ef93ed5ff9b562d9cec92d49d85a6b789b27"
-    },
-    {
-      "path": "docs/releases/v0.3.0-alpha.1.md",
-      "gitBlob": "bf023ba4ca2c38f0120c461781447d58fe239ae0"
-    },
-    {
-      "path": "docs/releases/v0.4.0-alpha.1.md",
-      "gitBlob": "769500b59800c02c536b76b0eb850d06d6cd8f58"
-    },
-    {
-      "path": "docs/releases/v0.5.0-alpha.1.md",
-      "gitBlob": "7c7354e89846ea816992aaf55d4ad04367d61a10"
-    },
-    {
-      "path": "docs/releases/v0.6.0-alpha.1.md",
-      "gitBlob": "3f2a0edfc4bccd9f3c60a7443ef4f8cbcbac1971"
-    },
-    {
-      "path": "docs/releases/v0.7.0-alpha.1.md",
-      "gitBlob": "57671d5ef5a6b9f16d1674e0a35ddeb86ff126a8"
-    },
-    {
-      "path": "docs/releases/v0.8.0-alpha.1.md",
-      "gitBlob": "12f77bda185c54fbbd136bf0dc7292716ecdfa39"
-    },
-    {
-      "path": "docs/releases/v0.9.0-alpha.1.md",
-      "gitBlob": "fa295fcf0967415bb052f238256919b32b3fe6ba"
-    },
-    {
-      "path": "docs/schemas/edict.cli-check-result.v1.schema.json",
-      "gitBlob": "eef8cd11f07e06d68b7051efa60ae05f2cfd8a63"
-    },
-    {
-      "path": "docs/schemas/edict.cli-diagnostic.v1.schema.json",
-      "gitBlob": "92a2151a76893c598a4191ed6cecd8a0e671613f"
-    },
-    {
-      "path": "docs/schemas/edict.cli-event.v1.schema.json",
-      "gitBlob": "705d82a893c2ea91caa91ad6977a9be8646b47bb"
-    },
-    {
-      "path": "docs/schemas/edict.cli-info.v1.schema.json",
-      "gitBlob": "2d9a0777b4190b56ff569625275d352d17363afa"
-    },
-    {
-      "path": "docs/schemas/edict.compiler-input.v1.schema.json",
-      "gitBlob": "26da3ba0fe85fab4c826ad79f13968ce09c4f29b"
-    },
-    {
-      "path": "docs/schemas/edict.compiler-settings.v1.schema.json",
-      "gitBlob": "a3e8ba469895b84ab81724da1075c73141a8dd0c"
-    },
-    {
-      "path": "docs/schemas/edict.projection-core.v1.schema.json",
-      "gitBlob": "8c0afe3834256abd1e18efb5f31eae1c4bdf0374"
-    },
-    {
-      "path": "docs/schemas/edict.projection-diagnostics.v1.schema.json",
-      "gitBlob": "28cfb0a67dff7b8f879122c74433158dc0a4e5df"
-    },
-    {
-      "path": "docs/schemas/edict.projection-syntax.v1.schema.json",
-      "gitBlob": "a85f2e14f536863f5e7b107b1a9f3f10816e6234"
-    },
-    {
-      "path": "docs/schemas/edict.projection-target-ir.v1.schema.json",
-      "gitBlob": "8bbb6495ad8800d775d1c08506e85351038d678a"
-    },
-    {
-      "path": "docs/topics/README.md",
-      "gitBlob": "99b06d3124c71cb62dfe6faff7604c13063162a7"
-    },
-    {
-      "path": "docs/topics/admission/README.md",
-      "gitBlob": "755dcba96c0a428eec18d58a529f3e26d57d118c"
-    },
-    {
-      "path": "docs/topics/admission/test-plan.md",
-      "gitBlob": "68ee0a2d2502103285985bf862de9fadf2bac5a0"
-    },
-    {
-      "path": "docs/topics/assurance/README.md",
-      "gitBlob": "cf382008f3d3094a5380a687abbf07538e07404d"
-    },
-    {
-      "path": "docs/topics/assurance/test-plan.md",
-      "gitBlob": "0ea6c971924db763088577a0a52bbd30bfec814c"
-    },
-    {
-      "path": "docs/topics/authority-facts/README.md",
-      "gitBlob": "c5589d2489d6e4a5729c0df2b2655ff281d8d88d"
-    },
-    {
-      "path": "docs/topics/authority-facts/test-plan.md",
-      "gitBlob": "e3769edf8309347b23ffa2e8f0901e06feabd654"
-    },
-    {
-      "path": "docs/topics/cli/README.md",
-      "gitBlob": "af38946c9ccae8da343877c3861b0f52b6076e1b"
-    },
-    {
-      "path": "docs/topics/cli/test-plan.md",
-      "gitBlob": "d72d69ef1d340ffd7057a63dd7bc07e3dfb2c166"
-    },
-    {
-      "path": "docs/topics/compiler-spine/README.md",
-      "gitBlob": "39e64c586dd8b217b72d481e533f28a7049b3b0d"
-    },
-    {
-      "path": "docs/topics/compiler-spine/test-plan.md",
-      "gitBlob": "73e31cad62f0915a06bf2c6fb40f216e96ea05a7"
-    },
-    {
-      "path": "docs/topics/contract-bundles/README.md",
-      "gitBlob": "2347499e8da9dd57bb1588faf67fe386c7a70c03"
-    },
-    {
-      "path": "docs/topics/contract-bundles/test-plan.md",
-      "gitBlob": "3ae4c7362f90fa89081ab9ff2bf1c3db1a811874"
-    },
-    {
-      "path": "docs/topics/core-ir/README.md",
-      "gitBlob": "d747a18d1f53de2b29473ada7a06b819c77cd162"
-    },
-    {
-      "path": "docs/topics/core-ir/canonical-encoding.md",
-      "gitBlob": "34927c69fb1de10b685294a155fc46bb4ac21628"
-    },
-    {
-      "path": "docs/topics/core-ir/test-plan.md",
-      "gitBlob": "0f80304a4dd6b160c78674b73605bdbbb7e11066"
-    },
-    {
-      "path": "docs/topics/developer-tooling/README.md",
-      "gitBlob": "8648d3c1bdf4f6b774bc5fec71c71aa8c59b0ce8"
-    },
-    {
-      "path": "docs/topics/developer-tooling/test-plan.md",
-      "gitBlob": "9240f717434dfbca08a6366e6d3ebafd4ef2c908"
-    },
-    {
-      "path": "docs/topics/documentation/README.md",
-      "gitBlob": "34fa7f4db136c274a88b680f99619d657fda15d5"
-    },
-    {
-      "path": "docs/topics/documentation/test-plan.md",
-      "gitBlob": "47964954fbf640211bc30b0dd361c44c9955c488"
-    },
-    {
-      "path": "docs/topics/external-action-requests/README.md",
-      "gitBlob": "45bc73e469919d3eff6e7eddbe9baa0383c7d91b"
-    },
-    {
-      "path": "docs/topics/external-action-requests/test-plan.md",
-      "gitBlob": "38e7e53827d223c031d414f4ecd63720eb78eae0"
-    },
-    {
-      "path": "docs/topics/fixtures/README.md",
-      "gitBlob": "c8b3b196109fb6d4e37d8ffa17635166010075fb"
-    },
-    {
-      "path": "docs/topics/fixtures/test-plan.md",
-      "gitBlob": "624357dbc544d365835390d3d3c2f11015b7b82f"
-    },
-    {
-      "path": "docs/topics/lawpack-authoring/README.md",
-      "gitBlob": "74bb25cc22e1f88cf4ee952b42313d919339113a"
-    },
-    {
-      "path": "docs/topics/lawpack-authoring/test-plan.md",
-      "gitBlob": "d7ad2eacde45dbce3eeb2b1a22c6482134b841ba"
-    },
-    {
-      "path": "docs/topics/lawpacks/README.md",
-      "gitBlob": "dedaa524dc55663a44bf8101241ab4b6d4755531"
-    },
-    {
-      "path": "docs/topics/lawpacks/test-plan.md",
-      "gitBlob": "f8aa2c7ce40dad2665134956dc95d951d311808f"
-    },
-    {
-      "path": "docs/topics/lowerability/README.md",
-      "gitBlob": "fb9519af3539d846dc5bf2915bf5ca86816e46f8"
-    },
-    {
-      "path": "docs/topics/lowerability/test-plan.md",
-      "gitBlob": "e0fbff0799ba805c9531097d6b8aeea657e2b815"
-    },
-    {
-      "path": "docs/topics/obstruction-strands/README.md",
-      "gitBlob": "a2930645065390cecff8008bfd48b7f034bfcd18"
-    },
-    {
-      "path": "docs/topics/obstruction-strands/test-plan.md",
-      "gitBlob": "20c54ffcaa19930a5bc772a49a5f01119054be2d"
-    },
-    {
-      "path": "docs/topics/providers/README.md",
-      "gitBlob": "8b5a07fb9c708b753861a4e156b866115f4d687b"
-    },
-    {
-      "path": "docs/topics/providers/architecture.md",
-      "gitBlob": "664b38347ccaf37f298d6ac9f19d3423c0277f9e"
-    },
-    {
-      "path": "docs/topics/providers/test-plan.md",
-      "gitBlob": "95c55f9e132ca6859fd9df70470973e678ed8d92"
-    },
-    {
-      "path": "docs/topics/public-rust-api/README.md",
-      "gitBlob": "c64a1081b7f693b02bd2ea63329f2610bae9d84c"
-    },
-    {
-      "path": "docs/topics/public-rust-api/test-plan.md",
-      "gitBlob": "4c3b9e9662afd9edb790ba2b5c57ed5e93df595c"
-    },
-    {
-      "path": "docs/topics/release-process/README.md",
-      "gitBlob": "a474ab8b6a4a58c5c73334c9e677be7c20d1837c"
-    },
-    {
-      "path": "docs/topics/release-process/policy.toml",
-      "gitBlob": "e40b4f4ec721ae61210ec1bb022a847bcb49fb4a"
-    },
-    {
-      "path": "docs/topics/release-process/runbook.md",
-      "gitBlob": "0b6bd8ef44cbfe8c7cdc347273fa74b7c96c4823"
-    },
-    {
-      "path": "docs/topics/release-process/test-plan.md",
-      "gitBlob": "61ecded1d2318d7dd74070cd1c6155f353c947e9"
-    },
-    {
-      "path": "docs/topics/result-projections/README.md",
-      "gitBlob": "d5c2f85a7681a15dcdc3e35f992a389c50d13461"
-    },
-    {
-      "path": "docs/topics/result-projections/test-plan.md",
-      "gitBlob": "9e69d58c88d6a9b7389334a78b994a3449721faa"
-    },
-    {
-      "path": "docs/topics/review-process/README.md",
-      "gitBlob": "25190d37dc30110f75ba5d3a41494575ffecc1c3"
-    },
-    {
-      "path": "docs/topics/review-process/policy.toml",
-      "gitBlob": "a826ba58aad2e509220b65aa8f96c290b600e094"
-    },
-    {
-      "path": "docs/topics/review-process/test-plan.md",
-      "gitBlob": "f1a50aeae47913e4513a8149c1679d9a94c5ef21"
-    },
-    {
-      "path": "docs/topics/rust-standards/README.md",
-      "gitBlob": "2fe29258705d117f4d10604a83fd832a8476e303"
-    },
-    {
-      "path": "docs/topics/rust-standards/test-plan.md",
-      "gitBlob": "0e0d6b306cd2b58db07a7a5da6a752925fe58764"
-    },
-    {
-      "path": "docs/topics/semantic-validation/README.md",
-      "gitBlob": "51cd9761755e7b5879069bf3774eeb487982ca97"
-    },
-    {
-      "path": "docs/topics/semantic-validation/test-plan.md",
-      "gitBlob": "b43969d8eb0a884c1663ab761662f9622617bb3b"
-    },
-    {
-      "path": "docs/topics/syntax/README.md",
-      "gitBlob": "b2a372bf41b1976567c61f400bf000f33abc20cc"
-    },
-    {
-      "path": "docs/topics/syntax/test-plan.md",
-      "gitBlob": "a69efaf12dfe12661fca049b8790b37fa3fb3665"
-    },
-    {
-      "path": "docs/topics/target-ir/README.md",
-      "gitBlob": "be30d1e24fda30aaa891ab03d53c2b8e287d9833"
-    },
-    {
-      "path": "docs/topics/target-ir/test-plan.md",
-      "gitBlob": "cc94ae24fb452521c21f55db52a5c3e9ba09c424"
-    },
-    {
-      "path": "docs/topics/target-profiles/README.md",
-      "gitBlob": "6a88f4d732f8069855b2ed2cb9a8769a117b2f60"
-    },
-    {
-      "path": "docs/topics/target-profiles/test-plan.md",
-      "gitBlob": "90084c3f3a1296745469cd86e9b5f2bc928825be"
-    },
-    {
-      "path": "docs/topics/tests/README.md",
-      "gitBlob": "4ad079b6a9718e2a8446a6c67ff45735015bef84"
-    },
-    {
-      "path": "docs/topics/tests/test-plan.md",
-      "gitBlob": "46bc0572d02a41e86f71c6d46baf5be611a462a6"
-    },
-    {
-      "path": "docs/topics/v2-design/README.md",
-      "gitBlob": "b33a07599e43e660aa4def7f119ddd02df6a16de"
-    },
-    {
-      "path": "docs/topics/v2-design/test-plan.md",
-      "gitBlob": "f17f96d381f81b20842393f70ff55b9597858b84"
-    },
-    {
-      "path": "editors/README.md",
-      "gitBlob": "7a933576262bc58bac197f9264fdbf649dd5e696"
-    },
-    {
-      "path": "editors/vscode/.vscodeignore",
-      "gitBlob": "f15b3142e4b8af11d580789a0c82acee3499f571"
-    },
-    {
-      "path": "editors/vscode/README.md",
-      "gitBlob": "8b29840ae9ec8f618b7364022329f694d0ed9746"
-    },
-    {
-      "path": "editors/vscode/language-configuration.json",
-      "gitBlob": "b7f583841649c9c437785edbfcb70ee24e495c79"
-    },
-    {
-      "path": "editors/vscode/package.json",
-      "gitBlob": "cd9e391e7c9afb6f9393fcead118e0e55aadc839"
-    },
-    {
-      "path": "editors/vscode/syntaxes/edict.tmLanguage.json",
-      "gitBlob": "5847d8edfdb32d822f0f3950f41d00c947982185"
-    },
-    {
-      "path": "fixtures/README.md",
-      "gitBlob": "470e3e0fc3aa00654930ecdef892ee9df8a42c8d"
-    },
-    {
-      "path": "fixtures/authority-facts/canonical/README.md",
-      "gitBlob": "28692ce70add5d4f2d4ff5318309c3353924caf9"
-    },
-    {
-      "path": "fixtures/authority-facts/canonical/example-effectful.authority-facts.cbor",
-      "gitBlob": "fe2e59a8e2602e02c52094010a130db2637c5227"
-    },
-    {
-      "path": "fixtures/authority-facts/canonical/example-effectful.authority-facts.json",
-      "gitBlob": "009faa5d2dc1dcf55cf284dcfd14c0b6405f3e0d"
-    },
-    {
-      "path": "fixtures/authority-facts/canonical/example-effectful.authority-facts.sha256",
-      "gitBlob": "a3d68f0a3b3a586e85b6a84cbd884866e662951f"
-    },
-    {
-      "path": "fixtures/bundle/assembly/bounded-hello.bundle-digests.txt",
-      "gitBlob": "da5402db7bd41dd88c6152b7799723561130c91e"
-    },
-    {
-      "path": "fixtures/cli/01-source-ok/expected.stdout.jsonl",
-      "gitBlob": "e08ccf8fdedd3a73beef5d06c443a1bc60274ce1"
-    },
-    {
-      "path": "fixtures/cli/01-source-ok/request.jsonl",
-      "gitBlob": "002fea597e6b93c8468d6972b73cc1344600fa87"
-    },
-    {
-      "path": "fixtures/cli/02-source-parse-rejection/exit",
-      "gitBlob": "d00491fd7e5bb6fa28c517a0bb32b8b506539d4d"
-    },
-    {
-      "path": "fixtures/cli/02-source-parse-rejection/expected.stderr.jsonl",
-      "gitBlob": "1077b73c9a7c02eae99f737bea7b6ff8c64d04da"
-    },
-    {
-      "path": "fixtures/cli/02-source-parse-rejection/request.jsonl",
-      "gitBlob": "dce01f0466bd9384fc6f5cbe2845b6e0bd9a9cfd"
-    },
-    {
-      "path": "fixtures/cli/03-source-semantic-rejection/exit",
-      "gitBlob": "d00491fd7e5bb6fa28c517a0bb32b8b506539d4d"
-    },
-    {
-      "path": "fixtures/cli/03-source-semantic-rejection/expected.stderr.jsonl",
-      "gitBlob": "5ec447700da52d0b4ce1f75825eb9bffaed4884b"
-    },
-    {
-      "path": "fixtures/cli/03-source-semantic-rejection/request.jsonl",
-      "gitBlob": "ddfd529e5448760387961febbd4ce013e49de435"
-    },
-    {
-      "path": "fixtures/cli/04-cli-missing-settings/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/04-cli-missing-settings/expected.stderr.jsonl",
-      "gitBlob": "5060bd2fd773ba9ea3ea6db8c80b86a846bfadbd"
-    },
-    {
-      "path": "fixtures/cli/04-cli-missing-settings/request.jsonl",
-      "gitBlob": "8eb12e58d427bd64ccfe339190e05bdccf4c8634"
-    },
-    {
-      "path": "fixtures/cli/05-path-input-ok/expected.stdout.jsonl",
-      "gitBlob": "a05fc582efc41b6414e785167b5deeb7532088ef"
-    },
-    {
-      "path": "fixtures/cli/05-path-input-ok/inputs/hello.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/05-path-input-ok/request.jsonl",
-      "gitBlob": "18facaab79dc198134c535df389cba79efe7dce7"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/expected.stdout.jsonl",
-      "gitBlob": "ef59591526e2084ddf5057249bbc96ab660cf256"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/inputs/a.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/inputs/ignore.txt",
-      "gitBlob": "ed34ae8da336ff94a67b6125fbd6be730c976d91"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/inputs/nested/b.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/06-directory-expansion-ok/request.jsonl",
-      "gitBlob": "bd9aad14fe79caccacaa6d00ffd32b5e13b3551f"
-    },
-    {
-      "path": "fixtures/cli/07-path-list-ok/expected.stdout.jsonl",
-      "gitBlob": "643ecb3e659c10cb98255ec1aced772778e76eb0"
-    },
-    {
-      "path": "fixtures/cli/07-path-list-ok/inputs/first.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/07-path-list-ok/inputs/second.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/07-path-list-ok/request.jsonl",
-      "gitBlob": "f11265b02c5b7559ced4d975471a78b5bef3ee27"
-    },
-    {
-      "path": "fixtures/cli/08-glob-expansion-ok/expected.stdout.jsonl",
-      "gitBlob": "90164a7fce6c51abdadef8f0586d2c56113d9712"
-    },
-    {
-      "path": "fixtures/cli/08-glob-expansion-ok/inputs/x.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/08-glob-expansion-ok/inputs/y.edict",
-      "gitBlob": "39c53bb184a7c10de61da0c637b607eb1d7cc454"
-    },
-    {
-      "path": "fixtures/cli/08-glob-expansion-ok/request.jsonl",
-      "gitBlob": "9335acf3a008ab8fb9942b3e22d73c456ed3827e"
-    },
-    {
-      "path": "fixtures/cli/09-shape-source-ok/expected.stdout.jsonl",
-      "gitBlob": "ac6f9259502ebfe484e1c07a5f53865888dd8207"
-    },
-    {
-      "path": "fixtures/cli/09-shape-source-ok/request.jsonl",
-      "gitBlob": "64c75d9a7b40985bacf0e59a943a16e20419c602"
-    },
-    {
-      "path": "fixtures/cli/10-input-extra-field/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/10-input-extra-field/expected.stderr.jsonl",
-      "gitBlob": "2f5a8fba093b71d15a5b37504ad0352191c8299c"
-    },
-    {
-      "path": "fixtures/cli/10-input-extra-field/request.jsonl",
-      "gitBlob": "6052212c652d41f03144a7d3d4018b1cdd18cd09"
-    },
-    {
-      "path": "fixtures/cli/11-input-hybrid-kind/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/11-input-hybrid-kind/expected.stderr.jsonl",
-      "gitBlob": "7b6d2ac0c8afbf5e3991498846c2fc4847ac9453"
-    },
-    {
-      "path": "fixtures/cli/11-input-hybrid-kind/request.jsonl",
-      "gitBlob": "b893b640aa6631c77f2a889a807afa31632ac2db"
-    },
-    {
-      "path": "fixtures/cli/12-input-too-large/env.json",
-      "gitBlob": "ab0c7f13fc6b22d61fc73da2f1787ff3aa298ecb"
-    },
-    {
-      "path": "fixtures/cli/12-input-too-large/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/12-input-too-large/expected.stderr.jsonl",
-      "gitBlob": "ebda022d79c978d4ff511579512be2c642e3e902"
-    },
-    {
-      "path": "fixtures/cli/12-input-too-large/request.jsonl",
-      "gitBlob": "1e2fbb102503356bbcc627f49a5b58590859f170"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/allowed/.gitkeep",
-      "gitBlob": "8b137891791fe96927ad78e64b0aad7bded08bdc"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/exit",
-      "gitBlob": "0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/expected.stderr.jsonl",
-      "gitBlob": "9c5b8567a755c9ea2ee6e0168bf96f429185f675"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/outside/outside.edict",
-      "gitBlob": "44abebc15811c38cc266007484dd74ae10a26a4d"
-    },
-    {
-      "path": "fixtures/cli/13-input-root-outside/request.jsonl",
-      "gitBlob": "116dbbb4b1a80938bc042e41747872cb6da161cd"
-    },
-    {
-      "path": "fixtures/cli/README.md",
-      "gitBlob": "9388df4182fedec41c353e85cf9210e88906fa3d"
-    },
-    {
-      "path": "fixtures/core/canonical/README.md",
-      "gitBlob": "d9a0ca79557c3623c0b843d9eff4808f94fd7b18"
-    },
-    {
-      "path": "fixtures/core/canonical/bounded-hello.core.cbor",
-      "gitBlob": "a0ec54aa1a5e20624192091526445cfd803e6f0c"
-    },
-    {
-      "path": "fixtures/core/canonical/bounded-hello.core.sha256",
-      "gitBlob": "86ba062c26a3ad3fd733ccd8c80d7faa7ed62d94"
-    },
-    {
-      "path": "fixtures/core/canonical/statement-branch.core.hex",
-      "gitBlob": "c22760cace0e4d146a2fdc8d7c7b50c38497622a"
-    },
-    {
-      "path": "fixtures/core/canonical/statement-branch.core.sha256",
-      "gitBlob": "0b62657b192232390479319f0a1c8f601020a58f"
-    },
-    {
-      "path": "fixtures/core/canonical/workspace-snapshot.core.cbor",
-      "gitBlob": "58e4f724610861f5b61537bf386a87062e8a57a7"
-    },
-    {
-      "path": "fixtures/core/canonical/workspace-snapshot.core.sha256",
-      "gitBlob": "4bcb3e0813cd3f4a7afc7cf311d846f1dfdd0a9d"
-    },
-    {
-      "path": "fixtures/core/schema/accepted/core-fn-body-minimal.fields",
-      "gitBlob": "bef3ca412ab0ea97465b8658499ae5e05e1ec760"
-    },
-    {
-      "path": "fixtures/core/schema/accepted/core-intent-minimal.fields",
-      "gitBlob": "268b28ce942fed4f139aafe5c7cd50c15a0ee640"
-    },
-    {
-      "path": "fixtures/core/schema/accepted/core-module-minimal.fields",
-      "gitBlob": "249ff76349f936c9a5ff6cb65d81de8e80d53de8"
-    },
-    {
-      "path": "fixtures/core/schema/rejected/core-fn-body-effect-node-field.fields",
-      "gitBlob": "9af8fa3540b25ec810936bc4dc82e26f6dd0dd48"
-    },
-    {
-      "path": "fixtures/core/schema/rejected/core-intent-unknown-verified-mode.fields",
-      "gitBlob": "667ae032ee117f32c1bcbafd21393e406621f517"
-    },
-    {
-      "path": "fixtures/core/schema/rejected/core-module-missing-intents.fields",
-      "gitBlob": "17f37c7ac4c199de4eace7f31e6a59b9a6d3a0f6"
-    },
-    {
-      "path": "fixtures/core/schema/rejected/local-ref-missing-alpha-name.fields",
-      "gitBlob": "456a89528ffe74d892be40c9c9be4a078ff5c18a"
-    },
-    {
-      "path": "fixtures/lang/bounds/bounded-hello.edict",
-      "gitBlob": "e3443a1d3b1c8f0e137ac698b621dd2f3afb673b"
-    },
-    {
-      "path": "fixtures/lang/effects/conditional-blob.edict",
-      "gitBlob": "1e4f2ca6112f26d57ee4d20058666ec7cd693b75"
-    },
-    {
-      "path": "fixtures/lang/effects/read-greeting.edict",
-      "gitBlob": "5e3838d1547be171e0a0384a7a200f52a2b9d139"
-    },
-    {
-      "path": "fixtures/lang/external-actions/workspace-snapshot.edict",
-      "gitBlob": "e54b0fbccad2fd680505f3ee46ca28d39d7e776e"
-    },
-    {
-      "path": "fixtures/lang/operations/explicit-basis-u64.edict",
-      "gitBlob": "444d8ca77b9827746df81885f0620dce2d1a3b73"
-    },
-    {
-      "path": "fixtures/lang/tooling/highlight-smoke.edict",
-      "gitBlob": "8c2d91084be22e5e1594a42159992aca95c73612"
-    },
-    {
-      "path": "fixtures/lang/types/color-match.edict",
-      "gitBlob": "dd98d6de677904f36d7601165a0094d92928e536"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/README.md",
-      "gitBlob": "52e8cc1e2af8aea86c1090a1b20b5f5ab3e07c06"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/adapter.cbor",
-      "gitBlob": "3b0c8b1b3a8591a322b6e785d9f963899319310c"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/adapter.sha256",
-      "gitBlob": "f8231bc941e1fbe02279865a82e183cbeeb0988a"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/echo-operation-configuration.cbor",
-      "gitBlob": "24527d30d0146b567fda157561ac6a2587cae919"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/echo-operation-configuration.sha256",
-      "gitBlob": "d293c8a14b1955a3e171703400c4df620c7871a1"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/exports.cbor",
-      "gitBlob": "384f4839adfe8e5b0f1aa848bfe2aeb1c3f640b6"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/exports.sha256",
-      "gitBlob": "4f836f6b03497338a1f8eacc55480cbe1a3b49e9"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/manifest.cbor",
-      "gitBlob": "b9311a236d7898861a0b90b1f30b852b35cef623"
-    },
-    {
-      "path": "fixtures/lawpack/causal-cell/manifest.sha256",
-      "gitBlob": "685fd6a6c72fc3100d595d009b6198a81c731a40"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/README.md",
-      "gitBlob": "79f6612f1f5608a8f7dc4835e5470878cd27f96e"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/adapter.cbor",
-      "gitBlob": "24e2f546e2b97747b53462a72faaa1d5d85d62f1"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/adapter.sha256",
-      "gitBlob": "91df491028061e026ecaaeb4e1598e2ac369af44"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.core.cbor",
-      "gitBlob": "246b6135855c415def0bd89b275f0457752ee563"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.core.sha256",
-      "gitBlob": "9adc71605e0a275349161809614bd17de97d129c"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.edict",
-      "gitBlob": "825d50565230bd71d62bfbeb59d0399a89864b4c"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.result-projection.cbor",
-      "gitBlob": "981cba6e1c7ab6bdae6829116749c4796167e4e6"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.result-projection.sha256",
-      "gitBlob": "d55e4083771e1d9791f59cf87fd5cc5f1ea3b9f4"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.target-ir.cbor",
-      "gitBlob": "c8a934cefec17dbab0a43d9be9cebd2533268798"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/create-greeting.target-ir.sha256",
-      "gitBlob": "20186cbe9482e8a7df7c44fabec13ffd4efbcf36"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/echo-operation-configuration.cbor",
-      "gitBlob": "84838ab0d8627237232fa5a9b9fa39087bcc5f8a"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/echo-operation-configuration.sha256",
-      "gitBlob": "0898688f14067560dd22abd04b97f020071fd3e8"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/exports.cbor",
-      "gitBlob": "0e1220ceed9442a7b35870eeb02fcb65454d8c5c"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/exports.sha256",
-      "gitBlob": "e1f3e9223de9ce935bc7f60dda3cfa7d12d54fdc"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/manifest.cbor",
-      "gitBlob": "d715900f03ec454a0ad96e6710f52a46120d0b9d"
-    },
-    {
-      "path": "fixtures/lawpack/hello-echo/manifest.sha256",
-      "gitBlob": "20171199b401cecace2dd74e18f3cc1d5c7ed3de"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/README.md",
-      "gitBlob": "67cd35f2e0660aa7455de1c197ad821d5438679b"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/adapter.cbor",
-      "gitBlob": "2d6f09a7e2fab381b97a05cfad1e692902e878c3"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/adapter.sha256",
-      "gitBlob": "d44eb9675e126716e8a5ef3c53fd39ade49d76fb"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.core.cbor",
-      "gitBlob": "6a88c127e426288a3e51d4749d5c31d5b0cb60cb"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.core.sha256",
-      "gitBlob": "0204b6f1d8b346a67800a7738ee39df49e78571f"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.edict",
-      "gitBlob": "6e11a3d022a53a8fb2c20a77e35e29840f5fe086"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.target-ir.cbor",
-      "gitBlob": "a6124a995a3cdbb5d39cd0a6e046b329048703aa"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/apply-validated-patch.target-ir.sha256",
-      "gitBlob": "f7ac419ce15b32d491e09bddbe7c75f8227f51d8"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/exports.cbor",
-      "gitBlob": "3a6fd19dc8059b9fe1bde74fb1da61398b0e80cc"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/exports.sha256",
-      "gitBlob": "b301dd883a31fffe324e9306ec90ae2b1ec44520"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/input-schema.cbor",
-      "gitBlob": "3045d9b696864fefe111c3eb641b3b68532752d2"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/input-schema.sha256",
-      "gitBlob": "9f1284b4f0a2c7f6dbe1915a6113cd13a9700cb8"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/manifest.cbor",
-      "gitBlob": "77e56c7525f0e64ab191f0adfeac12b540c87848"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/manifest.sha256",
-      "gitBlob": "8316978e68565f29a30a6978d33d907710185857"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/reconciliation-law.cbor",
-      "gitBlob": "0736b75f81913fca7ac95c56ec45f66b95aea4cf"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/reconciliation-law.sha256",
-      "gitBlob": "de31fc9fda59fa3c29397e5fc48db224e8e1fee7"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/request-profile-configuration.cbor",
-      "gitBlob": "5e2870b2f562bafaa73a91a3fc192f5ed39257c7"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/request-profile-configuration.sha256",
-      "gitBlob": "4345ae2e39ce3f4d9cfa6b0dddf4ce56d56c035c"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/settlement-schema.cbor",
-      "gitBlob": "0a93ac19c51b341602eeba524769147e962d5d60"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-patch/settlement-schema.sha256",
-      "gitBlob": "f1bb3fb0313dd6815b4184345194949ec40fe9e1"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/README.md",
-      "gitBlob": "996bd1d29b28769fff477084d9118d0833ca2970"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/adapter.cbor",
-      "gitBlob": "9be4ea568b602b56269af505deb809989a3fa8b5"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/adapter.sha256",
-      "gitBlob": "1e287be0a322e5444dea15fa14bcfc7cf12975c4"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/exports.cbor",
-      "gitBlob": "33fe04db74775c191d4b7400e1fb2b6393c5a010"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/exports.sha256",
-      "gitBlob": "e057cac7fc360e6599b7ddab88508aaf0f2f55f8"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/input-schema.cbor",
-      "gitBlob": "49c849169946e44c8b5f300279dd085bd6b63aeb"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/input-schema.sha256",
-      "gitBlob": "9dd7bb6e48192e90d19fc346d1705f736b1d85d7"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/manifest.cbor",
-      "gitBlob": "d4e58e3d4646ca967170a6882f2a617cb8d81390"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/manifest.sha256",
-      "gitBlob": "0edb311125a89a5816ee3fa0c9b700c9b3bcff3d"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.core.cbor",
-      "gitBlob": "a4b249dfb197f1a6b4adc06855f16e4305a1c798"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.core.sha256",
-      "gitBlob": "ea6b914d14907d9fd915058e579aff33c954da2c"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.edict",
-      "gitBlob": "c2c10f1ef1009796d67061b9722c4db9bb4e031b"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.target-ir.cbor",
-      "gitBlob": "bdab1b0c55a34360c7e9ab304af91fe2b1e4afce"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/observe-workspace.target-ir.sha256",
-      "gitBlob": "7342aaa96221d6c8efa75ead2af5563791ccfeff"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/reconciliation-law.cbor",
-      "gitBlob": "df55572b350002a3df98ccb3e72dd60c86b9aead"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/reconciliation-law.sha256",
-      "gitBlob": "957cd04c78c130b07d2cad2fd7e07ae69978be57"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/request-profile-configuration.cbor",
-      "gitBlob": "708f18918ee1703491a910df82e129e711a4cc46"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/request-profile-configuration.sha256",
-      "gitBlob": "d9953d9dcaa41c98387226d1980f40b24d2bc3cb"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/settlement-schema.cbor",
-      "gitBlob": "f01ad68531267666e6bf93bf30a37d5b311c1676"
-    },
-    {
-      "path": "fixtures/lawpack/workspace-snapshot/settlement-schema.sha256",
-      "gitBlob": "06fcc0ee2b976a09b3017bd93132a3c51eb1317e"
-    },
-    {
-      "path": "fixtures/obstruction-strands/v0/stale-basis/README.md",
-      "gitBlob": "25efbfa04e2e6104c5434f329128333e895e2b0a"
-    },
-    {
-      "path": "fixtures/obstruction-strands/v0/stale-basis/source.edict",
-      "gitBlob": "e487b46e81220c50e6f928922dada29f3a21ca6a"
-    },
-    {
-      "path": "fixtures/provider-contracts/v1/README.md",
-      "gitBlob": "447692907f9268ce3b6b78c43b7cbbb0417aeadf"
-    },
-    {
-      "path": "fixtures/provider-contracts/v1/edict-provider-contracts.cddl",
-      "gitBlob": "07048aeeadb5062eabb89e995713cbc0893b7d7e"
-    },
-    {
-      "path": "fixtures/provider-contracts/v1/manifest.json",
-      "gitBlob": "d2c8de5d61049e9f4182c630bf82b138f0f96792"
-    },
-    {
-      "path": "fixtures/providers/README.md",
-      "gitBlob": "c26ee60a4930e3e0784c76cb855e48234a5c6b58"
-    },
-    {
-      "path": "fixtures/providers/components/guests/Cargo.lock",
-      "gitBlob": "d7858ce7bc67deabb5ff352a24c85a7caa0ef4b0"
-    },
-    {
-      "path": "fixtures/providers/components/guests/Cargo.toml",
-      "gitBlob": "450a24aed25dc73661b0ae8adfe2630dfecc9b07"
-    },
-    {
-      "path": "fixtures/providers/components/guests/lowerer/Cargo.toml",
-      "gitBlob": "568aa137fa215b6b973fe31e12322530b393b9dc"
-    },
-    {
-      "path": "fixtures/providers/components/guests/lowerer/src/lib.rs",
-      "gitBlob": "b39a8a0b18fe9ed7cb90277f793056434afa1318"
-    },
-    {
-      "path": "fixtures/providers/components/guests/verifier/Cargo.toml",
-      "gitBlob": "f814f2c8c248bbf03389f5a0936f80cd4dada5b6"
-    },
-    {
-      "path": "fixtures/providers/components/guests/verifier/src/lib.rs",
-      "gitBlob": "3f07ffdfd808ff95b206a2c08c2d481ccaf0e165"
-    },
-    {
-      "path": "fixtures/providers/components/instantiation-failure-lowerer.component.wasm",
-      "gitBlob": "bd2d7c0d31798d7676aedab0bd0d289fc2053bef"
-    },
-    {
-      "path": "fixtures/providers/components/instantiation-failure-lowerer.wat",
-      "gitBlob": "f6f5a70edb80d3a7fa1dee13b34ab5b8b44274d7"
-    },
-    {
-      "path": "fixtures/providers/components/instantiation-fuel-lowerer.component.wasm",
-      "gitBlob": "0804d26d3ddb428682ca87ecad03cf0e05ef64af"
-    },
-    {
-      "path": "fixtures/providers/components/instantiation-fuel-lowerer.wat",
-      "gitBlob": "80e972463ef593602d27c7d7cec78d87d22ff727"
-    },
-    {
-      "path": "fixtures/providers/components/inventory.json",
-      "gitBlob": "45cf2e8e937a17a8ee05dfa8d68e94dcc155e129"
-    },
-    {
-      "path": "fixtures/providers/components/lowerer.component.wasm",
-      "gitBlob": "6c1cf123a44284d15b7b1e90f1905ae94e65c158"
-    },
-    {
-      "path": "fixtures/providers/components/malformed-lowerer.component.wasm",
-      "gitBlob": "be873af81100dc76ed1f3f1f818a41da45a38e4c"
-    },
-    {
-      "path": "fixtures/providers/components/malformed-lowerer.wat",
-      "gitBlob": "1e7bfffe0a0baf230d9fb5766083f82198f4029c"
-    },
-    {
-      "path": "fixtures/providers/components/verifier.component.wasm",
-      "gitBlob": "671adbe7931d0a9a5e0c78d459c244d37a135a69"
-    },
-    {
-      "path": "fixtures/providers/echo-generated/provider-manifest.json",
-      "gitBlob": "22c8560e7ddecacd5da388e52d3935d7fc1474b9"
-    },
-    {
-      "path": "fixtures/providers/echo-target-profile/README.md",
-      "gitBlob": "350c33dcda2d66d2d50e589c58db7c6d7b14a80b"
-    },
-    {
-      "path": "fixtures/providers/echo-target-profile/generated/primary/target-profile.echo-dpo.cbor",
-      "gitBlob": "9fa43529b1021dfd8e3a33256c832d4eee6f4a47"
-    },
-    {
-      "path": "fixtures/providers/wit/legacy-target-profile.wit",
-      "gitBlob": "ae7d6af764012b16bf06bfa260ccba98a7f04868"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/echo-effectful.target-ir.cbor",
-      "gitBlob": "727a80eb37319dbdbea40d7d9b4e37f0d93d8d84"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/echo-effectful.target-ir.sha256",
-      "gitBlob": "6d050bb46ac8981ea8e47c7a52371027b941fd89"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/gitwarp-append.target-ir.cbor",
-      "gitBlob": "89b46b138a7b90252a4397c0e8b622bceff10a33"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/gitwarp-append.target-ir.sha256",
-      "gitBlob": "a59a4ab9d46095d5be1797ed9e60fe841f821bce"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/workspace-snapshot.target-ir.cbor",
-      "gitBlob": "1854eeb549b3719fa2b0114867dbece6db1819d4"
-    },
-    {
-      "path": "fixtures/target-ir/canonical/workspace-snapshot.target-ir.sha256",
-      "gitBlob": "4d0e501323d415ef9e64c0a3d25bdd57dabfc998"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/README.md",
-      "gitBlob": "32dcab1dd9376a4eed2c73bb1b1a29255fe3ea05"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/canonical-cbor.cbor",
-      "gitBlob": "4a95ba3bd9dff190ca5ec9c83262bfa6254a91d3"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/canonical-cbor.sha256",
-      "gitBlob": "2168df5d4bf77ed2347139dd7c45fd808df8ec7e"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/determinism.cbor",
-      "gitBlob": "09cd11c36048939961408550763c04fad8241557"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/determinism.sha256",
-      "gitBlob": "5376d6bfe23bea659463a7e3c56ad1e8afd4095f"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/diagnostics.cbor",
-      "gitBlob": "c47fa05f463e0da745fbcdf8daf94d70e134eb8d"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/diagnostics.sha256",
-      "gitBlob": "69613ec4014f27b23245e23fbf7c9447566516b2"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/fuel.cbor",
-      "gitBlob": "b5a3484ec5b2bf7343c2fcedc67bcb2b63a37104"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/fuel.sha256",
-      "gitBlob": "6ec1c830358ee35bb12bd04cc1a6edf47fb20997"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/wasm-component.cbor",
-      "gitBlob": "6344996c283e0d1c332ea3ce597ad4593882a3c5"
-    },
-    {
-      "path": "fixtures/target-profile/contract-resources/wasm-component.sha256",
-      "gitBlob": "24bf3e552e4216d8258d2b85c8878af46a176c52"
-    },
-    {
-      "path": "grammars/textmate/README.md",
-      "gitBlob": "fc116a669725d4e965d658234d32d779955d5dc8"
-    },
-    {
-      "path": "grammars/textmate/edict.tmLanguage.json",
-      "gitBlob": "5847d8edfdb32d822f0f3950f41d00c947982185"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/README.md",
-      "gitBlob": "e2992a839d6719f1461db78c4e3f33d2e5ab0c09"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/grammar.js",
-      "gitBlob": "a82f5b9d9b78525f17a59272543fdcddd7a0da40"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/queries/highlights.scm",
-      "gitBlob": "0f46530b36996d13449901aed4e376a126577cba"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/grammar.json",
-      "gitBlob": "55df730a06b83c9f622e3ec17845fc9897c7d8c0"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/node-types.json",
-      "gitBlob": "520f6c4f7b30cd6892dd60faf6d76f3fbaa6a5c7"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/parser.c",
-      "gitBlob": "81cc4713cb5e05f9aa8dac16da202a864faefee6"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/tree_sitter/alloc.h",
-      "gitBlob": "1abdd1201578605b8d05a3001f01ebc0d58826d9"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/tree_sitter/array.h",
-      "gitBlob": "56fc8cd470996ded64a5452be25e26dbd2aa682a"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/src/tree_sitter/parser.h",
-      "gitBlob": "858107deb9e4a1ffcd2ed5e6ffe98a5fcab3e1f6"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/test/corpus/current-subset.txt",
-      "gitBlob": "732c5eda8e1bf95eef799476296a6ee061eb58eb"
-    },
-    {
-      "path": "grammars/tree-sitter-edict/tree-sitter.json",
-      "gitBlob": "97d3fdd498a3bef509c8615d98b9560b527c03cb"
-    },
-    {
-      "path": "scripts/consumer-witnesses/README.md",
-      "gitBlob": "2b7d2b9d81f9598fd8df232b3a76bef106ff7ef2"
-    },
-    {
-      "path": "scripts/consumer-witnesses/jedit-state-read.Dockerfile",
-      "gitBlob": "7462059be67686090d0097b24b9d14bfbbd4c6f7"
-    },
-    {
-      "path": "scripts/consumer-witnesses/jedit-state-read.Dockerfile.dockerignore",
-      "gitBlob": "ee41b3ca0a68fd5eb20e1b777b4b368fd8b44e63"
-    },
-    {
-      "path": "scripts/consumer-witnesses/jedit-state-read.py",
-      "gitBlob": "26db295d4eabfc4e57813fc9bf17314c23350777"
-    },
-    {
-      "path": "scripts/consumer-witnesses/run-jedit-state-read.sh",
-      "gitBlob": "18cd72bbbdfb17a5ea30a7821d47035071556d10"
-    },
-    {
-      "path": "spec.lock.json",
-      "gitBlob": "ef8b02386e0f269a99c1d2121764f70b76e67620"
-    },
-    {
-      "path": "xtask/Cargo.toml",
-      "gitBlob": "795c70a5172363bfcd55174b1bc76c9c131d21a3"
-    },
-    {
-      "path": "xtask/src/contract_check.rs",
-      "gitBlob": "9e80393accf79936033972fde0f2aa2cf40f1be3"
-    },
-    {
-      "path": "xtask/src/goldens.rs",
-      "gitBlob": "713f1f8266d9f6993684ae86db105fcd7d69ee2a"
-    },
-    {
-      "path": "xtask/src/lawpack_goldens.rs",
-      "gitBlob": "c499e8581c73313794b83c261937144b3917850a"
-    },
-    {
-      "path": "xtask/src/main.rs",
-      "gitBlob": "6c2c06038bb5ecdde60620071b200d8191dc116c"
-    },
-    {
-      "path": "xtask/src/provider_components.rs",
-      "gitBlob": "ee9d6a1028f9fbfad879faab4b15a94b996ef6d4"
-    },
-    {
-      "path": "xtask/src/provider_contract_pack.rs",
-      "gitBlob": "cf60d89892b7a57cc33300f273d2522a6e8f43f9"
-    },
-    {
-      "path": "xtask/src/provider_dependencies.rs",
-      "gitBlob": "c4b0539ed593d2a2777d294090d2a891b13ae628"
-    },
-    {
-      "path": "xtask/src/release_dates.rs",
-      "gitBlob": "1c6d7acb872f6d820eab3a30ca580e9c5cfba2ee"
-    },
-    {
-      "path": "xtask/src/release_prep.rs",
-      "gitBlob": "01ed64ccbb28c9d1e908b7b800ff58076e5e1a2b"
-    },
-    {
-      "path": "xtask/src/tests.rs",
-      "gitBlob": "9a3f6543c2dbae31d53e93d56f781e5d54f74f41"
-    },
-    {
-      "path": "xtask/src/util.rs",
-      "gitBlob": "c1bf39e93460c43ffdcfd9a76e0424750cbb9dfd"
-    }
-  ]
-}
diff --git a/edict/replace-range-probes/range-assembly/evidence/first-control-stderr.jsonl b/edict/replace-range-probes/range-assembly/evidence/first-control-stderr.jsonl
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/range-assembly/evidence/first-control-stdout.jsonl b/edict/replace-range-probes/range-assembly/evidence/first-control-stdout.jsonl
deleted file mode 100644
index a668538e..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/first-control-stdout.jsonl
+++ /dev/null
@@ -1 +0,0 @@
-{"checked":1,"command":"build","errors":0,"exitCode":0,"schema":"edict.cli.event/v1","status":"ok","type":"status"}
diff --git a/edict/replace-range-probes/range-assembly/evidence/public-build-red.json b/edict/replace-range-probes/range-assembly/evidence/public-build-red.json
deleted file mode 100644
index 33b9c136..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/public-build-red.json
+++ /dev/null
@@ -1,79 +0,0 @@
-{
-  "compiler": {
-    "commit": "ac836e5c42a5c47b0dab30cfb0b09848cca73215",
-    "tree": "dadd4703a9905a37ff366c7134aea5cfe351e2fd",
-    "fileCount": 446,
-    "manifestSha256": "1cf9cdb1a3bfacab2dfa515f7a07188c984ba0770399ee6ec3ef473b9383781e",
-    "binarySha256": "a937e6f150f73fa20e9868c84adee0a8270cc62130d4aef18e5b891ec268fee2"
-  },
-  "providerManifestSha256": "c5b9fb2fe3a0dc4dad282621a97413225c555be0071f3502b3272952069d42dc",
-  "results": {
-    "baseline": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "51797e77062585a9f59083ee8a1da3faaf486ef7691e1b62203369a9d9356ee0",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "1860ab8a6cb9a4bfd63a1db99d1c2bc00aa53dae52a9d1998295654379a95d85",
-        "verification-report.cbor": "d96e5d21eecbc1e5bbf6ce76ab438d55cc8e74f6843121d4ffb0f4343e648267"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "first-control": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "fa207e40f734fce99c581efbc5159a276c95e7b399d3acce854829ace05c6d2e",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "d950cebad1bb978e24dfa736efab302eb0f5c96135cb32f27ad8781d6ace6b51",
-        "verification-report.cbor": "412fb923e3dbd3f070624446ae953920058e08eda5fdc94f201d9b475842c803"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "second-control": {
-      "exitCode": 0,
-      "diagnostics": [],
-      "artifacts": [
-        "executable-operation-package.cbor",
-        "verification-report.cbor"
-      ],
-      "sourceSha256": "b7bdfce283a977bf2a04ec95d278138a9fbcaeb3e5eedefb909b6d617b1cf8c0",
-      "artifactSha256": {
-        "executable-operation-package.cbor": "e75c18f7265ea8fd7390e2e2d4ff49047323e99a07602d80442659d636fd61f4",
-        "verification-report.cbor": "463a47e58e00390937c565413305b4ec553928b86aae2979fbcbf631b55961d9"
-      },
-      "stdoutSha256": "ee9dd333c256f57a14f42869b19857a2e42c71b0483fcec23a7fc385802edd61",
-      "stderrSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
-    },
-    "assembly": {
-      "exitCode": 2,
-      "diagnostics": [
-        {
-          "command": "build",
-          "input": {
-            "kind": "stdin"
-          },
-          "kind": "ApplicationCompilationFailed",
-          "message": "Edict application did not compile to Core: [CompilerError { stage: TypeCheck, kind: TypeMismatch, message: \"string concatenation requires string operands\", span: Span { start: 430, end: 472 } }, CompilerError { stage: TypeCheck, kind: UnresolvedType, message: \"record shorthand `bytes` has no typed binding\", span: Span { start: 485, end: 490 } }, CompilerError { stage: TypeCheck, kind: TypeMismatch, message: \"return value does not match declared output type\", span: Span { start: 283, end: 495 } }, CompilerError { stage: TypeCheck, kind: TypeMismatch, message: \"intent body must return a value\", span: Span { start: 283, end: 495 } }]",
-          "schema": "edict.cli.diagnostic/v1",
-          "severity": "error",
-          "stage": "cli",
-          "type": "diagnostic"
-        }
-      ],
-      "artifacts": [],
-      "sourceSha256": "8e8d2703759fb30cb49b73650ba8ddfd637d68b33b86145661bfca3033c968fc",
-      "artifactSha256": {},
-      "stdoutSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
-      "stderrSha256": "dfa643796ce3ecbca02f70ede806e6c50566456b3126747e3b496f6f35250d14"
-    }
-  }
-}
diff --git a/edict/replace-range-probes/range-assembly/evidence/second-control-stderr.jsonl b/edict/replace-range-probes/range-assembly/evidence/second-control-stderr.jsonl
deleted file mode 100644
index e69de29b..00000000
diff --git a/edict/replace-range-probes/range-assembly/evidence/second-control-stdout.jsonl b/edict/replace-range-probes/range-assembly/evidence/second-control-stdout.jsonl
deleted file mode 100644
index a668538e..00000000
--- a/edict/replace-range-probes/range-assembly/evidence/second-control-stdout.jsonl
+++ /dev/null
@@ -1 +0,0 @@
-{"checked":1,"command":"build","errors":0,"exitCode":0,"schema":"edict.cli.event/v1","status":"ok","type":"status"}
diff --git a/edict/replace-range-probes/range-assembly/run.py b/edict/replace-range-probes/range-assembly/run.py
deleted file mode 100644
index 6d25b611..00000000
--- a/edict/replace-range-probes/range-assembly/run.py
+++ /dev/null
@@ -1,81 +0,0 @@
-"""Exercise authored range-fragment assembly at Edict's public build boundary."""
-
-import argparse
-import json
-from pathlib import Path
-import runpy
-
-
-COMPILER_COMMIT = "ac836e5c42a5c47b0dab30cfb0b09848cca73215"
-CANDIDATE_COMPILER_COMMIT = "01dc5abb9a8a74f8fd8b0e0a6d1041d0adb86d6e"
-SOURCE_EXPRESSION = b"input.firstFragment + input.secondFragment"
-
-
-def main():
-    parser = argparse.ArgumentParser(description=__doc__)
-    for name in ("compiler", "compiler-source", "compiler-manifest", "application-source",
-                 "provider-package", "work-root"):
-        parser.add_argument("--" + name, type=Path, required=True)
-    parser.add_argument("--boundary", choices=("source", "package"), default="source")
-    args = parser.parse_args()
-    if not Path("/.dockerenv").is_file():
-        raise RuntimeError("Run only under shared git-locks admission and the guarded Docker lease")
-    if not args.work_root.resolve().is_relative_to(Path("/tmp/echo-726-runtime")):
-        raise RuntimeError("Work must stay inside the declared runtime-data accounting root")
-    # Reuse the existing public-build orchestration without changing its specimen or pins.
-    common = runpy.run_path(str(Path(__file__).parent.parent / "leaf-slice/run.py"))
-    sha256, snapshot = common["sha256"], common["snapshot"]
-    verify = common["verify_compiler_source"]
-    args.work_root.mkdir()
-    expected_commit = COMPILER_COMMIT if args.boundary == "source" else CANDIDATE_COMPILER_COMMIT
-    compiler = verify(args.compiler_source, args.compiler_manifest, expected_commit)
-    compiler["binarySha256"] = sha256(args.compiler)
-    before = {"application": snapshot(args.application_source),
-              "provider": snapshot(args.provider_package)}
-    source = (Path(__file__).parent / "RangeAssembly.edict").read_bytes()
-    if source.count(SOURCE_EXPRESSION) != 1:
-        raise RuntimeError("Expected one exact authored fragment addition")
-    sources = {
-        "baseline": (args.application_source / "src/ReplaceRange.edict").read_bytes(),
-        "first-control": source.replace(SOURCE_EXPRESSION, b"input.firstFragment"),
-        "second-control": source.replace(SOURCE_EXPRESSION, b"input.secondFragment"),
-        "assembly": source,
-    }
-    evidence = {"compiler": compiler,
-                "providerManifestSha256": sha256(args.provider_package / "provider-manifest.echo.json"),
-                "results": {}}
-    for name, authored in sources.items():
-        root = args.work_root / name
-        common["prepare"](root, args.application_source, args.provider_package, authored)
-        evidence["results"][name] = common["build"](root, args.compiler)
-    (args.work_root / "evidence.json").write_text(json.dumps(evidence, indent=2) + "\n")
-    for name, result in evidence["results"].items():
-        print(json.dumps({"case": name, **result}, sort_keys=True), flush=True)
-    if before != {"application": snapshot(args.application_source),
-                  "provider": snapshot(args.provider_package)}:
-        raise RuntimeError("Witness changed an authoritative input")
-    if compiler["binarySha256"] != sha256(args.compiler):
-        raise RuntimeError("Compiler binary changed during witness")
-    verify(args.compiler_source, args.compiler_manifest, expected_commit)
-    for name in ("baseline", "first-control", "second-control"):
-        result = evidence["results"][name]
-        if result["exitCode"] != 0 or result["diagnostics"] or not result["artifacts"]:
-            raise RuntimeError(f"{name} positive control did not build")
-    result = evidence["results"]["assembly"]
-    if args.boundary == "package":
-        if (result["exitCode"] != 0 or result["diagnostics"]
-                or result["artifacts"] != ["executable-operation-package.cbor", "verification-report.cbor"]):
-            raise RuntimeError("Assembly did not reach the expected package build boundary")
-        print("JIM_RANGE_ASSEMBLY_PACKAGE_BOUNDARY_CONFIRMED", flush=True)
-        return
-    if result["exitCode"] != 2 or result["artifacts"]:
-        raise RuntimeError("Assembly must refuse without application artifacts")
-    refusal = result["diagnostics"]
-    if (len(refusal) != 1 or refusal[0].get("kind") != "ApplicationCompilationFailed"
-            or "string concatenation requires string operands" not in refusal[0].get("message", "")):
-        raise RuntimeError("Assembly did not produce the expected source refusal")
-    print("JIM_RANGE_ASSEMBLY_SOURCE_BOUNDARY_CONFIRMED", flush=True)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/edict/replace-range-probes/state-read/Dockerfile b/edict/replace-range-probes/state-read/Dockerfile
deleted file mode 100644
index ea6f274b..00000000
--- a/edict/replace-range-probes/state-read/Dockerfile
+++ /dev/null
@@ -1,18 +0,0 @@
-FROM rust:1.95.0-bookworm AS compiler
-WORKDIR /edict
-RUN git init && git remote add origin https://github.com/flyingrobots/edict.git \
-    && git fetch --depth=1 origin 77f4a91080a6c2c875fe349da6fc6a64525947a2 \
-    && git checkout --detach FETCH_HEAD \
-    && cargo build --locked -p edict-cli
-
-FROM debian:bookworm-slim
-RUN apt-get update && apt-get install -y --no-install-recommends \
-    ca-certificates git python3 && rm -rf /var/lib/apt/lists/*
-WORKDIR /echo
-RUN git init && git remote add origin https://github.com/flyingrobots/echo.git \
-    && git fetch --depth=1 origin 49e9efb68001dfd78563d18bac9359a87671e431 \
-    && git checkout --detach FETCH_HEAD \
-    && cp -R schemas/edict-provider/package/v1 /echo-provider
-COPY --from=compiler /edict/target/debug/edict /usr/local/bin/edict
-COPY edict/replace-range-probes/state-read /probe
-CMD ["python3", "/probe/run.py"]
diff --git a/edict/replace-range-probes/state-read/Dockerfile.dockerignore b/edict/replace-range-probes/state-read/Dockerfile.dockerignore
deleted file mode 100644
index 681a3149..00000000
--- a/edict/replace-range-probes/state-read/Dockerfile.dockerignore
+++ /dev/null
@@ -1,5 +0,0 @@
-*
-!edict/
-!edict/replace-range-probes/
-!edict/replace-range-probes/state-read/
-!edict/replace-range-probes/state-read/**
diff --git a/edict/replace-range-probes/state-read/README.md b/edict/replace-range-probes/state-read/README.md
deleted file mode 100644
index da41a87d..00000000
--- a/edict/replace-range-probes/state-read/README.md
+++ /dev/null
@@ -1,69 +0,0 @@
-# State-read ordering probe
-
-This is development evidence for [#296](https://github.com/flyingrobots/jedit/issues/296)
-and [PR #302](https://github.com/flyingrobots/jedit/pull/302). It is not the
-ReplaceRange implementation, an admitted operation, or a runtime capability.
-The frozen application and producer pins under `edict/replace-range/` are
-unchanged.
-
-ReplaceRange must read a buffer's canonical head and compare it with the
-requested basis before accepting an edit. A caller-provided head is not proof
-of current state. This deliberately small authored source asks for that
-read-then-check sequence through a Jim-owned semantic effect.
-
-The lawpack proposes `readCanonicalHead(BufferId) -> HeadId`, with a typed
-missing-fact obstruction. Its `snapshot-read-probe` target intrinsic is an
-explicit placeholder: **Echo does not implement it**. The retained pure-provider
-configuration is intentionally incompatible with stateful execution. This
-fixture establishes a compiler boundary, not an agreed future read ABI,
-footprint model, canonical fact decoder, or provider implementation.
-
-## Reproduce
-
-From the repository root, build and run without mounting a host repository:
-
-```sh
-docker build -f edict/replace-range-probes/state-read/Dockerfile \
-  -t jedit-state-read-boundary .
-docker run --rm jedit-state-read-boundary
-```
-
-The image pins Edict to `77f4a91080a6c2c875fe349da6fc6a64525947a2`
-and the existing Echo provider to
-`49e9efb68001dfd78563d18bac9359a87671e431`. Both revisions are fetched inside
-Docker. The harness copies inputs to disposable container storage and uses the
-public lawpack/application JSONL build API; it constructs no Core, Target IR,
-executable package, or native edit plan.
-
-Expected evidence:
-
-1. The complete lawpack builds, and its generated digest matches the authored
-   import.
-2. The source with the basis guard rejects at `TargetLoweringFailed`, with
-   `obstruction_requirement_step_output_dependency`.
-3. A control removes only that guard. It reaches the provider and rejects at
-   `ProviderLowererRefused`, with `UnsupportedSemantics`.
-4. Neither refusal publishes application output artifacts.
-
-The harness prints `JEDIT_STATE_READ_BOUNDARY_CONFIRMED` when both boundaries
-are observed. A passing harness therefore means the limitation is reproduced;
-it does **not** mean state reads or ReplaceRange work.
-
-## Required follow-through
-
-[Edict #218](https://github.com/flyingrobots/edict/issues/218) owns the ordered
-Target IR prerequisite exposed here.
-
-Edict currently separates pure bindings, requirements, and target steps.
-Requirements are pre-step guards. Supporting this operation requires an
-explicit ordering contract; deleting the rejection alone would lose the
-read-before-check meaning. The compiler must preserve dependencies and reject
-forward or fabricated references. Existing artifact identities and consumers
-need a deliberate compatibility path.
-
-After that compiler contract exists, Echo still needs an independently verified,
-generic snapshot-read and private staged-write execution path. Reads must share
-the admitted application snapshot; an obstruction must not publish partial
-edits. Jim owns canonical fact decoding, rope algorithms, identities, and typed
-obstructions. Complete rope transformation, oracle agreement, footprints,
-budgets, Tick/WAL/receipt, and recovery remain the acceptance criteria of #296.
diff --git a/edict/replace-range-probes/state-read/edict.application.json b/edict/replace-range-probes/state-read/edict.application.json
deleted file mode 100644
index b081d60c..00000000
--- a/edict/replace-range-probes/state-read/edict.application.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-  "schema": "edict.application/v1",
-  "coordinate": "jedit.text.replace_range@1",
-  "sources": [
-    "src/ReplaceRange.edict"
-  ],
-  "lawpacks": [
-    {
-      "manifest": "vendor/state-probe/manifest.cbor",
-      "exports": "vendor/state-probe/exports.cbor",
-      "adapter": "vendor/state-probe/adapter.cbor",
-      "targetConfiguration": "vendor/state-probe/echo-operation-configuration.cbor"
-    }
-  ],
-  "target": {
-    "profile": "echo.dpo@1",
-    "providerPackage": ".build/echo-provider"
-  },
-  "outputDirectory": ".build/application"
-}
diff --git a/edict/replace-range-probes/state-read/edict.lawpack.json b/edict/replace-range-probes/state-read/edict.lawpack.json
deleted file mode 100644
index 963fa1c5..00000000
--- a/edict/replace-range-probes/state-read/edict.lawpack.json
+++ /dev/null
@@ -1,247 +0,0 @@
-{
-  "schema": "edict.lawpack-build/v1",
-  "outputDirectory": "vendor/state-probe",
-  "lawpack": {
-    "schema": "edict.lawpack-authoring/v1",
-    "id": "jedit.text",
-    "version": "1",
-    "acceptedCoreAbi": [
-      "edict.core/v1"
-    ],
-    "dependencies": [],
-    "exportsCoordinate": "jedit.text.exports/v1",
-    "exports": {
-      "types": [
-        {
-          "coordinate": "jedit.text@1.NodeId",
-          "definition": "Bytes"
-        },
-        {
-          "coordinate": "jedit.text@1.BufferId",
-          "definition": "Nominal"
-        },
-        {
-          "coordinate": "jedit.text@1.HeadId",
-          "definition": "Nominal"
-        },
-        {
-          "coordinate": "jedit.text@1.ReplacementBytes",
-          "definition": "Bytes"
-        },
-        {
-          "coordinate": "jedit.text@1.ObstructionDetail",
-          "definition": "String"
-        }
-      ],
-      "constants": [
-        {
-          "coordinate": "jedit.text@1.maxCreatedLeaves",
-          "type": "U64",
-          "value": 4096
-        },
-        {
-          "coordinate": "jedit.text@1.maxCreatedBranches",
-          "type": "U64",
-          "value": 4096
-        }
-      ],
-      "pureFunctions": [
-        {
-          "source": "edict",
-          "coordinate": "jedit.text@1.maxCreatedLeafCount",
-          "typeParameters": [],
-          "parameterTypes": [],
-          "returnType": "U64",
-          "costTemplate": "jedit.text@1.replaceRangeBudget",
-          "determinismClass": "total",
-          "body": {
-            "params": [],
-            "body": {
-              "locals": [],
-              "bindings": [],
-              "result": {
-                "kind": "const",
-                "value": {
-                  "kind": "int",
-                  "width": "U64",
-                  "value": 4096
-                }
-              }
-            }
-          }
-        }
-      ],
-      "effects": [
-        {
-          "coordinate": "jedit.text@1.readCanonicalHead",
-          "typeParameters": [],
-          "inputType": "jedit.text@1.BufferId",
-          "outputType": "jedit.text@1.HeadId",
-          "executionClass": "runtime",
-          "effectKindHint": "read",
-          "footprintObligation": "jedit.text@1.replaceRangeFootprint",
-          "costObligation": "jedit.text@1.replaceRangeBudget",
-          "effectFailures": {
-            "missing": {
-              "authorityClass": "resourceFault",
-              "payloadType": "jedit.text@1.BufferId"
-            }
-          },
-          "guardSupport": true
-        }
-      ],
-      "obstructions": [
-        {
-          "coordinate": "jedit.text@1.RangeOrderInvalid",
-          "authorityClass": "domainMappable",
-          "payloadSchema": "jedit.text@1.ObstructionDetail"
-        },
-        {
-          "coordinate": "jedit.text@1.RangeOutOfBounds",
-          "authorityClass": "domainMappable",
-          "payloadSchema": "jedit.text@1.ObstructionDetail"
-        },
-        {
-          "coordinate": "jedit.text@1.Utf8BoundaryInvalid",
-          "authorityClass": "domainMappable",
-          "payloadSchema": "jedit.text@1.ObstructionDetail"
-        },
-        {
-          "coordinate": "jedit.text@1.NoOp",
-          "authorityClass": "domainMappable",
-          "payloadSchema": "jedit.text@1.ObstructionDetail"
-        },
-        {
-          "coordinate": "jedit.text@1.BasisNotCanonical",
-          "authorityClass": "domainMappable",
-          "payloadSchema": "jedit.text@1.ObstructionDetail"
-        },
-        {
-          "coordinate": "jedit.text@1.ArithmeticOverflow",
-          "authorityClass": "integrityFault",
-          "payloadSchema": "jedit.text@1.ObstructionDetail"
-        },
-        {
-          "coordinate": "jedit.text@1.FactMissing",
-          "authorityClass": "resourceFault",
-          "payloadSchema": "jedit.text@1.ObstructionDetail"
-        },
-        {
-          "coordinate": "jedit.text@1.FactMalformed",
-          "authorityClass": "integrityFault",
-          "payloadSchema": "jedit.text@1.ObstructionDetail"
-        },
-        {
-          "coordinate": "jedit.text@1.ContentIdentityMismatch",
-          "authorityClass": "integrityFault",
-          "payloadSchema": "jedit.text@1.ObstructionDetail"
-        },
-        {
-          "coordinate": "jedit.text@1.MalformedRope",
-          "authorityClass": "integrityFault",
-          "payloadSchema": "jedit.text@1.ObstructionDetail"
-        }
-      ],
-      "operationProfiles": {
-        "jedit.text@1.replaceRange": {
-          "opticTemplate": {
-            "opticKind": "affectReintegration",
-            "boundaryKind": "affect",
-            "supportPolicy": "jedit.text@1.basisBoundSupport",
-            "lossDisposition": "jedit.text@1.lossless",
-            "basisTemplate": "jedit.text@1.exactHeadBasis",
-            "apertureRequirement": {
-              "kind": "abstractFootprintObligation",
-              "reference": "jedit.text@1.replaceRangeFootprint"
-            }
-          },
-          "effectPredicate": "jedit.text@1.replaceRangeEffects"
-        }
-      }
-    },
-    "targetAdapters": [
-      {
-        "coordinate": "jedit.text.echo-adapter/v1",
-        "output": "adapter.cbor",
-        "acceptedTargetProfile": {
-          "id": "echo.dpo@1",
-          "digest": "sha256:2e2494121aecf5e6a2d920f5fb85408825d394765fad41484c416397c920fb04"
-        },
-        "acceptedTargetIr": {
-          "id": "echo.span-ir/v1",
-          "digest": "sha256:0057167e68f50c99dcce087b3e1cd677d17c5d1dc238bdb52d89469e1472fc2f"
-        },
-        "operationProfiles": {
-          "jedit.text@1.replaceRange": {
-            "core": "continuum.profile.read-write/v1",
-            "semanticEffects": [
-              "jedit.text@1.readCanonicalHead"
-            ],
-            "budgetObligation": "jedit.text@1.replaceRangeBudget",
-            "targetConfiguration": {
-              "local": "echo-config"
-            }
-          }
-        },
-        "effectImplementations": {
-          "jedit.text@1.readCanonicalHead": {
-            "targetIntrinsic": "echo.dpo@1.snapshot-read-probe",
-            "targetConfiguration": {
-              "local": "echo-config"
-            },
-            "writeClass": "read",
-            "footprintObligation": "jedit.text@1.replaceRangeFootprint",
-            "costObligation": "jedit.text@1.replaceRangeBudget",
-            "failureMappings": {
-              "missing": "echo.fact-missing/v1"
-            }
-          }
-        },
-        "budgets": {
-          "jedit.text@1.replaceRangeBudget": {
-            "maxSteps": 1048576,
-            "maxAllocatedBytes": 16777216,
-            "maxOutputBytes": 8388608
-          }
-        }
-      }
-    ],
-    "verifier": {
-      "class": "declarative",
-      "ruleset": {
-        "local": "verifier-rules"
-      }
-    },
-    "compatibility": {
-      "id": "jedit.text.compatibility/v1",
-      "digest": "sha256:2adf83f798205f52636ad64ca45178f33a8e1cc663874f8a6113484c945e3052"
-    },
-    "conformanceFixtureCorpus": {
-      "id": "jedit.text.ReplaceRange.oracle@1",
-      "digest": "sha256:b9b4707dd5e07897cbe7af36d88928401887e6af5d167d1a88a8d6181b4dbb0e"
-    },
-    "localResources": [
-      {
-        "name": "echo-config",
-        "coordinate": "echo.operation-lowering-configuration/v1",
-        "output": "echo-operation-configuration.cbor",
-        "value": {
-          "apiVersion": "echo.operation-lowering-configuration/v1",
-          "programKind": "compiler-produced-bounded-pure/v1"
-        }
-      },
-      {
-        "name": "verifier-rules",
-        "coordinate": "jedit.text.verifier-rules/v1",
-        "output": "verifier-rules.cbor",
-        "value": {
-          "schema": "jedit.text.schema@1",
-          "schemaDigest": "sha256:f49b0ff6c9c7010d3a72b46734d47832853f496739a083edc41dddec3431bac7",
-          "oracleIsExecutableInput": false,
-          "runtimeOntology": "generic-bounded-graph"
-        }
-      }
-    ]
-  },
-  "dependencyBundles": []
-}
diff --git a/edict/replace-range-probes/state-read/run.py b/edict/replace-range-probes/state-read/run.py
deleted file mode 100644
index 94087c6b..00000000
--- a/edict/replace-range-probes/state-read/run.py
+++ /dev/null
@@ -1,82 +0,0 @@
-"""Docker-only public compiler witness; this does not execute a rope edit."""
-
-import json
-import os
-from pathlib import Path
-import shutil
-import subprocess
-import tempfile
-
-
-GUARD = "  require canonicalHead == input.basisHeadId else text.BasisNotCanonical;\n"
-
-
-def build(binary, workspace, document):
-    request = {
-        "schema": "edict.compiler.settings/v1",
-        "type": "compilerSettings",
-        "operation": "build",
-        document: f"edict.{document}.json",
-    }
-    result = subprocess.run(
-        [binary], cwd=workspace, input=json.dumps(request) + "\n",
-        text=True, capture_output=True, timeout=120, check=False,
-    )
-    events = [
-        json.loads(line)
-        for stream in (result.stdout, result.stderr)
-        for line in stream.splitlines()
-    ]
-    return result, events
-
-
-def expect_refusal(binary, workspace, kind, detail):
-    result, events = build(binary, workspace, "application")
-    diagnostics = [event for event in events if event.get("type") == "diagnostic"]
-    if result.returncode != 2 or len(diagnostics) != 1:
-        raise RuntimeError(f"Unexpected build result: {result}\n{events}")
-    diagnostic = diagnostics[0]
-    if diagnostic["kind"] != kind or detail not in diagnostic["message"]:
-        raise RuntimeError(f"Wrong failure boundary: {diagnostic}")
-    output = workspace / ".build/application"
-    if output.exists() and list(output.rglob("*")):
-        raise RuntimeError("Refused application published output artifacts")
-    print(json.dumps(diagnostic, sort_keys=True))
-
-
-def main():
-    if not Path("/.dockerenv").is_file():
-        raise RuntimeError("Run this witness in its COPY-based Docker image")
-    binary = os.environ.get("EDICT_BINARY", "/usr/local/bin/edict")
-    provider = Path(os.environ.get("ECHO_PROVIDER_DIR", "/echo-provider"))
-    source = Path(__file__).resolve().parent
-    with tempfile.TemporaryDirectory(prefix="jedit-state-read-") as scratch:
-        workspace = Path(scratch) / "application"
-        workspace.mkdir()
-        for document in ("edict.application.json", "edict.lawpack.json"):
-            shutil.copyfile(source / document, workspace / document)
-        shutil.copytree(source / "src", workspace / "src")
-        shutil.copytree(provider, workspace / ".build/echo-provider")
-        result, events = build(binary, workspace, "lawpack")
-        if result.returncode != 0 or events[-1].get("status") != "ok":
-            raise RuntimeError(f"Lawpack did not build: {result}\n{events}")
-        authored = workspace / "src/ReplaceRange.edict"
-        text = authored.read_text()
-        manifest_digest = (workspace / "vendor/state-probe/manifest.sha256").read_text().strip()
-        if f'digest "{manifest_digest}"' not in text or text.count(GUARD) != 1:
-            raise RuntimeError("Source does not bind the exact generated lawpack and guard")
-        expect_refusal(
-            binary, workspace, "TargetLoweringFailed",
-            "obstruction_requirement_step_output_dependency",
-        )
-        # This control removes only the dependent guard. The proposed read is
-        # deliberately unsupported by the old provider; it must not execute.
-        authored.write_text(text.replace(GUARD, ""))
-        expect_refusal(
-            binary, workspace, "ProviderLowererRefused", "UnsupportedSemantics",
-        )
-    print("JEDIT_STATE_READ_BOUNDARY_CONFIRMED")
-
-
-if __name__ == "__main__":
-    main()
diff --git a/edict/replace-range-probes/state-read/src/ReplaceRange.edict b/edict/replace-range-probes/state-read/src/ReplaceRange.edict
deleted file mode 100644
index c59342c7..00000000
--- a/edict/replace-range-probes/state-read/src/ReplaceRange.edict
+++ /dev/null
@@ -1,13 +0,0 @@
-package jedit.text.replace_range@1;
-use lawpack jedit.text@1 digest "sha256:7d66e6d70629ab25602500ab5802c25114b3691d90e0858b98a3332ec088647c" as text;
-type Input = {bufferId: text.BufferId, basisHeadId: text.HeadId};
-intent replaceRange(input: Input) returns text.HeadId
-  profile text.replaceRange
-  basis input.basisHeadId
-  budget <= text.replaceRangeBudget
-{
-  let canonicalHead: text.HeadId = text.readCanonicalHead(input.bufferId)
-    else { missing(id) => text.FactMissing };
-  require canonicalHead == input.basisHeadId else text.BasisNotCanonical;
-  return canonicalHead;
-}
diff --git a/quality-baseline.json b/quality-baseline.json
index 101c833e..6f1f7b77 100644
--- a/quality-baseline.json
+++ b/quality-baseline.json
@@ -10,8 +10,7 @@
     "spec/workspace-runtime.spec.mjs": 520,
     "spec/workspace-text-boundaries.spec.mjs": 559,
     "spec/workspace-text-cutover.spec.mjs": 2045,
-    "spec/workspace-title-screen.spec.mjs": 730,
-    "tests/replace-range-law-cycle.spec.mjs": 539
+    "spec/workspace-title-screen.spec.mjs": 730
   },
   "forbiddenTypeKeywords": {},
   "booleanParameters": {}
diff --git a/scripts/ci/changed-shards.mjs b/scripts/ci/changed-shards.mjs
index 9f665fda..dc486265 100644
--- a/scripts/ci/changed-shards.mjs
+++ b/scripts/ci/changed-shards.mjs
@@ -148,7 +148,7 @@ export function impactForPath(pathName, packageChangeKind = PACKAGE_CHANGE_KINDS
     return shardImpact('workspace-ui-change', [TEST_SHARDS.WorkspaceUi, TEST_SHARDS.EchoAuthority], false);
   }
   if (isDocsPath(pathName)) {
-    return shardImpact('docs-change', [TEST_SHARDS.DocsRelease], false);
+    return shardImpact('docs-change', [], false);
   }
   return fullImpact('unknown-path');
 }
diff --git a/scripts/ci/frozen-paths.mjs b/scripts/ci/frozen-paths.mjs
index 30baa8d1..09f278b5 100644
--- a/scripts/ci/frozen-paths.mjs
+++ b/scripts/ci/frozen-paths.mjs
@@ -10,7 +10,7 @@ export const FROZEN_TITLE_PATH_PATTERNS = Object.freeze([
   /^scripts\/title/,
 ]);
 
-const FREEZE_POLICY_DOC = 'docs/method/backlog/leash/title-scene-freeze.md';
+const FREEZE_POLICY_DOC = 'docs/method/title-scene-freeze.md';
 
 export function isFrozenTitlePath(pathName) {
   return FROZEN_TITLE_PATH_PATTERNS.some((pattern) => pattern.test(pathName));
diff --git a/scripts/ci/shellcheck.sh b/scripts/ci/shellcheck.sh
index b5e99597..3c552bc1 100755
--- a/scripts/ci/shellcheck.sh
+++ b/scripts/ci/shellcheck.sh
@@ -17,6 +17,8 @@ unparsed=()
 while IFS= read -r -d '' path; do
   case "$path" in
     *.sh) scripts+=("$path") ;;
+    # Documentation is never opened by a check, even to read a shebang.
+    *.md) ;;
     *)
       [[ -f "$path" ]] || continue
       status=0
diff --git a/scripts/ci/test-shards.mjs b/scripts/ci/test-shards.mjs
index 6a4ac418..9f714f8f 100644
--- a/scripts/ci/test-shards.mjs
+++ b/scripts/ci/test-shards.mjs
@@ -17,14 +17,6 @@ const CONTRACT_SPEC_PATTERNS = Object.freeze([
   'rope',
   'save-checkpoint',
 ]);
-const DOCS_SPEC_PATTERNS = Object.freeze([
-  'codegen-docs',
-  'docs',
-  'guide',
-  'quickstart',
-  'release-gate-script',
-  'release-quickstart',
-]);
 const ECHO_SPEC_PATTERNS = Object.freeze([
   'echo',
   'hot-buffer',
@@ -64,7 +56,6 @@ const WORKSPACE_SPEC_PATTERNS = Object.freeze([
 export const TEST_SHARDS = Object.freeze({
   ContractApi: 'contract-api',
   CycleProofs: 'cycle-proofs',
-  DocsRelease: 'docs-release',
   EchoAuthority: 'echo-authority',
   MiscFast: 'misc-fast',
   TitleRendering: 'title-rendering',
@@ -74,7 +65,6 @@ export const TEST_SHARDS = Object.freeze({
 export const TEST_SHARD_NAMES = Object.freeze([
   TEST_SHARDS.ContractApi,
   TEST_SHARDS.CycleProofs,
-  TEST_SHARDS.DocsRelease,
   TEST_SHARDS.EchoAuthority,
   TEST_SHARDS.MiscFast,
   TEST_SHARDS.TitleRendering,
@@ -105,9 +95,6 @@ export function testShardForSpec(filePath) {
   if (includesAny(name, TITLE_SPEC_PATTERNS)) {
     return TEST_SHARDS.TitleRendering;
   }
-  if (includesAny(name, DOCS_SPEC_PATTERNS)) {
-    return TEST_SHARDS.DocsRelease;
-  }
   if (repoPath.startsWith('tests/')) {
     return TEST_SHARDS.CycleProofs;
   }
diff --git a/scripts/quality-gate.mjs b/scripts/quality-gate.mjs
index 1522aa4d..52492979 100644
--- a/scripts/quality-gate.mjs
+++ b/scripts/quality-gate.mjs
@@ -10,7 +10,6 @@ const SOURCE_ROOT = path.join(ROOT, 'src');
 // max-lines applies here; the other rules encode TypeScript-specific doctrine.
 const SPEC_ROOTS = [path.join(ROOT, 'spec'), path.join(ROOT, 'tests')];
 const BASELINE_PATH = path.join(ROOT, 'quality-baseline.json');
-const PACKAGE_PATH = path.join(ROOT, 'package.json');
 const MAX_LINES_PER_FILE = 500;
 const MAX_PARAMETERS_PER_FUNCTION = 5;
 const MAX_RUNTIME_IMPORTS_PER_FILE = 12;
@@ -20,14 +19,6 @@ const MAX_NESTING_DEPTH = 4;
 const MAX_STATEMENTS_PER_FUNCTION = 25;
 const MAX_SOURCE_LINE_LENGTH = 160;
 const JSON_FLAG = '--json';
-const IDENTITY_DOCTRINE_DOC = path.join(ROOT, 'docs/design/echo-identity-doctrine.md');
-const IDENTITY_DOCTRINE_REQUIRED_LINKS = [
-  { file: 'ARCHITECTURE.md', marker: 'docs/design/echo-identity-doctrine.md' },
-  { file: 'README.md', marker: 'docs/design/echo-identity-doctrine.md' },
-  { file: 'docs/BEARING.md', marker: 'design/echo-identity-doctrine.md' },
-  { file: 'docs/echo-application-hosting-guide.md', marker: 'docs/design/echo-identity-doctrine.md' },
-  { file: 'docs/design/0027-echo-hosted-production-cutover.md', marker: 'echo-identity-doctrine.md' },
-];
 
 function main() {
   const baseline = loadBaseline();
@@ -35,7 +26,6 @@ function main() {
   const regressions = [];
   const debt = [];
   const improvements = [];
-  validateIdentityDoctrineReferences(regressions);
 
   for (const filePath of files) {
     const relativePath = toRepoPath(filePath);
@@ -215,7 +205,6 @@ function main() {
       'max-line-length-160',
       'no-magic-comparison-literal',
       'max-lines-500',
-      'identity-doctrine-links',
     ],
     fileCount: files.length + collectSpecFiles().length,
     regressions,
@@ -232,64 +221,6 @@ function main() {
   process.exitCode = result.ok ? 0 : 1;
 }
 
-function validateIdentityDoctrineReferences(regressions) {
-  if (!isJeditRepoRoot()) {
-    return;
-  }
-
-  if (!fs.existsSync(IDENTITY_DOCTRINE_DOC)) {
-    regressions.push({
-      file: 'docs/design/echo-identity-doctrine.md',
-      rule: 'identity-doctrine-links',
-      actual: 'missing',
-      allowed: 'present',
-    });
-    return;
-  }
-
-  const doctrineText = fs.readFileSync(IDENTITY_DOCTRINE_DOC, 'utf8');
-  const hasTitle = doctrineText.includes('# Echo Identity Doctrine');
-  if (!hasTitle) {
-    regressions.push({
-      file: 'docs/design/echo-identity-doctrine.md',
-      rule: 'identity-doctrine-links',
-      actual: 'missing doctrine heading',
-      allowed: 'Echo Identity Doctrine',
-    });
-  }
-
-  for (const entry of IDENTITY_DOCTRINE_REQUIRED_LINKS) {
-    const fullPath = path.join(ROOT, entry.file);
-    if (!fs.existsSync(fullPath)) {
-      regressions.push({
-        file: entry.file,
-        rule: 'identity-doctrine-links',
-        actual: 'missing',
-        allowed: `include marker ${entry.marker}`,
-      });
-      continue;
-    }
-    const content = fs.readFileSync(fullPath, 'utf8');
-    if (!content.includes(entry.marker)) {
-      regressions.push({
-        file: entry.file,
-        rule: 'identity-doctrine-links',
-        actual: 'marker missing',
-        allowed: `include marker ${entry.marker}`,
-      });
-    }
-  }
-}
-
-function isJeditRepoRoot() {
-  if (!fs.existsSync(PACKAGE_PATH)) {
-    return false;
-  }
-
-  const packageJson = JSON.parse(fs.readFileSync(PACKAGE_PATH, 'utf8'));
-  return packageJson.name === 'jedit';
-}
-
 function recordCountRule(options) {
   if (options.actual > options.allowed) {
     options.regressions.push({
diff --git a/spec/audit-docs.spec.mjs b/spec/audit-docs.spec.mjs
deleted file mode 100644
index b43f8276..00000000
--- a/spec/audit-docs.spec.mjs
+++ /dev/null
@@ -1,95 +0,0 @@
-import assert from 'node:assert/strict';
-import { readFileSync } from 'node:fs';
-import test from 'node:test';
-
-const READY_AUDIT = 'docs/audits/ready-to-ship-assessment-2026-06-28.md';
-const TWO_PHASE_AUDIT = 'docs/audits/two-phase-assessment-2026-06-28.md';
-const DOC_AUDIT = 'docs/audits/documentation-readme-audit-2026-06-28.md';
-
-function readRepoText(path) {
-  return readFileSync(path, 'utf8');
-}
-
-test('ready-to-ship audit does not prescribe forbidden unknown annotations', () => {
-  const audit = readRepoText(READY_AUDIT);
-
-  assert.doesNotMatch(audit, /nodeErrorCode\(cause: unknown\)/);
-  assert.doesNotMatch(audit, /loadErrorResult\(filePath: string, cause: unknown\)/);
-  assert.match(audit, /nodeErrorCode\(cause: Error\): string \| undefined/);
-});
-
-test('ready-to-ship audit includes parent directory fsync in atomic save guidance', () => {
-  const audit = readRepoText(READY_AUDIT);
-
-  assert.match(audit, /fsync the parent directory after rename/);
-});
-
-test('ready-to-ship audit separates production export preflight from legacy save risk', () => {
-  const audit = readRepoText(READY_AUDIT);
-
-  assert.match(audit, /Ctrl-S and `:write`.*saveProductionText/s);
-  assert.match(audit, /materializationPreflightIssue/);
-  assert.match(audit, /legacy.*saveEditor/s);
-  assert.doesNotMatch(audit, /Two Jim instances, or Jim plus any external tool, silently clobber each other/);
-});
-
-test('ready-to-ship audit reflects the current CI quality gate', () => {
-  const audit = readRepoText(READY_AUDIT);
-
-  assert.match(audit, /\.github\/workflows\/ci\.yml.*quality job/s);
-  assert.match(audit, /scripts\/quality-gate\.mjs/);
-  assert.match(audit, /npm run quality/);
-  assert.match(audit, /aggregate `check` job.*quality/s);
-  assert.doesNotMatch(audit, /no lint job in CI/);
-  assert.doesNotMatch(audit, /CI `\.github\/workflows\/ci\.yml` = build \+ sharded tests, no lint\/audit gate/);
-});
-
-test('two-phase audit names exact and ranged first-party dependencies correctly', () => {
-  const audit = readRepoText(TWO_PHASE_AUDIT);
-
-  assert.match(audit, /`@flyingrobots\/graft` is exact-pinned to `0\.10\.1`/);
-  assert.match(audit, /`@flyingrobots\/bijou-i18n` and its tools use `\^7\.0\.0`/);
-  assert.doesNotMatch(audit, /Pin @flyingrobots\/graft to an exact version/);
-});
-
-test('documentation audit prompt covers all stale Advanced Guide runtime references', () => {
-  const audit = readRepoText(DOC_AUDIT);
-
-  assert.match(audit, /`src\/app\/workspace\/editor\/model\.ts`/);
-  assert.match(audit, /`src\/app\/workspace\/editor-editing-core\.ts`/);
-  assert.match(audit, /`src\/app\/workspace\/runtime\.ts`/);
-  assert.match(audit, /`src\/ui\/workspace-render\.ts`/);
-  assert.match(audit, /`src\/main-workspace\.ts`/);
-  assert.match(audit, /`src\/main\.ts` only remains the process entrypoint/);
-});
-const AGENTS = 'AGENTS.md';
-const DURABLE_DECISIONS = 'docs/method/durable-decisions.md';
-const ARCHITECTURE = 'ARCHITECTURE.md';
-const OWNERSHIP = 'docs/jim-component-ownership.md';
-const POLICY_RULE = /Identify one canonical owner before completing the change/;
-const OWNERSHIP_RULE = /is Jim's mind/;
-
-test('the durable decision policy states its rules in exactly one document', () => {
-  const owner = readRepoText(DURABLE_DECISIONS);
-  const agents = readRepoText(AGENTS);
-
-  assert.match(owner, POLICY_RULE);
-  assert.doesNotMatch(agents, POLICY_RULE);
-  assert.match(agents, /docs\/method\/durable-decisions\.md/);
-});
-
-test('the documentation router lists the durable decision owner', () => {
-  assert.match(
-    readRepoText(AGENTS),
-    /- `docs\/method\/durable-decisions\.md` owns the durable decision policy/,
-  );
-});
-
-test('target ownership rules are stated only by their canonical owner', () => {
-  const owner = readRepoText(OWNERSHIP);
-  const architecture = readRepoText(ARCHITECTURE);
-
-  assert.match(owner, OWNERSHIP_RULE);
-  assert.doesNotMatch(architecture, OWNERSHIP_RULE);
-  assert.match(architecture, /docs\/jim-component-ownership\.md/);
-});
diff --git a/spec/causal-roadmap-signpost.spec.mjs b/spec/causal-roadmap-signpost.spec.mjs
deleted file mode 100644
index 1d7ceece..00000000
--- a/spec/causal-roadmap-signpost.spec.mjs
+++ /dev/null
@@ -1,81 +0,0 @@
-import assert from 'node:assert/strict';
-import { readFileSync } from 'node:fs';
-import path from 'node:path';
-import test from 'node:test';
-
-const REPO_ROOT = process.cwd();
-const CAUSAL_ROADMAP_PATH = path.join(REPO_ROOT, 'docs', 'design', '0108-causal-command-provenance-surface.md');
-const GEORDI_ROADMAP_PATH = path.join(REPO_ROOT, 'docs', 'design', '0107-geordi-raytraced-title-render-pipeline.md');
-
-function readRepoFile(filePath) {
-  return readFileSync(filePath, 'utf8');
-}
-
-test('title-render follow-up arcs do not reserve active Jim cycle ids', () => {
-  const causalRoadmap = readRepoFile(CAUSAL_ROADMAP_PATH);
-  const geordiRoadmap = readRepoFile(GEORDI_ROADMAP_PATH);
-
-  assert.match(causalRoadmap, /WF-0108 - Jim Command Provenance And :why/);
-  assert.doesNotMatch(geordiRoadmap, /WF-0108 - Bijou UI GraphQL Profile/);
-  assert.doesNotMatch(geordiRoadmap, /WF-0109 - Geordi Scene3D Authoring Profile/);
-  assert.match(geordiRoadmap, /WF-0112 - Bijou UI GraphQL Profile/);
-  assert.match(geordiRoadmap, /WF-0113 - Geordi Scene3D Authoring Profile/);
-});
-
-test('WF-0108 current truth cites merge-target evidence links', () => {
-  const causalRoadmap = readRepoFile(CAUSAL_ROADMAP_PATH);
-  const currentTruth = sectionBetween(causalRoadmap, '## Current Truth', '## Problem');
-  const evidenceLinks = currentTruth.match(
-    /https:\/\/github\.com\/flyingrobots\/jedit\/blob\/[0-9a-f]{40}\/[^)\s]+#L[0-9]+/g,
-  );
-
-  assert.ok(evidenceLinks, 'Current Truth should include fully-qualified GitHub evidence links');
-  assert.ok(evidenceLinks.length >= 7, 'Current Truth should cite every strong baseline claim');
-});
-
-test('WF-0108 validation commands are runnable shell commands', () => {
-  const causalRoadmap = readRepoFile(CAUSAL_ROADMAP_PATH);
-  const validationPlan = sectionBetween(causalRoadmap, '## Validation Plan', '## Playback / Witness');
-
-  assert.doesNotMatch(validationPlan, /spec\/<[^>]+>\.spec\.mjs/);
-});
-
-test('WF-0108 follow-on debt is issue-backed', () => {
-  const causalRoadmap = readRepoFile(CAUSAL_ROADMAP_PATH);
-  const followOnDebt = sectionBetween(causalRoadmap, '## Follow-On Debt', '## Retrospective');
-  const debtItems = followOnDebt
-    .split('\n')
-    .filter((line) => line.startsWith('- '));
-
-  assert.ok(debtItems.length >= 10, 'expected issue-backed follow-on items');
-  for (const item of debtItems) {
-    assert.match(item, /^- \[[^\]]+\]\(https:\/\/github\.com\/flyingrobots\/jedit\/issues\/[0-9]+\)\.?$/);
-  }
-});
-
-test('WF-0108 playback exits insert mode before :why', () => {
-  const causalRoadmap = readRepoFile(CAUSAL_ROADMAP_PATH);
-  const playback = sectionBetween(causalRoadmap, '## Playback / Witness', 'Current repo command');
-
-  assert.match(playback, /\n\n:why/);
-});
-
-test('WF-0108 names command-event invariant enforcement', () => {
-  const causalRoadmap = readRepoFile(CAUSAL_ROADMAP_PATH);
-  const dataModel = sectionBetween(causalRoadmap, '## Data / State Model', '## Accessibility Posture');
-
-  assert.match(dataModel, /createJeditCommandEvent/);
-  assert.match(dataModel, /JeditCommandEventRejected/);
-  assert.match(dataModel, /AppliedCommandEvent/);
-  assert.match(dataModel, /RangeResolvedCommandEvent/);
-});
-
-function sectionBetween(documentText, startHeading, endHeading) {
-  const start = documentText.indexOf(startHeading);
-  const end = documentText.indexOf(endHeading, start);
-
-  assert.notEqual(start, -1, `${startHeading} missing`);
-  assert.notEqual(end, -1, `${endHeading} missing after ${startHeading}`);
-
-  return documentText.slice(start, end);
-}
diff --git a/spec/causal-rope-text-authority-inventory.spec.mjs b/spec/causal-rope-text-authority-inventory.spec.mjs
deleted file mode 100644
index 899ad199..00000000
--- a/spec/causal-rope-text-authority-inventory.spec.mjs
+++ /dev/null
@@ -1,65 +0,0 @@
-import assert from 'node:assert/strict';
-import { readFileSync } from 'node:fs';
-import path from 'node:path';
-import test from 'node:test';
-
-const REPO_ROOT = process.cwd();
-const INVENTORY_PATH = path.join(REPO_ROOT, 'docs', 'design', '0151-causal-rope-text-authority-inventory.md');
-const REQUIRED_COVERAGE = Object.freeze([
-  'Installed transport',
-  'Workspace authority state',
-  'Command handlers',
-  'Save/export',
-  'Source rendering',
-  'Why command',
-  'Tests and witnesses',
-]);
-const REQUIRED_CLASSIFICATIONS = Object.freeze([
-  'causal rope authority',
-  'materialized projection',
-  'fixture',
-  'migration/import',
-  'forbidden',
-]);
-const REQUIRED_ISSUES = Object.freeze([
-  '#217',
-  '#218',
-  '#222',
-  '#247',
-  '#249',
-]);
-
-test('causal rope text authority inventory covers required product surfaces', () => {
-  const source = readFileSync(INVENTORY_PATH, 'utf8');
-
-  for (const heading of REQUIRED_COVERAGE) {
-    assert.match(source, new RegExp(`\\| ${escapeRegExp(heading)} \\|`, 'u'));
-  }
-});
-
-test('causal rope text authority inventory defines every CR-00 classification', () => {
-  const source = readFileSync(INVENTORY_PATH, 'utf8');
-
-  for (const classification of REQUIRED_CLASSIFICATIONS) {
-    assert.match(source, new RegExp(`\\*\\*${escapeRegExp(classification)}\\*\\*`, 'u'));
-  }
-});
-
-test('causal rope text authority inventory links concrete follow-up blockers', () => {
-  const source = readFileSync(INVENTORY_PATH, 'utf8');
-
-  for (const issue of REQUIRED_ISSUES) {
-    assert.match(source, new RegExp(escapeRegExp(issue), 'u'));
-  }
-});
-
-test('causal rope text authority inventory states full materialized strings are not authority', () => {
-  const source = readFileSync(INVENTORY_PATH, 'utf8');
-
-  assert.match(source, /Full materialized strings are allowed only as import inputs/u);
-  assert.match(source, /forbidden as product text authority/u);
-});
-
-function escapeRegExp(value) {
-  return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
-}
diff --git a/spec/ci-frozen-paths.spec.mjs b/spec/ci-frozen-paths.spec.mjs
index 2b34ec93..d4691154 100644
--- a/spec/ci-frozen-paths.spec.mjs
+++ b/spec/ci-frozen-paths.spec.mjs
@@ -46,7 +46,7 @@ test('the unfreeze label allows title-scene changes through', () => {
 
 test('non-title changes are never frozen', () => {
   const verdict = evaluateFrozenPaths(
-    ['src/domain/graph-rope-types.ts', 'docs/BEARING.md', 'src/ui/theme-builder.ts'],
+    ['src/domain/graph-rope-types.ts', 'docs/method/ci.md', 'src/ui/theme-builder.ts'],
     { allowTitleChanges: false },
   );
 
diff --git a/spec/ci-shards.spec.mjs b/spec/ci-shards.spec.mjs
index a20a3650..99ec224c 100644
--- a/spec/ci-shards.spec.mjs
+++ b/spec/ci-shards.spec.mjs
@@ -36,15 +36,14 @@ test('known specs map to stable shard owners', () => {
   assert.equal(testShardForSpec('spec/jedit-echo-host-witness.spec.mjs'), TEST_SHARDS.EchoAuthority);
   assert.equal(testShardForSpec('spec/graph-rope-contract.spec.mjs'), TEST_SHARDS.ContractApi);
   assert.equal(testShardForSpec('tests/anchor-transform-cycle.spec.mjs'), TEST_SHARDS.CycleProofs);
-  assert.equal(testShardForSpec('spec/release-quickstart.spec.mjs'), TEST_SHARDS.DocsRelease);
 });
 
-test('planner keeps docs-only changes narrow', () => {
-  const plan = planChangedShards(['docs/BEARING.md']);
+test('planner runs no test shards for docs-only changes', () => {
+  const plan = planChangedShards(['docs/method/ci.md']);
 
   assert.equal(plan.full, false);
   assert.equal(plan.releaseGate, false);
-  assert.deepEqual(plan.testShards, [TEST_SHARDS.DocsRelease]);
+  assert.deepEqual(plan.testShards, []);
 });
 
 test('planner routes workspace changes through workspace and Echo authority shards', () => {
diff --git a/spec/ci-shellcheck-shebang.spec.mjs b/spec/ci-shellcheck-shebang.spec.mjs
index a5bab5c1..ab19ef3f 100644
--- a/spec/ci-shellcheck-shebang.spec.mjs
+++ b/spec/ci-shellcheck-shebang.spec.mjs
@@ -78,3 +78,23 @@ test('the ShellCheck driver refuses a tracked file whose env shebang it cannot c
   assert.equal(result.status, 1);
   assert.match(result.stderr, /cannot tell whether run is a shell script/);
 });
+
+test('the ShellCheck driver never opens tracked Markdown files', (t) => {
+  const repo = temporaryDirectory(t, 'jedit-shellcheck-markdown-');
+  mkdirSync(path.join(repo, 'scripts', 'ci'), { recursive: true });
+  cpSync(path.join(process.cwd(), 'scripts', 'ci'), path.join(repo, 'scripts', 'ci'), { recursive: true });
+  writeFileSync(path.join(repo, 'run'), '#!/usr/bin/env -S bash -e\necho hi\n', { mode: 0o755 });
+  writeFileSync(path.join(repo, 'notes.md'), '#!/usr/bin/env -S bash -e\n# Notes\n');
+  git(repo, 'init', '-q');
+  git(repo, 'add', '-A');
+
+  const result = spawnSync(path.join(repo, 'scripts', 'ci', 'shellcheck.sh'), [], {
+    cwd: repo,
+    encoding: 'utf8',
+    env: cleanGitEnv(),
+  });
+
+  assert.equal(result.status, 1);
+  assert.match(result.stderr, /cannot tell whether run is a shell script/);
+  assert.doesNotMatch(result.stderr, /notes\.md/);
+});
diff --git a/spec/design-cycle-policy.spec.mjs b/spec/design-cycle-policy.spec.mjs
deleted file mode 100644
index b4d7d86c..00000000
--- a/spec/design-cycle-policy.spec.mjs
+++ /dev/null
@@ -1,346 +0,0 @@
-import assert from 'node:assert/strict';
-import { readFileSync } from 'node:fs';
-import path from 'node:path';
-import test from 'node:test';
-
-const REPO_ROOT = process.cwd();
-const AGENTS_PATH = path.join(REPO_ROOT, 'AGENTS.md');
-const PROCESS_PATH = path.join(REPO_ROOT, 'docs', 'method', 'process.md');
-const TEMPLATE_PATH = path.join(REPO_ROOT, 'docs', 'design', 'TEMPLATE.md');
-const POLICY_DESIGN_PATH = path.join(REPO_ROOT, 'docs', 'design', '0034-design-cycle-template-and-lifecycle.md');
-const BEARING_PATH = path.join(REPO_ROOT, 'docs', 'BEARING.md');
-const WHY_OBSERVATION_ROADMAP_PATH = path.join(
-  REPO_ROOT,
-  'docs',
-  'design',
-  '0108a-why-observation-evidence-roadmap.md',
-);
-const GRAPH_RUNTIME_DISCOVERY_PATH = path.join(
-  REPO_ROOT,
-  'docs',
-  'design',
-  '0149-graph-backed-rope-runtime-discovery.md',
-);
-const GRAPH_RUNTIME_RED_MATRIX_PATH = path.join(REPO_ROOT, 'spec', 'graph-rope-runtime-red-matrix.spec.mjs');
-const WF_0154_DESIGN_PATH = path.join(REPO_ROOT, 'docs', 'design', '0154-e-brake-absurdity-fixes.md');
-const CAUSAL_UNDO_BACKLOG_PATH = path.join(
-  REPO_ROOT,
-  'docs',
-  'method',
-  'backlog',
-  'cool-ideas',
-  'causal-undo-family.md',
-);
-
-const REQUIRED_TEMPLATE_HEADINGS = Object.freeze([
-  '## Linked Issue',
-  '## Decision Summary',
-  '## Sponsored Human',
-  '## Sponsored Agent',
-  '## Hill',
-  '## Current Truth',
-  '## Problem',
-  '## Scope',
-  '## Non-Goals',
-  '## User Experience / Product Shape',
-  '## Runtime / API Contract',
-  '## Lower Modes',
-  '## Accessibility Posture',
-  '## Localization / Directionality Posture',
-  '## Agent Inspectability / Explainability Posture',
-  '## Implementation Slices',
-  '## Tests To Write First',
-  '## Acceptance Criteria',
-  '## Validation Plan',
-  '## Playback / Witness',
-  '## Retrospective',
-]);
-
-const REQUIRED_PROCESS_SECTIONS = Object.freeze([
-  '## Cycle Doctrine',
-  '## Design Classes',
-  '## Starting A Full Cycle',
-  '## During A Cycle',
-  '## Ready For Review',
-  '## Landing A Cycle',
-]);
-
-const GRAPH_RUNTIME_RED_WITNESSES = Object.freeze([
-  'RED: graph-backed runtime retention is not O(buffer size * edit count)',
-  'RED: narrow replacement preserves untouched subtree identity recursively',
-  'RED: save and export read from a named head or checkpoint without mutating text authority',
-  'RED: range why cites head leaf blob rewrite diff tick checkpoint and basis evidence',
-]);
-
-function readRepoFile(filePath) {
-  return readFileSync(filePath, 'utf8');
-}
-
-test('full cycle design template includes the required proof-oriented sections', () => {
-  const template = readRepoFile(TEMPLATE_PATH);
-
-  for (const heading of REQUIRED_TEMPLATE_HEADINGS) {
-    assert.match(template, new RegExp(`^${escapeRegExp(heading)}$`, 'm'), `${heading} missing from template`);
-  }
-
-  assert.match(template, /documentation tests cannot be the only proof for implementation work/);
-  assert.match(template, /Echo authority boundary/);
-  assert.match(template, /Graft API boundary/);
-  assert.match(template, /terminal size constraints/);
-  assert.match(template, /Agent Inspectability/);
-});
-
-test('WF-0108A roadmap preserves required full-cycle design headings', () => {
-  const roadmap = readRepoFile(WHY_OBSERVATION_ROADMAP_PATH);
-
-  for (const heading of REQUIRED_TEMPLATE_HEADINGS) {
-    assert.match(roadmap, new RegExp(`^${escapeRegExp(heading)}$`, 'm'), `${heading} missing from WF-0108A`);
-  }
-});
-
-test('HT-0149 runtime discovery pins Current Truth evidence to git SHAs', () => {
-  const discovery = readRepoFile(GRAPH_RUNTIME_DISCOVERY_PATH);
-  const sha = '[0-9a-f]{40}';
-
-  for (const repoPath of [
-    'src/domain/text-edit-contract.ts',
-    'src/ports/hot-text-runtime.ts',
-    'src/adapters/in-memory-hot-text-runtime.ts',
-    'src/adapters/installed-jedit-contract-echo-transport.ts',
-    'docs/design/jedit-echo-graph-model.md',
-  ]) {
-    assert.match(
-      discovery,
-      new RegExp(`https://github\\.com/flyingrobots/jedit/blob/${sha}/${escapeRegExp(repoPath)}#L\\d+`),
-      `${repoPath} needs a pinned Current Truth evidence link`,
-    );
-  }
-});
-
-test('HT-0149 rope fact validation receives admission context', () => {
-  const discovery = readRepoFile(GRAPH_RUNTIME_DISCOVERY_PATH);
-
-  assert.match(discovery, /^interface RopeFactValidationContext \{$/m);
-  assert.match(discovery, /readonly writeSet: readonly RopeAdmittedFact\[\];/);
-  assert.match(discovery, /readonly admittedBasis:/);
-  assert.match(discovery, /readonly blobStore:/);
-  assert.match(discovery, /readonly hash: TextBlobHashPort;/);
-  assert.match(
-    discovery,
-    /declare function validateRopeFact\(\n  payload: RopeAdmittedFact,\n  context: RopeFactValidationContext,\n\): FactValidationResult {
-  const discovery = readRepoFile(GRAPH_RUNTIME_DISCOVERY_PATH);
-
-  for (const factName of ['RopeRewriteFact', 'RopeDiffFact']) {
-    assert.match(discovery, new RegExp(`^interface ${factName} \\{$`, 'm'));
-  }
-
-  assert.match(discovery, /^type EchoReceiptId =/m);
-  assert.match(discovery, /^interface TextByteRange \{$/m);
-  assert.match(discovery, /readonly range: TextByteRange;/);
-  assert.match(discovery, /readonly diffId: RopeDiffId;/);
-  assert.match(discovery, /readonly spans: readonly RopeDiffSpan\[\];/);
-  assert.match(discovery, /readonly createdByEchoReceiptId: EchoReceiptId;/);
-  assert.match(discovery, /readonly admittedByEchoReceiptId: EchoReceiptId;/);
-  assert.doesNotMatch(discovery, /interface TickReceiptFact/);
-  assert.doesNotMatch(discovery, /readonly admittedAtSequence: number;/);
-});
-
-test('HT-0149 checkpoint fact carries schema version', () => {
-  const discovery = readRepoFile(GRAPH_RUNTIME_DISCOVERY_PATH);
-
-  assert.match(discovery, /interface RopeCheckpointFact \{[\s\S]*readonly schemaVersion: 1;/);
-});
-
-test('HT-0149 checkpoint facts are validated rather than deferred', () => {
-  const discovery = readRepoFile(GRAPH_RUNTIME_DISCOVERY_PATH);
-  const deferredFacts = sectionBetween(discovery, 'The full design must also define jedit facts for:', 'Echo remains generic');
-  const admittedFacts = sectionBetween(discovery, 'type RopeAdmittedFact =', 'interface RopeFactReadModel');
-
-  assert.doesNotMatch(admittedFacts, /\| TickReceiptFact/);
-  assert.match(admittedFacts, /\| RopeCheckpointFact\b/);
-  assert.match(admittedFacts, /\| RopeCheckpointAnchoredFact;/);
-  assert.match(discovery, /\): FactValidationResult;/);
-  assert.doesNotMatch(deferredFacts, /`RopeCheckpoint`/);
-});
-
-test('HT-0149 validation exposes typed admitted facts', () => {
-  const discovery = readRepoFile(GRAPH_RUNTIME_DISCOVERY_PATH);
-
-  assert.match(discovery, /^type RopeAdmittedFact =$/m);
-  assert.match(discovery, /getFact\(id: string\): RopeAdmittedFact \| null;/);
-  assert.match(discovery, /\): FactValidationResult;/);
-  assert.doesNotMatch(discovery, /hasFact\(id: string\): boolean;/);
-  assert.match(discovery, /reference validation must retrieve typed facts/);
-});
-
-test('HT-0149 diff spans are kind-specific', () => {
-  const discovery = readRepoFile(GRAPH_RUNTIME_DISCOVERY_PATH);
-
-  for (const spanName of ['RopeEqualDiffSpan', 'RopeDeleteDiffSpan', 'RopeInsertDiffSpan']) {
-    assert.match(discovery, new RegExp(`^interface ${spanName} \\{$`, 'm'));
-  }
-
-  assert.match(discovery, /^type RopeDiffSpan = RopeEqualDiffSpan \| RopeDeleteDiffSpan \| RopeInsertDiffSpan;$/m);
-  assert.doesNotMatch(discovery, /readonly kind: "equal" \| "delete" \| "insert";/);
-  assert.doesNotMatch(discovery, /readonly basisRange\?: TextByteRange;/);
-  assert.match(discovery, /diff spans are kind-specific/);
-});
-
-test('HT-0149 keeps Echo receipt authority outside Jim facts', () => {
-  const discovery = readRepoFile(GRAPH_RUNTIME_DISCOVERY_PATH);
-
-  assert.match(discovery, /Echo receipts are kernel-owned evidence and remain opaque to jedit/);
-  assert.match(discovery, /jedit must not define an application-local receipt fact/);
-  assert.doesNotMatch(discovery, /interface TickReceiptFact/);
-});
-
-test('HT-0149 defines structural maintenance facts for rebalance exceptions', () => {
-  const discovery = readRepoFile(GRAPH_RUNTIME_DISCOVERY_PATH);
-  const admittedFacts = sectionBetween(discovery, 'type RopeAdmittedFact =', 'interface RopeFactReadModel');
-
-  assert.match(discovery, /^type RopeStructuralMaintenanceId =/m);
-  assert.match(discovery, /^type RopeStructuralMaintenanceOperation =$/m);
-  assert.match(discovery, /^interface RopeStructuralMaintenanceFact \{$/m);
-  assert.match(discovery, /readonly operation: RopeStructuralMaintenanceOperation;/);
-  assert.match(discovery, /readonly replacedNodeIds: readonly RopeNodeId\[\];/);
-  assert.match(discovery, /readonly replacementNodeIds: readonly RopeNodeId\[\];/);
-  assert.match(discovery, /readonly affectedRange: TextByteRange;/);
-  assert.match(admittedFacts, /\| RopeStructuralMaintenanceFact/);
-  assert.match(discovery, /structural maintenance facts must reference the semantic rewrite/);
-});
-
-test('HT-0149 specifies concrete rope balance invariants', () => {
-  const discovery = readRepoFile(GRAPH_RUNTIME_DISCOVERY_PATH);
-
-  assert.match(discovery, /target leaf byte length is 4096 bytes/);
-  assert.match(discovery, /minimum non-edge leaf byte length is 1024 bytes/);
-  assert.match(discovery, /maximum leaf byte length is 8192 bytes/);
-  assert.match(discovery, /branch height difference must be no greater than 1/);
-});
-
-test('HT-0149 follow-on debt is issue-backed', () => {
-  const discovery = readRepoFile(GRAPH_RUNTIME_DISCOVERY_PATH);
-  const followOnDebt = sectionBetween(discovery, '## Follow-On Debt', '## Retrospective');
-  const issueLinks = followOnDebt.match(/https:\/\/github\.com\/flyingrobots\/jedit\/issues\/\d+/g) ?? [];
-
-  assert.ok(issueLinks.length >= 6, 'follow-on debt should link tracker issues for every deferred item');
-  assert.doesNotMatch(followOnDebt, /should create narrower issues/);
-});
-
-test('HT-0149 graph runtime RED matrix declares all Slice 4 witnesses', () => {
-  const discovery = readRepoFile(GRAPH_RUNTIME_DISCOVERY_PATH);
-  const redMatrix = readRepoFile(GRAPH_RUNTIME_RED_MATRIX_PATH);
-
-  assert.match(discovery, /\[x\] Slice 4: Add failing retention/);
-
-  for (const witnessName of GRAPH_RUNTIME_RED_WITNESSES) {
-    assert.match(redMatrix, new RegExp(escapeRegExp(`test.skip('${witnessName}`)));
-  }
-});
-
-test('BEARING distinguishes the compatibility corridor from Jim.edict', () => {
-  const bearing = readRepoFile(BEARING_PATH);
-  const currentTruth = sectionBetween(bearing, '## Current Truth', '## Authority Boundary');
-  const authorityBoundary = sectionBetween(bearing, '## Authority Boundary', '## Artifact Boundaries');
-
-  assert.match(currentTruth, /Production startup launches `jedit-echo-host`/);
-  assert.match(
-    currentTruth,
-    /Buffer open\/create, insert, replace, delete, checkpoint declaration, and\s+bounded text-window reads are implemented/,
-  );
-  assert.match(currentTruth, /Multi-range edit, save\/export,\s+`:why`, causal line-diff, and undo\/redo return typed obstructions/);
-  assert.match(currentTruth, /checkpoint declaration and an Echo causal anchor remain separate\s+propositions/);
-  assert.match(authorityBoundary, /Wesley-generated EINT and installed package/);
-  assert.match(authorityBoundary, /canonical event envelope with stable\s+event, source, ordering, normalized-input, and admission coordinates/);
-  assert.match(authorityBoundary, /Echo realm admits and delivers it opaquely under an exact JimRelease/);
-  assert.match(authorityBoundary, /Only `jim\.core`[^\n]*interprets editor meaning/);
-  assert.match(authorityBoundary, /combined Jim-and-buffer candidate/);
-  assert.match(authorityBoundary, /atomically settles Jim, Buffer, result, and evidence/);
-  assert.match(authorityBoundary, /CandidateSettlementRejected/);
-  assert.match(authorityBoundary, /renders one declared causal view basis/);
-  assert.match(authorityBoundary, /syscall stub, not Jim/);
-  assert.match(
-    authorityBoundary,
-    /direct generated-client invocation of `ReplaceRange`\s+is permitted only in an explicitly test-only operation conformance harness/,
-  );
-  assert.match(bearing, /oracle is never a program/);
-  assert.match(
-    bearing,
-    /Do not put `ReplaceRange`, rope operations, `Buffer`, or `TextWindow`\s+semantics in Echo production code/,
-  );
-  assert.match(bearing, /Do not reintroduce an in-process text authority/);
-});
-
-test('WF-0154 landed closeout has no unchecked gates or stale provenance deferral', () => {
-  const design = readRepoFile(WF_0154_DESIGN_PATH);
-  const bearing = readRepoFile(BEARING_PATH);
-  const tests = sectionBetween(design, '## Tests To Write First', '## Acceptance Criteria');
-  const acceptance = sectionBetween(design, '## Acceptance Criteria', '## Validation Plan');
-  const retrospective = sectionBetween(design, '## Retrospective', 'PR:');
-
-  assert.doesNotMatch(tests, /^- \[ \]/m);
-  assert.doesNotMatch(acceptance, /^- \[ \]/m);
-  assert.doesNotMatch(retrospective, /provenance naming half is deferred/);
-  assert.match(bearing, /derive undo\/redo\s+candidates from retained Echo history/i);
-  assert.match(bearing, /invoke generated\s+inverse\s+operations/);
-});
-
-test('causal undo blockers preserve plain undo and name only unshipped prerequisites', () => {
-  const backlog = readRepoFile(CAUSAL_UNDO_BACKLOG_PATH);
-  const blockers = sectionBetween(backlog, 'blocked_by:', 'acceptance_criteria:');
-
-  assert.doesNotMatch(blockers, /plain stack undo cutover/);
-  assert.match(blockers, /Historical Basis Preview/);
-  assert.match(blockers, /Search Sets \/ proposal strand preview \+ :admit/);
-});
-
-test('process doc defines the official cycle lifecycle and proof boundary', () => {
-  const processDoc = readRepoFile(PROCESS_PATH);
-
-  for (const heading of REQUIRED_PROCESS_SECTIONS) {
-    assert.match(processDoc, new RegExp(`^${escapeRegExp(heading)}$`, 'm'), `${heading} missing from process doc`);
-  }
-
-  assert.match(processDoc, /A design doc defines intent\. It does not prove implementation\./);
-  assert.match(processDoc, /Every implementation cycle must name at least one executable witness/);
-  assert.match(processDoc, /Create a new branch from the merge target/);
-  assert.match(processDoc, /Apply `work-in-progress` to the GitHub issue and PR/);
-  assert.match(processDoc, /Draft PRs are allowed only for cycle kickoff and active cycle work/);
-  assert.match(processDoc, /Never rebase a cycle branch/);
-});
-
-test('agent contract points future agents at the process and template', () => {
-  const agents = readRepoFile(AGENTS_PATH);
-
-  assert.match(agents, /`docs\/method\/process\.md` is the canonical cycle workflow/);
-  assert.match(agents, /`docs\/design\/TEMPLATE\.md` is the required template for full cycle designs/);
-  assert.match(agents, /Design docs define intent\. They do not prove implementation\./);
-  assert.match(agents, /Fill in the design doc retrospective before marking the PR ready/);
-});
-
-test('policy design links the GitHub issue and records the retrospective', () => {
-  const policy = readRepoFile(POLICY_DESIGN_PATH);
-
-  assert.match(policy, /issue: "https:\/\/github\.com\/flyingrobots\/jedit\/issues\/51"/);
-  assert.match(policy, /## Retrospective/);
-  assert.match(policy, /What the tests proved:/);
-  assert.match(policy, /Other repositories still need their own adapted templates/);
-});
-
-function sectionBetween(documentText, startHeading, endHeading) {
-  const start = documentText.indexOf(startHeading);
-  const end = documentText.indexOf(endHeading, start + startHeading.length);
-
-  assert.notEqual(start, -1, `${startHeading} missing`);
-  assert.notEqual(end, -1, `${endHeading} missing`);
-
-  return documentText.slice(start, end);
-}
-
-function escapeRegExp(value) {
-  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
-}
diff --git a/spec/echo-application-hosting-guide.spec.mjs b/spec/echo-application-hosting-guide.spec.mjs
deleted file mode 100644
index 2ea0abb8..00000000
--- a/spec/echo-application-hosting-guide.spec.mjs
+++ /dev/null
@@ -1,65 +0,0 @@
-import assert from 'node:assert/strict';
-import { readFileSync } from 'node:fs';
-import { spawnSync } from 'node:child_process';
-import path from 'node:path';
-import test from 'node:test';
-
-const REPO_ROOT = process.cwd();
-const GUIDE_PATH = path.join(REPO_ROOT, 'docs', 'echo-application-hosting-guide.md');
-
-function sectionBetween(documentText, startHeading, endHeading) {
-  const start = documentText.indexOf(startHeading);
-  const end = documentText.indexOf(endHeading, start + startHeading.length);
-
-  assert.notEqual(start, -1, `${startHeading} missing`);
-  assert.notEqual(end, -1, `${endHeading} missing`);
-
-  return documentText.slice(start, end);
-}
-
-test('Echo application hosting guide states the real authority boundary', () => {
-  const source = readFileSync(GUIDE_PATH, 'utf8');
-  const targetBoundary = sectionBetween(
-    source,
-    '## Target Active-Observer Boundary',
-    '## Current Intent Lifecycle',
-  );
-
-  assert.match(source, /`Jim\.edict` is the application/);
-  assert.match(source, /Echo owns generic admission,\s+scheduling, ticks/);
-  assert.match(source, /Wesley compatibility package currently supplies/);
-  assert.match(source, /Edict owns the generated semantic boundary/);
-  assert.match(targetBoundary, /canonical event envelope with stable\s+event, source, ordering, normalized-input, and admission coordinates/);
-  assert.match(targetBoundary, /Echo authority realm/);
-  assert.match(targetBoundary, /deliver opaquely under exact JimRelease/);
-  assert.match(targetBoundary, /jim\.core/);
-  assert.match(targetBoundary, /basis-bound Reading/);
-  assert.match(targetBoundary, /combined Jim-and-Buffer candidate/);
-  assert.match(targetBoundary, /atomically settle candidate or retain conflict outcome/);
-  assert.match(targetBoundary, /projection for one declared causal view basis/);
-  assert.match(targetBoundary, /generated client in this boundary is a codec and transport stub/);
-  assert.match(targetBoundary, /It may not\s+decide what a key means, derive a `ReplaceRange`, calculate a rope patch, or\s+advance cursor, mode, register, or operator state/);
-  assert.match(
-    source,
-    /Echo production code must not implement or branch on `ReplaceRange`/,
-  );
-  assert.match(source, /Launch `native\/jedit-echo-host`/);
-  assert.match(source, /Recover the graph and continue editing/);
-  assert.match(source, /typed obstructions/);
-  assert.match(source, /Jim checkpoint declaration and an Echo causal anchor are separate facts/);
-  assert.match(source, /every user-visible text\s+transition and authoritative reading/i);
-  assert.doesNotMatch(source, /in-memory state port/);
-  assert.doesNotMatch(source, /installed jedit contract transport/i);
-  assert.doesNotMatch(source, /JEDIT_ECHO_WASM_MODULE/);
-});
-
-test('Echo application hosting guide cutover guard command is executable', () => {
-  const result = spawnSync(process.execPath, [
-    'scripts/jedit-production-cutover-guard.mjs',
-  ], {
-    cwd: REPO_ROOT,
-    encoding: 'utf8',
-  });
-
-  assert.equal(result.status, 0, result.stderr || result.stdout);
-});
diff --git a/spec/graph-rope-runtime-red-matrix.spec.mjs b/spec/graph-rope-runtime-red-matrix.spec.mjs
deleted file mode 100644
index 120957d8..00000000
--- a/spec/graph-rope-runtime-red-matrix.spec.mjs
+++ /dev/null
@@ -1,40 +0,0 @@
-import assert from 'node:assert/strict';
-import test from 'node:test';
-
-const PENDING_GRAPH_RUNTIME = 'graph-backed rope runtime is not implemented yet';
-
-// RED matrix: these witnesses define the graph-backed runtime acceptance gate.
-// They intentionally remain skipped until create/read/replace/checkpoint exists.
-
-test.skip('RED: graph-backed runtime retention is not O(buffer size * edit count)', () => {
-  // Fixture: create a 10 MB buffer, apply 1000 one-byte replacements, then ask
-  // debugRopeShape for authoritative retained bytes.
-  // Expected: retained authoritative bytes are bounded by initial blobs,
-  // changed leaves, copied branches, rewrites, diffs, receipts, and checkpoints.
-  // Forbidden: retaining a fresh 10 MB text root per edit.
-  assert.fail(PENDING_GRAPH_RUNTIME);
-});
-
-test.skip('RED: narrow replacement preserves untouched subtree identity recursively', () => {
-  // Fixture: create a multi-leaf rope, record debugRopeShape(headA), replace a
-  // narrow middle range, then record debugRopeShape(headB).
-  // Expected: every subtree outside the closed edit path keeps its node ID.
-  // Forbidden: rebuilding the whole tree while preserving only materialized text.
-  assert.fail(PENDING_GRAPH_RUNTIME);
-});
-
-test.skip('RED: save and export read from a named head or checkpoint without mutating text authority', () => {
-  // Fixture: export text from head H, then create a manual-save checkpoint C for
-  // H and export from C.
-  // Expected: export receipts cite H or C as their basis and do not create a new
-  // RopeHead unless an explicit checkpoint fact is admitted.
-  assert.fail(PENDING_GRAPH_RUNTIME);
-});
-
-test.skip('RED: range why cites head leaf blob rewrite diff tick checkpoint and basis evidence', () => {
-  // Fixture: query :why for a byte range introduced by a prior rewrite and later
-  // shifted by an unrelated edit.
-  // Expected: answer walks retained graph evidence from current head to the
-  // owning leaf/blob/rewrite/diff/tick/checkpoint/basis without string search.
-  assert.fail(PENDING_GRAPH_RUNTIME);
-});
diff --git a/spec/guide-path-references.spec.mjs b/spec/guide-path-references.spec.mjs
deleted file mode 100644
index 025ac2ef..00000000
--- a/spec/guide-path-references.spec.mjs
+++ /dev/null
@@ -1,87 +0,0 @@
-import assert from 'node:assert/strict';
-import { existsSync, readFileSync } from 'node:fs';
-import path from 'node:path';
-import test from 'node:test';
-import { REPO_ROOT } from './dist-helpers.mjs';
-
-const GUIDE_PATHS = [
-  'README.md',
-  'GUIDE.md',
-  'ADVANCED_GUIDE.md',
-  'ARCHITECTURE.md',
-  'docs/BEARING.md',
-];
-
-const PATH_TOKEN_PATTERN = /(?:src|scripts)\/[A-Za-z0-9._/-]+/g;
-const TRAILING_PUNCTUATION_PATTERN = /[.,:;)\]}'"`]+$/;
-
-const DOCUMENTED_FUTURE_PATH_ALLOWLIST = new Set([]);
-
-function referencedPaths(markdown) {
-  const references = new Map();
-  const lines = markdown.split('\n');
-
-  lines.forEach((lineText, lineIndex) => {
-    for (const match of lineText.matchAll(PATH_TOKEN_PATTERN)) {
-      const token = match[0].replace(TRAILING_PUNCTUATION_PATTERN, '');
-      if (token.includes('*')) {
-        continue;
-      }
-      if (!references.has(token)) {
-        references.set(token, lineIndex + 1);
-      }
-    }
-  });
-
-  return references;
-}
-
-function unresolvedReferences(guidePath) {
-  const markdown = readFileSync(path.join(REPO_ROOT, guidePath), 'utf8');
-  const unresolved = [];
-
-  for (const [token, lineNumber] of referencedPaths(markdown)) {
-    if (DOCUMENTED_FUTURE_PATH_ALLOWLIST.has(token)) {
-      continue;
-    }
-    if (!existsSync(path.join(REPO_ROOT, token))) {
-      unresolved.push(`${guidePath}:${lineNumber} -> ${token}`);
-    }
-  }
-
-  return unresolved;
-}
-
-for (const guidePath of GUIDE_PATHS) {
-  test(`every src/ and scripts/ path referenced by ${guidePath} exists`, () => {
-    const unresolved = unresolvedReferences(guidePath);
-
-    assert.deepEqual(
-      unresolved,
-      [],
-      `dead path references:\n${unresolved.join('\n')}`,
-    );
-  });
-}
-
-test('the guide path witness sees through fenced code and plain prose', () => {
-  const references = referencedPaths(
-    [
-      'Prose mentions src/main.ts inline.',
-      '```text',
-      '-> src/adapters/in-memory-example.ts',
-      '```',
-      'A [link](src/domain/errors.ts) and `scripts/quality-gate.mjs`.',
-    ].join('\n'),
-  );
-
-  assert.deepEqual(
-    [...references.keys()].sort(),
-    [
-      'scripts/quality-gate.mjs',
-      'src/adapters/in-memory-example.ts',
-      'src/domain/errors.ts',
-      'src/main.ts',
-    ],
-  );
-});
diff --git a/spec/release-quickstart.spec.mjs b/spec/release-quickstart.spec.mjs
deleted file mode 100644
index 940dbc7a..00000000
--- a/spec/release-quickstart.spec.mjs
+++ /dev/null
@@ -1,62 +0,0 @@
-import assert from 'node:assert/strict';
-import { readFileSync } from 'node:fs';
-import { spawnSync } from 'node:child_process';
-import path from 'node:path';
-import test from 'node:test';
-
-const REPO_ROOT = process.cwd();
-const QUICKSTART_PATH = path.join(REPO_ROOT, 'docs', 'releases', 'v0.1.0', 'quickstart.md');
-const RELEASE_README_PATH = path.join(REPO_ROOT, 'docs', 'releases', 'v0.1.0', 'README.md');
-const FINAL_WITNESS_PATH = path.join(REPO_ROOT, 'docs', 'releases', 'v0.1.0', 'final-witness-report.json');
-const LOCAL_REPLAY_PATH = path.join(REPO_ROOT, 'docs', 'releases', 'v0.1.0', 'local-replay-report.json');
-const CUTOVER_GUARD = path.join(REPO_ROOT, 'scripts', 'jedit-production-cutover-guard.mjs');
-
-test('v0.1.0 quickstart revokes the retired local witness claim', () => {
-  const source = readFileSync(QUICKSTART_PATH, 'utf8');
-
-  assert.match(source, /npm run build/);
-  assert.match(source, /jedit-production-cutover-guard\.mjs/);
-  assert.match(source, /npm run witness:echo/);
-  assert.match(source, /npm start/);
-  assert.match(source, /trusted native Echo host/);
-  assert.match(source, /GraphQL\/Wesley/);
-  assert.match(source, /Edict will replace/);
-  assert.match(source, /may be described as Echo-powered/);
-  assert.doesNotMatch(source, /JEDIT_ECHO_WASM_MODULE/);
-  assert.doesNotMatch(source, /allow-full-snapshot-fixture/);
-});
-
-test('v0.1.0 release docs identify the invalidated authority claim', () => {
-  const source = readFileSync(RELEASE_README_PATH, 'utf8');
-
-  assert.match(source, /retired and invalidated/);
-  assert.match(source, /process-local TypeScript/);
-  assert.match(source, /trusted native Echo host/);
-  assert.match(source, /GraphQL contract/);
-  assert.match(source, /Edict will replace/);
-  assert.match(source, /Echo remains generic/);
-  assert.match(source, /must not be cited as proof/);
-});
-
-test('v0.1.0 closeout records final witness and local replay reports', () => {
-  const finalWitness = JSON.parse(readFileSync(FINAL_WITNESS_PATH, 'utf8'));
-  const localReplay = JSON.parse(readFileSync(LOCAL_REPLAY_PATH, 'utf8'));
-
-  assert.equal(finalWitness.ok, true);
-  assert.equal(finalWitness.report.outcome.status, 'APPLIED');
-  assert.equal(finalWitness.report.restartPosture.acceptedSubmissionRecovery, 'UNAVAILABLE');
-  assert.equal(localReplay.replayLocal.status, 'MATCH');
-  assert.equal(localReplay.replayLocal.wallClockCadenceSemantic, false);
-});
-
-test('v0.1.0 quickstart cutover guard command executes', () => {
-  const result = spawnSync(process.execPath, [
-    CUTOVER_GUARD,
-  ], {
-    cwd: REPO_ROOT,
-    encoding: 'utf8',
-  });
-
-  assert.equal(result.status, 0, result.stderr);
-  assert.equal(result.stdout, 'jedit production cutover guard ok\n');
-});
diff --git a/spec/rope-fact-inspector-design.spec.mjs b/spec/rope-fact-inspector-design.spec.mjs
deleted file mode 100644
index 19b42b18..00000000
--- a/spec/rope-fact-inspector-design.spec.mjs
+++ /dev/null
@@ -1,80 +0,0 @@
-import assert from 'node:assert/strict';
-import fs from 'node:fs';
-import path from 'node:path';
-import test from 'node:test';
-import { REPO_ROOT } from './dist-helpers.mjs';
-
-const DESIGN_PATH = path.join(
-  REPO_ROOT,
-  'docs',
-  'design',
-  '0157-rope-fact-inspector-and-range-why.md',
-);
-const MOCKUP_PATHS = [
-  '0157-rope-fact-inspector-wide.svg',
-  '0157-rope-fact-inspector-narrow.svg',
-  '0157-rope-fact-inspector-xs.svg',
-].map(fileName => path.join(REPO_ROOT, 'docs', 'design', fileName));
-
-test('rope fact inspector design pins the runtime evidence chain', () => {
-  const design = fs.readFileSync(DESIGN_PATH, 'utf8');
-
-  assert.match(design, /issues\/209/);
-  assert.match(design, /0149-graph-backed-rope-runtime-discovery/);
-  assert.match(design, /pull\/205/);
-  for (const evidenceKind of [
-    'RopeHead',
-    'leaf',
-    'blob',
-    'rewrite',
-    'diff',
-    'text-tick',
-    'checkpoint',
-    'anchor',
-  ]) {
-    assert.match(design, new RegExp(evidenceKind, 'i'));
-  }
-});
-
-test('range why contract is basis-pinned bounded and fragmented', () => {
-  const design = fs.readFileSync(DESIGN_PATH, 'utf8');
-
-  for (const field of [
-    'basisHeadId',
-    'queriedRange',
-    'maxFacts',
-    'maxDepth',
-    'maxHistoricalTextBytes',
-    'coverage',
-    'fragments',
-    'continuation',
-  ]) {
-    assert.match(design, new RegExp(`\\b${field}\\b`));
-  }
-  assert.match(design, /checkpoint declaration does not imply/i);
-  assert.match(design, /multiple fragments/i);
-  assert.match(design, /stale evidence fails closed/i);
-});
-
-test('responsive inspector mockups use named semantic token roles', () => {
-  const design = fs.readFileSync(DESIGN_PATH, 'utf8');
-
-  for (const mockupPath of MOCKUP_PATHS) {
-    const fileName = path.basename(mockupPath);
-    const svg = fs.readFileSync(mockupPath, 'utf8');
-    assert.match(design, new RegExp(fileName.replaceAll('.', '\\.')));
-    assert.match(svg, /]+role="img"/);
-    assert.match(svg, /surface\.workspace/);
-    assert.match(svg, /evidence\.identity/);
-    assert.match(svg, /class="workspace"/);
-    assert.match(svg, /class="identity/);
-    assert.doesNotMatch(svg, /\b(?:fill|stroke)="#[0-9a-fA-F]+"/);
-  }
-});
-
-test('deferred deleted-text and semantic-scope work is issue-backed', () => {
-  const design = fs.readFileSync(DESIGN_PATH, 'utf8');
-
-  assert.match(design, /issues\/278/);
-  assert.match(design, /issues\/279/);
-});
diff --git a/spec/vim-power-parity-matrix.spec.mjs b/spec/vim-power-parity-matrix.spec.mjs
deleted file mode 100644
index b2df3a8f..00000000
--- a/spec/vim-power-parity-matrix.spec.mjs
+++ /dev/null
@@ -1,133 +0,0 @@
-import assert from 'node:assert/strict';
-import { readFileSync } from 'node:fs';
-import path from 'node:path';
-import test from 'node:test';
-
-const REPO_ROOT = process.cwd();
-const MATRIX_PATH = path.join(REPO_ROOT, 'docs', 'design', '0105-vim-power-moves-parity-matrix.json');
-const DESIGN_PATH = 'docs/design/0105-vim-power-moves-causal-parity.md';
-
-const REQUIRED_CATEGORIES = Object.freeze([
-  'motions',
-  'operators',
-  'transactionSemantics',
-  'textObjects',
-  'visualModes',
-  'registers',
-  'repeat',
-  'macros',
-  'marksJumps',
-  'searchSubstitute',
-  'exCommands',
-]);
-
-const REQUIRED_KEYS = Object.freeze({
-  motions: ['h', 'j', 'k', 'l', '0', '^', '$', 'gg', 'G', 'w', 'b', 'e', 'W', 'B', 'E', '/', '?', 'n', 'N', '%', '{', '}', '[[', ']]'],
-  operators: ['d', 'c', 'y', 'p', 'P', 'r', 'R', '>', '<', '=', 'gq', 'gu', 'gU', 'g~', 'J', 'gJ', '!', ':'],
-  transactionSemantics: ['di"', 'ci"', 'daw', 'gqap', 'd', 'c', 'y', 'p', '"', '_', 'q{register}', '@{register}', '@@', 'u', 'Ctrl-r'],
-  textObjects: ['iw', 'aw', 'iW', 'aW', 'is', 'as', 'ip', 'ap', 'i"', 'a"', "i'", "a'", 'i`', 'a`', 'i(', 'a(', 'i[', 'a[', 'i{', 'a{'],
-  visualModes: ['v', 'V', 'Ctrl-v', 'o'],
-  registers: ['"', '0', '1', '9', '-', 'a-z', 'A-Z', '_', '+', '*', '='],
-  repeat: ['.'],
-  macros: ['q{register}', 'q', '@{register}', '@@'],
-  marksJumps: ['m{mark}', '`{mark}', "'{mark}", "''", 'Ctrl-o', 'Ctrl-i', 'g;', 'g,'],
-  searchSubstitute: ['/', '?', 'n', 'N', '*', '#', 'g*', 'g#', ':s', ':%s', 'c', ':g', ':v'],
-  exCommands: [':edit', ':e', ':write', ':w', ':quit', ':q', ':wq', ':x', ':1,10', ':%', ':s', ':%s', ':g', ':v', ':help'],
-});
-
-const STATUS_VOCABULARY = Object.freeze([
-  'supported',
-  'partial',
-  'unsupported',
-  'causally-enhanced',
-]);
-
-test('Vim power-moves parity matrix has stable metadata and categories', () => {
-  const matrix = readMatrix();
-  const categoryIds = matrix.categories.map(category => category.id);
-
-  assert.equal(matrix.schemaVersion, 1);
-  assert.equal(matrix.designDoc, DESIGN_PATH);
-  assert.equal(matrix.owner, 'jedit');
-  assert.equal(matrix.futureCommandName, 'jim');
-  assert.deepEqual(matrix.statusVocabulary, STATUS_VOCABULARY);
-  assert.match(matrix.echoBoundary, /Echo remains generic/);
-  assert.match(matrix.graftBoundary, /not editable text authority/);
-  assert.deepEqual(categoryIds, REQUIRED_CATEGORIES);
-});
-
-test('Vim power-moves parity matrix items carry proof, boundaries, and slice targets', () => {
-  const matrix = readMatrix();
-  const statusSet = new Set(matrix.statusVocabulary);
-
-  for (const item of allItems(matrix)) {
-    assert.equal(typeof item.id, 'string', `${item.id} id must be a string`);
-    assert.ok(item.id.length > 0, 'item id must not be empty');
-    assert.ok(Array.isArray(item.keys), `${item.id} keys must be an array`);
-    assert.ok(item.keys.length > 0, `${item.id} must declare key coverage`);
-    assert.ok(statusSet.has(item.status), `${item.id} uses unknown status ${item.status}`);
-    assertTargetSlices(item);
-    assert.equal(typeof item.targetParity, 'string', `${item.id} targetParity missing`);
-    assert.equal(typeof item.currentJedit, 'string', `${item.id} currentJedit missing`);
-    assert.equal(typeof item.proofGap, 'string', `${item.id} proofGap missing`);
-    assert.equal(typeof item.causalOpportunity, 'string', `${item.id} causalOpportunity missing`);
-    assert.equal(typeof item.echoBoundary, 'string', `${item.id} echoBoundary missing`);
-    assert.ok(Array.isArray(item.currentProof), `${item.id} currentProof must be an array`);
-  }
-});
-
-test('Vim power-moves parity matrix covers the required surface from WF-0105', () => {
-  const matrix = readMatrix();
-
-  for (const category of matrix.categories) {
-    const coveredKeys = new Set(category.items.flatMap(item => item.keys));
-    const missing = REQUIRED_KEYS[category.id].filter(key => !coveredKeys.has(key));
-
-    assert.deepEqual(missing, [], `${category.id} is missing required keys`);
-  }
-});
-
-test('Vim power-moves parity matrix keeps current support honest', () => {
-  const matrix = readMatrix();
-  const items = allItems(matrix);
-  const statuses = new Set(items.map(item => item.status));
-
-  assert.ok(statuses.has('supported'), 'matrix should name already supported behavior');
-  assert.ok(statuses.has('partial'), 'matrix should name partial behavior');
-  assert.ok(statuses.has('unsupported'), 'matrix should name unsupported behavior');
-  assert.ok(statuses.has('causally-enhanced'), 'matrix should name causal extension targets');
-
-  for (const item of items) {
-    if (item.status === 'supported') {
-      assert.ok(item.currentProof.length > 0, `${item.id} supported rows need current proof`);
-      assert.equal(item.proofGap, '', `${item.id} supported rows should not carry a proof gap`);
-    }
-
-    if (item.status === 'unsupported' || item.status === 'causally-enhanced') {
-      assert.deepEqual(item.currentProof, [], `${item.id} must not pretend unsupported work is proven`);
-      assert.ok(item.proofGap.length > 0, `${item.id} needs an explicit proof gap`);
-    }
-
-    if (item.status === 'causally-enhanced') {
-      assert.doesNotMatch(item.causalOpportunity, /^none$/i, `${item.id} needs a real causal opportunity`);
-    }
-  }
-});
-
-function readMatrix() {
-  return JSON.parse(readFileSync(MATRIX_PATH, 'utf8'));
-}
-
-function allItems(matrix) {
-  return matrix.categories.flatMap(category => category.items);
-}
-
-function assertTargetSlices(item) {
-  assert.ok(Array.isArray(item.targetSlices), `${item.id} targetSlices must be an array`);
-  assert.ok(item.targetSlices.length > 0, `${item.id} targetSlices must not be empty`);
-
-  for (const slice of item.targetSlices) {
-    assert.equal(Number.isInteger(slice), true, `${item.id} target slice must be an integer`);
-    assert.ok(slice >= 2 && slice <= 30, `${item.id} target slice must fit WF-0105`);
-  }
-}
diff --git a/spec/vim-power-target-usability-fixtures.spec.mjs b/spec/vim-power-target-usability-fixtures.spec.mjs
deleted file mode 100644
index db45b0a2..00000000
--- a/spec/vim-power-target-usability-fixtures.spec.mjs
+++ /dev/null
@@ -1,92 +0,0 @@
-import assert from 'node:assert/strict';
-import { readFileSync } from 'node:fs';
-import path from 'node:path';
-import test from 'node:test';
-
-const REPO_ROOT = process.cwd();
-const FIXTURES_PATH = path.join(REPO_ROOT, 'docs', 'design', '0105-vim-power-target-usability-fixtures.json');
-const MATRIX_PATH = path.join(REPO_ROOT, 'docs', 'design', '0105-vim-power-moves-parity-matrix.json');
-const DESIGN_PATH = 'docs/design/0105-vim-power-moves-causal-parity.md';
-const MATRIX_REPO_PATH = 'docs/design/0105-vim-power-moves-parity-matrix.json';
-
-const REQUIRED_WORKFLOWS = Object.freeze([
-  'open-edit-save-reopen',
-  'text-object-surgery',
-  'search-substitute-confirm',
-  'macro-repeat-transform',
-  'marks-jumps-causal-anchors',
-  'causal-strand-preview',
-]);
-
-const REQUIRED_ROW_REFERENCES = Object.freeze({
-  'open-edit-save-reopen': ['ex.edit', 'ex.write-quit'],
-  'text-object-surgery': ['text-object.quotes', 'text-object.brackets', 'operator.delete-change-yank', 'transaction.read-resolve-write'],
-  'search-substitute-confirm': ['search.pattern-history', 'substitute.file-confirm'],
-  'macro-repeat-transform': ['macro.record', 'macro.replay', 'repeat.transformed-replay', 'transaction.macro-script'],
-  'marks-jumps-causal-anchors': ['marks.local-global', 'marks.jump', 'jumps.list', 'transaction.undo-redo'],
-  'causal-strand-preview': ['substitute.file-confirm', 'global.vglobal', 'ex.ranges'],
-});
-
-test('Vim power target usability fixtures have stable metadata', () => {
-  const fixtures = readJson(FIXTURES_PATH);
-
-  assert.equal(fixtures.schemaVersion, 1);
-  assert.equal(fixtures.designDoc, DESIGN_PATH);
-  assert.equal(fixtures.parityMatrix, MATRIX_REPO_PATH);
-  assert.equal(fixtures.owner, 'jedit');
-  assert.equal(fixtures.futureCommandName, 'jim');
-  assert.equal(fixtures.currentExecutionPosture, 'target-fixtures-not-runtime-proof');
-  assert.deepEqual(fixtures.workflows.map(workflow => workflow.id), REQUIRED_WORKFLOWS);
-});
-
-test('Vim power target usability fixtures reference real parity matrix rows', () => {
-  const fixtures = readJson(FIXTURES_PATH);
-  const matrixRows = new Set(readJson(MATRIX_PATH).categories.flatMap(category => category.items.map(item => item.id)));
-
-  for (const workflow of fixtures.workflows) {
-    assert.ok(workflow.matrixRows.length > 0, `${workflow.id} must reference matrix rows`);
-
-    for (const rowId of workflow.matrixRows) {
-      assert.ok(matrixRows.has(rowId), `${workflow.id} references missing matrix row ${rowId}`);
-    }
-
-    for (const requiredRow of REQUIRED_ROW_REFERENCES[workflow.id]) {
-      assert.ok(workflow.matrixRows.includes(requiredRow), `${workflow.id} must reference ${requiredRow}`);
-    }
-  }
-});
-
-test('Vim power target usability fixtures separate human task prose from witness data', () => {
-  const fixtures = readJson(FIXTURES_PATH);
-
-  for (const workflow of fixtures.workflows) {
-    assert.equal(typeof workflow.humanTask, 'string', `${workflow.id} humanTask missing`);
-    assert.ok(workflow.humanTask.length > 40, `${workflow.id} humanTask should be descriptive`);
-    assert.equal(typeof workflow.witness.command, 'string', `${workflow.id} witness command missing`);
-    assert.match(workflow.witness.command, /jedit-vim-power-witness\.mjs --json/);
-    assert.equal(typeof workflow.witness.workspace.cwd, 'string', `${workflow.id} workspace cwd missing`);
-    assert.ok(workflow.witness.workspace.files.length > 0, `${workflow.id} needs seed files`);
-    assert.ok(workflow.witness.steps.length >= 4, `${workflow.id} needs enough witness steps`);
-    assert.ok(workflow.witness.requiredFacts.length >= 5, `${workflow.id} needs required facts`);
-
-    for (const step of workflow.witness.steps) {
-      assert.equal(typeof step.id, 'string', `${workflow.id} step id missing`);
-      assert.equal(typeof step.input, 'string', `${workflow.id}:${step.id} input missing`);
-      assert.equal(typeof step.expect, 'string', `${workflow.id}:${step.id} expectation missing`);
-    }
-  }
-});
-
-test('Vim power target usability fixtures stay honest about current execution', () => {
-  const fixtures = readJson(FIXTURES_PATH);
-  const allowedOutcomes = new Set(['partially-supported', 'not-yet-supported']);
-
-  for (const workflow of fixtures.workflows) {
-    assert.ok(allowedOutcomes.has(workflow.expectedCurrentOutcome), `${workflow.id} has unknown outcome`);
-    assert.notEqual(workflow.expectedCurrentOutcome, 'passing', `${workflow.id} must not claim runtime proof yet`);
-  }
-});
-
-function readJson(filePath) {
-  return JSON.parse(readFileSync(filePath, 'utf8'));
-}
diff --git a/spec/wf-0102-docs-closeout.spec.mjs b/spec/wf-0102-docs-closeout.spec.mjs
deleted file mode 100644
index 1ffb5acc..00000000
--- a/spec/wf-0102-docs-closeout.spec.mjs
+++ /dev/null
@@ -1,40 +0,0 @@
-import assert from 'node:assert/strict';
-import { readFileSync } from 'node:fs';
-import path from 'node:path';
-import test from 'node:test';
-
-const REPO_ROOT = process.cwd();
-const DESIGN_PATH = path.join(
-  REPO_ROOT,
-  'docs',
-  'design',
-  '0102-vim-command-line-completion-surface.md',
-);
-const TEARDOWN_PATH = path.join(REPO_ROOT, 'docs', 'technical-teardown.md');
-
-test('WF-0102 closeout documents Vim command completion truth', () => {
-  const design = readRepoFile(DESIGN_PATH);
-  const teardown = readRepoFile(TEARDOWN_PATH);
-
-  assert.match(teardown, /### Vim Command-Line And Completion Surface/);
-  assert.match(teardown, /Pressing `:`[\s\S]*opens `WorkspaceModel\.commandLine`/);
-  assert.match(teardown, /`:edit ` opens through `createWorkspaceTextOpenCmd`/);
-  assert.match(teardown, /`:write` and `:w` call the existing save path/);
-  assert.match(teardown, /`:quit` and `:q` route through normal quit confirmation/);
-  assert.match(teardown, /`:wq` and `:x` write first and then request the same quit posture/);
-  assert.match(teardown, /Vim command mode is the primary type-to-open surface/);
-  assert.match(teardown, /`ctrl\+b` remains the standard browsable file drawer/);
-  assert.match(teardown, /no longer owns printable type-to-search input/);
-  assert.match(teardown, /Graft-backed symbol suggestions can use the same/);
-
-  assert.match(design, /- \[x\] Slice 20: Update technical teardown, retrospective, and playback witness\./);
-  assert.match(design, /Automated closeout playback:/);
-  assert.match(design, /What changed from the design:/);
-  assert.match(design, /The startup file selector remains available/);
-  assert.match(design, /What remains open:/);
-  assert.match(design, /PR #111: https:\/\/github\.com\/flyingrobots\/jedit\/pull\/111/);
-});
-
-function readRepoFile(filePath) {
-  return readFileSync(filePath, 'utf8');
-}
diff --git a/tests/anchor-transform-cycle.spec.mjs b/tests/anchor-transform-cycle.spec.mjs
index 59b76434..55f9da14 100644
--- a/tests/anchor-transform-cycle.spec.mjs
+++ b/tests/anchor-transform-cycle.spec.mjs
@@ -1,18 +1,10 @@
 import assert from 'node:assert/strict';
-import fs from 'node:fs';
 import { spawnSync } from 'node:child_process';
 import path from 'node:path';
 import test from 'node:test';
 import { pathToFileURL } from 'node:url';
 
 const REPO_ROOT = process.cwd();
-const DESIGN_DOC_PATH = path.join(
-  REPO_ROOT,
-  'docs',
-  'design',
-  '0002-anchor-transform-semantics',
-  'anchor-transform-semantics.md',
-);
 const MODULE_PATH = path.join(REPO_ROOT, 'dist', 'domain', 'anchor-transform-contract.js');
 const CONTRACT_SPEC_PATH = path.join('spec', 'anchor-transform.contract.spec.mjs');
 const QUALITY_GATE_PATH = path.join('scripts', 'quality-gate.mjs');
@@ -28,10 +20,6 @@ const EXPECTED_RUNTIME_EXPORTS = [
 
 let cachedContractPromise;
 
-function readDesignDoc() {
-  return fs.readFileSync(DESIGN_DOC_PATH, 'utf8');
-}
-
 function runCommand(args) {
   const result = spawnSync(process.execPath, args, {
     cwd: REPO_ROOT,
@@ -49,54 +37,6 @@ async function loadContract() {
 
   return cachedContractPromise;
 }
-
-test('Anchor transforms are defined in terms of logical ReplaceRange deltas rather than rope maintenance.', () => {
-  const designDoc = readDesignDoc();
-
-  assert.match(
-    designDoc,
-    /Anchor transforms are defined in terms of logical ReplaceRange deltas\s+rather than rope maintenance\./,
-  );
-  assert.match(designDoc, /logical ReplaceRange deltas/i);
-  assert.match(designDoc, /rope-maintenance\s+semantics/i);
-});
-
-test('This cycle pins down left-bias, right-bias, forward shift, and collapse semantics for point anchors.', () => {
-  const designDoc = readDesignDoc();
-
-  assert.match(
-    designDoc,
-    /This cycle pins down left-bias, right-bias, forward shift, and collapse\s+semantics for point anchors\./,
-  );
-  assert.match(designDoc, /left-biased point anchor stays before inserted text/i);
-  assert.match(designDoc, /right-biased point anchor moves after inserted text/i);
-  assert.match(designDoc, /replacement shifts by the replacement byte delta/i);
-  assert.match(designDoc, /deleted span collapses to the replacement start/i);
-});
-
-test('This cycle limits scope to point anchors over ReplaceRange deltas.', () => {
-  const designDoc = readDesignDoc();
-
-  assert.match(designDoc, /This cycle limits scope to point anchors over ReplaceRange deltas\./);
-  assert.match(
-    designDoc,
-    /This cycle\s+does not implement interval anchors, anchor persistence, rope-maintenance\s+semantics, or editor UI integration\./,
-  );
-  assert.match(designDoc, /Non-goals/);
-});
-
-test('This cycle makes accessibility, localization, and agent inspectability explicit.', () => {
-  const designDoc = readDesignDoc();
-
-  assert.match(
-    designDoc,
-    /This cycle makes accessibility, localization, and agent inspectability\s+explicit\./,
-  );
-  assert.match(designDoc, /Accessibility and Assistive Reading/);
-  assert.match(designDoc, /Localization and Directionality/);
-  assert.match(designDoc, /Agent Inspectability and Explainability/);
-});
-
 test('A left-biased point anchor stays before inserted text at its byte.', async () => {
   const contract = await loadContract();
   const anchor = contract.createPointAnchor(5, contract.leftAnchorBias());
diff --git a/tests/replace-range-law-cycle.spec.mjs b/tests/replace-range-law-cycle.spec.mjs
index 5ce7b30a..1cbdee05 100644
--- a/tests/replace-range-law-cycle.spec.mjs
+++ b/tests/replace-range-law-cycle.spec.mjs
@@ -4,18 +4,6 @@ import fs from "node:fs";
 import path from "node:path";
 import test from "node:test";
 
-import {
-  CHANGED_SECTION,
-  FINAL_AUDIT_EVIDENCE_LOCATIONS,
-  PROVED_SECTION,
-} from "./support/replace-range-audit-ledger.mjs";
-
-const DESIGN_PATH = path.join(
-  process.cwd(),
-  "docs",
-  "design",
-  "0158-replace-range-canonical-fact-law.md",
-);
 const ORACLE_SUPPORT_PATH = path.join(
   process.cwd(),
   "native",
@@ -58,352 +46,18 @@ const PUBLISHED_ARTIFACTS = [
   "replace-range-v1.oracle.json",
 ];
 
-function readDesign() {
-  return fs.readFileSync(DESIGN_PATH, "utf8");
-}
-
-function currentTruth(design = readDesign()) {
-  const parts = design.split("## Current Truth");
-  assert.equal(parts.length, 2, "expected one Current Truth section");
-  return parts[1].split("## Problem")[0];
-}
-
-function artifactDigestClaim(design) {
-  const retrospective = design.split("## Retrospective")[1];
-  const marker = "- **Artifact digest ledger.** ";
-  const parts = retrospective.split(marker);
-  assert.equal(parts.length, 2, "expected one artifact digest ledger claim");
-  return parts[1].split("\n- **")[0].replaceAll(/\s+/g, " ").trim();
-}
-
-function assertArtifactDigestLedger(design = readDesign()) {
-  const actualDigests = new Map();
-  let oracleBytes;
-
+test("ReplaceRange published lawpack artifacts match their digest sidecars", () => {
   for (const fileName of PUBLISHED_ARTIFACTS) {
     const artifactPath = path.join(LAWPACK_PATH, fileName);
-    const artifactBytes = fs.readFileSync(artifactPath);
     const actualDigest = crypto
       .createHash("sha256")
-      .update(artifactBytes)
+      .update(fs.readFileSync(artifactPath))
       .digest("hex");
     const sidecarPath = artifactPath.replace(/\.json$/, ".sha256");
     const publishedDigest = fs.readFileSync(sidecarPath, "utf8").trim();
 
     assert.equal(publishedDigest, actualDigest, `${fileName} sidecar drifted`);
-    actualDigests.set(fileName, actualDigest);
-    if (fileName === "replace-range-v1.oracle.json") {
-      oracleBytes = artifactBytes;
-    }
-  }
-
-  assert.ok(
-    oracleBytes,
-    "oracle artifact must be present in the published set",
-  );
-  const sourceSetDigest = JSON.parse(oracleBytes).sourceSet.digestHex;
-  const mapping =
-    /^The published SHA-256 digests are `(?[a-f0-9]{64})` for the schema, `(?[a-f0-9]{64})` for codec vectors, and `(?[a-f0-9]{64})` for the oracle\. The oracle source-set digest is `(?[a-f0-9]{64})`\./.exec(
-      artifactDigestClaim(design),
-    );
-  assert.ok(mapping, "artifact digest ledger drift");
-  assert.deepEqual(
-    [
-      mapping.groups.schema,
-      mapping.groups.codec,
-      mapping.groups.oracle,
-      mapping.groups.sourceSet,
-    ],
-    [
-      actualDigests.get("text-schema-v1.json"),
-      actualDigests.get("codec-vectors-v1.json"),
-      actualDigests.get("replace-range-v1.oracle.json"),
-      sourceSetDigest,
-    ],
-    "artifact digest ledger drift",
-  );
-}
-
-function retrospectiveClaims(design = readDesign()) {
-  const retrospectiveParts = design.split("## Retrospective");
-  assert.equal(retrospectiveParts.length, 2, "expected one Retrospective");
-  const changedParts = retrospectiveParts[1].split(
-    "What changed from the design:",
-  );
-  assert.equal(changedParts.length, 2, "expected one changed-design marker");
-  const openParts = changedParts[1].split("What remains open:");
-  assert.equal(openParts.length, 2, "expected one remaining-work marker");
-
-  const claims = [];
-  let currentClaim;
-  let currentSection = CHANGED_SECTION;
-  let testsProvedMarkers = 0;
-  for (const line of openParts[0].split(/\r?\n/)) {
-    if (line === "") {
-      currentClaim = undefined;
-      continue;
-    }
-    if (line === "What the tests proved:") {
-      testsProvedMarkers += 1;
-      currentSection = PROVED_SECTION;
-      currentClaim = undefined;
-      continue;
-    }
-    if (line.startsWith("- ")) {
-      const match =
-        /^- \*\*(?[^*]+)\.\*\* (?\S.*)$/.exec(line);
-      assert.ok(match, `unlabeled retrospective claim: ${line}`);
-      assertPlainEvidenceProse(match.groups.claimText);
-      currentClaim = {
-        citations: [],
-        evidenceClass: match.groups.evidenceClass,
-        section: currentSection,
-      };
-      claims.push(currentClaim);
-      continue;
-    }
-
-    assert.ok(currentClaim, `unsupported retrospective syntax: ${line}`);
-    assert.doesNotMatch(
-      line,
-      /^\s*(?:#{1,6}\s|[-+*]\s|\d+[.)]\s|>|```|~~~|\||=+\s*$|(?:(?:\*\s*){3,}|(?:_\s*){3,}|(?:-\s*){3,})$)/,
-      `unsupported retrospective syntax: ${line}`,
-    );
-    assert.match(line, /^  \S/, `unsupported retrospective syntax: ${line}`);
-    const citation = parseEvidenceCitation(line);
-    if (citation) {
-      currentClaim.citations.push(citation);
-    }
-  }
-  assert.equal(testsProvedMarkers, 1, "expected one tests-proved marker");
-  return claims;
-}
-
-function evidenceCitation([commit, sourcePath, line]) {
-  return {
-    label: `${sourcePath}#L${line}@${commit}`,
-    url: `https://github.com/flyingrobots/jedit/blob/${commit}/${sourcePath}#L${line}`,
-  };
-}
-
-function parseEvidenceCitation(line) {
-  const match =
-    /^  \[`(?