fix(triage): harden JSON parsing against model preamble in parseDecisions#165
Merged
Conversation
…ions Extract the JSON array by finding the outermost `[` and `]` before calling JSON.parse, so conversational preamble emitted by the model no longer causes a SyntaxError. Falls back to the full string (and the original error) when no brackets are present. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5 tasks
Owner
Author
|
[Baton Reviewer] [must] The bracket scanner can still misparse or fail on bracket characters inside prose or JSON string values. A preamble like |
keinstn
commented
Jun 24, 2026
keinstn
left a comment
Owner
Author
There was a problem hiding this comment.
The indexOf/lastIndexOf bracket extraction has two confirmed misfire cases and one silent-wrong-data regression. The core issue is that character-level bracket scanning cannot distinguish JSON delimiters from brackets in natural-language prose (issue refs like [#42], markdown, etc.). See inline comments for specifics.
4 tasks
keinstn
commented
Jun 24, 2026
…isfires Replace the indexOf/lastIndexOf bracket extraction with a balanced-bracket scanner that tries each outermost [...] candidate in order, returning the first one that parses as valid JSON. Also try JSON.parse on the full clean string first so well-formed output skips extraction entirely. Adds tests covering preamble containing '[' and postamble containing ']', both of which the original indexOf/lastIndexOf approach misfired on. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
keinstn
commented
Jun 24, 2026
…actJsonArray Brackets inside JSON string values (e.g. `"reason": "] edge case"`) could cause the depth counter to hit zero prematurely, making the scanner return a bad substring rather than the full decisions array. Fix by tracking quoted-string and escape state so brackets inside strings are ignored. Also require each candidate to be an array of objects (not scalars), so a preamble like "See [1,2]" is not mistaken for the decisions array. Co-Authored-By: Claude Sonnet 4.6 <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.
Fixes #161
Summary
parseDecisionsinscripts/triage/parse.tsnow extracts the JSON array by finding the outermost[and]before callingJSON.parse, so any conversational preamble emitted by the model (e.g. "I'll check each issue...") no longer causes aSyntaxErrorJSON.parseerror message for non-JSON responsestest/triage-parse.test.tswith unit tests covering bare JSON, preamble, preamble+postamble, code-fenced preamble, no-JSON, non-array, and invalid field casesTest plan
npm run test— 347 tests pass (29 test files)npm run typecheck— no errorsnpm run lint— no errorsparseDecisions("I'll check each issue.\n[{...}]")parses successfullyparseDecisions("no json here")still throwsSyntaxError🤖 Generated with Claude Code