Skip to content

Keep JS blocks that follow a block in another language - #209

Open
DavertMik wants to merge 2 commits into
mainfrom
fix/code-block-extraction
Open

DavertMik wants to merge 2 commits into
mainfrom
fix/code-block-extraction

Conversation

@DavertMik

Copy link
Copy Markdown
Contributor

Found while investigating a failed Tester session (Langfuse trace 078285ca5b32d556be2695c50141c5c8, session VariableIncreasedBrown198), where four verify() calls came back as "No assertion could express this claim" for claims the model had, in fact, answered correctly.

The bug

extractCodeBlocks matched an opening fence only when the info string was js, javascript or empty:

/```(?:js|javascript)?\s*\n([\s\S]*?)\n```/g

A ```html opener never matches — after the backticks the pattern needs \n, and finds h. The scan then walks forward and pairs that block's closing fence with the next block's closer, so every later fence shifts by one. The captured text is prose plus a nested fence, which fails the new Function('I', code) guard and is dropped.

One markup snippet in an answer is therefore enough to drop every assertion after it.

What it cost in the trace

Navigator wrote three valid assertions and got zero back, so totalAttempted === 0 and verifyState returned inexpressible. Tester was told the claim was unexpressible and rewrote an assertion that had been fine. Reproduced against the real response from that trace:

with html block    -> 0 blocks
html block removed -> 3 blocks

The fix

Match any info string, then keep the block only when it names JavaScript. A foreign block is consumed and skipped, so the scan stays in sync. The language filter also stops a ```text block whose content happens to parse as JavaScript from becoming an assertion.

Tests

New tests/unit/code-extractor.test.ts covers the js block, the unlabelled block, js blocks after a foreign block, a foreign block whose content parses as JS, and a js block that is not valid JS. The last test in that file fails on main. tests/unit/research-parser.test.ts (which feeds research markdown through the same function) still passes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JCYmFZvUsENZBx71Yqojs6

extractCodeBlocks matched an opening fence only when the info string was
js, javascript or empty, so a ```html block never matched as an opener.
The scan then paired that block's closing fence with the next block's
closer, shifting every later fence by one and producing text that failed
the JavaScript parse guard.

One markup snippet in an answer was therefore enough to drop every
assertion after it. Navigator read that as zero usable code blocks and
reported the claim as inexpressible, which sent Tester off to reword an
assertion that had been correct.

Match any info string and keep the block only when it names JavaScript,
so a foreign block is consumed and skipped instead of desynchronising
the scan.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JCYmFZvUsENZBx71Yqojs6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants