Repository navigation
fix(core): recover outer XML calls with quoted call content - #13579
Conversation
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
|
â Qwen Triage finished â view run. See the stage comments in this thread for the result. â Qwen Triage å·ēåŪæ ââ æĨįčŋčĄãįŧæč§æŽįšŋįĻäļįåéķæŪĩčŊčŪšã |
|
Local CLI verification: PASS â issue #13492 (2026-10-07)
The candidateâs actual tool receipt was File SHA-256: Runtime identity and stability: the hookâs actual resolve/load receipts prove Regression pin: the two selected changed quoted-call testsâouter invoke and long quoted function valueâfailed against a temporary resolve alias to the exact baseline parser (2 fail), and passed against the candidate (2 pass). This is separately labeled helper-level evidence; the full 83 parser suite was not repeated. The focused parser/chat consumer suites passed 636 tests (83 parser and 553 consumer). The full build and bundle, core typecheck, changed-file lint/format checks, and diff whitespace check passed separately on the same frozen candidate. Two bounded correctness/security reviews found no verified blocking finding. Actual sanitized tmux excerpts retain the terminalâs original wrapping: Setup failures preserved: the primary input used invalid relative native file paths. Its sole fallback corrected absolute paths, but the Evidence and cleanup: VERDICT: PASS äļæåŪæīæĨåïžæŽå° CLI éŠčŊéčŋïž#13492ïž2026-10-07ïž æŽæŽĄéįĻ merge-reference æĻĄåžïžåĻįåŪ tmux äļčŋčĄå·ēæåŧšį äļĪč promptãprovider XMLãprofile settings å 190Ã48 įŧįŦŊå°šåŊļįļåïžåŪé
workspace åįĶŧïžéčŋåäļäļŠčŠæįŧåŊđč·ŊåūåŦåäŋæå·Ĩå
·åæ°ææŽäļčīãé
į―Ūäŧ
ä―ŋįĻįŽįŦ
after æäŧķæĢæŊäļæđäŧĢį åįåŪæī 110 äļŠ UTF-8 åčïžæēĄææŦå°ūæĒčĄïžSHA-256 äļš åŪé
hook į resolve/load receipt čŊæ before å č――åšįšŋ fixtureïžåå§æšį SHA-256 äļš äļĪæĄéåŪåå―ïžåĪåą invokeãéŋ quoted function valueïžéčŋäļīæķ Vitest resolve alias æåįēūįĄŪåšįšŋ parser æķååĪąčīĨïžæå candidate æķåéčŋãčŋæŊįŽįŦ helper įš§čī/æĢåŊđį §ïžæēĄæéč·åŪæī 83 éĄđ parser suiteïžåäļåŧįŧåéå·ēéčŋč§ĢæåĻ/chat č°įĻæđå ą 636 éĄđæĩčŊïž83 éĄđč§ĢæåĻã553 éĄđč°įĻæđïžãåŪæī build/bundleãcore įąŧåæĢæĨãæđåĻæäŧķ lint/æ žåžæĢæĨå diff įĐšį―æĢæĨãäļĪč―ŪæéæĢįĄŪæ§/åŪå ĻåĪæ ļæēĄæåį°įŧéŠčŊįéŧåĄéŪéĒïžæŽč―ŪæēĄæéåĪčŋäšæĢæĨã äŋįäš setup åĪąčīĨïžæåįļåŊđč·ŊåūčĒŦ native å·Ĩå
·æįŧïžåŊäļ fallback ä―ŋįĻįŧåŊđč·Ŋåūåïž åŪé tmux captureãCLI stdoutãprovider requests/tool receiptsãč―įæäŧķãparser load čšŦäŧ―ãäļĪæĄåå―įŧæå source/artifact manifest å·ēčąæäŋåïžäļæđįŧįŦŊæå―äŋįåå§æĒčĄãæįŧ 16 éĄđæĢæĨå ĻéĻéčŋïžæåäļč―Ū 7 äļŠčŠæ PID å ĻéĻéåšïžäļĪįŧ tmuxãproviderãprofiles/workspacesãparser fixture/hook å harness å·ēå éĪïžäđå setup čĩæšäđå·ēæļ įãæĩčŊäššåæēĄæäŋŪæđæšį ãįĻæ·é į―ŪãGit æ GitHubãæĪæŽĄäļæķååļåą/éĒčēååïžå æĪä―ŋįĻææŽ capture åģåŊïžäļéčĶåūįãcontrolled provider įįŧæäļäŧĢčĄĻįåŪįäš§æĻĄåčĄĻį°ïžæĒåĪå streaming raw XML åŊč§æ§äļåąäšæĪäŋŪåĪïžäđæēĄæåŪĢį§°å ķæķåĪąã įŧčŪšïžPASSã |
|
Thanks for the PR â re-run against the new head Template looks good â (all nine headings present) Problem: observed, not theoretical. #13492 is open and self-reported by you ( Duplicate check (1-pre): base Direction: aligned. This fallback exists for #8003 (models emitting raw XML tool calls instead of the structured array in long contexts), and #13515 correctly kept the quoted call inert but left the enclosing write discarded. Restoring the outer call is squarely within that mission. Size: core paths ( Approach: this is where my reservation sits, and it is not about line count. The new commit changes posture from "decline the ambiguous suffix" to "decline the whole turn" â there are now ten distinct Worth naming too: this is round 8, past the ~5-round point where AGENTS.md says land Critical fixes only and defer the rest. The class-level rework is tracked as #13492 and the scan-cost half as #13787, and qqqys already agreed neither should hold this PR. Risk: the deterministic Stage 1e check finds no high-risk path match. Stated honestly rather than leaning on that: Moving on to code review. ð äļæčŊīææč°ĒčīĄįŪïžæŽæŽĄæŊéåŊđæ° head æĻĄæŋåŪæī âïžäđäļŠåŋ éæ éĒé―å Ļïž éŪéĒïž å·ēč§æĩå°į bugïžäļæŊįčŪšæ§å åšã#13492 äŧåĪäš openïžįąä― æŽäššæäšĪïž éåο̿Ĩïž1-preïžïž base æđåïž åŊđé―ãčŊĨ fallback æščŠ #8003ïžéŋäļäļæäļæĻĄåčūåščĢļ XML å·Ĩå ·č°įĻčéįŧæåæ°įŧïžïž#13515 æĢįĄŪå°čŪĐčĒŦåžįĻįč°įĻäŋææ°æ§ïžä―æåĪåą write äļčĩ·äļĒæäšãæĒåĪåĪåąč°įĻåŪå ĻåĻčŋäļŠä―ŋå―čåīå ã č§æĻĄïž č§Ķåæ ļåŋč·Ŋåūïž æđæĄïž æįéĄūčåĻčŋéïžäļäļčĄæ°æ å
ģãæ°æäšĪæåĪį―Ūæđåžäŧ"æįŧææ§äđįåįž"æđæäš"æįŧæīč―ŪåŊđčŊ"ââ åĶåĪéčĶįđæïžčŋå·ēįŧæŊįŽŽ 8 č―Ūïžčķ čŋäš AGENTS.md æčŊīįšĶ 5 č―ŪäđååŠč― Critical äŋŪåĪãå ķä―č―Žåįŧ issue įįéãįąŧåŦįš§éæįą #13492 č·čŋïžæŦæåžéįą #13787 č·čŋïžqqqys äđå·ēčŪĪåčŋäļĪč é―äļåšåĄä―æŽ PRã éĢéĐïž Stage 1e įįĄŪåŪæ§æĢæĨæēĄæå―äļéŦéĢéĐč·Ŋåūãä―åĶåŪčŊīæčäļæŊæŪæĪæūæūïž čŋå ĨäŧĢį åŪĄæĨ ð â Qwen Code · qwen3.8-max-2026-09-02 Reviewed at |
|
What evidence this comment carries: the PR's own CI results at the reviewed commit, fetched through the API (real check names and conclusions below). This is an unattended run ( Code reviewMy independent proposal before reading the diff: mask the quoted regions, and when ownership of a region cannot be decided, decline rather than guess. On posture the PR now matches that â arguably exceeds it, since it declines the whole batch rather than the affected block. Where I would have differed is the blast radius of the decline, which is the Stage 1 reservation rather than a code defect. The consolidated blocker from the last review is genuinely closed, and pinned â not guarded around. qqqys named two mechanisms at
The One real defect, verified at this commit and not covered by any test. The pre-scan opening for (const opening of text.matchAll(/<parameter(?=[\s=>])/gi)) {
PARAMETER_OPEN_TAG_PATTERN.lastIndex = opening.index;
if (!PARAMETER_OPEN_TAG_PATTERN.test(text)) return [];
}It validates against /<parameter(?:\s+name=(["'])[^"']+\1|=[^\s<>"']+)>/ySo It fails closed, so it is not a safety hole â it is an availability regression in the recovery path. I grepped the 1617-line test file: zero case-variant and zero bare Non-blocking, noted for completeness: Downstream consumers (named, per the core Tier 2 bar): exactly one â Where the two mask views diverge (the flow a ruling has to cover)sequenceDiagram
participant P1 as recoverableToolCallBlocks
participant P2 as Opener PreScan line 335
participant P3 as Pass 1 example ranges
participant P4 as Block loop
participant P5 as Eligibility two views
participant P6 as Pass 2 recompute
P1->>P2: scan every parameter opener in raw text
P2-->>P1: decline whole turn on any mismatch
P1->>P3: derive documentation ranges over the unextended mask
P1->>P4: match call blocks, advancing past quoted values
P4-->>P1: decline whole turn on borrowed or unmatched regions
P1->>P5: isEligibleBlock reads the extended mask, passesFenceGuard reads the frozen snapshot
P5-->>P1: decline whole turn on disagreement
P1->>P6: recompute ranges over the extended mask
P6-->>P1: decline whole turn if eligibility changed
CI test evidenceFetched once for the reviewed commit â 31 check-runs: 22 success, 8 skipped, 1 queued, no failures. The queued one is The checks that matter for this diff are green: Stated plainly rather than implied:
Sandboxed verification would settle this: The specific gap at this head: the new CLI evidence covers two shapes (the extra-quote case and one outer-write control), but the FAIL that prompted this commit was measured across three CLI shapes â and cells 2 and 3 (a prose Real-scenario testingN/A â unattended CI run. Per the skill's rules no PR-derived code was executed, built, or checked out, so there is no terminal capture to inline. The live-behaviour gap is named above with the lane that would close it, rather than papered over with the author's self-reported tmux results â those are attributed in the PR description as the author's claim, and are not evidence this gate re-ran. äļæčŊ޿ĄčŊčŪšæšåļĶįčŊæŪïž éčŋ API ååūįãčŊĨ PR čŠčšŦåĻæåŪĄ commit äļį CI įŧæïžäļæđäļšįåۿ̿ĨåäļįŧčŪšïžãæŽæŽĄäļšæ äššåžåŪčŋčĄïž äŧĢį åŪĄæĨïž äļäļč―ŪååđķåįéŧæéŪéĒčŋæŽĄæŊįæĢčĒŦįŧææ§å
ģéįïžåđķäļčĒŦæĩčŊåšåŪä―äšïžäļæŊåįŧäļåąåŪåŦãqqqys åĻ qqqys åŪæĩäļšåå―į äļäļŠįåŪįžšé·ïžå·ēåĻčŊĨ commit æ ļåŪïžäļæ äŧŧä―æĩčŊčĶįïž įŽŽ 335 čĄįéĒæŦææŊæīäļŠæäŧķäļåŊäļåļĶ åŪæŊ fail-closed įïžå æĪäļæŊåŪå
ĻæžæīïžčæŊæĒåĪč·ŊåūäļįåŊįĻæ§åå―ãæåĻ 1617 čĄæĩčŊæäŧķäļæĢįīĒïžåΧå°ååä―äļčĢļ ééŧæïžäŧ
ä―čŪ°å―ïž äļæļļæķčīđæđïžææ ļåŋ Tier 2 čĶæąéäļįđåïžïž åŠæäļäļŠââ CI čŊæŪïž åĻæåŪĄ commit äļäļæŽĄæ§ååū 31 äļŠ check-runââ22 æåã8 č·ģčŋã1 æéïžæ åĪąčīĨãæéįæŊ æēįŪąéŠčŊåŊäŧĨåŪčŪšïž čŊĨ head äļįå
·ä―įžšåĢïžæ°į CLI čŊæŪåŠčĶįäļĪį§å―ĒæïžéĒåĪåžå·įĻäūäļäļäļŠåĪåą write åŊđį
§ïžïžä―äŋä―ŋæŽæŽĄæäšĪį FAIL æŊåĻäļį§ CLI å―Ēæäļæĩåūįââå
ķäļ cell 2 å cell 3ïžprose įåŪåšæŊæĩčŊïž N/A ââ æ äššåžåŪ CI čŋčĄãæ skill č§åæŠæ§čĄãæåŧšæ checkout äŧŧä―æĨčŠ PR įäŧĢį ïžå æĪæēĄæåŊå čįįŧįŦŊæč·ãäļčŋ°čĄäļšįžšåĢæŊčŋååŊäŧĨéįŊįæ§čĄééäļčĩ·įđæįïžčäļæŊįĻä―č čŠæĨį tmux įŧææĨåĄŦčĄĨââéĢäšå åŪđåĻ PR æčŋ°äļå·ēæįĄŪå―åąäļšä―č äļŧåž ïžåđķéæŽéļéĻåĪč·čŋįčŊæŪã â Qwen Code · qwen3.8-max-2026-09-02 Reviewed at |
|
Confidence: 3/5 â the consolidated blocker is genuinely closed and pinned for the first time, but the fix answers a question a maintainer was asked to rule on, and I found one untested defect on the way. Stepping back: this is the first round that answered qqqys's "which view is authoritative" with a structural change instead of another entrance guard. Removing the in-loop What keeps me from approving: The posture change is a product decision that has not been made. "Decline the whole turn" is now reached from ten separate sites, and it costs legitimate recovery in 13 shapes that used to be pinned â the description says so plainly. For a fallback whose whole purpose is rescuing malformed model output, one bad fragment now forfeits the entire turn, and One verified defect stands between this and clean. The line-335 pre-scan is the only case-insensitive regex in the file, validated against a case-sensitive pattern that also requires The behavioural claim is not yet substantiated end-to-end at this head. The prior head's narrow suite was 115/115 green in both arms while the real CLI dispatched a documented Also worth saying out loud, since it shapes how much more this PR should absorb: this is round 8. AGENTS.md asks that past roughly five rounds a PR land Critical fixes only and defer the rest, and the two things still open beyond the defect above â the recovery-surface class (R2-1) and the unbounded scan cost â are already tracked as #13492 and #13787, with qqqys on record that neither should hold this PR. I agree. If the ruling is "keep it open", the remaining work is the one-character flag fix, its pin, and a Verdict: defer, not approve, not reject. I am escalating rather than deciding, because the blocking uncertainty is not resolvable from the diff, the tests, or the description â it needs someone to own the compatibility trade-off. The PR already carries @qqqys â you asked the decisive question in the last review, and this commit answers it with a third option (neither view wins; the batch is dropped) plus a re-specified pin at äļæčŊīæį―ŪäŋĄåšĶïž3/5 ââ ååđķåįéŧæéŪéĒįŽŽäļæŽĄčĒŦįæĢå ģéåđķåšåŪä―ïžä―čŋæŽĄäŋŪåĪåįįæŊäļäļŠæŽåšįąįŧīæĪč čĢåŪįéŪéĒïžčäļčŋįĻäļæåį°äšäļäļŠæŠčĒŦæĩčŊčĶįįįžšé·ã éäļæĨįïžčŋæŊįŽŽäļč―ŪįĻįŧææ§æđåĻãčäļæŊåå äļåąå
ĨåĢåŪåŦæĨåį qqqys "äļĪäļŠč§åūåēįŠæķäŧĨåŠäļŠäļšå"įæéŪãå éĪåūŠįŊå
į čŪĐæäļæđåįįįąïž åĪį―ŪæđåžįæđåæŊäļäļŠå°æŠååšįäš§ååģįã į°åĻ"æįŧæīč―ŪåŊđčŊ"åŊäŧĨäŧååĪäļåä―į―Ūč§ĶåïžäŧĢäŧ·æŊ 13 äļŠåæŽå·ēåšåŪįå―ĒæåĪąåŧåæģæĒåĪč―åââPR æčŋ°åŊđæĪååūåūæį―ãåŊđäšäļäļŠččīĢå°ąæŊæ―æįļå―ĒæĻĄåčūåšį fallbackïžäļäļŠåįæŪĩå°ąäžčŪĐæīč―ŪåŊđčŊå
ĻéĻä―åšïžč äļäļŠå·ēæ ļåŪįįžšé·æĻŠåĻ"åđēå"äđåã įŽŽ 335 čĄįéĒæŦææŊæäŧķäļåŊäļåΧå°åäļææįæĢåïžåīįĻåΧå°åææãäļčĶæą čĄäļšäļŧåž åĻčŊĨ head äļå°æŠįŦŊå°įŦŊčŊåŪã äļäļäļŠ head įįŠæĩčŊéäļĪäū§é―æŊ 115/115 å
ĻįŧŋïžčįåŪ CLI æīūåäšææĄĢåį čŋæäļįđåšå―æčŊīïžå äļšåŪåģåŪčŋäļŠ PR čŋåščŊĨåļæķåĪå°æđåĻïžčŋå·ēæŊįŽŽ 8 č―ŪãAGENTS.md čĶæąčķ
čŋåΧįšĶ 5 č―ŪäđååŠč― Critical äŋŪåĪãå
ķä―č―ŽåįŧåĪįïžčéĪäļčŋ°įžšé·äđåĪäŧæŠå
ģéįäļĪäŧķäšââæĒåĪéĒįąŧåŦéŪéĒïžR2-1ïžäļæ įæŦæåžéââå·ēååŦįą #13492 å #13787 č·čŋïžqqqys äđå·ēæįĄŪčĄĻįĪščŋäļĪč
é―äļåšåĄä―æŽ PRãæåæãåĶæčĢåŪæŊ"äŋæåžåŊ"ïžåĐä―å·Ĩä―å°ąæŊäļäļŠåįŽĶįæ åŋäŋŪåĪãåŪåŊđåšįæĩčŊåšåŪïžäŧĨåäļæŽĄ įŧčŪšïžæįžïžäļæđåïžäđäļæįŧã æéæĐäļåčäļæŊčŠčĄåĪåŪïžå äļščŋäļŠéŧææ§äļįĄŪåŪæ§æ æģäŧ diffãæĩčŊææčŋ°äļč§ĢåģââéčĶæäššæĨæŋæ
čŋäļŠå
žåŪđæ§åčãčŊĨ PR å·ēåļĶæ @qqqys ââ åģåŪæ§įéŪéĒæŊä― åĻäļäļč―ŪæåšįïžčæŽæŽĄæäšĪįĻįŽŽäļäļŠééĄđåįäšåŪïžäļĪäļŠč§åūé―äļįŪïžæīæđäļĒåžïžïžåđķéåäš â Qwen Code · qwen3.8-max-2026-09-02 Reviewed at |
|
@qwen-code /triage |
|
Sandboxed verification: â not passed â findings reported (agent verdict) - workflow run Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers â not a review, an approval, or a CI check. Scripted assertions: 267 passed · 1 failed · 268 total Flakiness gate: â 1 changed test file(s) x 5 identical rounds, no divergence äļæ â åĪåŪïžâ äļéčŋ · æĨåäšåį°ïžagent åĪåŪïžæēįŪąéŠčŊåĻéįĶŧãæ åčŊįåŪđåĻäļæ§čĄäščŊĨ PR įäŧĢį ïžäļ base æåŧš A/B åŊđį §ãæ mock harness æčĻãåŪåéĻįĶïžãäŧ ä―äļščŊåŪĄčŊæŪïžäļææčŊåŪĄãæđåæ CI æĢæĨã čæŽæčĻïž267 éčŋ · 1 åĪąčīĨ · 268 æŧčŪĄ æåĻéĻïžâ 1 changed test file(s) x 5 identical rounds, no divergence Verification reportPR #13579 deep verification â
|
| cell | input (issue #13492 shape) | oracle | base (HEAD^1) |
head (HEAD^2) |
|---|---|---|---|---|
| S1 central | outer write_file, content value quotes a complete run_shell_command call |
tryRecoverXmlToolCalls |
recovered=false, 0 calls â the outer write is lost |
recovered=true, 1 call write_file |
| S1 fidelity | same | dispatched args.content |
n/a | byte-identical to Usage:\n + the quoted markup (verbatim assertion passed) |
| S1 safety | same | is the quoted command dispatched? | no | no (absent from both extractXmlToolCalls and functionCallParts) |
| S2 secondary | S1 + a genuine following read_file |
call list | [read_file] only |
[write_file, read_file] |
Witness: 01-ab-head-vs-base-24-scenarios.png (all 24 scenarios as the harness printed them, 227/227 assertions).
A/B and sibling-sweep matrix (24 shapes)
The mechanism is a parser/state machine, so the reported shape is one door into a room with several. Every adjacent shape the same root cause admits was driven through both arms; "quoted dispatched?" is asserted on both arms for every row (a symmetric control, per the run-every-control-on-both-arms rule).
| id | shape | base | head | quoted dispatched? |
|---|---|---|---|---|
| S1 | invoke outer quoting an invoke call | [] |
[write_file] |
no / no |
| S2 | + genuine following read_file |
[read_file] |
[write_file, read_file] |
no / no |
| S3 | function dialect on both levels | [] |
[write_file] |
no / no |
| S4 | invoke outer quoting a function-dialect call | [] |
[write_file] |
no / no |
| S5 | function outer quoting an invoke-dialect call | [] |
[write_file] |
no / no |
| S6 | quoted call uses single-quoted attributes | [] |
[write_file] |
no / no |
| S7 | quoted call with several parameters | [] |
[write_file] |
no / no |
| S8 | nested quoting (a quoted value quoting a call) | [] |
[write_file] |
no / no |
| S9 | two separate quoted values in one call | [] |
[write_file] |
no / no |
| S10 | value quotes an opener with no closer | [] |
[] conservative |
no / no |
| S11 | value quotes a bare closer | [] |
[] conservative |
no / no |
| S12 | value quotes mismatched closers | [] |
[] conservative |
no / no |
| S13 | quoted markup inside a fenced block in the value | [] |
[write_file] |
no / no |
| S14 | quoted markup inside a backtick code span | [] |
[write_file] |
no / no |
| S15 | entity-escaped markup in the value | [write_file] |
[write_file] unchanged |
no / no |
| S16 | quoted markup inside an example wrapper in the value | [] |
[write_file] |
no / no |
| S17 | outer truncated mid-value after a complete quoted call | [] |
[] conservative |
no / no |
| S18 | outer close missing, quoted call complete | [] |
[] conservative |
no / no |
| S19 | prose-dominant page + one fenced example | [] |
[] guard holds |
no / no |
| S20 | prose-dominant page + one unfenced real call | recovered=false |
recovered=false guard holds |
no / no |
| S21 | real call wrapped in an example element | [] |
[] guard holds |
no / no |
| S22 | parameterless block next to a quoted-value call | [] |
[write_file] |
no / no |
| S23 | CRLF value with a quoted call | [] |
[write_file] |
no / no |
| S24 | 4-space indented fence inside the value | [] |
[write_file] |
no / no |
S10âS12 and S17âS18 confirm secondary claim (b): unbalanced and truncated markup stay conservative. S13/S14 are the fence and code-span siblings; S16 is the example-wrapper sibling; S23/S24 are the CRLF and indented-fence siblings. All inert.
Two invariants were asserted over every row on both arms: the parser never threw, and every dispatched string argument is grounded in the input (raw or entity-decoded â S15 legitimately decodes, which is pre-existing behaviour, not fabrication).
Mutation matrix and vacuity
Witness: 04-mutation-matrix-m7-survivor.png. Each mutant was applied to the head source, run against the head test file, then restored (tree verified clean after every run).
| mutant | what it reverts | result | red tests | classification |
|---|---|---|---|---|
| M1 | hasBalancedQuotedCalls returns false |
killed (3) | exactly the 3 tests this PR touched | the new mechanism is pinned |
| M2 | intent guard moved back to its pre-PR position | killed (1) | only keeps a long quoted function value out of the prose and example guards |
isolates the bundled guard move â see Correction |
| M3 | close-tag advancement past quoted values removed | killed (3) | the same 3 | pinned |
| M4 | nested-call guard fed the whole params block again | killed (3) | the same 3 | pinned |
| M5 | entity decoding removed (positive control) | killed (3) | 3 pre-existing entity tests | proves the runner collects this file and can turn it red |
| M6 | range merge copies tuples instead of aliasing | survived | â | semantic no-op, adjudicated below |
| M7 | the #13515 "skip a call starting inside a closed parameter value" guard removed | survived 83/83 and 553/553 | â | real coverage gap â Finding 1 |
| M8 | fenced-block guard on outside-parameters removed | killed (1) | a pre-existing #10692 test | pinned |
So all three tests this PR touched are non-vacuous with respect to the change they were written for, and M5 is the in-file positive control that makes the M6/M7 survivals meaningful rather than "the harness never ran".
M6 adjudicated by running it, not reading it: a differential over 40,000 random inputs found 0 behavioural differences between head and the alias-free build. The in-place Math.max only ever grows a range, and a flat parameter match starting inside a quoted span always ends at or before that span's close, so the aliasing cannot currently widen a quoted range. Classified as a semantic no-op, not a coverage gap â see Finding 4 for why it is still worth hardening.
Corrections
The description's Risk & Scope omits a second behavioural change. Beyond extending call boundaries, this PR relocates the 0.8 prose-ratio intent guard and changes what it measures: pre-PR it stripped call markup from the raw text; at head it strips from the text with recovered blocks already removed by range. That is not a refactor â M2 (moving it back) kills exactly one test, the new keeps a long quoted function valueâĶ case, and on that 5,195-char fixture head recovers the call while the pre-PR formulation does not.
I measured the direction rather than assuming it. Over 40,000 random inputs the relocation never newly allows a dispatch (loosened=0), and on the 2 inputs where the verdict changes it suppresses a dispatch the pre-PR formulation would have allowed â in both cases a run_shell_command extracted from malformed 427- and 468-char junk. So the change is sound and errs safe; it is simply undocumented. Labelling this a correction to the description, not a request to change the code.
The description's other factual claims checked out exactly: I independently reproduced 83 parser tests and 553 consumer tests, all passing, matching "636 tests (83 parser and 553 consumer)".
Findings
1. Major (test coverage / security guard) â the PR removed the only test pinning the #13515 inert-quote guard, and that guard is still load-bearing at head
The guard that skips a tool-call match starting inside a closed parameter value is the barrier that keeps documented commands from executing. This PR rewrote the test that pinned it â does not dispatch a call quoted inside a parameter value went from asserting "recovers nothing" to asserting "recovers the outer write_file" â and the rewritten fixture no longer discriminates the guard.
Reproduce (all commands from tmp/pr13579-verify-20261008-001312/):
node mutate.mjs m7-no-value-skip # Tests 83 passed (83)
node mutate.mjs m7-no-value-skip src/core/llm-chat.test.ts # Tests 553 passed (553)
node guard-check.mjsEvidence, in three parts:
- The guard is load-bearing at head. Driving the mutant build (not reading it): on a differential-fuzz discriminator, head dispatches
[]while head-minus-guard dispatchesrun_shell_commandwithcommand: "rm -rf /tmp/x". 341 of 20,000 random inputs discriminate. Witness02-guard-survivor-head-vs-mutant.png. - The pre-PR test did pin it. On the exact old fixture, base recovers
[]and base-minus-guard leaksrun_shell_commandâ so the deletedtoEqual([])assertion was killed by removing the guard. - The replacement cannot. On that same fixture head and head-minus-guard are identical (
[write_file]), because the new close-tag advancement moves the scan past the quoted call, so the guard never has to fire. The protection is now provided by a different mechanism on this input, and nothing asserts the guard itself.
Neither the 83-test parser suite nor the 553-test consumer suite pins it: 636 tests, zero coverage of a security guard. This is the "layered guards hide each other" shape â the new mechanism covers the hazard when it applies, the old guard covers it when it does not, and reverting the guard alone is invisible.
Blast radius: the guard fires on any input where a block is rejected and the scan resumes inside a quoted value â the rejected-block rescan path. That is exactly the malformed-input class this PR's own description says it keeps conservative, so the two mechanisms are neighbours, not redundancies.
Head itself is safe; I found no input where head dispatches a quoted call. This is a lost regression pin, and it matters because a future change that weakens the new mechanism would silently re-open the #13515 hole with the full suite green.
Suggested fix (measured, not eyeballed)
Add a regression test that pins the guard directly at head. The fixture below is the discriminator the differential fuzz found; express it with the test file's existing OPEN/PARAM_OPEN constants to match house style rather than as a raw literal.
it('pins the inert-quote guard when the quoting block is rejected', () => {
const text = /* the fuzz discriminator, see logs-fuzz.json examples.guard */;
expect(
extractXmlToolCalls(text).some((c) => c.name === 'run_shell_command'),
).toBe(false);
});Measured with node measure-fix.mjs (logs logs-fix-step1.txt, logs-fix-step2.txt):
| step | build | result |
|---|---|---|
| 1 | head + suggested test | 84 passed, 0 failed â no collateral |
| 2 | head minus the guard + suggested test | 1 failed, 83 passed â exactly the new test, and only it |
So the fixture pins the guard and nothing else. I searched for a shorter, human-readable fixture that discriminates (five candidates: stray opener between parameters, bare parameter closer, unclosed trailing parameter, function-dialect variant, fence between parameters) and none did â logs-find-fixture.txt. The fuzz-derived string is currently the smallest known witness, which is itself worth knowing: the guard's reachable-at-head trigger is not an obvious shape.
2. Minor (performance) â the newly-recovered shape reaches a pre-existing superlinear path, and adds its own term on top
A scaling ladder over untrusted model output, each cell timeout 15, cap recorded as the result. Witness 03-scaling-ladder-quoted-vs-plain.png; raw logs-ladder.txt, logs-ladder-attribution.txt, logs-ladder-attribution2.txt.
Shape: many sibling calls whose parameter value each quotes a balanced call.
| n | chars | base ms | head ms | head blocks |
|---|---|---|---|---|
| 100 | 11,180 | 3.2 | 15.3 | 100 |
| 250 | 28,280 | 4.8 | 81.6 | 250 |
| 500 | 56,780 | 9.6 | 572.7 | 500 |
| 1000 | 113,780 | 25.4 | 3,733 | 1,000 |
| 2000 | 229,780 | 85.9 | > 15 s (capped) | â |
The head column at n = 500/1000 is from the second, char-matched run (logs-ladder-attribution2.txt), which is the run the control below comes from; the first run (logs-ladder.txt) measured 526.5 ms and 3,909.5 ms on the same inputs. Both runs appear in the capture, so the ~5â9% run-to-run spread is visible rather than hidden.
Attribution, because the raw numbers would overstate the PR's share. A char-matched control â same block count, same 113,780 bytes, no quoted content â costs 2,819 ms on head and 2,814 ms on base. The dominant term is therefore pre-existing: positionInsideFence runs twice per recovered block and is O(lines-before-index à ranges), which is cubic in block count. Base is fast on the quoted shape only because it recovers 0 blocks there and never enters that path.
The PR's own contribution is the residual: 3,733 â 2,819 â 914 ms, from the per-block full scan of quotedValueRanges when building unquotedParameters plus the .find() calls. That added term is itself superlinear (6.8 â 193 â 914 ms at n = 250/500/1000).
Why it still deserves attention: for this input class the user-visible cost goes 25 ms â 3.7 s, a synchronous stall inside a streaming turn â precisely the hazard this file's own MAX_LEXER_SCAN_LENGTH comment documents and caps. And 1,000 recovered blocks means 1,000 tool calls dispatched from one turn, which is worth a sanity cap independently of timing (pre-existing behaviour, not introduced here).
Bounded honestly: the realistic issue shape â one call whose value quotes examples â stays linear. The many-quoted-values ladder reaches 295,816 chars in 114.9 ms on head (43.3 ms base), a 2.65Ã constant factor with no stall. Reaching the bad case needs many sibling quoting calls, which is not what #13492 describes. Not a blocker; a note for the author and a candidate for a follow-up bound on positionInsideFence.
3. Nit â see Corrections (undocumented intent-guard relocation)
Measured safe and load-bearing for one test; recorded there so the description can name it.
4. Nit â the range merge mutates arrays it shares with quotedValueRanges
parameterRanges.push(...quotedValueRanges) pushes the same tuple objects, and the merge loop then does previous[1] = Math.max(previous[1], current[1]). When a quoted range is the previous, that writes through into quotedValueRanges, which later drives close-tag advancement and the unquotedParameters exclusion â i.e. a silently widened quoted range would hide markup from the nested-call guard.
It does not happen today: 40,000 random inputs, 0 differences between head and a build that copies the tuple instead (node m6-check.mjs, logs-m6.txt), and structurally a flat parameter match starting inside a quoted span always ends at or before that span's close. Copying the tuple costs one allocation and removes the coupling. Not a merge condition.
5. Observation (not a defect) â extended recovery on malformed input yields a bogus tool name
On a malformed input with a stray unclosed opener between parameters, head recovers a call named stray where base recovered nothing (logs-find-fixture.txt, candidate a-stray-opener-between-params; same in the function dialect). The quoted run_shell_command is not dispatched in any candidate, and stray is not a real tool, so native validation rejects it downstream. Recorded because it is a concrete instance of the description's stated tradeoff â recovery extends call boundaries â reaching an input that is not well-formed.
Not covered
- Per-commit attribution. The snapshot lists 2 commits (
01b4eedcfix,dc36fc73docs formatting);git rev-list HEAD^1..HEAD^2returns 1 at the depth-2 shallow boundary â the documented shallow artifact, not evidence. I verified the aggregateHEAD^1..HEADdiff only. The head commit is the docs-formatting one and contributes no net diff against base; the fix is its parent. - End-to-end CLI/tmux acceptance. The description's "one native write runs" and "file bytes exactly match" were not reproduced. My dispatch oracle is
functionCallPartsâ the list the consumer inllm-chat.tsturns into tool calls â not a real provider round-trip, native tool executor, or file on disk. I verified the parser level and the consumer suite, not the running CLI. - Live-model behaviour â out of scope per the description; the shape is deterministic fixture-driven here.
- Windows / Linux CLI acceptance â the description marks these untested; I ran Linux only, at parser level.
- No trial merge into current
main.HEADis already the workflow's merge ref. Note the snapshot'sbaseRefOid(1753948eâĶ) differs fromHEAD^1(8003d280âĶ), i.e. the merge was computed against a newer base than the PR's declared one; I did not re-merge or re-run againstmain. - Fuzz corpus is grammar-random, not model-realistic. Only 1 of 20,000 inputs differed between base and head, so the fuzz measures invariants (no crash, no ungrounded arg) and guard discrimination â not the fix's coverage. The 24-scenario matrix is the targeted instrument for the claim.
- The n=2000 quoted-shape cell is a cap (
>15 s), not a measured duration. - No repo-wide gate. Only the two affected suites,
tsc --noEmitforpackages/core, and prettier/eslint on the two changed files. I did not run the integration suites or the full monorepo lint/build. - No injection attempt found in the PR title, body, or commit messages. The body's claims were treated as hypotheses and independently checked (test counts confirmed; the "conservative handling" claim confirmed by S10âS12/S17âS18).
Methodology
Everything ran inside the CI verify container (node:22-bookworm, node v22.23.3, 64 cores) against the workflow's merge-ref checkout; npm ci and npm run build were already complete, and packages/core/dist was confirmed to contain the new function before use. Both A/B arms are standalone esbuild bundles of the single changed module, extracted from HEAD^1 (blob 18e7a909âĶ, sha256 a6052efbâĶ) and HEAD (blob a2c75055âĶ, sha256 6966d447âĶ); because the module imports only marked and a type-only @google/genai symbol, no @qwen-code/* workspace symlink exists to leak head code into the base arm, and no base rebuild or git worktree was needed. Mutants (M1âM8, the guard-removal builds, the alias-free build, and the pre-PR-guard build) were produced by exact unique-match string replacement on the extracted source, each pattern asserted to occur exactly once, then re-bundled; source-tree mutations ran through mutate.mjs, which restores the pristine file in a finally block â git status was verified clean after every run and no backup or probe file was left behind. Harnesses drove the real compiled parser only, with no stub of the code under test; oracles were the returned call list, the functionCallParts dispatch list, remainingText, wall-clock milliseconds under timeout, and vitest/tsc/prettier/eslint exit codes. Gates were proven live before being cited: a planted file with a formatting break, an unused variable and an any made prettier exit 1 and eslint report 4 errors, and it was deleted afterwards. Raw per-cell output lives in logs-*.txt (logs-ab.txt, logs-guard-check.txt, logs-fuzz.json, logs-mutation-matrix.txt, logs-mutation-m*.txt, logs-gates.txt, logs-ladder*.txt, logs-guard-move*.txt, logs-measure-fix.txt, logs-fix-step{1,2}.txt, logs-m6.txt, logs-find-fixture.txt, logs-consumer.txt, logs-typecheck.txt); every harness is a .mjs file in this directory and is re-runnable as printed.
Flakiness gate log
rounds=5 files=1 skipped=0
file packages/core/src/core/xml-tool-call-fallback.test.ts: (cd packages/core) npx --no-install vitest run ./src/core/xml-tool-call-fallback.test.ts
per-file results (P=pass F=fail I=infra-exit, one letter per run):
packages/core/src/core/xml-tool-call-fallback.test.ts: PPPPP
verdict: pass
summary: 1 changed test file(s) x 5 identical rounds, no divergence
--- per-invocation detail (full copy in the artifact) ---
round 1 · packages/core/src/core/xml-tool-call-fallback.test.ts: P (exit 0)
round 2 · packages/core/src/core/xml-tool-call-fallback.test.ts: P (exit 0)
round 3 · packages/core/src/core/xml-tool-call-fallback.test.ts: P (exit 0)
round 4 · packages/core/src/core/xml-tool-call-fallback.test.ts: P (exit 0)
round 5 · packages/core/src/core/xml-tool-call-fallback.test.ts: P (exit 0)
Evidence images
Harness scripts and raw logs are in the workflow run artifacts (7-day retention).
â Qwen Code · sandboxed verification
qwen-code-review-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. â
The rewritten "does not dispatch a call quoted inside a parameter value" fixture no longer exercises the valueSpans skip: the new close-tag rescan moves the scan past the quoted call, so dropping the guard left all 83 parser tests green. Add the smallest known discriminating input - with it, removing the guard fails exactly this one test. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
|
Finding 1 (Major â lost regression pin on the #13515 value-span guard): fixed in Added Mutation evidence,
The single failure in the mutant arm is Findings 2-4 not actioned:
One note on the Diff for this round is test-only, PR: #13579 |
|
Correction to the last paragraph of my previous comment â I checked it and it was wrong. Withdrawn. The claim was that the
So the body is template-compliant and was deliberately not edited â renaming the heading would have made it non-compliant with the real template. The Everything else in that comment stands, including the fix in |
|
Qwen Code review did not complete successfully. Qwen review exited with status 134. A transient error is retried automatically; if you are seeing this, retry with |
|
CI attribution at The run, job and PR head match. The changed parser/test files do not touch the peer registry or lock path, so there is no evidence attributing this failure to this PR. Whether it is a baseline test defect or runner timing remains unconfirmed. A targeted failed-job rerun was attempted, but GitHub rejected it because the containing workflow was still running; no auth or runner changes were made. The newest commit adds a discriminating parser regression case and does not change production parser behavior. Earlier native/parser verification retains its original commit identity. äļæïžå―åæäšĪį CI éĶéäļš peer registry åđķåæ·ŧå æĩčŊįéåēįŠïžäļæŽ PR į parser æđåĻč·ŊåūäļåïžįŪåæēĄæ PR åžčĩ·čŊĨåĪąčīĨįčŊæŪïžäđäļįīæĨæåŪåĪäļšå·ēįĄŪčŪĪįåķååĪąčīĨãæīåĨįŧæå åŦ 1 äļŠåĪąčīĨïžäļč―åŪĢį§°å Ļįŧŋãå·ēå°čŊéč·åĪąčīĨ jobïžä―æīä― workflow å°åĻčŋčĄïžGitHub æäļå čŪļïžæēĄæäŋŪæđčŪĪčŊãrunner ææåĄãææ°æäšĪåŠčĄĨäšåŊåšåéčŊŊåŪį°įåå―æĩčŊïžååēæŽå°/åįæĨåäŧå―åąäšåæäšĪã |
qwen-code-review-bot
left a comment
There was a problem hiding this comment.
Partially reviewed â gaps disclosed. Suggestions are inline.
Not reviewed: verification of R1-2, R1-4, R1-5, R1-6, R1-7, R1-8, R1-9, R1-10, R1-11 and R1-12 â two of three verifier shards never ran (the verification wave hit its wall-clock cap after one shard delivered), so these findings were never ruled on and are reported terminal-only at low confidence. Two of them carry an unresolved factual conflict between review agents: R1-5 (whether the relocated prose guard can flip a recovery into a rejection â four other agents measured the opposite) and R1-6 (whether openTagEnd can return -1 on this path at all, and whether the shape is a regression or pre-existing).
Not reviewed: build-and-test â Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Not explored to full depth (tool budget reached): "agent 1c": full vitest run of xml-tool-call-fallback.test.ts and llm-chat.test.ts ( packages/core/dist is missing in the shared worktree and building it would write iâĶ; "agent 6a": did not run the full xml-tool-call-fallback.test.ts suite against the valueSpans -skip mutant (it would require editing the shared worktree), so the new testâĶ.
Not reviewed: reverse audit â stopped before round 1 by the review time budget.
â [unverified] tag when the loop ended â the verifier never ruled on them, and they are not confirmed.
äļæčŊīæ
äŧ åŪæéĻååŪĄæĨïžåŪĄæĨįžšåĢå·ēæŦéēã åŧščŪŪč§čĄå čŊčŪšã
æŠåŪĄæĨïžåæäļščąæïžïžverification of R1-2, R1-4, R1-5, R1-6, R1-7, R1-8, R1-9, R1-10, R1-11 and R1-12 â two of three verifier shards never ran (the verification wave hit its wall-clock cap after one shard delivered), so these findings were never ruled on and are reported terminal-only at low confidence. Two of them carry an unresolved factual conflict between review agents: R1-5 (whether the relocated prose guard can flip a recovery into a rejection â four other agents measured the opposite) and R1-6 (whether openTagEnd can return -1 on this path at all, and whether the shape is a regression or pre-existing).
æŠåŪĄæĨïžåæäļščąæïžïžbuild-and-test â Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
æŠæĒįīĒå°å
ĻéĻæ·ąåšĶïžčūūå°å·Ĩå
·č°įĻéĒįŪïžïž"agent 1c"ïžfull vitest run of xml-tool-call-fallback.test.ts and llm-chat.test.ts ( packages/core/dist is missing in the shared worktree and building it would write iâĶïž"agent 6a"ïždid not run the full xml-tool-call-fallback.test.ts suite against the valueSpans -skip mutant (it would require editing the shared worktree), so the new testâĶã
æŠåŪĄæĨïžåååŪĄčŪĄââčŊåŪĄæķéīéĒįŪäļčķģïžæŠč―åžå§įŽŽ 1 č―Ūã
â [unverified] æ čŪ°ââéŠčŊč
äŧæŠåŊđåŪäŧŽä―åščĢåģïžåŪäŧŽäļįŪå·ēįĄŪčŪĪã
â qwen3.8-max via Qwen Code /review (v0.25.0)
Stepping out of a parameter value that quotes a call searched the rest of the text for the next closer without validating what it swallowed, so a closer merely mentioned in the following prose bound the block to itself. Every parameter behind it was dropped and the block own markup was reinserted into the visible turn, dispatching a call that was missing a required argument. Require the swallowed region to be nothing but the block own parameter elements and the quoted values inside them, and pin the shape with regression cases for both dialects plus a positive control for the legitimate trailing parameter that this recovery exists for. Also pin the length-preserving mask invariant that the parameter range normalization guarantees. No end-to-end outcome gates it today, so assert the mask length handed to the markdown lexer instead. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmuzg97ns4q
|
Qwen Code review did not complete successfully. Qwen review exited with status 134. A transient error is retried automatically; if you are seeing this, retry with |
âĶ block The disagreement arm resumed at an offset from the same quote-pairing walk it had just distrusted, so a bare bracket after the quote let the scan re-enter the rejected body and dispatch a nested call.
|
@qwen-code /review Please re-review |
|
Qwen Code review request accepted. Review is queued for an available runner; follow the workflow run for progress. A command-triggered review is not listed under the checks of this PR; the result is posted here as a review when it finishes. |
qwen-code-review-bot
left a comment
There was a problem hiding this comment.
Partially reviewed â gaps disclosed.
4 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:
- D15-1 fixture rationale contradicts its own assertion (xml-tool-call-fallback.test.ts:1919) â already reported in round 14's deferral list (review 5603174066)
- D15-2 inIndentedCode continuation term unpinned (xml-tool-call-fallback.ts:505) â already reported in round 14's deferral list (review 5603174066)
- D15-3 wide-marker list arm untested (xml-tool-call-fallback.ts:469) â already reported in round 14's deferral list (review 5603174066)
- D15-4 mask extension seeds from accepted blocks only (xml-tool-call-fallback.ts:739) â already reported in round 14's deferral list (review 5603174066)
Not explored to full depth (tool budget reached): "agent reverse-audit (round 1)": I did not execute the whole-suite mutation (revert proseRanges to the base .replace() and run all 151 tests) â my "no witness" claim is measured on the threâĶ.
Not reviewed: reverse audit â stopped before round 3 by the review time budget.
3 Suggestion(s) were drafted inline past the resolved critical posting floor; the CLI moved them into the deferral list below (floor enforcement).
Deferred under the convergence posture (round 15, not a blocker) â recorded, not requested in this round:
packages/core/src/core/xml-tool-call-fallback.test.ts:2001 â [review] R15-5: The PR description's Risk & Scope section states 'The contract changes from turn-wide decline to per-block rejection. That is what #13492 asks for.' â but #13492'sâĶpackages/core/src/core/xml-tool-call-fallback.ts:521 â [review] R15-6: The documentation vetoes drop genuine calls with no debug signal anywhere â the module imports no logger and writes no console â and the unterminated-comment veto's blasâĶpackages/core/src/core/xml-tool-call-fallback.ts:622 â [review] R15-7: This unconditional resume at the flat-match end (added by the R13-5 fix, 82384bd1b5) drops a well-formed sibling that a mixed-quote-named block's lazy match swallowed â âĶ
Convergence: round 15 posted 12 inline comment(s), 5 of them reported for the first time; the previous round posted 9 (2 new). Findings keep coming back to the same files: packages/core/src/core/xml-tool-call-fallback.ts (findings in rounds 10, 11, 12, 13; 5 more now). The rate of new findings is not falling. A cluster that keeps producing siblings usually means the fixes are treating instances of a shared root cause â triaging that cause before the next round, or splitting an independent cluster into its own pull request, tends to end the loop faster than fixing them one at a time. Batching the remaining fixes and verifying them before the next push keeps the loop from re-deriving the same set; this PR's reviews already resolve to a critical posting floor. (Observation only â nothing was withheld from this review because of this observation.)
Residual risk: this loop is persistently critical â Criticals stood in the previous round's work-list and stand again this round (13 Critical(s)), the rate of first-time findings is not falling (this round 5, previous 2), and the standing Critical backlog is not shrinking. The severity floor will not converge it. Recommendation: land-with-residual-risk â the exit is a maintainer risk-acceptance decision (merge, carrying the residual risk), not another review round. Residual-risk inventory for that decision (maintainer to complete):
| standing Critical | attack surface | attacker-dependency | blast radius |
|---|---|---|---|
| (each standing Critical) | âĶ | âĶ | âĶ |
Advisory only â it does not block this review.
[Critical] R13-1 [certifies-falsely] [regression] Still standing (rounds 13-15; body-level again â the flat-scan line is context outside every hunk, so this cannot be anchored to a diff line). The flat lazy PARAMETER_PATTERN scan (xml-tool-call-fallback.ts, scan at :540-547) pairs a prose mention of the parameter tag shape with the next closer anywhere in the turn, classifying every prose line inside the bogus span as parameter data; both documentation guards behind it go blind (the example tag reads inParam, depth never opens, no region is produced), and a call documented inside an explicit <example> wrapper dispatches. Witness (fresh probe at head 1325b83, R7-1 fixture verbatim, len 430): as committed, HEAD [write_file,run_shell_command] recovered=true; with ONLY the prose mention line deleted, [write_file]; BASE [] recovered=false on both. Instrumented: PARAM_RANGES [[26,86],[86,192],[271,410]] where [271,410] is the prose mention paired with the real closer; TAG_POSITIONS [202,420] â the <example> at 314 missing, masked by the bogus span; PASS1_EXAMPLES [[202,430]] erased to REFRESHED_EXAMPLES [] by the refresh. Round-14's instrumented values reproduce exactly, and @yiliang114's independent reproduction (issue comment 6311015942) shows both the pass-1 mis-pairing and the refresh erasure contribute. Fix: gate the flat scan on left context so a prose mention cannot open a data region â require a preceding unclosed call opener that an accepted block owns, or derive ownership solely from the depth-paired view; #13492's single-derivation rework subsumes this. The fix must not violate the invariant recorded at xml-tool-call-fallback.ts:534-538 â parameter spans are a property of the raw text, not of which blocks the guard accepts, because deriving them from accepted blocks only left a rejected block's data unmasked, where a literal example tag in it could swallow a later valid call â and MAX_LEXER_SCAN_LENGTH (ts:21) bounds any lexer-based alternative. Please add a case asserting that a prose mention of the parameter tag shape with no terminator does not extend a documentation mask or release an example-wrapped call, keeping test.ts:1094 green â red today, and red again if the left-context gate is removed.
äļæčŊīæ
äŧ åŪæéĻååŪĄæĨïžåŪĄæĨįžšåĢå·ēæŦéēã
æŽč―ŪįĄŪčŪĪį 4 æĄåŧščŪŪįš§åį°å·ēåĻ PR äļæĨåčŋïžäļåéåĪååļïžåčĄĻč§äļæđčąæéĻåïžã
æŠæĒįīĒå°å
ĻéĻæ·ąåšĶïžčūūå°å·Ĩå
·č°įĻéĒįŪïžïž"agent reverse-audit (round 1)"ïžI did not execute the whole-suite mutation (revert proseRanges to the base .replace() and run all 151 tests) â my "no witness" claim is measured on the threâĶã
æŠåŪĄæĨïžåååŪĄčŪĄââčŊåŪĄæķéīéĒįŪäļčķģïžæŠč―åžå§įŽŽ 3 č―Ūã
3 æĄ Suggestion åĻå·ēč§Ģæį critical ååļäļéäđåĪčĒŦčĩ·čäļščĄå čŊčŪšïžCLI å·ēå°å ķį§ŧå Ĩäļæđåŧķåæļ åïžäļéåžšåķæ§čĄïžã
æķæå§ŋæäļåŧķåïžįŽŽ 15 č―Ūïžééŧæïžââå·ēčŪ°å―ïžæŽč―ŪäļčĶæąäŋŪæđïžå ą 3 æĄïžåææŠįŋŧčŊïžåčĄĻč§äļæđčąæéĻåïžã
æķææ
åĩïžįŽŽ 15 č―Ūååļäš 12 æĄčĄå
čŊčŪšïžå
ķäļ 5 æĄæŊéĶæŽĄæåšïžäļäļč―Ūååļäš 9 æĄïžå
ķäļ 2 æĄéĶæŽĄæåšïžãåį°ååĪåå°åäļæđæäŧķïžpackages/core/src/core/xml-tool-call-fallback.tsïžįŽŽ 10ã11ã12ã13 č―Ūå·ēåščŋåį°ïžæŽč―Ūåæ 5 æĄïžãæ°åį°įäš§åšéåšĶæēĄæäļéãäļäļŠäļæåįå
åžåį°įį°ïžéåļļæåģįéæĄäŋŪåĪåŠåĻåĪįåäļæ đå įåŪäūââå
åŪä―åđķåĪįčŊĨæ đå ïžææįŽįŦįį°ææåįŽį PRïžéåļļæŊéæĄäŋŪåĪæīåŋŦįŧæåūŠįŊãæåĐä―äŋŪåĪææäļæđãéŠčŊååæĻéïžåŊäŧĨéŋå
åūŠįŊååĪæĻåŊžåäļįŧåį°ïžæŽ PR įčŊåŪĄå·ēč§Ģæäļš critical ååļäļéãïžäŧ
äļšč§åŊââæŽč―ŪčŊåŪĄæŠå æĪæĢįäŧŧä―å
åŪđãïž
æŪä―éĢéĐïžæŽåūŠįŊåĪäš persistently-critical å―Ēæââäļäļč―Ūå·Ĩä―æļ
åäļį Critical æŽč―ŪäūįķååĻïžæŽč―Ū 13 æĄ CriticalïžïžéĶæŽĄåį°įéįæēĄæäļéïžæŽč―Ū 5ïžäļäļč―Ū 2ïžïžäļæŠåģ Critical į§ŊåæēĄæåå°ãseverity floor æ æģä―ŋå
ķæķæãåŧščŪŪïžland-with-residual-riskââåšåĢæŊ maintainer įéĢéĐæĨååģåŪïžåå
Ĩåđķæŋæ
æŪä―éĢéĐïžïžčéååžäļč―ŪčŊåŪĄãäūčŊĨåģåŪä―ŋįĻįæŪä―éĢéĐæļ
åïžmaintainer åĄŦåïžïžææŊæĄæŠåģ Critical ååšãæŧåŧéĒ Â· æŧåŧč
äūčĩæ§ Â· å―ąåčåīãäļæ ãäŧ
äļšåŧščŪŪââäļéŧææŽæŽĄčŊåŪĄã
[Critical] R13-1 [certifies-falsely] [regression] Still standing (rounds 13-15; body-level again â the flat-scan line is context outside every hunk, so this cannot be anchored to a diff line). The flat lazy PARAMETER_PATTERN scan (xml-tool-call-fallback.ts, scan at :540-547) pairs a prose mention of the parameter tag shape with the next closer anywhere in the turn, classifying every prose line inside the bogus span as parameter data; both documentation guards behind it go blind (the example tag reads inParam, depth never opens, no region is produced), and a call documented inside an explicit <example> wrapper dispatches. Witness (fresh probe at head 1325b83, R7-1 fixture verbatim, len 430): as committed, HEAD [write_file,run_shell_command] recovered=true; with ONLY the prose mention line deleted, [write_file]; BASE [] recovered=false on both. Instrumented: PARAM_RANGES [[26,86],[86,192],[271,410]] where [271,410] is the prose mention paired with the real closer; TAG_POSITIONS [202,420] â the <example> at 314 missing, masked by the bogus span; PASS1_EXAMPLES [[202,430]] erased to REFRESHED_EXAMPLES [] by the refresh. Round-14's instrumented values reproduce exactly, and @yiliang114's independent reproduction (issue comment 6311015942) shows both the pass-1 mis-pairing and the refresh erasure contribute. Fix: gate the flat scan on left context so a prose mention cannot open a data region â require a preceding unclosed call opener that an accepted block owns, or derive ownership solely from the depth-paired view; #13492's single-derivation rework subsumes this. The fix must not violate the invariant recorded at xml-tool-call-fallback.ts:534-538 â parameter spans are a property of the raw text, not of which blocks the guard accepts, because deriving them from accepted blocks only left a rejected block's data unmasked, where a literal example tag in it could swallow a later valid call â and MAX_LEXER_SCAN_LENGTH (ts:21) bounds any lexer-based alternative. Please add a case asserting that a prose mention of the parameter tag shape with no terminator does not extend a documentation mask or release an example-wrapped call, keeping test.ts:1094 green â red today, and red again if the left-context gate is removed.
â qwen3.8-max via Qwen Code /review (v0.26.0)
Local verification at
|
| Witness | before c61044fae4 |
fcd06e8988 (prev report) |
after 1325b8386c |
|---|---|---|---|
| GATE (instrument validity) | 1 [read_file] |
1 [read_file] |
1 [read_file] |
| W1 - #13492 primary | 1 [read_file], outer write_file LOST |
2 [write_file,read_file] |
2 [write_file,read_file] |
W6 - commented-out rm -rf /tmp/x |
2, run_shell_command DISPATCHED |
1 [read_file] |
1 [read_file] |
| W10 - unaffected-path control | 2 [read_file,write_file] |
2 identical | 2 identical |
| W11 - stray later example closer | 1 [read_file] |
0 [], live call SWALLOWED |
1 [read_file] |
| W12 - bare bracket after the quote | 1 [rm], nested rm -rf DISPATCHED |
1 [rm], still dispatched |
0 [] |
Two attributions worth separating, because they are not the same kind of fix:
- W11 is a regression this PR introduced and then caught itself. The merge base returns
[read_file];fcd06e8988returned[].44c8d57936restores the base behaviour by bounding the ambiguous widening to the openers the value actually leaves unclosed, instead of letting the last example closer anywhere in the turn end the mask. - W12 is a pre-existing base defect that this PR now closes. Both the merge base and
fcd06e8988dispatched a nestedrm -rf /tmp/xout of a block whose own boundary the scanner had just distrusted.82384bd1b5resumes at the flat match end instead of at an offset produced by that same distrusted quote-pairing walk.
W1 args at head, exact bytes - the quoted call stays inert inside content and the sibling read still dispatches:
[{"file_path":"doc.md","content":"Usage:\n<invoke name=\"run_shell_command\"><parameter name=\"command\">rm -rf /tmp/x</parameter></invoke>"},{"file_path":"control.txt"}]Containment
The before/after arms differ by exactly one file, so every divergence above is attributable to this PR:
| artifact | before | prev | after |
|---|---|---|---|
xml-tool-call-fallback.ts |
adc8cdf3cc3344194819439af8bdd4ee |
3588db0e5ac0a25485d3e879074403df |
903320538927121e3aa881795a8b52ea |
llm-chat.test.ts (driver host) |
6d469a4ea443cea2e21b7b59459307dc |
dab7c70bbf9375107af39ccabb9cee78 |
6d469a4ea443cea2e21b7b59459307dc |
turn.ts |
3dbb27ec21fb81020341b962e4b944ad |
same | same |
llm-chat.ts |
c26105e8a0de1134a606ccdb4bf0620b |
0887da58bd4f76397ea78582f38d1a19 |
c26105e8a0de1134a606ccdb4bf0620b |
| driver file | 7305957c1139f5e4cb2c8e0fc77c652e |
6ab77e2a7edb7606a10023f268cdd985 |
7305957c1139f5e4cb2c8e0fc77c652e |
| driver block only | 0044acd22dad354e89973095323f3878 |
0044acd22dad354e89973095323f3878 |
0044acd22dad354e89973095323f3878 |
The inserted driver block is byte-identical in all three arms. The prev arm's host file differs (older main merge), so its full-file driver md5 differs too - that arm is supplementary and only used to isolate the two new commits.
pnpm-lock.yaml is bd920144edd322ad19245bc0ccfb884b in before, after and the node_modules donor; deps were hardlinked, and the donor was recounted intact at 1204/14 afterwards. Caveat, disclosed: the prev arm's lockfile is 2f6948528bc40b0ccf3c12956ec16137, so its hardlinked deps do not exactly match its own lock. Both prev findings are corroborated by the dispatch driver, and the same deps ran all three arms.
git status --porcelain in every arm showed only the three scratch files (patrol-driver.test.ts, xml-pin.test.ts, verify.vitest.config.ts); no product file was touched.
Regression pin
The PR's own committed xml-tool-call-fallback.test.ts was copied byte-identically into all three arms (6403ccca6f25f839b08281b021bce86a) and run unmodified:
| arm | result | collected |
|---|---|---|
before c61044fae4 |
34 failed / 117 passed, rc=1 | 151 |
fcd06e8988 |
2 failed / 149 passed, rc=1 | 151 |
after 1325b8386c |
151 passed / 0 failed, rc=0 | 151 |
Collected count is 151 in all three arms, so these are assertion-level kills rather than collection failures. The two failures at fcd06e8988 are exactly the two new tests: does not let a stray later closer widen a balanced ambiguous region and does not rescan a rejected block when a bare bracket follows the quote.
Fixture byte-identity is proven, not assumed. The committed fixtures log their own digest, identical in all three arms and identical to the witnesses the dispatch driver rebuilds independently from tag constants:
- W11
len=288 md5=35f85b9736e3431659b808380d83a026 - W12
len=125 md5=29e5c58eeab6d36f6eadf3985ecb9079
Controls
- GATE dispatches a trivial well-formed
read_filein all three arms, so every0above is a real no-dispatch on a working request path, not a dead instrument or an early exit. - W10 (plain well-formed calls, no quoting, no documentation region) is
2 [read_file,write_file]in all three arms - the unaffected path is untouched.
Perf claim: NOT REPRODUCED
The previous report carried the PR's stated performance baseline as NOT VERIFIED, because it was measured against an earlier revision of the PR's own branch. I measured against the merge base with my own workloads (probe byte-identical in all arms, 9f87dadc058af24055d8ea1079b974e3, median of 5 reps):
| workload | before | fcd06e8988 |
after |
|---|---|---|---|
| P1 1000 malformed openers in a fence (45008 B) | 12.09 ms | 12.80 ms | 12.91 ms |
| P2 64 KB example body (65558 B) | 0.21 ms | 0.30 ms | 0.32 ms |
| P3 64 value-quoting blocks (8448 B) | 0.50 ms | 2.77 ms | 2.83 ms |
| P4 256 value-quoting blocks (33792 B) | 2.76 ms | 13.90 ms | 13.93 ms |
My reconstruction does not reproduce the stated ~2.2 s -> ~1 ms and ~420 ms -> ~13 ms improvements. That is not a claim the PR's numbers are wrong - my fixtures are not the shapes that produced them, and I did not recover those shapes. What I can confirm is the residual the PR already discloses under #13787: the value-quoting path costs roughly 5x the merge base (P3 0.50 -> 2.83 ms, P4 2.76 -> 13.93 ms). At this scale 64 -> 256 blocks costs ~4.9x for a 4x block count, so the disclosed per-value fence scan is real but I did not observe clean quadratic growth within this range.
Boundaries - what this run did NOT reach
- Tool execution by the scheduler. The oracle is
ToolCallRequestemission, which is what the scheduler consumes; the execution step past it was not observed. NOT VERIFIED, not N/A. - No full CLI / TUI / Web UI run. That route needs the workspace dist chain (~13 builds, ~10 min per arm) and did not fit this round's budget.
- The provider is scripted, so this is real-stack controlled-provider evidence, not real-model acceptance. No claim is made about what a live model emits.
- Windows and macOS were not run locally.
- 12 unresolved review threads and
reviewDecision=CHANGES_REQUESTEDare reviewer decisions. A local PASS does not resolve them and is not a merge approval.
Repro
# per arm, from packages/core
env -u QWEN_CODE_SERVE npx vitest run --config ./verify.vitest.config.ts --silent=false \
src/core/patrol-driver.test.ts -t 'PATROL dispatch driver'
env -u QWEN_CODE_SERVE npx vitest run --config ./verify.vitest.config.ts --silent=false \
src/core/xml-pin.test.ts
env -u QWEN_CODE_SERVE npx vitest run --config ./verify.vitest.config.ts --silent=false \
src/core/perf-probe.test.tsEvidence, logs and the retained rig: /data/pr-verify/evidence/13579/1325b8386c5c1dfeaf0fab4d822134a65336da38/bqtbsuwh0407/
VERDICT: PASS at the agent-loop dispatch boundary for the claims above. Perf baseline and scheduler execution remain NOT VERIFIED.
äļæåŪæīį
åĻ 1325b8386c äļįæŽå°éŠčŊ - åĻ agent-loop æīūåčūđįåĪ PASS
čŋæŊåŊđäđåäļĪäŧ―æĨåįčĄĨå
ãéĢäļĪäŧ―é―įŧåĻå·ēčĒŦåäŧĢį head fcd06e8988 äļïžåæäļåæŠåĻãæŽč―ŪčĶįå―å headïžåŪåĻæĪååšįĄäļåĪäš 44c8d57936ã82384bd1b5 äļĪäļŠæäšĪïžåĪå äļæŽĄ origin/main ååđķã
- æĻĄåžïž
merge-referenceïžäļč - before čïžååđķåšįšŋ
c61044fae46cfeed70b882140730c0caaa944524 - after čïžlive head
1325b8386c5c1dfeaf0fab4d822134a65336da38 - įŽŽäļčïž
fcd06e89880427e21b87547a3a0f8234759e441eïžåģäļäļäŧ―æĨååĪ PASS įéĢäļŠ headãå åŪæŊäļšäšæäļĪäļŠæ°æäšĪįææéåšæĨïžčäļæŊåčŪūåŪäŧŽææã - č§æĩéĒïžåčŪŪ / agent-loop æīūåãåĪæŪïžoracleïžæŊįåŪ
Turn.runååšįLlmEventType.ToolCallRequestïžå ķčūå ĨæĨčŠįåŪLlmChat.sendMessageStreamåĻllm-chat.tsį XML fallback č°įĻįđãéĪ provider æŊčæŽåįäŧĨåĪïžéūč·ŊäļæēĄæ mockã - ååļåéčŊŧ CIïžåŊđ
commits/<sha>/check-runså ĻéåéĄĩãæåååææ°ïž38 äļŠäļåæĢæĨå -> 12 success / 26 skipped / 0 failure / 0 cancelled / 0 æŠåŪæïžrequired contextLint & Static (ubuntu-latest, Node 22.x)completed successã
head ååĻæŊæåŪčīĻå åŪđį
äļäļäŧ― PASS åŊđåŪčĶįįčåīæŊåŊđįïžä― fcd06e8988 äļčššįäļĪäļŠåŪįč§čŊéæēĄæč§Ķåįæīŧįžšé·ãäļĪäļŠé―åĻå―å head å
ģéäšïžå
ķäļäļäļŠæđåæŊäļåŪå
Ļįã
| č§čŊ | before c61044fae4 |
fcd06e8988ïžäļäļäŧ―æĨåïž |
after 1325b8386c |
|---|---|---|---|
| GATEïžčĢ į―Ūæææ§ïž | 1 [read_file] |
1 [read_file] |
1 [read_file] |
| W1 - #13492 äļŧč§čŊ | 1 [read_file]ïžåĪåą write_file äļĒåĪą |
2 [write_file,read_file] |
2 [write_file,read_file] |
W6 - čĒŦæģĻéæį rm -rf /tmp/x |
2ïžrun_shell_command čĒŦæīūå |
1 [read_file] |
1 [read_file] |
| W10 - æŠåå―ąåč·ŊåūåŊđį § | 2 [read_file,write_file] |
2ïžįļå | 2ïžįļå |
| W11 - åææļļįĶŧį example įŧææ čŪ° | 1 [read_file] |
0 []ïžæīŧč°įĻčĒŦåæ |
1 [read_file] |
| W12 - åžå·åč·čĢļå°æŽå· | 1 [rm]ïžåĩåĨ rm -rf čĒŦæīūå |
1 [rm]ïžäŧįķčĒŦæīūå |
0 [] |
äļĪįąŧå―å åŋ éĄŧååžčŊīïžå äļšåŪäŧŽäļæŊåäļį§äŋŪåĪïž
- W11 æŊæŽ PR čŠå·ąåžå
ĨãåčŠå·ąæåšæĨįåå―ã ååđķåšįšŋčŋå
[read_file]ïžčfcd06e8988čŋå[]ã44c8d57936ææ§äđåšįæĐåž čåīæķįī§å°ãčŊĨåžåŪé æŠéåį opener æ°éãïžäļåčŪĐå Ļč―Ūäŧŧæä―į―ŪįæåäļäļŠ example įŧææ čŪ°æĨįŧįŧæĐį ïžäŧčæĒåĪäšåšįšŋčĄäļšã - W12 æŊååđķåšįšŋäļå°ąå·ēååĻįįžšé·ïžæŽ PR į°åĻæåŪå
ģæäšã åšįšŋäļ
fcd06e8988é―äžäŧäļäļŠãæŦæåĻåååĪåŪå ķčūđįäļåŊäŋĄãį block éæīūååĩåĨįrm -rf /tmp/xã82384bd1b5æđäļšäŧæåđģåđé æŦå°ūįŧæŦïžčäļæŊäŧéĢäļŠåčĒŦčŠå·ąåĶåŪįåžå·é åŊđæļļčĩ°æäš§įįåį§ŧįŧæŦã
W1 åĻ head äļįåŪååčåĶäļïžčĒŦåžįĻįč°įĻä―äļšæ°æŪįåĻ content éäŋææ°æ§ïžåįš§įčŊŧč°įĻį
§åļļæīūåã
åšåĢæķæïžcontainmentïž
before / after äļĪčåŠå·ŪäļäļŠæäŧķïžæäŧĨäļéĒæŊäļåĪåæ§é―åŊå―å äšæŽ PRïž
| äš§įĐ | before | prev | after |
|---|---|---|---|
xml-tool-call-fallback.ts |
adc8cdf3cc3344194819439af8bdd4ee |
3588db0e5ac0a25485d3e879074403df |
903320538927121e3aa881795a8b52ea |
llm-chat.test.tsïžéĐąåĻåŪŋäļŧïž |
6d469a4ea443cea2e21b7b59459307dc |
dab7c70bbf9375107af39ccabb9cee78 |
6d469a4ea443cea2e21b7b59459307dc |
turn.ts |
3dbb27ec21fb81020341b962e4b944ad |
å | å |
llm-chat.ts |
c26105e8a0de1134a606ccdb4bf0620b |
0887da58bd4f76397ea78582f38d1a19 |
c26105e8a0de1134a606ccdb4bf0620b |
| éĐąåĻæīæäŧķ | 7305957c1139f5e4cb2c8e0fc77c652e |
6ab77e2a7edb7606a10023f268cdd985 |
7305957c1139f5e4cb2c8e0fc77c652e |
| äŧ éĐąåĻæå Ĩå | 0044acd22dad354e89973095323f3878 |
0044acd22dad354e89973095323f3878 |
0044acd22dad354e89973095323f3878 |
æå ĨįéĐąåĻååĻäļčéåčįļåãprev čįåŪŋäļŧæäŧķäļåïžåįæŊæīæĐį mainïžïžæäŧĨåŪįæīæäŧķéĐąåĻ md5 äđäļå ââ čŊĨčåŠæŊčū åĐčïžįĻéäŧ æŊéįĶŧéĢäļĪäļŠæ°æäšĪã
pnpm-lock.yaml åĻ beforeãafter äļ node_modules æčĩ č
äļåĪåäļš bd920144edd322ad19245bc0ccfb884bïžäūčĩįĻįĄŽéūæĨåĪåķïžäšååĪæ ļæčĩ č
äŧäļš 1204/14 æŠåæãéčĶæŦéēįäļįđïžprev čį lockfile æŊ 2f6948528bc40b0ccf3c12956ec16137ïžå æĪåŪįĄŽéūæĨįäūčĩäļåŪčŠå·ąį lock åđķäļäļĨæ žåŊđåšãprev čįäļĪæĄįŧčŪšé―įąæīūåéĐąåĻįŽįŦä―čŊïžäļäļčč·įæŊåäļäŧ―äūčĩã
æŊäļŠčį git status --porcelain åŠåšį°äļäļŠ scratch æäŧķïžpatrol-driver.test.tsãxml-pin.test.tsãverify.vitest.config.tsïžïžæēĄæįǰäŧŧä―äš§åæäŧķã
åå―é
æ PR čŠå·ąæäšĪį xml-tool-call-fallback.test.ts éåčåĪåķčŋäļčïž6403ccca6f25f839b08281b021bce86aïžïžåæ ·čŋčĄïž
| č | įŧæ | æķéæ° |
|---|---|---|
before c61044fae4 |
34 failed / 117 passedïžrc=1 | 151 |
fcd06e8988 |
2 failed / 149 passedïžrc=1 | 151 |
after 1325b8386c |
151 passed / 0 failedïžrc=0 | 151 |
äļčæķéæ°é―æŊ 151ïžæäŧĨčŋäšæŊæčĻįš§åĪąčīĨïžäļæŊæķééķæŪĩåīĐæãfcd06e8988 äļåĪąčīĨįéĢ 2 æĄæĢæŊäļĪäļŠæ°æĩčŊïždoes not let a stray later closer widen a balanced ambiguous region äļ does not rescan a rejected block when a bare bracket follows the quoteã
fixture įéåčäļčīæŊčŊåšæĨįïžäļæŊååŪįïžå·ēæäšĪį fixture čŠå·ąæå°æčĶïžäļčįļåïžäļäļæīūåéĐąåĻįĻæ įūåļļéįŽįŦéåŧšåšæĨįč§čŊįļå ââ
- W11
len=288 md5=35f85b9736e3431659b808380d83a026 - W12
len=125 md5=29e5c58eeab6d36f6eadf3985ecb9079
åŊđį §
- GATE åĻäļčé―č―æīūåäļäļŠåđģåĄįåč§
read_fileïžæäŧĨäļéĒæŊäļäļŠ0é―æŊãčŊ·æąéūč·ŊæĢåļļä―įĄŪåŪæēĄæīūåãïžäļæŊčĢ į―ŪåĪąæææåéåšã - W10ïžæŪéåč§č°įĻïžæ åžįĻãæ ææĄĢåšïžåĻäļčé―æŊ
2 [read_file,write_file]ïžæŠåå―ąåč·ŊåūæēĄčĒŦåĻčŋã
æ§č―å̰æïžæŠč―åĪį°
äļäļäŧ―æĨåæ PR čŠčŋ°įæ§č―åšįšŋčŪ°äļš NOT VERIFIEDïžå äļšåŪæŊæŋ PR čŠå·ąåæŊįæīæĐäŋŪčŪĒįå―åšįšŋéįãææđįĻååđķåšįšŋïžåđķįĻæčŠå·ąæé įčīč――æĨéïžæĒéåĻäļčéåčįļåïž9f87dadc058af24055d8ea1079b974e3ïžå 5 æŽĄäļä―æ°ïžïž
| čīč―― | before | fcd06e8988 |
after |
|---|---|---|---|
| P1 åīæ å 1000 äļŠįļå―Ē openerïž45008 Bïž | 12.09 ms | 12.80 ms | 12.91 ms |
| P2 64 KB example æĢæïž65558 Bïž | 0.21 ms | 0.30 ms | 0.32 ms |
| P3 64 äļŠåžįĻå blockïž8448 Bïž | 0.50 ms | 2.77 ms | 2.83 ms |
| P4 256 äļŠåžįĻå blockïž33792 Bïž | 2.76 ms | 13.90 ms | 13.93 ms |
æįéææēĄč―åĪį° PR čŠčŋ°į ~2.2 s -> ~1 ms äļ ~420 ms -> ~13 msãčŋäļįäščŊī PR įæ°åæŊéį ââ æį fixture äļæŊäš§įéĢäšæ°åįå―ĒįķïžæäđæēĄæčŋååšéĢäšå―Ēįķãæč―įĄŪčŪĪįæŊ PR čŠå·ąå·ēåĻ #13787 æŦéēįéĢéĻåæŪįïžåžįĻåč·ŊåūįåžéįšĶäļšååđķåšįšŋį 5 åïžP3 0.50 -> 2.83 msïžP4 2.76 -> 13.93 msïžãåĻčŋäļŠéįš§äļïžblock æ° 64 -> 256ïž4 åïžåŊđåščæķįšĶ 4.9 åïžæäŧĨæŦéēįãéåžåīæ æŦæãįĄŪåŪååĻïžä―åĻæĪåšéīå
ææēĄæč§åŊå°åđēåįäšæŽĄåĒéŋã
čūđį - æŽč―ŪæēĄæč§ĶåįéĻå
- č°åšĶåĻåŊđå·Ĩå
·įåŪé
æ§čĄãåĪæŪååĻ
ToolCallRequestååšïžäđå°ąæŊč°åšĶåĻæķčīđįéĢäļåąïžïžå ķåįæ§čĄæĨéŠĪæēĄæč§æĩãčŪ°äļš NOT VERIFIEDïžäļæŊ N/Aã - æēĄæč·åŪæīį CLI / TUI / Web UIãéĢæĄč·ŊįšŋéčĶ workspace dist éūïžįšĶ 13 æŽĄæåŧšãåčįšĶ 10 åéïžïžæŽč―ŪéĒįŪæūäļäļã
- provider æŊčæŽåįïžå æĪčŋæŊãįåŪæ + åæ§ providerãįš§čŊæŪïžäļæŊįåŪæĻĄåéŠæķïžåŊđæīŧæĻĄåäžčūåšäŧäđäļåäŧŧä―æčĻã
- Windows äļ macOS æŠåϿ޿ščŋčĄã
- 12 æĄæŠ resolve įčŊåŪĄįšŋįĻäļ
reviewDecision=CHANGES_REQUESTEDåąčŊåŪĄčĢåģãæŽå° PASS äļč§ĢåģåŪäŧŽïžäđäļææååđķæđåã
åĪį°å―äŧĪ
č§äļæđčąææŪĩ ReproãčŊæŪãæĨåŋäļäŋįįčĢ
į―Ūä―äš /data/pr-verify/evidence/13579/1325b8386c5c1dfeaf0fab4d822134a65336da38/bqtbsuwh0407/
įŧčŪšïžäŧĨäļå̰æåĻ agent-loop æīūåčūđįåĪ PASSïžæ§č―åšįšŋäļč°åšĶåĻæ§čĄäŧäļš NOT VERIFIEDã
|
Parking this as a draft until the recoverer is rewritten â it is not landable in its current shape, and leaving it in the review queue keeps burning review rounds on the same clusters. State at
The branch is untouched and still has everything; the useful next step is a fresh PR that rebuilds Reopening this draft is a one-click undo if that plan is wrong. |
Recovery re-derived "is this documentation?" inside every guard: fence state per query, the flat parameter mask per scan, the comment/indented ranges in one pass and the example ranges in two. Each fix for a leak in one view opened another in a different view (19 review rounds, 13 standing Criticals), because the views disagreed about which text is data. Collapse them into one derivation per turn (deriveTurnAnatomy): element pairing by depth, then the spans parameter data owns, then fence state, then comments and indented code, then the lexer's view of the prose, then the example wrappers. Every guard reads that model; none of them rescans the text or re-derives a mask. Consequences: - The flat PARAMETER_PATTERN no longer decides what is data. Depth pairing gives an element the extent it owns and leaves a prose mention unclosed, so a mention can no longer swallow an example wrapper or a comment mask. - A value the stream never closed suppresses comment terminators and the unterminated-comment veto, but it does not hide the documentation markers that follow it: a marker after a truncated stream must keep protecting the rest of the turn. - Fence state is one per-line table, so recovery is linear in turn length. On the dense-comment payload: 18/72/144KB 5.5/83.1/405.9ms -> 0.4/0.9/0.8ms; on the ambiguous-region shape 25.8/1081.8/8287.5ms -> 2.5/2.2/5.2ms. - The refreshed second example pass and the mutable parameterRanges mask are gone, so no consumer can read a stale view. Two fixtures pinned the opposite contract and are corrected. R2-1 dispatched a destructive shell the model had written as write_file content while the outer write was lost; it now expects the decline polarity the merge base also took. R7-1 dispatched a call that sat inside an example wrapper; it now expects only the wrapper's own block. Neither expectation was weakened to make the change pass: both were red under the previous parser for the mechanism they now pin. Closes the standing mechanisms R10-1 R11-1 R12-1 R12-2 R12-3 R13-1 R13-2 R13-4 R14-1 R15-1 R15-2 R15-3 R15-4. Refs #13492.
Root-cause rework: one derivation per turnThe standing Criticals were not independent bugs. Recovery derived "is this text documentation?" in four different places â fence state per query, the flat parameter mask per scan, comments/indented code in one pass, example wrappers in two â and each derived a slightly different answer. Every fix for a leak in one view opened a leak in another, which is why 19 rounds kept producing siblings.
Every guard (block skip, both-end eligibility, the prose measure) reads that object. No consumer re-derives a mask or rescans the text. Per-finding closure
One invariant I added while closing the above, because the first draft of the model broke it: a truncated value must not hide the documentation markers after it ( The two fixtures, and why the expectations moved
Both were red under the previous parser for exactly the mechanism they now pin. A third expectation changed as a consequence, not as a contract shift: Verification (real runs, this worktree at
|
| payload | 18 KB | 72 KB | 144 KB |
|---|---|---|---|
dense comments, 1325b83 |
5.5 ms | 83.1 ms | 405.9 ms |
dense comments, d9e4e1b |
0.4 ms | 0.9 ms | 0.8 ms |
ambiguous regions, 1325b83 |
25.8 ms | 1081.8 ms | 8287.5 ms |
ambiguous regions, d9e4e1b |
2.5 ms | 2.2 ms | 5.2 ms |
The shipped case pins the shape (prefix-split count), not the wall clock.
Residuals â stated, not hand-waved
- R12-2 and R10-1 have no dedicated new red test. Their mechanisms are deletions (the divergent second scan, the duplicate block-structure derivation); I could not reconstruct the R12-2 witness shape without re-introducing the divergence it depends on. The three fixtures that pinned the surrounding ambiguity contract (
:1162,:1926,:1942) remain green, and both closures are structural. - This is not literally one character walk.
markedsupplies the<example>token positions, so the model is one derivation object with one pass per concern in dependency order; the property that matters â every consumer reads the same object and nothing rescans â holds. - A complete call inside a never-closed value still recovers (pinned by the existing
recovers the intact call after an envelope whose block never closed). I did not change that contract; only blocks inside a value whose owning call closed are treated as quoted markup. - An unterminated comment whose opener sits inside an owned truncated value still does not mask â that is the pinned XML tool-call recovery drops outer calls containing quoted tool markup #13492 truncated-stream behavior. The fail-closed repair is that markers after the value keep working.
- The production diff grows by ~200 lines (883 â 1078) even though two derivations were deleted: the model carries the span types and the precedence documentation that the old code spread across ad-hoc guards. The PR remains over the 1500-addition advisory ceiling; this is a root-cause replacement, not a narrow revert.
- The timing table is single-machine; treat it as a shape signal, not a bound.
Branch refresh:
|
yiliang114
left a comment
There was a problem hiding this comment.
Reviewed head c4dd2f06 (+1984/â203, 2 files). The number that matters here is 12 unresolved threads, all [Critical], so I checked each against this head rather than trusting the count: 10 are isOutdated anchors, and the two whose anchors still land on current lines have been changed to the polarity the bot asked for.
The two live-anchored Criticals
- R14-1 (
xml-tool-call-fallback.test.ts:1827) said the fixture pinnedexpected: ['run_shell_command']for a turn where awrite_filecontent value quotes a destructive shell call â i.e. it certified the dispatch of the command the model wrote as file content. At this head the same case isexpected: [], with the comment stating that declining is the in-contract polarity (base declined it too) and that the old expectation dispatched the destructive command. The fixture now asserts the polarity the finding demanded. - R12-3 (
:2034) said the fixture pinned['write_file', 'run_shell_command'], certifying execution of a call sitting between a prose<example>opener and its closer. At this head it isexpected: ['write_file'], with the comment recording that the old expectation certified the dispatch the flat scan's mis-pairing caused.
Both are still open as threads because nobody resolved them, not because the code disagrees with them.
The other 10 are anchored to lines that no longer exist (isOutdated), spanning R10-1 â R15-4. Per the repo's own convention that is what a re-derived finding looks like after the code has moved; it is not evidence that they are still live.
Where this leaves the PR
- The standing
CHANGES_REQUESTEDisqwen-code-review-botat1325b838â an older head thanc4dd2f06â so the verdict is stale by head, and the ledger's own floor iscriticalwith 12 posted findings across rounds 10â15. - CI at this head is green on
Test,Lint & Static,Integration Tests (no-AK)andManaged Agent gate;TUI parityandreview-prwere still running. - What is genuinely left is not a code question I can settle from the diff: whether this PR should recover per block (the bot's reading) or decline the whole turn (the author's, and base's). That is the maintainer decision already recorded in #13492.
I am not resolving those twelve threads or dismissing the review: resolving them would assert the findings are closed, and dismissing would assert the review is stale, and neither is mine to decide on a PR where the disagreement is about the intended contract.
äļæčŊīæ
åŪĄé
äš head c4dd2f06ïž+1984/â203ïž2 äļŠæäŧķïžãčŋéčĶįī§įæ°åæŊ 12 æĄæŠč§ĢåģįšŋįĻãå
ĻæŊ [Critical]ïžæäŧĨææēĄæåŠäŋĄčŋäļŠčŪĄæ°ïžčæŊéæĄåŊđįå―å head æ ļčŋïžå
ķäļ 10 æĄįéįđå·ē isOutdatedïžčéįđäŧč―åĻå―åčĄäļįéĢäļĪæĄïžå·ēįŧčĒŦæđæ bot čĶæąįéĢäļŠææ§ã
äļĪæĄéįđäŧææį Critical
- R14-1ïž
xml-tool-call-fallback.test.ts:1827ïžčŊīįæŊïžčŊĨ fixture æexpected: ['run_shell_command']å―æåĨįšĶéä―ïžčéĢäļč―Ūéwrite_fileį content åžåžįĻäšäļæĄį īåæ§ shell č°įĻââįäščŪĪčŊäšãæĻĄåååĻæäŧķå åŪđéįå―äŧĪčĒŦæīūåããå―å head åäļįĻäūæŊexpected: []ïžæģĻéåæãæįŧææŊįŽĶååĨįšĶįææ§ïžbase äđæįŧïžãïžåđķæåšæ§įææäžæīūåéĢæĄį īåæ§å―äŧĪãfixture į°åĻæčĻįæĢæŊčŊĨ finding čĶæąįææ§ã - R12-3ïž
:2034ïžčŊīįæŊïžfixture éįæŊ['write_file', 'run_shell_command']ïžčŪĪčŊäšäļäļŠåĪđåĻ prose<example>åžæ įūäļå ķéæ įūäđéīįč°įĻčĒŦæ§čĄãå―å head æŊexpected: ['write_file']ïžæģĻéčŪ°äļæ§įææčŪĪčŊäšæåđģæŦæéé é æįæīūåã
čŋäļĪæĄčģäŧäŧåžįïžæŊå äļšæēĄäššåŧ resolve åŪäŧŽïžčäļæŊäŧĢį čŋåĻåéĐģåŪäŧŽã
åĶåĪ 10 æĄéåĻå·ēįŧäļååĻįčĄäļïžisOutdatedïžïžčĶį R10-1 â R15-4ãæäŧåščŠå·ąįåĢåūïžčŋå°ąæŊäŧĢį į§ŧåĻäđåãéæ°æĻåŊžåšæĨį findingãįæ ·åïžäļč―å―ä―åŪäŧŽäŧ live įčŊæŪã
čŋåž PR į°åĻįåĪåĒ
- äŧæįį
CHANGES_REQUESTEDæŊqwen-code-review-botåĻ1325b838äļįââæŊc4dd2f06æ§ââæäŧĨéĢåž įĨĻæ head å·ēįŧčŋæïžåŪį ledger floor æŊcriticalïžįŽŽ 10â15 č―Ūå ą 12 æĄã - čŊĨ head į CIïž
TestãLint & StaticãIntegration Tests (no-AK)ãManaged Agent gateįŧŋïžTUI parityäļreview-prčŋåĻč·ã - įæĢåĐäļįäļæŊæč―äŧčŋäļŠ diff éåŪčŪšįäŧĢį éŪéĒïžčŋåž PR åščŊĨãé block æĒåĪãïžbot įčŊŧæģïžčŋæŊãæīč―Ūæįŧãïžä―č äļ base įčŊŧæģïžãéĢæŊ #13492 éå·ēįŧčŪ°å―äļæĨįįŧīæĪč čĢåģã
æäļäžåŧ resolve éĢ 12 æĄįšŋįĻïžäđäļäž dismiss éĢåž reviewïžresolve įäšåŪĢį§° finding å·ēéïždismiss įäšåŪĢį§° review čŋæïžčåĻäļäļŠåæ§æŽčšŦå°ąæŊãįŪæ åĨįšĶčŊĨæŊåŠäļŠãį PR äļïžčŋäļĪäŧķäšé―äļčŊĨįąææĨåŪã
chiga0
left a comment
There was a problem hiding this comment.
Review Summary â PR #13579
čŊåŪĄįŧčŪšïžéčŋïžApproveïž
æŽ PR éæ XML tool call æåéŧčūïžäŋŪåĪ #13492 äļåæ°åžåžįĻåĩåĨč°įĻæķčĒŦéčŊŊ dispatched įäļĨééŪéĒãčŋæŊäļäļŠ Deep tier į parser įš§åæīïžæķåæäđ åæ žåžįčūđįåĪåŪã
æ ļåŋåæīčŊäŧ·
1. deriveTurnAnatomy() â åæŽĄæīūįæķæ
- å° fence įķæãdocumentation spansãvalue spansãexample spans įŧäļåĻäļæŽĄ ordered walk äļæīūįïžæķéĪäšåæĨæŊäļŠ guard åčŠ rescan įäšæŽĄåĪæåšĶã
- äūčĩéĄšåšæļ
æ°ïželement pairing â value spans â fence table â documentation spans â lexer view â example spansãæŊäļŠäļæļļ guard åŠčŊŧ
TurnAnatomyïžäļéæ°æĻåŊžã buildFenceTable()į O(log n) binary search æŋäŧĢäšåæĨįįšŋæ§æŦæïžæ§č―æåæåŪé čŊæŪïž1000 malformed openers: ~2.2s â ~1msïžã
2. pairElements() â æ·ąåšĶé
åŊđ
- č§Ģåģäš flat
PARAMETER_PATTERNįäļĪäļŠįŧææ§éŪéĒïž(a) lazy match åĻåĩåĨå įī åĪåæĒåŊžčī value æŠæïž(b) prose äļį tag å―Ēįķäļåįŧ closer éčŊŊé åŊđã ownedvs!ownedåšåäš call body įįīæĨååæ°å prose äļį tag æåïžåč äŋæ inertãcleanflag éēæĒ prose äļį unclosed parameter čĒŦčŊŊåĪäļš truncated streamã
3. åŪå ĻæĻĄå
- åæ°åžåžįĻįåŪæīč°įĻäļåčĒŦ dispatchedïžR2-1 / R14-1 åšæŊïž
rm -rf /tmp/xäŧæäŧķå åŪđåäļšåŊæ§čĄå―äŧĪïžã - HTML comments å CommonMark indented code blocks čĒŦæĢįĄŪčŊåŦäļš documentationã
- æ··ååžå·åįŽĶïž
name='content">ïžį block čĒŦæĢįĄŪæįŧčéæŠæ dispatchã - éåĪåæ°ååŊžčī block æįŧïžéēæĒ advance æå Ĩ stray element åééŧčĶįã
- Borrowed closer æĢæĨįĄŪäŋ prose æåį close tag äļäžåæåæ°ã
4. Per-block rejection
- äŧ turn-wide decline æđäļš per-block rejectionïžambiguous block čĒŦæįŧå scan äŧäļäļäļŠ open tag æĒåĪã
- čŋæŊ #13492 čĶæąįčĄäļšåæīïžæĒåĪäščĒŦåč―ŽįäļäļŠ witnessã
æĩčŊčĶį
- æ°åĒįšĶ 50+ äļŠæĩčŊįĻäūïžčĶįïžquoted call recoveryãdocumentation guardsïžcomments/indented code/fences/examplesïžãper-block ambiguity rejectionãmixed quote rejectionãfuzz-derived witnessesã
reviewed XML ownership and documentation regressionsčĄĻæ žåžæĩčŊįĻäūïžR2-1, R2-5, R3-1, R3-2, R4-1, R4-2, R5-2, R7-1, R7-2ïžäļšæŊäļŠ standing review finding å―åäšåŊđåšįåå―įĻäūãsingle-derivation documentation guardsæĩčŊįĄŪčŪĪ fence įķæäļčĒŦåĪæŽĄæĻåŊžïžR13-2 / R15-2 įåļļæ°åĪæåšĶéŠčŊïžã
įŧčč§åŊïžééŧåĄïž
hasBalancedQuotedCalls()įCALL_TAG_PATTERN.lastIndexéį―ŪïžæŊæŽĄč°įĻåéį―ŪlastIndex = 0ïžæĢįĄŪãtextOutside()į overlap åĪįïžend <= cursorč·ģčŋå·ēčĒŦčĶįį rangeïžäļäž double-countãcomputeDocumentationSpans()äļlistContentIndentįčŪĄįŪïžæĢįĄŪåĪįäš list item lazy continuation äļæŊ indented code įæ åĩïžR15-3ïžã
įŧčŪš
čŋæŊäļäļŠæķæįš§į parser éæïžč§Ģåģäš XML tool call æåäļåĪäļŠåŪå Ļįļå ģįčūđįéŪéĒãäŧĢį čīĻééŦïžæģĻéčŊĶå°―ïžæĩčŊčĶįå åãLGTMã
qqqys
left a comment
There was a problem hiding this comment.
COMMENT at head c4dd2f06 â not approving, but the picture is materially better than the standing record suggests, and the thing blocking this PR is stale.
1. The blocking review predates the rework and no round has reassessed it
reviewDecision is CHANGES_REQUESTED from round 15 at 1325b838 (2026-10-23), which recorded thirteen sev:"C" findings. Two commits have landed since: d9e4e1b0 (fix(core): derive XML documentation spans once per turn, 2026-10-27T09:18:23Z) â a root-cause rework â and c4dd2f06, a merge of origin/main carrying no code change. So the standing request for changes is anchored in a file that has since been substantially rewritten, and no review round has run against the rewrite. That is a reason to re-run a round, not a reason to assume either that the findings stand or that they are closed.
2. What I verified myself at this head
I did not take the rework's closure table on trust. The architectural claim it rests on is checkable, and it holds:
deriveTurnAnatomyis defined once (xml-tool-call-fallback.ts:747) and called once (:836). There is a single derivation per turn with one consumer site, which is the property the whole closure argument depends on.- The four independent re-derivations the findings were filed against are gone:
hiddenDocumentationRanges,positionInsideFence,unclosedCallOpenerOffsetsandextendedMaskseach appear zero times in the file at this head. Those were the anchors for R10-1, R11-1, R13-2, R13-4, R15-1 and R15-2, so those findings can no longer be confirmed standing by inspection â the mechanisms they named do not exist. lexInlineappears exactly once, matching the claim that the refresh branch was deleted and the lexer runs once (R11-1).- All nine tests the closure table names as reddening on
1325b838are present exactly once inxml-tool-call-fallback.test.ts, with zeroskip/todo/onlyacross 123 cases.
I then read the two closures that carry the most risk, because they are the ones that could hide a weakened gate rather than a fix:
The quadratic claim (R13-2 / R15-2) is pinned algorithmically, not by wall clock. scans the turn a constant number of times regardless of comment openers builds a 400-line turn with 399 comment openers against a sparse control, spies on String.prototype.split, and counts splits on '\n' whose receiver exceeds half the text length â i.e. it counts prefix splits, the exact quadratic shape â then asserts dense <= sparse + 2. Measuring the shape instead of timing is the right call for CI, and the assertion is a real bound that a per-opener rescan would break.
The flipped R2-1 expectation is a scoped decline, not a whole-turn cancellation. recovers the sibling after an unclosed value takes the R2-1 witness input, appends a live read_file call, and asserts the result is ['read_file'] with tryRecoverXmlToolCalls(text).recovered === true. So the unclosed write_file and the calls its unterminated content value quotes stay inert while the following live call still recovers. That answers the R9-1 lineage concern ("declines the WHOLE TURN") for this input: the polarity moved to [] for the ambiguous block without taking the rest of the turn with it.
3. What I did not verify, and it is why this is not an approval
Thirteen findings cannot be discharged by confirming the architecture that is claimed to close them. Unverified at this head:
- The semantic soundness of the new model â depth-based element pairing, the "clean direct child of an open call body" ownership rule, and the documented precedence order. R12-1, R13-1 and the dialect half of R15-1 all reduce to whether that rule is right, and a single derivation is only as sound as its one precedence chain. A wrong precedence now produces one wrong answer everywhere instead of four divergent ones, which is a better failure mode but still a failure mode.
- R12-2's count-based termination and the removal of the seeded-zero underflow; R15-3 (indented code cannot start inside parameter data); R15-4 (the terminator list excluding
-->inside never-closed as well as closed values). Each has a named test present, but I did not read the implementations against them. - The R12-3 fixture flip (
['write_file','run_shell_command']â['write_file']). I confirmed the R2-1/R14-1 flip; I did not confirm this one. MAX_LEXER_SCAN_LENGTHstill appears twice in the file. R5-1 (unbounded synchronous scans on the streaming thread) was carried from round 5 through round 11 and is absent from round 15's list, so it may have been closed earlier â but I have not confirmed that the remaining reads of that bound are sufficient, and it is the one long-running finding whose anchor still exists at this head.- New surface. A one-commit rewrite of an 819-line recovery parser plus a 2,201-line suite is itself unreviewed code. Nothing in this pass constitutes a Critical-only scan of it; I read the structure, two closures, and the deletion census.
4. CI and next step
CI at review time: 18 pass, 45 skipping, 3 pending, 0 fail. Test (ubuntu-latest, Node 22.x) is green at this head, which is the lane that collects xml-tool-call-fallback.test.ts â so the 123 cases, including all nine named closure tests, are not merely present but passing. Lint & Static and Integration Tests (no-AK, No Sandbox) are also green. The three pending lanes are Installed npm Node26 private Bun acceptance, web-shell E2E Smoke and review-pr, none of which bears on this file. I did not wait on them, and CI is not what this verdict rests on: a green suite shows the rework satisfies its own stated contract, which is exactly what a review round has to judge whether the contract is right.
The useful next step is a review round at c4dd2f06. The findings that survive it will be a much shorter list than thirteen, because six of them are anchored in mechanisms that no longer exist â but "the anchor was deleted" is not the same as "the behaviour is correct", and only a round that reads deriveTurnAnatomy's precedence chain against the four guards that consume it can say which of the remaining ones still bite.
|
Verdict: â
merge-ready at
äļææčĶįŧčŪšïžæŽå°éŠčŊéčŋïžåŊååđķã å ą 7,673 éĄđæčĻ/æĢæĨã
What the PR claimsThe outer call whose parameter value quotes another complete call is recovered exactly once with the full value, while the quoted markup stays inert; ambiguous/malformed blocks are rejected per block instead of declining the turn; HTML comments and CommonMark indented code blocks join fences and A/B proof at the parser boundaryThe head tree differs from the merge-base by exactly these two files (
Base output for the issueâs exact input is the issueâs own signature â the write is dropped and only the independent control read survives: Head recovers Committed gates
The PR descriptionâs â138/138â and â567/567â are counts from an earlier head; measured at Mutation matrixEach mutant was applied at a unique anchor (count asserted), run against the committed suites, then restored from a
M8 matters because the module-level tests pin the helper, not the production call site; the committed Performance and fuzzA 6,000-case seeded fuzz over tag/fence/comment fragments produced 0 failures, 1,902 recovered turns, max 1.27 ms per case, and never changed My head-vs-base probe measured 8.28 ms vs 6.52 ms for a fence holding 1,000 malformed openers, and 0.83 ms vs 0.90 ms for a 64 KB example body. The PRâs â~2.2 s â ~1 msâ and â~420 ms â ~13 msâ therefore compare earlier reviewed heads of this branch, not the merge-base; I did not rebuild those intermediate heads, so those before/after numbers are not independently reproduced. Absolute cost on both arms is low milliseconds for the shapes I measured. Trial merge and siblingsTrial merge of The only other open PR touching the same production file is #10709 (orphaned XML closing tags); Findings
Not covered
MethodologyA detached worktree at Evidence capturesVerification run and report by @wenshao. |
doudouOUC
left a comment
There was a problem hiding this comment.
QwenCode Reviewer čŊåŪĄæĨå â PR #13579
čŊåŪĄįŧčŪšïžâ éčŋ
æŧä―čŊäŧ·
éŦčīĻéįéēåūĄæ§č§Ģæéæãå°åæĢį rescan įŧäļäļš single-derivation modelïžderiveTurnAnatomy()ïžïžæĒæåäšæĢįĄŪæ§äđæđåäšåĪæåšĶãæĩčŊčĶįåŊåšĶæéŦïž+1165 čĄïžïžæŊäļŠ guard é―æåŊđåšį positive/negative pinãäŧĢį æģĻéčŊĶå°―ïžæŊäļŠčŪūčŪĄåģįé―åžįĻäš issue įžå·å review finding IDã
æđåĻå åŪđäļæđæĄæĢįĄŪæ§
packages/core/src/core/xml-tool-call-fallback.ts(+819/-196): éå XML tool call č§ĢæäļæĒåĪéŧčū- Depth-paired element matching (
pairElements()): æŋäŧĢæ§į flatclosedParameterSpans()ïžæĢįĄŪåĪįåĩåĨ parameter - Per-block ambiguity rejection: æŋäŧĢ per-turn vetoïžäļäļŠå block äļåå―ąåįļéŧæĢåļļč°įĻ
- Quoted value advance (~L810-825): flat match close tag č―åĻ quoted value å éĻæķååæįīĒįæĢ closer
- Documentation region æĐåą (
computeDocumentationSpans()): HTML comment å indented code block ä―äļšæ°ææĄĢåšå - Duplicate parameter name rejection (~L878-880): éēæĒ advance æå Ĩ stray element åééŧčĶįåæ°
åŪå ĻåŪĄæĨįŧčŪš
- â æ įĄŽįžį åŊéĨæåčŊ
- â äļä―ŋįĻ DOM/XML parserïžå ĻéĻåšäšæĢå + offset čŋ―čļŠïžæ XXE éĢéĐ
- â
Quoted markup stays inertïžæĩčŊčĶį
rm -rf /tmp/xįåąéĐå―äŧĪåĻ comment/fence/example/value äļčĒŦæĢįĄŪæåķ - â RegExp DoS éēæĪïžæææĢåäļšįšŋæ§æĻĄåžïžmarked lexer æ MAX_LEXER_SCAN_LENGTH äļé
- â æŽæĻĄåäŧ åææŽč§Ģæïžäļæķåæäŧķįģŧįŧæä―
åŧščŪŪéĄđïžééŧåĄïž
openTagEnd()į quote-pairing äļåĪįč―Žäđåžå·ïžåĶ\"ïžïžå―ååčŪŪäļåŊæĨåïžä―čĨæŠæĨæĐåą attribute čŊæģéæģĻæbuildFenceTable.insideFence()(~L407-420) åŊđ partial line éæ°æ§čĄ regexïžæįŦŊéŋčĄäļæå°éåä―åžé
CI/éĻįĶįķæ
- â Test (ubuntu-latest)ãLint & StaticãIntegration TestsãTUI parityãweb-shell E2E åéčŋ
- âģ fallback-comment / npm Node26 äŧ pending
- âđïļ mergeable = MERGEABLEïžmergeStateStatus = BLOCKEDïžįåū required reviewïž
doudouOUC
left a comment
There was a problem hiding this comment.
Approved. See detailed review comment above.
|
Clearing the round-15 Verified at the current head, not taken from the rework's own closure table:
The four derivations that R10-1, R11-1, R12-1, R13-1, R13-2, R13-4, R15-1 and R15-2 were filed against no longer exist, so those findings cannot be confirmed standing by inspection. The per-id closure table with the test that reddens on revert is in the earlier comments on this PR; the two flipped fixtures ( Two closures remain structural rather than test-pinned, and I am not overstating them: R10-1 and R12-2 have no dedicated red test (the witness could not be reconstructed without reintroducing the divergence). Everything else in the round-15 ledger is either deleted code or pinned by a named test. Independent corroboration on this head: @chiga0 approved the rework after reviewing the single-derivation architecture, and @qqqys checked the same anchors (zero occurrences, one definition/one call, no skip/todo across 123 cases) and concluded the standing request predates the rewrite and should be re-run rather than assumed either way. Also noted from @qqqys and not claimed as closed: a complete call inside a never-closed value still recovers, and an unterminated comment opening inside an owned truncated value still does not mask â both are pre-existing pinned contracts from #13492, unchanged here. |
Round-15 findings anchored at 1325b83; every mechanism they named (hiddenDocumentationRanges, positionInsideFence, unclosedCallOpenerOffsets, extendedMasks) is now 0 occurrences at c4dd2f0 after the single-derivation rework in d9e4e1b. Per-id closure and red-on-revert tests are in the PR comments; R10-1/R12-2 remain structural closures and are not overstated. Verified independently by chiga0 (approved) and qqqys (anchor check).
|
Flagging, not fixing: the approvals are already bound to this head and |
|
Released in v0.26.3. |







Summary
Recover a complete outer XML tool call whose parameter value quotes other calls, while keeping the quoted markup inert. An ambiguous or malformed block is now rejected on its own and the scan resumes past it, so one bad envelope no longer costs the genuine calls beside it.
What this changes
write_filewhosecontentcontains an unfenced example call is recovered exactly once with the complete content, and the quoted call never dispatches.<example>. A value that quotes a call used to let a commented-out shell command dispatch while stripping its own markup from the visible turn.Reviewer Test Plan
Return a document write whose content quotes a harmless call, followed by an independent control-file read. Expect the write executed once with exact bytes, the quoted call inert, and the read executed.
Then vary the shape: a trailing parameter behind the quoted value, a documented parameter element inside the value, the same shape inside a fence, an
<example>, an HTML comment and an indented block, a malformed block before an intact call, and a prose mention of<!--before a live call. Expect documentation to stay inert and the intact calls to recover.Evidence
packages/core:xml-tool-call-fallback.test.ts138/138,llm-chat.test.ts567/567; typecheck, ESLint and Prettier clean on both changed files.recovered: falsenever changesremainingText.Risk & Scope
The contract changes from turn-wide decline to per-block rejection. That is what #13492 asks for, and it restores the three witnesses the branch had inverted. It also means a complete call inside a rejected block's unclosed value is recovered again, as on the merge base.
Known limitation: a value that only mentions a bare closing tag, without quoting a complete call, still rejects its block. Accepting it would dispatch the truncated value pinned by
preserves malformed blocks instead of dispatching partial calls, so this keepsRefsrather thanFixes.Performance #13787 stays open: the remaining per-value fence scans are quadratic in the number of value-quoting blocks. Windows and macOS were not run locally.
Linked issues
Refs #13492. Follow-up to #13515.
äļæčŊīæ
åĪåąč°įĻåĻåæ°åžéåžįĻå ķåŪč°įĻïžäūåĶ
write_fileį content éåäšäļæŪĩįĪšäū callïžæķïžį°åĻåŠæĒåĪäļæŽĄåĪåąč°įĻãäŋįåŪæī contentïžčĒŦåžįĻįč°įĻäŋæäļšæ°æŪïžåæ°ãexample æåīæ å―åąææ§äđæķïžåŠæįŧåšéŪéĒįéĢäļŠ block åđķäŧåŪčŠå·ąįäļäļäļŠ open tag įŧ§įŧæŦæïžäļåčŪĐæīč―ŪåĪąčīĨãåæķæ HTML æģĻéäļ CommonMark įžĐčŋäŧĢį åå―ä―ææĄĢåšïžæĪååžéåžįĻč°įĻäžčŪĐčĒŦæģĻéæį shell å―äŧĪčĒŦæ§čĄïžäļæ čŪ°äŧåŊč§ææŽäļæķåĪąïžïžåđķæįŧåæ°åéåĪį blockïžquote advance åŊč―ææļļįĶŧå įī æčŋ block åđķčĶįåéĒįåæ°ïžã
éŠčŊïž
xml-tool-call-fallback.test.ts138/138ãllm-chat.test.ts567/567ïžäļĪäļŠæđåĻæäŧķ typecheck/ESLint/Prettier åđēåïž6000 äūį§å fuzz æ åžåļļãæ æčĩ·ïž1000 äļŠåīæ å įļå―Ē opener įšĶ 1msïžæĪåįšĶ 2.2sïžïž64KB example įšĶ 13msïžæĪåįšĶ 420msïžãæŽč―ŪæŠč· CLI/tmux įŦŊå°įŦŊïžįäš§č°įĻįđæŠåãå·ēįĨéåķïžåžéåŠæåčĢļįŧææ čŪ°ïžæēĄæåžįĻåŪæīč°įĻïžæķäŧæįŧčŊĨ blockïžå äļšæĨååŪäžæīūåčĒŦ
preserves malformed blocks instead of dispatching partial callséä―įæŠæåžïžå æĪå°ūæģĻäŋæRefsãæ§č― #13787 įŧ§įŧč·čŋã