Repository navigation
feat: parse ladder — three string-ladder rungs for weak-model drift (billion-context#1559) - #477
ranxianglei wants to merge 1 commit into
Conversation
📦 Built Package ArtifactBranch: Option A — Install from npm PR tag (recommended)In your adapter project: npm install acp-kernel@pr-477Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf acp-kernel-pr477.tgz
npm install ./packageThis comment is automatically updated on each push. |
[bot] 🏷 Review complete. I fetched the branch ( ① Direction (original issue) — billion-context#1559 asks for string-in- ② Regression inventory — behaviors owned by the touched paths, each audited (probe = my A–M matrix; suite = full 1217):
No unintended regressions found. Every changed line is additive recovery on inputs that previously yielded 0 ranges. Behavior changes (old → new, per Deliverables rule 4):
③ Code — escape-aware scanner is correct ( ④ Tests — the 15 new tests are real regression tests: exact refs/summaries/kinds/flags asserted, and they pin the non-recovery cases (punctuation-only remainder, prose without refs, single cut block, #1001 array header-only) plus escape decoding and the quote-repair-retry interaction. Each rung regressing would flip an assertion. Valid. ⑤ Diff cleanliness — 2 files, +303/−9, every line serves the feature; no unrelated churn, no lockfile/generated artifacts, no mass whitespace. Clean. Verdict: ready to merge (human action — I won't merge). Post-merge plan as proposed is sound: isolated release commit 修复了弱模型漂移产生的三种字符串形态压测参数(单行槽内字符串、顶层裸字符串、截断字符串化参数)被整体拒绝的问题,在解析梯子上补了三档只救确定内容、绝不猜测的恢复;经本地全量门与 13 项前后行为矩阵对照确认无回归,仅有一处已披露的诊断字段增强,可以合并。 |
…billion-context#1559)
c2b4dc7 to
68a7bb6
Compare
Three new rungs on the salvage ladder for weak-model syntax drift, per billion-context#1559 (filed during the v0.1.165 pre-release sweep). All changes confined to
src/parse-compress-input.ts; no prompt/tool-surface change, no fixture churn, zero new dependencies.Background
The 0.0.98 ladder (#470/#471) recovers object-in-slot and nested
ranges, andparseObjectValuealready routes non-JSON slot strings through the line-form path (splitLineEntries). Missing were the shapes where line-form text lives OUTSIDE any JSON shell:{"content": "m00150-m00220 topic: summary here"}→ wascontent-not-array, 0 ranges. Weak models / lossy gateways drop the line break of the taught header+body form; the text after the refs had nowhere to go (a single-line entry must have its body after a\n, so it always failed validation).compress("m00150–m00220 Auth\nsummary…")raw, or as a JSON string literal decoding to text → wasmalformed-json/not-object, 0 ranges.salvageContentEntriesrequires the"content": [marker, so shell-less text had no recovery path at all.'"{"content": "m1–m5 A\nfull\nm6–m8 B\npar'→ wastruncated, 0 ranges. The array walker only handles[slots, so every complete leading block was lost.Changes
inlineSingleLineEntry(G1): when the line-form path yields exactly ONE part holding no line break, re-home the text after the refs header as the summary body by synthesizing the missing break. Applied to the bare-string paths only (object-slot branch + top-level salvage) — never to array elements, whose single-line header-only form has sibling-adoption semantics (#1001) and stays rejected.salvageLineFormEntries+finishLineFormSalvage(G2): bare-string recovery with a new diagnostic flagstringSalvage: true(additive optional field onCompressParseDiagnostics). Adopted only when ≥1 valid range is found; otherwise the caller keeps its own verdict.salvageStringSlotEntries(G3): extracts the surviving string-slot prefix (to the closing quote, or EOF when unterminated), decodes\n, returns the line-form blocks. Never-guess rule: while the slot is unterminated the trailing block may be mid-write and is dropped; an unterminated single block yields nothing. ReusescontentSalvage: true(set only on non-empty recovery), keeping parseCompressArgs: content given as a single entry object is rejected (content-not-array) while the same drift at the top level is tolerated — asymmetric salvage wall #470's flag semantics.content-not-arrayrejection now carriesinvalidItems/invalidReasons(previously absent) so hosts can log WHY a shape was rejected.Behavior changes (old → new)
content-not-array, 0 rangesok, 1 range (inline summary, derived topic, unflagged)"m1–m5 …")content-not-array, 0malformed-json/not-object, 0ok, N ranges +stringSalvage: truemalformed-json/not-objecttruncated, 0truncated, N +contentSalvage: truetruncated, 0no-valid-rangesDesign decisions
see m00510–m00520) are indistinguishable from headers; mis-splitting would silently corrupt a legitimate summary. A collapsed multi-block single line therefore recovers the FIRST block only (whole remainder becomes its summary) — under-recovery keeps the receipt honest so the model retries the rest. Pinned by test.\p{L}|\p{N}), so"m1–m5 …"stays rejected.Tests
15 new regression tests in
tests/parse-compress-input.test.tscovering every row above, including the deliberate non-recovery pins. Full gate green on this head: typecheck ✓, 1217/1217 tests, build ✓, prettier stable ✓. Before/after verified with the A–K shape matrix from the issue thread.Release plan
After merge: isolated
release v0.0.99PR (version bump only) → CI publish → verifynpm view acp-kernel version→ then the billion-context pin-bump PR referencing billion-context#1559.中文摘要:为弱模型语法漂移补上解析梯级三档(单行槽内字符串内联摘要、顶层裸行式字符串回收、截断字符串槽完整块回收),全部带回归测试,1217/1217 全绿;合并后走 v0.0.99 发布流程,再升 billion-context 钉版本。