Improve local verified model harness
ober
f15ddc51c95f0d9ef82599d2449cc3eb296b8bf2
--- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ else JCODE_OS_LIBS := -lm -ldl -lpthread -luuid -lncurses -lstdc++ endif -.PHONY: all help ensure-jerboa-tools build gen run test test-providers clean repl binary install tui-shim run-tui native-rs sqlite-bundled linux linux-check linux-amd64 linux-arm64 jcode-linux-amd64 jcode-linux-arm64 test-linux test-linux-amd64 freebsd freebsd-amd64 jcode-freebsd-amd64 purge-stale sqlite-shim sqlite-lib android android-clean vendor-deps vendor-clean +.PHONY: all help ensure-jerboa-tools build gen run test test-providers local-eval clean repl binary install tui-shim run-tui native-rs sqlite-bundled linux linux-check linux-amd64 linux-arm64 jcode-linux-amd64 jcode-linux-arm64 test-linux test-linux-amd64 freebsd freebsd-amd64 jcode-freebsd-amd64 purge-stale sqlite-shim sqlite-lib android android-clean vendor-deps vendor-clean all: help @@ -60,6 +60,7 @@ help: @echo " build Compile src/ → lib/ and pre-compile imports (jerbuild)" @echo " test Run test suite (test/run.ss)" @echo " test-providers Live 'say hello' smoke test per configured provider" + @echo " local-eval Run live local-model verified eval (PROVIDER=mlx2 MODEL=/path/model)" @echo " run Start interactive agent REPL" @echo " run-tui Start TUI mode" @echo " repl Open a bare Scheme REPL with project libdirs" @@ -279,6 +280,17 @@ test-providers: build DYLD_LIBRARY_PATH=$(LDPATH) LD_LIBRARY_PATH=$(LDPATH) \ $(JEXEC) test/run-providers.ss +PROVIDER ?= mlx2 +MODEL ?= /Users/user/models/qwen3-coder-next-mlx +LOCAL_EVAL_JCODE ?= $(HOME)/.local/bin/jcode + +local-eval: build + DYLD_LIBRARY_PATH=$(LDPATH) LD_LIBRARY_PATH=$(LDPATH) \ + $(JEXEC) eval/local-model/run-local-eval.ss \ + --provider "$(PROVIDER)" \ + --model "$(MODEL)" \ + --jcode "$(LOCAL_EVAL_JCODE)" + # --- Static binary targets --- # Self-contained: `jerbuild build` reads .jerbuild (entry, libdirs, ffi-symbols, new file mode 100644 --- /dev/null +++ b/docs/local-model-smartness-plan.md @@ -0,0 +1,1522 @@ +# Making Local Models More Effective in `jcode verified` + +This document is an implementation plan for making weak or medium local coding +models perform better on Jerboa and general coding tasks. The goal is not to +make the model inherently smarter. The goal is to move planning, validation, and +recovery out of free-form model text and into structured, verified harness +behavior. + +The intended reader is another implementation agent. Each section describes the +desired behavior, the likely files to modify, test coverage, rollout order, and +acceptance criteria. + +## Background + +Recent local runs against `mlx2` at `http://127.0.0.1:8001/v1` showed the same +pattern repeatedly: + +- The local model can use tools when they are surfaced clearly. +- It can call MCP tools, including Jerboa-specific advisor tools. +- It often writes invalid Scheme on the first attempt. +- It tends to loop on rejected drafts unless the harness constrains it. +- It copies tool argument names across tools, such as using MCP-style + `old_string` and `new_string` with native `edit`. +- It obeys concrete verifier output more reliably than prose advice. + +The Conway Game of Life task became successful only after the harness did more +of the work: + +- `jcode verified` called `jerboa_request_advisor` before the first provider + turn. +- MCP tools were exposed as structured workflow tools. +- The `.ss` syntax guard blocked unbalanced code before it reached disk. +- Rejected-draft recovery messages became more explicit. +- Native edit accepted `old_string` and `new_string` aliases. +- Passing verifies stopped calling the failure advisor. + +That is the central lesson: local models improve when the system is more +deterministic, more structured, and less dependent on the model reading long +instructions correctly. + +## North Star + +`jcode verified` should behave like a strict coding harness with a small local +model in the loop, not like an open-ended chat session with a verify tool. + +For a Jerboa task, the ideal flow is: + +```text +classify task +choose verifier +choose write scope +load task-specific recipes and anti-patterns +choose a small verified scaffold +ask model to fill or repair limited regions +run verifier +map failure to a repair action +enforce that repair action +repeat until pass or actionable failure +``` + +The model should not be responsible for inventing the whole plan, remembering +every tool rule, or deciding when to abandon a bad strategy. + +## Design Principles + +1. Prefer structured state over prose. + + MCP can still return human-readable advice, but `jcode` should consume + machine-readable fields whenever possible: task kind, recommended verifier, + write scope, required first action, allowed tools, anti-pattern IDs, and + recovery policy. + +2. Enforce the workflow the model is supposed to follow. + + If a `.ss` file was rejected before it hit disk, `read` and `balance` may be + useful for one or two turns, but `run`, `verify`, `replace_range`, MCP file + edit tools, and broad inspection should not keep working normally forever. + +3. Make tools do high-level work. + + Weak models should not synthesize complex Jerboa programs from scratch when a + deterministic scaffold or repair helper can produce a syntactically valid + baseline. + +4. Keep templates small and executable. + + Large cookbooks become context burden. Small verified templates are useful. + Each template should include code and a verifier or smoke test. + +5. Use the local model for local generation, not global strategy. + + Let `jcode` and MCP choose the path. Let the model fill small code regions, + choose between explicit options, or repair a named span. + +6. Learn from actual traces. + + Every repeated local-model failure should become either an alias, a guard, a + new recovery policy, a template, or a test. Avoid relying on "better prompt" + alone. + +## Current Baseline + +As of this plan, the harness already has: + +- `jcode verified` with verify-gated workflow. +- Write scope enforcement. +- Jerboa `.ss` syntax guard for known bad generated patterns. +- Rejected-draft inspection support for files that were not written. +- Hard recovery messaging after rejected-draft inspection limit. +- MCP tool discovery and MCP-origin workflow tool exposure. +- Automatic `jerboa_request_advisor` preflight for Jerboa-looking verified + tasks. +- MCP failure advisor on failing verify results. +- Native edit aliases for `old_str`/`new_str` and `old_string`/`new_string`. + +This plan builds on those capabilities. + +## Repository Boundaries + +Primary repository: + +- `~/mine/jerboa-code` + +Primary implementation areas: + +- `src/jcode/core/verified-run.ss` +- `src/jcode/core/workflow-runner.ss` +- `src/jcode/core/workflow.ss` +- `src/jcode/mcp/client.ss` +- `src/jcode/provider/provider.ss` +- `test/run.ss` +- `docs/verified.md` +- new evaluation fixtures under `eval/`, `test/`, or `support/` + +Secondary repository: + +- `~/mine/jerboa` + +Use the Jerboa MCP repository only for capabilities that genuinely belong in +MCP: + +- new advisor fields +- new verified scaffold tools +- new cookbook/task data +- failure classification helpers +- anti-pattern data + +Do not move generic `jcode verified` state-machine behavior into MCP. MCP should +advise, scaffold, classify, and validate. `jcode` should enforce the workflow. + +## Phase 1: Establish a Fixed Local-Model Eval Suite + +### Goal + +Create a stable benchmark that measures whether harness changes help the local +model, instead of relying on anecdotes. + +### Scope + +Build a repeatable suite of 20 to 50 verified tasks. It should include Jerboa +tasks and general coding tasks. Each task must have: + +- task text +- working directory setup +- write scope +- verifier command +- timeout +- expected status +- tags +- optional model/provider overrides + +### Suggested File Layout + +```text +eval/local-model/ + README.md + tasks.sexp + run-local-eval.ss + summarize-local-eval.ss + traces/ +``` + +If the existing eval framework already has a better location, extend it instead +of creating a parallel system. + +### Task Schema + +Use an S-expression or JSON format. S-expression fits the codebase style. + +Example: + +```scheme +((id . "jerboa-life-text") + (title . "Text Conway Game of Life in Jerboa") + (tags . ("jerboa" "script" "vectors" "syntax-guard" "game-of-life")) + (cwd_mode . "tempdir") + (files . ()) + (task . "Write a text-based Conway's Game of Life in Jerboa Scheme in life.ss...") + (write_scope . "life.ss") + (verify . "/Users/user/mine/jerboa/.chez/bin/scheme --libdirs /Users/user/mine/jerboa/lib --script life.ss | rg -q '^PASS$'") + (timeout_seconds . 300) + (expected . "pass")) +``` + +### Starter Task List + +Create at least these tasks: + +1. `jerboa-minimal-script` + - Create a script that prints `PASS`. + - Verifier greps `PASS`. + +2. `jerboa-cli-args` + - Create a script that reads command-line arguments and sums two numbers. + - Verifier checks output for `7`. + +3. `jerboa-vector-grid` + - Create a 3x3 vector grid and render it. + - Verifier checks exact ASCII output. + +4. `jerboa-life-text` + - Conway Game of Life with blinker. + - Verifier checks `PASS`. + +5. `jerboa-repair-unbalanced-existing` + - Seed an existing `.ss` file with an extra close paren. + - Task asks the model to repair it. + +6. `jerboa-repair-invalid-context` + - Seed invalid define context. + - Verifier triggers known structural repair. + +7. `jerboa-main-not-called` + - Seed script with `main` but no call. + - Task asks to make script run. + +8. `jerboa-forbidden-racketism` + - Ask for code likely to use Racket-specific APIs. + - Verifier catches missing identifiers. + +9. `general-json-transform` + - Non-Jerboa small code task. + +10. `general-cli-file-edit` + - Modify an existing file and run a simple shell verifier. + +### Runner Requirements + +The eval runner should: + +- create temp working directories +- copy seed files +- run installed or local `jcode` +- support provider/model flags +- support trace output per task +- write one JSON result per task +- capture: + - pass/fail + - exit reason + - number of provider turns + - number of tool calls + - number of verify calls + - first verifier failure + - final verifier result + - count of syntax-guard rejections + - count of MCP calls by tool name + - elapsed time + +### Acceptance Criteria + +- `make local-model-eval-smoke` or equivalent runs 3 cheap tasks locally. +- Full eval can run with: + + ```bash + jcode-local-eval --provider mlx2 --model /Users/user/models/qwen3-coder-next-mlx + ``` + +- Results are machine-readable. +- A summary report shows pass rate by task tag and failure type. + +## Phase 2: Add Structured MCP Preflight Contracts + +### Goal + +Stop treating MCP advisor output as only prompt text. Make it a structured +contract that `jcode verified` can enforce. + +### Current Behavior + +`verified-preflight-guidance` calls `jerboa_request_advisor` and prepends the +result as text. This helps, but weak models may ignore it. + +### Desired Behavior + +MCP advisor should return both: + +- human-readable guidance +- structured fields + +Suggested MCP result shape: + +```json +{ + "text": "Jerboa request advisor...", + "task_kind": "script", + "project_kind": "jerboa-or-scratch", + "recommended_verify": "...", + "recommended_write_scope": "life.ss", + "first_action": { + "kind": "create_complete_file", + "path": "life.ss" + }, + "allowed_initial_tools": ["edit", "write", "read", "balance", "jerboa_script_scaffold_verify"], + "blocked_initial_tools": ["verify", "run", "replace_range", "replace_def"], + "recipes": [ + { + "id": "jerboa-cli-script-args-verify-friendly", + "title": "...", + "fetch_tool": "jerboa_howto_get" + } + ], + "anti_patterns": [ + { + "id": "script-main-not-called", + "avoid": "...", + "repair": "..." + } + ], + "recovery_policy": { + "syntax_guard_reject": "full_file_rewrite", + "max_rejected_draft_inspections": 2, + "after_limit": "only_full_file_create" + } +} +``` + +### jcode Implementation + +Add an internal struct for preflight policy, for example: + +```scheme +(defstruct verified-preflight-policy + text + task-kind + recommended-verify + recommended-write-scope + first-action + allowed-initial-tools + blocked-initial-tools + recovery-policy + recipes + anti-patterns) +``` + +Likely file: + +- `src/jcode/core/verified-run.ss` + +Add parsing helpers: + +- `mcp-advisor-result->policy` +- `policy->prompt-text` +- `policy-allows-tool?` +- `policy-next-required-action` + +Do not require MCP to support JSON on day one. Implement layered parsing: + +1. If result is a hash or JSON string with known keys, parse structured fields. +2. Otherwise keep current text-only behavior. +3. If parsing fails, log debug and continue with text-only guidance. + +### Enforcement + +Use the policy to initialize workflow state: + +- required first action +- initial allowed tools +- recovery behavior +- recommended write scope mismatch warning + +Examples: + +- If first action is `create_complete_file`, block `verify` until a file exists + or a deliberate read of an existing file occurs. +- If task kind is `script`, warn/block creation of `.sls` libraries for a + simple `.ss` script task. +- If recovery policy says `only_full_file_create`, enforce that after rejected + draft limit. + +### Tests + +Add unit tests in `test/run.ss`: + +- structured advisor result is parsed +- text-only advisor result remains supported +- first-action policy blocks premature verify +- recommended write scope is surfaced +- malformed JSON does not crash verified run + +### Acceptance Criteria + +- `jcode verified` uses structured advisor fields when present. +- Existing text-only MCP behavior still works. +- Local eval shows fewer premature verify/run/list calls on create-from-empty + tasks. + +## Phase 3: Add High-Level Verified Tools + +### Goal + +Give weak models tools that do useful units of work, not only primitive edit and +read tools. + +### Candidate Tools + +#### `create_verified_script` + +Purpose: + +Create a syntactically valid `.ss` script from a template and optionally run a +smoke verifier. + +Inputs: + +```json +{ + "path": "life.ss", + "kind": "minimal|cli_args|vector_grid|text_grid|custom", + "main_name": "main", + "expected_output": "PASS", + "overwrite": false +} +``` + +Behavior: + +- Generate a complete `.ss` script with `(import (jerboa prelude))`. +- Include a top-level `(main)` call unless configured otherwise. +- Run local syntax/balance guard before write. +- If `expected_output` is set, optionally run the script. + +Where to implement: + +- Prefer MCP if the generated script is Jerboa-specific: + - `~/mine/jerboa/mcp/server.ss` +- Expose through `jcode verified` as MCP workflow tool. + +But add `jcode` policy around it: + +- allow this tool as a first action for Jerboa script tasks +- treat successful scaffold write as satisfying create-file requirement + +#### `repair_rejected_draft` + +Purpose: + +Repair an in-memory rejected draft that has not been written to disk. + +Inputs: + +```json +{ + "path": "life.ss", + "strategy": "remove_extra_close|balance_span|full_rewrite|minimal_scaffold", + "hint": "unexpected close at line 60" +} +``` + +Important boundary: + +MCP cannot read `jcode`'s in-memory rejected draft unless `jcode` passes it. +This tool therefore probably belongs in `jcode`, not MCP. + +Where to implement: + +- `src/jcode/core/verified-run.ss` + +Behavior: + +- Use current rejected draft content. +- Apply deterministic repairs when safe. +- If deterministic repair is not safe, return a minimal scaffold request. +- Never blindly add or remove random parens across the whole file. + +#### `explain_and_patch_verify_failure` + +Purpose: + +Convert verifier output into a constrained repair action. + +Inputs: + +```json +{ + "verify_output": "...", + "path": "life.ss" +} +``` + +Output: + +```json +{ + "diagnosis": "unexpected-close", + "recommended_tool": "replace_range", + "path": "life.ss", + "start": 60, + "end": 60, + "instructions": "Replace this exact line, then verify." +} +``` + +Implementation split: + +- MCP can classify Jerboa-specific errors. +- `jcode` should enforce the recommended repair action. + +### Tool Naming + +Use names that make the model's choice obvious: + +- Good: `create_verified_jerboa_script` +- Good: `repair_rejected_draft` +- Good: `classify_verify_failure` +- Bad: `advisor2` +- Bad: `smart_helper` + +### Tests + +For each high-level tool: + +- success path +- missing required args +- out-of-scope path +- invalid generated code refused +- recovery state updated correctly + +### Acceptance Criteria + +- Local eval shows the model using high-level tools on at least half of Jerboa + script tasks. +- First-write syntax-guard rejection rate drops. +- No tool can write outside `write_scope`. + +## Phase 4: Enforce MCP Advice as Workflow State + +### Goal + +When MCP or verifier classification says "next action must be X", make `jcode` +enforce X. + +### Current Examples + +Already implemented patterns: + +- after failed verify, repeated broad inspection is limited +- after rejected draft inspection limit, non-edit tools are blocked +- required range repairs can block unrelated edits + +Extend this pattern. + +### Required Action State + +Add a general required-action state, not a collection of ad hoc parameters. + +Suggested struct: + +```scheme +(defstruct required-action + kind ;; symbol: create-file, replace-range, verify, full-rewrite, no-edit + path + start + end + allowed-tools + blocked-tools + reason + detail + attempts + max-attempts) +``` + +Possible current parameters to consolidate later: + +- `current-required-range-repair` +- `current-pending-ss-create-repair` +- `current-rejected-ss-draft` +- inspection counters + +Do not refactor everything at once. Add the generalized mechanism behind the +existing behavior, then migrate one state at a time. + +### Enforcement Function + +Implement: + +```scheme +(def (required-action-block-message action tool-name args cwd) ...) +``` + +It should return: + +- `#f` if the tool call is allowed +- a model-facing string if blocked softly +- optionally raise a tool error for hard violations + +Soft block is often better for weak models because it becomes tool result text +instead of ending the run. + +### Initial Required Actions + +Set required action from: + +- structured MCP preflight +- rejected draft state +- verifier failure classification +- write-scope none +- existing full-file rewrite rejection + +### Tests + +- required create-file blocks verify/list/run +- required create-file allows full edit/write +- required replace-range blocks unrelated full edit +- required verify blocks more reads after edit budget +- required action clears after successful edit or verify + +### Acceptance Criteria + +- Fewer repeated invalid tool calls in traces. +- Tool output tells the model one next action, not several alternatives. + +## Phase 5: Small Verified Templates + +### Goal + +Give the local model known-good code patterns it can adapt without inventing +syntax from scratch. + +### Template Requirements + +Each template must include: + +- ID +- tags +- imports +- complete code +- expected output or smoke verifier +- notes about common modifications + +Keep templates small. Prefer 20 to 80 lines. A 250-line template is probably +too much context for a weak model. + +### Starter Templates + +#### `jerboa-minimal-pass-script` + +```scheme +(import (jerboa prelude)) + +(define (main) + (display "PASS\n")) + +(main) +``` + +#### `jerboa-cli-two-args` + +Demonstrates: + +- `command-line-arguments` +- string to number +- top-level main call + +#### `jerboa-vector-grid-render` + +Demonstrates: + +- `make-vector` +- nested vector access +- `vector-set!` +- rendering characters + +#### `jerboa-table-driven-tests` + +Demonstrates: + +- local test cases +- simple assertion function +- failing with `(error 'test "...")` + +#### `jerboa-read-file-lines` + +Only if APIs are confirmed. Do not invent file APIs. + +### Where Templates Live + +Preferred source of truth: + +- `~/mine/jerboa/data/cookbooks.sexp` for MCP consumption + +Optional compiled/minimal mirror: + +- `~/mine/jerboa-code/support/templates/` if jcode needs offline fallback + +Avoid duplicating large templates in both repos without a sync mechanism. + +### jcode Use + +`jcode verified` should not dump every template into the prompt. Instead: + +1. Ask MCP for relevant template IDs. +2. Include at most 1 to 3 compact candidates in the prompt. +3. Encourage or enforce fetching one full recipe if needed. +4. Prefer a high-level scaffold tool for the initial file. + +### Tests + +In `jerboa`: + +- data validation for every template +- every template code block passes syntax/balance +- smoke verifier passes where provided + +In `jerboa-code`: + +- MCP template candidate is surfaced in preflight +- prompt remains below a defined size +- local model can call scaffold/fetch tool + +### Acceptance Criteria + +- Jerboa script tasks commonly start from a verified template. +- First-draft syntax rejection decreases in eval. + +## Phase 6: Failure Memory from Real Traces + +### Goal + +Turn repeated local-model mistakes into deterministic harness behavior. + +### Trace Collection + +Every local eval task should save: + +- `.trace` +- status JSON +- final files +- summarized event stream + +Add a trace summarizer that extracts: + +- syntax-guard rejections +- repeated identical writes +- rejected draft inspections +- MCP tool errors +- unknown tool args +- verify failures +- final result + +### Failure Pattern Data + +Create a local data file: + +```text +data/local-model-failures.sexp +``` + +or in `jerboa-code`: + +```text +eval/local-model/failures.sexp +``` + +Example entry: + +```scheme +((id . "mcp-arg-alias-on-native-edit") + (pattern . "edit called with old_string/new_string") + (observed_on . ("jerboa-life-text")) + (fix . "accept aliases in native edit") + (status . "implemented") + (tests . ("verified-run: exact replacement aliases can repair rejected draft"))) +``` + +### Automated Recommendations + +The summarizer should produce suggestions: + +- add arg alias +- add syntax guard +- add template +- add required action +- add MCP anti-pattern +- add provider-specific extraction/rescue + +Do not auto-apply these suggestions initially. Emit a reviewable report. + +### Acceptance Criteria + +- After an eval run, maintainers can see top failure patterns by count. +- At least one new harness issue can be created directly from the report. +- Existing implemented patterns are not re-suggested. + +## Phase 7: Constrain Model Role + +### Goal + +Reduce the number of choices the local model has to make. + +### Strategy + +Instead of: + +```text +Please write a Jerboa program. You have many tools. Good luck. +``` + +Use: + +```text +The harness classified this as a Jerboa script task. +You must choose one of these next actions: +1. create_verified_jerboa_script(...) +2. edit(path="life.ss", content=<complete file>) +3. read(path="life.ss") if the file already exists +``` + +### Implementation + +Add a compact "next allowed actions" block to the workflow prompt and update it +after each tool result. + +This may require changing the workflow runner so dynamic state can append a +short system/tool message before the next model call. + +Potential files: + +- `src/jcode/core/workflow-runner.ss` +- `src/jcode/core/verified-run.ss` +- `src/jcode/core/workflow.ss` + +### Dynamic Tool Availability + +Longer-term, hide blocked tools from the tool schema for that turn rather than +only returning block messages. + +Implementation approach: + +1. Add optional per-turn tool filter to workflow runner. +2. Filter tool specs before provider call. +3. Keep blocked tool messages as a fallback for providers that call stale tools. + +### Tests + +- when required action is create-file, tool schema excludes `verify` +- after file exists, `verify` returns +- blocked tool call still gets a clear message if model somehow calls it + +### Acceptance Criteria + +- Local model calls fewer irrelevant tools. +- Tool schema size shrinks during constrained states. + +## Phase 8: Improve Provider-Level Tool Call Recovery + +### Goal + +Handle local model quirks before they become workflow failures. + +### Known Quirks + +- emits MCP-style args to native tools +- emits tool calls in text instead of structured API +- repeats same tool call after soft failure +- omits required args +- confuses path aliases + +### Implement Alias Normalization + +Add common aliases at the tool boundary: + +- `old_string` -> `old_str` +- `new_string` -> `new_str` +- `filepath` -> `path` +- `file_path` -> `path` +- `target_path` -> `path` +- `contents` -> `content` +- `body` -> `content` + +Some aliases already exist. Audit all verified workflow tools and make behavior +consistent. + +### Add Tool-Specific Repair Nudges + +If required args are missing, return a message with the exact corrected call. + +Example: + +```text +edit replacement is missing old_str/new_str. Retry as: +edit(path="life.ss", old_str=<text to replace>, new_str=<replacement>) +Aliases old_string/new_string are also accepted. +``` + +### Tests + +- every alias works for native edit/write +- missing args return exact retry shape +- repeated malformed args trip no-progress breaker + +### Acceptance Criteria + +- Local model no longer fails solely because it mixed MCP and native arg names. + +## Phase 9: Add Deterministic Script Repair Helpers + +### Goal + +When a generated `.ss` script is unbalanced, attempt safe deterministic repair +before asking the model to reason through the whole file again. + +### Safe Repair Cases + +Only repair cases with high confidence: + +- one extra close delimiter at end of line +- missing final close delimiter at EOF for a top-level form +- known bad spacing such as `(set!*x ...)` +- forbidden simple API replacement when exact replacement is known + +### Unsafe Cases + +Do not auto-repair: + +- complex nested delimiter confusion +- code with strings/heredocs where delimiter scanner is uncertain +- multiple independent errors +- cases requiring semantic choices + +### Implementation + +Add helper: + +```scheme +(def (safe-repair-rejected-ss-draft path content guard-message) ...) +``` + +Return: + +```scheme +;; success +(cons 'repaired new-content) + +;; cannot repair +(cons 'unhandled reason) +``` + +Use it in: + +- initial rejected create +- rejected full-file rewrite