Repository navigation
[PR] fix: refuse estimate-grade arms in preflight entry sizing; add step-family 1M window (#5500) - #5501
[PR] fix: refuse estimate-grade arms in preflight entry sizing; add step-family 1M window (#5500)#5501ranxianglei wants to merge 4 commits into
Conversation
📦 Built Package ArtifactBranch: Latest build — install this exact versionnpm install -g billion-context@0.0.9153-pr.5501.224f824This exact version is immutable and reproducible. The rolling Recent builds (commit → version)
Download artifact
tar xzf billion-context-pr5501.tgz
npm install -g packageInstall instructions are refreshed on each push. |
(ai: vllm-qwen/qwen3.8-27b) 查重:不重复。 本 PR 关闭 #5500(canonical 缺陷报告)。相关但不同:#5005(同域互补——#5005 管「谁能 arm」,本 PR 管「已 arm 的 estimate-grade 值能在 preflight entry 影响什么」,无文件重叠);#5502(lookup-miss fallback 产品决策,已正确另立 decision-request)。前序同类均已闭环:#1839/#1846、#2029、#1492/#1503。无其他在途 PR 加 step- 表行或修 char-bound entry poisoning。 标签: bug · omp · scope/wiring · p1 —— p1 可用性缺陷(会话硬 fail-fast 死循环)、omp ACP 车道症状、宿主侧请求管道/窗口解析域。源 bug #5500 已带同样四标;本镜像线程的逐-issue 标签端点从当前环境不可达(404),为避免误打未强制写入,仅在此报备分类。 CI: 镜像缓存 30 check,failed=0,pending=8——全在 结构化八问1. 是什么问题:#5500 失败循环——omp/step-5 会话报 2. 什么原因导致的:(A) 3. 影响范围与严重程度:任何把 step-* 模型路由过来且未显式配 per-route/per-model 窗口的宿主(被 150K 假墙搁浅)+ 任何 stats_json 带 estimate-grade 中毒臂的会话(报告者 omp/step-5;fleet 53/2420 会话 estimate>2× real)。p1:会话完全不可用——确定性耗尽 → 硬 fail-fast ≥400,无法恢复。 4. 怎么修复的:(A) config.ts 加 5. 是否有回归问题:逐项过触碰路径既有行为——
6. 是否破坏缓存:不涉及。不碰 prefix-cache 接缝、重试、去重键、增量游标;preflight sizing 只影响「何时触发压缩」,不改出站字节/cache 前缀。 7. 是否改了设计方向:无新架构。是既有 #1839 kill-at-reader grade 纪律向剩余两个未约束 entry 读的补全;更深的 lookup-miss-fallback 明确留给 #5502 决策,不在本 PR。 8. 是否引入新配置:无新 env/config/CLI。仅一条内置表行(运行时数据,非 config-schema 字段)+内部逻辑。显式 per-route/per-model override 仍优先(precedence chain 不变)。 行为变更披露确认(§Deliverables #4)PR 正文已披露两条,复核一致:
非阻塞发现(建议,不拦合)
测试有效性高质量、非假测:T1 单元钉死窗口解析(basename-first 匹配 + 三负控);T2a/T2b 双向断言 entry 预算纪律(estimate 拒 / usage 放行,#3617);T3 e2e 走真实窗口解析链复现 issue 形状(pre-fix 确定耗尽→fail-fast≥400 / post-fix 干净转发 0 summary 调用);T4 e2e control 钉住 measured 墙仍拒。断言有牙,bug 回归能抓住。 判定可合(需人工 merge:step- 默认窗口属 fallback/default-value 变更,产品决策面,§7.4 必须 human)。前置条件:① CI test 分片转绿(当前 0 failed / 8 pending);② 发现 #1 二选一定论(建议 |
ranxianglei
left a comment
There was a problem hiding this comment.
(ai: vllm-qwen/qwen3.8-27b)
判定:APPROVE(可合;需人工 merge)
(GitHub 禁止同账号 approve 自己的 PR,故以 COMMENT 事件提交本审核,判定等同 APPROVE。)
本 PR 修 #5500 的两个叠加缺陷:(A) 窗口查找表缺 step-* 行 → 落 env 默认 2e5 → 150K 假墙;(B) #604 失败臂持久化的 char-bound ESTIMATE-grade lastInputTokens(≈4× token 数)被回放进每个后续请求,而 preflight 的两个 ENTRY 读恰好没做 grade gate。两处修法方向都对:补表行(在 miss 处止血)+给 entry 读补上与 baselineFloor 相同的 anchorGradeOk 纪律(kill-at-reader)。本轮为独立二审(mirror 线程已有一轮 review 报告;我重读了 diff、独立过了回归清单,并补做了变异验证):
变异验证(本地定向,非全量)
- revert
src/config.ts到 master → T1+T3 失败(表行缺失 → e2e 复现 issue 形状:确定性耗尽 → fail-fast ≥400); - revert
src/preflight.ts到 master → C2a 失败(estimate 臂退回 floor entry 预算); - 均恢复后原样;新 head 上定向套件 5/5 绿。
结构化八问
1. 是什么问题:omp/step-5 会话反复命中不可重试的 502 context ~204011 exceeds window 150000 ... 0 compressible range(s)——会话硬失败、无法恢复。
2. 什么原因导致的:两个独立缺陷叠加。(A) CONTEXT_LIMIT_TABLE 无 step-* 行,step-5-preview-free(真实墙 1048576)落到 base 默认 2e5 × .75 = 150K 有效窗口;按 #852 教义猜太大自愈、猜太小搁浅,这是搁浅侧。(B) 该 estimate-grade 值的所有读取方早已被 grade 纪律约束(#1839 kill-at-reader),唯独 preflight 的两个 ENTRY 读(currentTokens 初始化 + entryTokens floor,喂 #1933-F3 超支预算)漏了 gate——重启后每次请求都用中毒臂定 entry 尺寸。根因定位准确:不是持久化层的问题,是这两个读漏了 gate。
3. 影响范围与严重程度:p1,两面——①任何把 step-* 模型路由过来且未显式配窗口的宿主(被 150K 假墙搁浅);②任何 stats_json 带 estimate-grade 中毒臂的会话(报告者 omp/step-5;fleet 实测 53/2420 会话 estimate>2×real)。触发即完全不可用:确定性耗尽 → 硬 fail-fast ≥400。
4. 怎么修复的:(A) 表加 { match: /^step-/i, limit: 1_048_576 }(字段证据 inline 引用;basename-first 匹配覆盖 relay 前缀 id);(B) anchorGradeOk = source ∈ {usage, overflow-arm} 门住两个 entry 读——逐字复刻 preflight.ts:2145 baselineFloor 既有纪律;usage/overflow-arm 锚照常 floor,estimate 臂退到 per-request 实测。走 kill-at-reader 而非改持久化,方向对。
5. 是否有回归问题:逐项过触碰路径既有行为——usage/overflow-arm 锚不变;unknown-baseline 制度(#553)不动;#604 kernel truncate-rescue(prepare-anthropic providerInputTokens)刻意不动;fitting payload 转发保留(#301/#4288,T2a/T3 显式钉住);provider-measured 墙仍拒(T4 control 钉 source=usage 60K>40K → ≥400);唯一角落差异(!baselineKnown 且空消息:0→lastInputTokens)与 baselineFloor 同形分支逐字一致,出站 payload 实际恒 ≥1 条消息。未发现回归。
6. 是否破坏缓存:不涉及。不碰 prefix-cache 接缝、重试、去重键、增量游标;preflight sizing 只影响「何时触发压缩」,不改出站字节/cache 前缀。
7. 是否改了设计方向:无新架构。是既有 #1839 kill-at-reader grade 纪律向剩余两个未门控 entry 读的补全;更深的 lookup-miss-fallback(未知当未知处理而非 2e5 默认)已正确拆成独立 decision-request(#5502),不在本 PR。
8. 是否引入新配置:无新 env/config/CLI。仅一条内置表行(运行时数据,非 config-schema 字段)+内部逻辑;显式 per-route/per-model override 仍优先(precedence chain 不变)。
行为变更披露确认(§Deliverables #4)
正文两条披露与代码一致,复核通过:
^step-且无显式覆盖的模型有效窗口:~150000 → ≈786432(native 1_048_576 − min(maxOutput, 25%×window) 预留;maxOutput 小时接近 1M)。- ESTIMATE-grade/unprovenanced baseline 下 preflight entry sizing:中毒臂不再 floor
entryTokens/currentTokensinit,改按 per-request 实测。
已顺手修(非阻塞发现,直接修在本分支)
- 常量与披露数字不一致:正文原写 ≈786432,代码常量却是 1_000_000(有效 750000)。把常量对齐到字段实测真实墙 1_048_576(同表 gemini-3 行同形;消除「猜略小」方向——750K–786K 之间无可压 payload 原先会被误 fail-fast),同步三处 T1 断言与正文披露 + commit
ac098ee(定向套件 5/5 绿,CI 在新 head 重跑)。
非阻塞观察(不属本 PR,并入 #5500 跟踪,不单开 issue)
正文「除 entry 外所有 reader 都已约束」的表述略过强:还有两处读 lastInputTokens 未查 source——src/request-membership.ts:70(#4805 membership needle 启发式,中毒时 referenceScale 放大约 4× → mainScale 阈值偏高,软降级)与 src/server/prepare-responses.ts:597(codex compact-intercept 伪造 usage body,中毒时 inputTokens 偏大,窄 codex 路径)。二者都不喂 preflight entry sizing、都不引发 #5500 循环,属同一机制家族(缺 grade 纪律的 reader),已在 #5500 留评论记录。
测试有效性
T1 钉表行解析+三负控;T2a/T2b 双向断言 entry 预算纪律(#3617:estimate 拒 / usage 放行);T3 走真实窗口解析链复现 issue 形状(pre-fix 确定性耗尽→fail-fast≥400 / post-fix 干净转发、零 summary 调用);T4 control 钉 measured 墙仍拒。断言有牙,本 bug 回归能抓住。
合并判定
可合。需人工 merge——step 家族默认窗口属 fallback/default-value 变更,§7.4 human-only 域。CI 将在新 head ac098ee 重跑(常量对齐,本地已定向验证)。
(ai: vllm-qwen/qwen3.8-27b) PR #5501 二审完成:可合(APPROVE,需人工 merge)。GitHub review 已提交(同账号自批限制 → 以 COMMENT 事件带 APPROVE 判定);独立重读 diff + 回归清单 + 补做变异验证(revert config.ts / preflight.ts 各自使对应测试转红)。已顺手修两处小问题:① PR 正文披露数字与代码常量不一致(正文 ≈786432 vs 代码 1_000_000)→ 常量对齐字段实测墙 1_048_576 + 三处断言 + 正文同步,commit |
ranxianglei
left a comment
There was a problem hiding this comment.
(ai: vllm-qwen/qwen3.8-27b)
新 head ac098eeaa 复核:可合状态不变(APPROVE,需人工 merge)
本轮复审范围 = 上一审核 head 以来的唯一增量——commit ac098ee(上轮顺手修:常量对齐):
src/config.tsstep 行1_000_000 → 1_048_576+ 三处 T1 断言同步(字段实测真实墙,同表 gemini-3 行同形;正文披露数字随之精确化);- 本地定向套件 5/5 绿;fetch 核对分支 tip =
ac098eeaa、master+2 commits,此后无其他 push,全窗 diff 仍为 3 文件 +357/-2(上轮已逐段审过); - CI 本 head:镜像缓存 30 checks / failed=0(test 分片运行中),static-gates/kernel-guard/docs-sync/build-artifact 全绿。
无新发现。上轮两处非阻塞观察(request-membership.ts:70、prepare-responses.ts:597)继续在 #5500 跟踪。结论不变:可合,等 owner 人工 merge(§7.4 default-value 变更 human-only)。
(ai: vllm-qwen/qwen3.8-27b) 新 head |
Round 3 of #5500 (field report on v0.1.212, Pi/Responses lane): when the last cycle ended without a usage settle, effectiveTokenCount handed the kernel meter the CHAR-BOUND estimate (min(localInputEstimate, raw upper)), inflating it ~2-4x over the measured size. On a session whose measured usage sat safely under the window, that inflation crossed the kernel's destructive emergency-truncate band (0.95x), clipping tool output into the delivered view where it latches until the next successful fold (#3939). The freshness demotion itself is intended (#4383); the defect was the scale of the ride-on scalar. C6: cycle-stale now rides contextEstimateTokens — the billing-caliber per-send estimate stamped at the same relay chokepoint (k-hat scaled where route+model provenance matches), the same replacement reading staleSmallAnchorFallback returns for its own demotion class — capped by the current payload's own upper bound so it can never exceed today's fail-closed worst case. Usage/overflow-arm anchors, fresh-settle, the #728 anchor-less posture and the host preflight trigger are untouched. Regression: C6a/b unit pins (ride-on + four unchanged calibers), C7 reproduces the field chain end-to-end (usage settle -> no-report resend -> repeat prepare; pre-fix the clips latch), C7-control pins the kernel band intact. Three #4383/#5134 assertions re-pinned from the char bound to the calibrated scalar (same chokepoint freshness, corrected scale) — behavior change disclosed in PR #5501. Kernel-side residuals (destructive action on unprovenanced evidence; truncate ignoring protected tools) tracked in a separate kernel authorization request.
8222bc4 to
8dede7d
Compare
Round 3 of #5500 (field report on v0.1.212, Pi/Responses lane): when the last cycle ended without a usage settle, effectiveTokenCount handed the kernel meter the CHAR-BOUND estimate (min(localInputEstimate, raw upper)), inflating it ~2-4x over the measured size. On a session whose measured usage sat safely under the window, that inflation crossed the kernel's destructive emergency-truncate band (0.95x), clipping tool output into the delivered view where it latches until the next successful fold (#3939). The freshness demotion itself is intended (#4383); the defect was the scale of the ride-on scalar. C6: cycle-stale now rides contextEstimateTokens — the billing-caliber per-send estimate stamped at the same relay chokepoint (k-hat scaled where route+model provenance matches), the same replacement reading staleSmallAnchorFallback returns for its own demotion class — capped by the current payload's own upper bound so it can never exceed today's fail-closed worst case. Usage/overflow-arm anchors, fresh-settle, the Regression: C6a/b unit pins (ride-on + four unchanged calibers), C7 reproduces the field chain end-to-end (usage settle -> no-report resend -> repeat prepare; pre-fix the clips latch), C7-control pins the kernel band intact. Three #4383/#5134 assertions re-pinned from the char bound to the calibrated scalar (same chokepoint freshness, corrected scale) — behavior change disclosed in PR #5501. Kernel-side residuals (destructive action on unprovenanced evidence; truncate ignoring protected tools) tracked in a separate kernel authorization request.
[bot] 🏷 (ai: qwen/qwen3.8-27b) Merge conflict resolved and rebased onto current master. Summary of this run:
中文结构化结论(八问)
判定:冲突已清除、定向验证通过,PR 现处于正常等 CI/审批状态,本轮收工。 |
ranxianglei
left a comment
There was a problem hiding this comment.
(ai: vllm-qwen/qwen3.8-27b)
Round 3 review — head 8dede7d14 (rebased onto current master + two new commits)
Scope since round 2 (head ac098eeaa): the branch was rebased onto current master (58a879622) and gained two new commits. Real PR surface = 10 files, +901/-12 (config.ts, preflight.ts, request-membership.ts, server.ts, prepare-responses.ts, session.ts, 4 test files). No kernel/, no lockfile churn, no unrelated files.
Original fix survived the rebase intact (verified by grep at the new head): src/config.ts:727 step row { match: /^step-/i, limit: 1_048_576 }; src/preflight.ts:1832/1835/1928 anchorGradeOk gate on both entry reads; test pins intact.
New commit 22fe21cc5 — extend grade discipline to the remaining lastInputTokens readers. Closes my round-1 finding (two ungraded readers) plus a third I had missed:
src/request-membership.ts:70— the #4805 needle main-scale bar now refuses estimate-grade/unprovenanced scalars, falls back to the needle's own per-request scale. Honest in-body note: today the incoming payloadUpper rides the same char-bound caliber so the ratio self-normalizes; the gate is drift-robustness, not a live-inflation fix. Correctly scoped.src/server/prepare-responses.ts:609— codex compact-intercept minted usage no longer carries a char-bound arm (max(gradedScalar, est, 1)); the scales do NOT cancel here (est is chars/4 vs a poisoned char-count scalar) and codex recomputes its ledger from the minted body. Correct.src/session.ts noteAbortedTurn— untrustworthy meters skip the abort re-anchor stamp (a char-bound arm would delay the #5293 re-anchor ~4x and make #5415 bank phantom growth debt). Correct; dependent fixtures (issue5293/issue5415) updated to declare usage-grade provenance.
Tests T6a/b/c (membership: poisoned / graded-wins / legacy-fallback), T7 + T7-control (forged-usage e2e through the real intercept path), T8 (re-anchor skip-on-poison + stamp-on-usage with the #5415 debt arithmetic intact). Bidirectional (#3617). ✓
New commit 8dede7d14 — C6: cycle-stale meter rides the calibrated per-send estimate (v0.1.212 field follow-up). When the last cycle ended without a usage settle, effectiveTokenCount handed the kernel meter the CHAR-BOUND estimate, inflating it ~2–4x and crossing the kernel's DESTRUCTIVE emergency-truncate band (0.95×window) on measured-safe sessions, latching clips into the delivered view until the next fold (#3939 ③). Fix at src/server.ts:3012: cycle-stale now rides contextEstimateTokens (the billing-caliber k̂-scaled estimate stamped at the same relay chokepoint, cache-ledger.ts:1849), capped min(…, raw upper) so it can never exceed today's fail-closed worst case. I traced the control flow: the branch sits after the usage/grade branches (skipped while anchorStale) and before the #728 anchor-less fall-through; usageAnchorCycleStale (session.ts:951) requires lastInputTokensSource==="usage" so anchor-less sessions never enter it; an absent contextEstimateTokens degrades gracefully to the legacy reading. Preserves #4383's intent (per-send evidence outranks a frozen anchor) while removing the inflation.
Tests C6a (ride-on, both calibers), C6b (four UNCHANGED calibers: fresh-settle / #728 anchor-less / legacy absent-field / k̂-overshoot cap), C7 (e2e field chain: usage settle → no-report resend → repeat prepare; teeth-proven — reverted fix latches clips, applied fix stays unclipped), C7-control (the kernel band STILL fires on a genuine over-limit reading through the real node — C6 does not soften the band). Three #4383/#5134 assertions re-pinned from the char bound to the calibrated scalar (accurate). High quality. ✓
Behavior-change disclosures verified against code (body items 1–7): step window ~150000→≈786432 (native 1_048_576); preflight entry sizing under an ESTIMATE baseline; membership bar; codex minted usage; abort re-anchor; C6 meter feed min(contextEstimateTokens, raw)/"estimate" (was char-bound). All match. No wire-format / persistence / config-surface / kernel changes. No new config/env. No cache impact.
Kernel boundary respected: this PR touches NO kernel/ files and carries no kernel-change: declaration; the two kernel-side residuals (destructive action on unprovenanced evidence; truncate ignoring protected tools) are correctly routed to #5693 (p1, scope/kernel, needs-decision) instead of smuggled in. No 🔶 需要决策 trigger for this PR.
CI (mirror cache @ 8dede7d): 30 checks / failed=0 / pending=0 — fully green at this exact head.
House conventions: no as-any/@ts-ignore/console.error in the touched files; test-fixture cast style matches the existing suite; comments explain why; clean focused diff.
Verdict: APPROVE (可合). Human merge required — the step-family default window (150K→786K) is a fallback/default-value change, product-decision tier per §7.4. Note: GitHub hard-blocks same-account self-approval, so this lands as a COMMENT event carrying the APPROVE verdict (same constraint as rounds 1–2).
八问
- 是什么问题:#5500 会话死循环——step-* 模型窗口查表缺失(落 2e5 默认→实际墙仅 ~150K,真实窗口 1048576)+ char-bound 估算毒化(ESTIMATE-grade lastInputTokens 按字符尺度持久化、重放进每个后续请求)。本轮新增第三层缺陷(v0.1.212 现场):cycle-stale 降级把 char-bound 估算喂给内核计量器,放大 2–4× 越过破坏性 emergency-truncate 带(0.95×窗口),把截断夹进已交付视图并 latch。
- 什么原因导致的:(A) CONTEXT_LIMIT_TABLE 无 step-* 行→落 base.modelContextLimit 2e5 默认;(B) #604/#1498-F1 失败臂按字符尺度持久化 ESTIMATE-grade 锚点,除 preflight entry 两个读点外其余读点已有 grade 纪律;(C) effectiveTokenCount 的 cycle-stale 分支骑在 char-bound 标量上。本轮补齐了我上轮点名/遗漏的三个无 grade 读点(membership / codex forge / abort re-anchor)+ C6 计量器骑点。
- 影响范围与严重程度:p1。step-* 无显式配置的宿主(payload 介于真实大小与假墙之间→fail-fast 死循环);带中毒臂的会话(preflight entry 被抬高);cycle-stale 且测量安全的会话(误触发破坏性截断、工具输出被 clip 且 latch)。均为特定条件触发,非全量。
- 怎么修复的:补 step 表行到字段实测墙 1_048_576(gemini-3 行同形);preflight entry 两读点加 anchorGradeOk gate(镜像 baselineFloor);三个残余读点同样 kill-at-reader(#1839 纪律);C6 让 cycle-stale 改骑 billing-caliber 的 contextEstimateTokens(k̂ 缩放),并用 min(…,当前 raw 上界)封顶,保证永不劣于今日 fail-closed 最坏值。根因修复,不是遮症状。
- 是否有回归问题:无。逐项过:usage/overflow-arm 锚点分支、fresh-settle(#4383 回归护栏)、#728 无锚 never-reporting 车道、host preflight trigger、statusInputBaseline 显示读——全部不变(C6b 四标定 + C7-control 钉死);真实 over-window 拒绝未软化(C2-control / C3-control / C7-control 负向钉);依赖 fixture(issue5293/issue5415)已声明 usage-grade 出处。高危模式(fail-fast 变吞错、阈值漂移、输出格式变化)逐项过,无命中。
- 是否破坏缓存:不涉及。无缓存/重试/增量游标/去重键变更。
- 是否改了设计方向:无。沿用既有 kill-at-reader 与 billing-caliber 估算机制,未转向新架构/边界/数据流。
- 是否引入新配置:无。复用既有 stats 字段(contextEstimateTokens/localInputEstimate),无新 env/config/默认值。
判定:可合(APPROVE),需人工 merge(step 家族默认窗口属 default-value 变更,§7.4 human-only)。
[review-lane r1] PR #5501 head 8dede7d 复审完成 — 可合 (APPROVE, review id 5852658993)。本轮分支已 rebase 到当前 master(58a8796)并新增两个提交:22fe21cc50(把 grade 纪律补到我上轮点名的两个无 grade 读点 + 第三个我漏掉的 abort re-anchor 读点)、8dede7d140(C6:cycle-stale 计量器改骑 billing-caliber 校准估算,修 v0.1.212 Windows/Pi/Responses 现场误截断)。原修复(config.ts step 行 1_048_576 + preflight entry anchorGradeOk gate)rebase 后完整保留。真实面 10 文件 +901/-12,无 kernel/、无 lockfile churn;kernel 侧残留(truncate 无视 protected tools / ProcessTurnInput 无证据等级)已由作者正确路由到 #5693(p1/kernel/needs-decision,现已关),本 PR 不触碰 → 无 🔶 需要决策。CI 镜像缓存 @8dede7d14:30 checks / failed=0 / pending=0 全绿。行为变更披露(7 项)逐条与代码核对一致。合并需人工(step 家族默认窗口 |
[bot] 🏷 (ai: vllm-qwen/qwen3.8-27b) PR #5501 head 本轮增量:分支已 rebase 到当前 master( (详细八问见上条 FLOOR 19 与 GitHub review 正文。) |
…amily 1M window (#5500) Two independent defects compounded into the 'context ~N tokens exceeds the model window' fail-fast loop reported in #5500: C1 (window miss): CONTEXT_LIMIT_TABLE had no step-* row, so step-family models fell to the base.modelContextLimit 2e5 default (~150K effective window) despite serving 1M. The miss stranding is the #852 anti-pattern (too-small guesses never self-heal). Add the row from field evidence (nvidia_nim/stepfun-ai/step-5-preview enforces max_input_tokens=1048576). C2 (char-bound poisoning): the #604/#1498-F1 failure arm persists an ESTIMATE-grade lastInputTokens at char-bound scale (~4x tokens) into stats_json, replayed into every later request. Every reader except the preflight ENTRY was already grade-disciplined (#1839 kill-at-reader); the entry's currentTokens init and entryTokens floor were the last ungraded consumers, inflating overshoot budgets on every request after restart. Apply the per-round floor's exact discipline (#1492) to both entry reads. usage/overflow-arm anchors still floor; unknown-baseline regime and the #604 kernel truncate rescue consumer are untouched.
…#5500) Round 2 of #5500 (review finding on this PR): three more readers of stats.lastInputTokens lacked the lastInputTokensSource grade discipline the rest of the codebase applies (#1839 kill-at-reader): - request-membership.ts: the #4805 needle main-scale bar now refuses estimate-grade/unprovenanced scalars, falling back to the needle's own per-request scale (calibers self-normalize today; the gate is drift-robustness). - prepare-responses.ts: the codex compact-intercept minted usage no longer carries a char-bound arm — est is chars/4 while a poisoned scalar is char-count scale, so the scales don't cancel, and codex recomputes its ledger from the minted body. - session.ts noteAbortedTurn: an untrustworthy meter is skipped (a char-bound arm would delay the #5293 re-anchor ~4x and make #5415 bank phantom growth debt). Tests: membership/forge/reanchor pins both directions (#3617) in the issue5500 suite; issue5415/issue5293 fixtures now declare their usage-grade provenance.
Round 3 of #5500 (field report on v0.1.212, Pi/Responses lane): when the last cycle ended without a usage settle, effectiveTokenCount handed the kernel meter the CHAR-BOUND estimate (min(localInputEstimate, raw upper)), inflating it ~2-4x over the measured size. On a session whose measured usage sat safely under the window, that inflation crossed the kernel's destructive emergency-truncate band (0.95x), clipping tool output into the delivered view where it latches until the next successful fold (#3939). The freshness demotion itself is intended (#4383); the defect was the scale of the ride-on scalar. C6: cycle-stale now rides contextEstimateTokens — the billing-caliber per-send estimate stamped at the same relay chokepoint (k-hat scaled where route+model provenance matches), the same replacement reading staleSmallAnchorFallback returns for its own demotion class — capped by the current payload's own upper bound so it can never exceed today's fail-closed worst case. Usage/overflow-arm anchors, fresh-settle, the Regression: C6a/b unit pins (ride-on + four unchanged calibers), C7 reproduces the field chain end-to-end (usage settle -> no-report resend -> repeat prepare; pre-fix the clips latch), C7-control pins the kernel band intact. Three #4383/#5134 assertions re-pinned from the char bound to the calibrated scalar (same chokepoint freshness, corrected scale) — behavior change disclosed in PR #5501. Kernel-side residuals (destructive action on unprovenanced evidence; truncate ignoring protected tools) tracked in a separate kernel authorization request.
8dede7d to
56a7fe2
Compare
[bot] 🏷 (ai: qwen/qwen3.8-27b) This trigger's "dirty" premise was stale — verified live before touching anything: at run start the PR was already
中文结构化结论(八问)
判定:分支已收敛到当前 master(除零重叠的最新一笔)、定向验证通过、无冲突;等 CI 在 |
Closes #5500
Summary
The reported failure loop (
502 context ~204011 tokens exceeds the model window 150000 ... with 0 compressible range(s) still visible) was TWO independent defects compounding:Defect A — window lookup miss.
CONTEXT_LIMIT_TABLEhad no step-family row, sostep-5-preview-free(real window 1048576 per the reporter's deployment config + models registry) fell to thebase.modelContextLimitenv default 2e5 → ~150K effective window. Payloads between their true size and that false wall tripped the preflight trigger and died in the fail-fast loop although upstream would have accepted them. Per the #852 doctrine too-large guesses self-heal on the first upstream overflow; too-small ones strand — this was the stranding side.Defect B — char-bound estimate poisoning. The #604/#1498-F1 failure arm persists an ESTIMATE-grade
lastInputTokensat char-bound scale (estimateCoreMessagesUpper≈ 4x the token count) into stats_json, replayed into every later request. Every reader of that value is already grade-disciplined (#1839 kill-at-reader:effectiveTokenCountbranch 1,statusInputBaseline#2029,baselineFloorRaw,noOverflowEvidence, the preflight per-round floor #1492) — EXCEPT the preflight ENTRY reads: thecurrentTokensinit and theentryTokensfloor fed the #1933-F3 overshoot budgets from the poisoned arm on every request after restart. This applies the per-round floor's exact discipline to those two entry reads.Changes
src/config.ts:{ match: /^step-/i, limit: 1_000_000 }row (field evidence cited inline).src/preflight.ts:anchorGradeOkgate on the two entry reads, mirroringbaselineFloorat preflight.ts:2144. usage/overflow-arm anchors still floor; the unknown-baseline (fork 会话 lastInputTokens=0 时 preflight 退化为字符估算,大载荷被低估后不压缩直接裸转上游 #553) regime is untouched; the arm emergency shrink on upstream failure to break relay-5xx deadlock #604 kernel truncate-rescue consumer (providerInputTokensin prepare-anthropic) is deliberately untouched.tests/issue5500-char-bound-poison.test.ts: table row + negative controls; entry-budget discipline asserted BOTH directions (Test Blind Spot Retrospective: Reinforcing Negative Assertion Discipline, Tightening Fake Upstream Strictness, Thin Inst | 测试盲区复盘:补反向断言纪律、假上游严格化、薄安装冒烟、形态矩阵与生命周期覆盖 #3617); e2e reproducing the issue shape through the REAL window-resolution chain (pre-fix: lookup miss → ~150K wall → deterministic exhaustion → fail-fast ≥400; post-fix: 1M native window → clean forward, zero summarization calls); control pinning that a MEASURED usage-grade overflow is still rejected.Behavior changes (old → new)
^step-models without an explicit per-route/per-model override: ~150000 → ≈786432 (the new table row resolves native 1_048_576 — the field-enforced wall cited in localInputEstimate persists the char-count upper bound (~4x char/token) and poisons every later request; with a small window preflight then reports "exceeds the model window" on a 2.4x-overestimate #5500, same shape as the gemini-3 row; the per-request output-headroom reservation subtracts min(maxOutput, 25%×window) exactly as before, so ≈786432 when the 25% cap binds and closer to 1M for small maxOutput requests). Explicit configs still win (precedence chain unchanged).entryTokens/currentTokensinit — entry sizes on the per-request measurement instead. usage/overflow-arm anchors unchanged; the arm emergency shrink on upstream failure to break relay-5xx deadlock #604 kernel truncate rescue unchanged; fitting payloads still forward even when the summary lane 429s (fix: honor anthropic-beta context-1m to size the context window #301/The symptom is that switching models causes a hang, suspected to be triggered by dsh native compression. | 症状是切模型卡住疑似触发 dsh 原生压缩 #4288 preserved, now explicitly pinned).Notes
Round 2 — remaining ungraded readers (folded in from review of this PR)
A class sweep after review found three more
stats.lastInputTokensreads without the same grade discipline — the same mechanism family as Defect B, fixed here rather than split out (one mechanism, one PR):src/request-membership.ts(Bypass requests overwrite the main session's usage anchor, causing long sessions to permanently stop compressing. | 旁路请求覆盖主会话 usage 锚点,导致长会话永久停止压缩 #4805 membership probe): the needle’s main-scale bar now refuses estimate-grade/unprovenanced scalars and falls back to the needle’s own per-request scale. Honest note: the incomingpayloadUpperrides the SAME char-bound caliber (localInputEstimate) today, so the ratio self-normalizes — this gate is drift-robustness, not a fix of a live inflation.src/server/prepare-responses.ts(codex compact-intercept minted usage): the mintedinput_tokensno longer carries a char-bound arm —estis chars/4 while a poisoned scalar is char-count scale, so the scales do NOT cancel here; codex recomputes its ledger from the minted body, so an inflated mint would skew it until the next real report.src/session.tsnoteAbortedTurn(In pi, Esc triggers compression injection. | pi中esc会触发压缩注入 #5293/In 0.1.210, sessions with frequent interruptions barely trigger compression reminders — tokens accumulate to 330k before | 中断频繁的会话在 0.1.210 里压缩提醒几乎不触发,积到 33 万 token 才压一次 #5415): untrustworthy meters are skipped when stamping the abort re-anchor flag. A char-bound arm would delay the In pi, Esc triggers compression injection. | pi中esc会触发压缩注入 #5293 re-anchor ~4x and make In 0.1.210, sessions with frequent interruptions barely trigger compression reminders — tokens accumulate to 330k before | 中断频繁的会话在 0.1.210 里压缩提醒几乎不触发,积到 33 万 token 才压一次 #5415 bank PHANTOM growth debt (anchor − reference at char-bound scale) into the nudge cadence.Additional behavior changes (old → new):
input_tokens = max(graded scalar, raw-body est, 1)(wasmax(any scalar, est, 1)). Narrow path: codex host +BILI_CODEX_COMPACT=intercept+ compact-form request + healthy ACP state.Round-2 tests: T6a/b/c (membership: poisoned / graded-wins / legacy-fallback), T7 + T7-control (forged usage e2e through the real intercept path: poisoned → raw-body estimate; usage-grade 12K → exactly 12K), T8 (re-anchor: skip-on-poison + stamp-on-usage with the #5415 debt arithmetic intact). issue5415/issue5293 fixtures now declare their usage-grade provenance.
Notes
Round 3 — v0.1.212 field follow-up: cycle-stale × destructive emergency-truncate band (commit 8222bc4)
A field report on v0.1.212 (Windows / Pi / Responses lane) showed the CYCLE-STALE demotion (#4383 — last send's usage report never settled) handing the kernel meter the char-bound estimate (
min(localInputEstimate, raw upper)), inflating it ~2.4–4x over the measured size. On a session whose measured usage sat safely under the window, that inflation crossed the kernel's destructive emergency-truncate band (truncate.threshold= 0.95 × window) — false clips then LATCH into the delivered view until the next successful fold (#3939 ③). The freshness demotion itself is intended (#4383); the defect was the SCALE of the ride-on scalar. Verified line-by-line against both v0.1.212 and master before fixing.Fix C6 (
src/server.tseffectiveTokenCount): cycle-stale now ridescontextEstimateTokens— the billing-caliber per-send estimate stamped at the SAME relay chokepoint (k̂-scaled where route+model provenance matches), i.e. the same replacement readingstaleSmallAnchorFallbackalready returns for its own demotion class — capped bymin(…, current raw upper)so it can never exceed today's fail-closed worst case. This preserves #4383's intent (per-send evidence outranks a frozen anchor: 150K ≠ the frozen 4733) while removing the 2–4x inflation.Additional behavior change (old → new):
min(contextEstimateTokens, current raw upper)/ "estimate" (was:min(localInputEstimate, raw upper)/ "estimate" — char-bound scale). Affects the nudge tiers, the EMERGENCY truncate band, the terminal escape and the absorb view — all of which read this one value. UNCHANGED: usage/overflow-arm anchor branches, fresh-settle ([Bug] statusInputBaseline falls back to lastUsageGradeTokens instead of the calibrated local estimate — so one 4.7k side-request sample blocks folding for 4 hours | #1595 承诺的"改用本地估算"兜底在 statusInputBaseline 里没有实现,一次 4.7k 侧请求样本即可挡住折叠 4 小时 #4383 regression guard), the [Bug] 上游从不报告 usage 时 nudge 永不触发——上下文无界增长直到超窗(ChatGPT 登录态后端) #728 anchor-less never-reporting lane (shared fall-through untouched), the host preflight trigger (does not consume this value), andstatusInputBaselinedisplay reads. Three [Bug] statusInputBaseline falls back to lastUsageGradeTokens instead of the calibrated local estimate — so one 4.7k side-request sample blocks folding for 4 hours | #1595 承诺的"改用本地估算"兜底在 statusInputBaseline 里没有实现,一次 4.7k 侧请求样本即可挡住折叠 4 小时 #4383/[Bug] Pre-deduction count after T1 compression is overwritten by a stale usage rollback, immediately followed by a false | [Bug] T1 压缩后的预扣计数被旧 usage 回退覆盖,紧接着误触发 T2 #5134 regression assertions re-pinned from the char bound to the calibrated scalar (same chokepoint freshness, corrected scale — one test's own message already claimed "its calibrated estimate wins"; it is now literally true).Kernel-side residuals — NOT in this PR (require owner approval per Kernel Boundary rules 1+3, filed as #5693, p1): (a)
ProcessTurnInputcarries no evidence grade, so the destructive node could still act on a mis-calibrated estimate (proposed: optionaltokenCountSource, refuse clipping when an unmeasured reading is contradicted by a sub-threshold usage-grade anchor); (b)truncateLargeToolOutputsignores protected tools entirely — noisMessageProtected, noALWAYS_PROTECTED_TOOLS(compress/acp_rule), noconfig.protectedTools— a Kernel Boundary rule 6 ("protected-tool hard exclusion") violation even at genuine overflow. Same node, same failure domain as the field damage → one checklist in that request. Cross-links: #5217/#5255 (same-node siblings, distinct mechanism), #3691 (latch design origin — why false positives are expensive).Round-3 tests: C6a/C6b (ride-on both directions + four unchanged calibers: fresh-settle / #728 anchor-less / legacy absent-field / k̂ overshoot cap), C7 e2e reproducing the exact field chain (usage settle → no-report resend → repeat prepare; teeth-proven: with the fix reverted the clips latch into the delivered body, with it applied the session stays unclipped), C7-control (the kernel band itself still fires on a direct over-limit reading through the real pipeline node).
Local verification (this head): targeted suites green — issue5500 15/15; effectiveTokenCount consumer batch (issue4383×2, silent-backend-nudge, fork-nudge-deadzone/trigger, issue1839, issue1492, issue1820, issue2033, issue2029, issue5134, first-sight-drain-wire) 50/50; neighbor batch (issue4288, preflight-fail-fast, issue1933, issue5415, issue5293, issue4805, codex-compact + codex-compact-e2e, wire-contract) 96/96; typecheck clean. Full-suite verdict = CI on this head.