fix(code/search): forgive glob-shaped pattern — list files instead of looping the search forever#1949
Merged
Merged
Conversation
…of looping the search forever Glass-boxed live: a local 14B on a SWE task fired `code/search(pattern="**/*.py")` twelve times in a row and never advanced to read/edit. Root cause: it conflates code/search (grep file CONTENTS — `pattern` is the search TERM, `file_glob` filters files) with code/glob (find files BY name). A glob in `pattern` greps contents for the literal text "**/*.py" → 0 matches → the model retries the identical call and stalls. This is the same class of confusing-tool-contract bug as the code/edit `edit_mode`-as-"any" fix (#1946): a 14B can't infer the two-param split, so the tool must meet it halfway. Fix: when `pattern` looks like a file glob (`*`/`?` + a path-glob shape, conservative so a real content regex like `foo.*bar` / `fn .*Params` is NOT misclassified — unit-tested) and no `file_glob` was given, do what it MEANT — run the glob and return the matching FILE paths as results, plus a one-line note on the correct shape. One call now makes progress instead of looping. Strictly-better for the detected case (which otherwise always returns 0); the normal grep path (real term, or file_glob set) is untouched, so no regression is possible. Behavior-validation (persona reads→edits) is PENDING a stable coder lane: this session's heavy core-reboot churn left the local llama-server 500ing "Compute error" on restart, which blocks all evals (separate infra issue, being left to stabilize). Unit test green; logic is opt-in on a currently-useless case. [[px-persona-experience-tools-as-good-ux]] Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo
joelteply
added a commit
that referenced
this pull request
Jul 9, 2026
…er paths — the two barriers past the search-loop (#1951) Glass-boxed live (loop-perception PR #1950 got the 14B PAST the search-loop and hammering code/edit; these are the two walls it then hit): 1. edit_mode shape: it sent `edit_mode:"append"` (bare variant string) and, later, the fields flat at top level with no edit_mode at all. EditMode is a serde-tagged enum, so both 400'd at deserialize. Fix: `edit_mode` accepts a Value; `normalize_edit_mode` tries the strict tagged object first (unchanged), then a bare mode string, then INFERS the mode from which top-level fields are present (search/replace→search_replace, content→append, etc.), failing LOUD and naming the missing field (never a silent no-op → false-zero). Same "meet the model halfway" forgiveness as code/search #1949; strict callers are untouched, so no regression. 2. placeholder path: it wrote `file_path:"<path_to_blueprints.py>"` — echoing the schema's angle-bracket placeholder instead of the concrete path it had already seen in its search results. `reject_placeholder_path` fails loud on `<...>`/`path_to`/`your_file` templates and points at the real value ("use the path from your search results, e.g. src/flask/blueprints.py") instead of a confusing file-not-found. VALIDATED live: with these, the inference path fires (she now sends content/search flat and the mode resolves) — the remaining 0-diff is purely the placeholder path, which now fails loud with guidance instead of silently. Unit-tested (strict/bare/inferred/loud-missing; placeholder-vs-real). The rails are now maximally forgiving; what's left past this is base-model COHERENCE (it has the real path in memory but writes the template) — the Devstral lever, not more tool fixes. [[px-persona-experience-tools-as-good-ux]] [[built-to-teach-lesser-tuned-intelligences-win]] Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Glass-boxed live: a local 14B on a SWE task fired
code/search(pattern="**/*.py")twelve times in a row andnever advanced to read/edit. Root cause: it conflates code/search (grep file CONTENTS —
patternis the searchTERM,
file_globfilters files) with code/glob (find files BY name). A glob inpatterngreps contents for theliteral text "**/*.py" → 0 matches → the model retries the identical call and stalls. This is the same class of
confusing-tool-contract bug as the code/edit
edit_mode-as-"any" fix (#1946): a 14B can't infer the two-paramsplit, so the tool must meet it halfway.
Fix: when
patternlooks like a file glob (*/?+ a path-glob shape, conservative so a real content regex likefoo.*bar/fn .*Paramsis NOT misclassified — unit-tested) and nofile_globwas given, do what it MEANT —run the glob and return the matching FILE paths as results, plus a one-line note on the correct shape. One call now
makes progress instead of looping. Strictly-better for the detected case (which otherwise always returns 0); the
normal grep path (real term, or file_glob set) is untouched, so no regression is possible.
Behavior-validation (persona reads→edits) is PENDING a stable coder lane: this session's heavy core-reboot churn
left the local llama-server 500ing "Compute error" on restart, which blocks all evals (separate infra issue, being
left to stabilize). Unit test green; logic is opt-in on a currently-useless case. [[px-persona-experience-tools-as-good-ux]]
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo