Improve local verified model harness

ober

f15ddc51c95f0d9ef82599d2449cc3eb296b8bf2

diff --git a/Makefile b/Makefile
index 5768d99..ba809ef 100644
--- 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,
diff --git a/docs/local-model-smartness-plan.md b/docs/local-model-smartness-plan.md
new file mode 100644
index 0000000..c530e48
--- /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