1ee30352ca
The self-improvement review fork advertises the parent's full tool schema (deliberate — tools[] must stay byte-identical for prompt-cache parity) but denied everything except memory/skill tools at dispatch. Models naturally reach for read_file to inspect a SKILL.md before patching, got denied, then attempted a blind skill_manage patch which the read-before-write guard correctly refused. One deployment logged ~142 denials + ~204 refusals over 2 days: the self-improvement loop ran continuously but almost never landed a skill patch. Fix is dispatch-side ONLY — zero request-body change, cache untouched: - Whitelist read_file + search_files on the review fork (reads are side-effect-free). Write tools (write_file/patch/terminal) stay denied: autonomous maintenance must go through skill_manage's validation. - read_file now registers full reads with the review fork's read-before-write guard (same as skill_view), so the natural read_file -> skill_manage(patch) sequence lands. Partial reads (offset>1 / truncated) don't count. No-op outside review forks. - Self-correcting deny message: names skill_view/skill_manage/memory as substitutes so one denial redirects the model instead of a storm (the actionable half of #61521's proposal 2). Rejects #39997's alternative (narrow the advertised schema on local endpoints): local backends have KV/prefix caches too, and re-prefilling a large snapshot is most expensive exactly there. Live A/B (real dispatch path, isolated HERMES_HOME): on main, read_file DENIED -> patch REFUSED (read-before-write); on this branch, read_file OK -> patch LANDED. tools[] identical in both.