Skip to content

[PR] fix: panel "saved $" replay cost priced at input tier instead of cache-write tier (#4956) - #4963

Open
ranxianglei wants to merge 6 commits into
masterfrom
2026-10-27_saved-panel-cache-write-price
Open

ranxianglei wants to merge 6 commits into
masterfrom
2026-10-27_saved-panel-cache-write-price

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

(ai: vllm-qwen/qwen3.8-27b)

Closes #4956

What

The panel's money mirror (savedUsd / ≈$ cards / break-even turns) computed the fold re-upload at (input−read)·T on the live-price path, while every other user of the fold formula's w prices the cache-WRITE re-upload: kernel computeFoldEconomics (kernel/src/cache-report.ts), the savedUsdFromFolds docstring (src/billing.ts), and priceProfileFromRow (src/registry.ts). The stamped-profile branch of the very same function already carried the write rate — so Anthropic-type tiers (3 / 3.75 / 0.3 / 15 $/Mt) read the replay term as 2.7·T instead of the contractual 3.45·T (net savings overstated; the issue's ~28% is the ratio 3.45/2.7), and the number jumped whenever a model left the registry.

Behavior changes (disclosed)

  • Write-premium providers: savedUsd / replayUsd / break-even move DOWN. Fixture session (S=50000, σ=5000, T=3000, 10 turns after): oneTime 68100 → 70350 units, savedUsd 0.0669 → 0.0647 (my earlier in-thread estimate of 0.0645 was an arithmetic slip; exact figure here). Net impact is shape-dependent — larger near break-even; the replay term itself changes 2.7 → 3.45 $/Mt on T.
  • No-write-premium providers are byte-identical — finalize() resolves cache_write ?? input, so w was already equal to input for them.
  • WebSessionSummary.rates / WebOverview.moneyRates gain an additive optional field i (input $/Mtok). Absent on stamped-only sessions (they have no input-priced face). Fleet uniformity now also requires agreeing i values before printing the fleet-level rate line.
  • Label wording: ov.net_rates / ov.payback_rates say write−read instead of input−read (zh+en); ov.miss_rates prints ${i} (input) instead of ${w}. The detail-page input card and the overview input-token card now annotate the input tier from i instead of w — they bill at input, so printing w there would have been a new mislabel introduced by this fix if left alone (third consumer the issue did not list).
  • Dead code removed: the second branch of the rates construction in summaryOf was unreachable — a defined livePrice always yields a defined usdProf, so its guard could never hold.

Not changed (deliberate, different mechanism)

  • Anchored dimensionless-ratio branch keeps w ≡ 1×input anchoring (user ratio convention, last-resort path for sessions with no resolvable price row).
  • missUsd bucket pricing (new content @ input, rebuild/repay @ read) and the fold-less flat estimate (@ input) — those quantities genuinely bill at input.
  • Dollar-face override surface stays billing.prices (absolute $/Mt, wins over the models.dev snapshot); compress.priceProfile remains the dimensionless stamped-path profile. (The issue's 顺带确认, answered in-thread.)

Tests

tests/billing-web.test.ts: expectations re-derived at the write tier; #3617 both gate legs pinned — positive leg: fixture row carries cache_write: 3.75 ≠ input 3 ⇒ rates.w must be 3.75; negative leg: override row WITHOUT cache_write ⇒ w falls back to input (6). Targeted suites green locally (billing-web 7/7, billing-prices 10/10, typecheck + build clean); full regression = CI on this head.

No config-surface change. No kernel/ change. No version bump.

The live-price branch of savedUsdProfileForSummary fed the fold formulas w the INPUT rate while every other user of w (kernel cache-report, stamped profiles, registry priceProfileFromRow) uses the cache-WRITE rate: the panel understated the replay term (2.7*T vs contractual 3.45*T for Anthropic-type tiers) and the number jumped when a model left the registry, where the stamped branch already carried the write rate.

- live branch returns {w: cacheWrite, r: cacheRead, q: output}
- exposed rates/moneyRates gain additive optional i (input $/Mtok); the spend/miss/input-card faces that bill new content at input print i, not w (detail page, overview input card, miss-rate lines)
- labels ov.net_rates/ov.payback_rates reworded input->write (zh+en); ov.miss_rates takes ${i}
- removed the unreachable second branch of the rates construction (defined livePrice always implies defined usdProf)
- tests: expectations re-derived at the write tier; #3617 both gate legs pinned (cache_write present => w=3.75; absent => w falls back to input)
@ranxianglei ranxianglei changed the title fix: panel "saved $" replay cost priced at input tier instead of cache-write tier (#4956) [PR] fix: panel "saved $" replay cost priced at input tier instead of cache-write tier (#4956) Oct 27, 2026
@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

📦 Built Package Artifact

Branch: 2026-10-27_saved-panel-cache-write-price (7afc599)

Latest build — install this exact version

npm install -g billion-context@0.0.7381-pr.4963.2b2ed39

This exact version is immutable and reproducible. The rolling pr tag tracks the newest test build across all PRs.

Recent builds (commit → version)

commit version build
7afc599 billion-context@0.0.7381-pr.4963.2b2ed39 build
2863394 billion-context@0.0.7179-pr.4963.4c8667e build
cbb31bd billion-context@0.0.7119-pr.4963.da6bf34 build
8818aef billion-context@0.0.6872-pr.4963.c15b02e build
7a3f4fd billion-context@0.0.6498-pr.4963.decadc0 build
b398c33 billion-context@0.0.6475-pr.4963.5a7d8a1 build

Download artifact

  1. Download the artifact from the Actions run
  2. Extract the tarball and install:
tar xzf billion-context-pr4963.tgz
npm install -g package

Install instructions are refreshed on each push.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 (ai: vllm-qwen/qwen3.8-27b)

查重: 不重复 —— 检索 open/closed issue 与 PR(「panel saved dollars replay cost price tier」「savedUsd cache write tier pricing」等失败签名),无同机制在途条目;本 PR 即 #4956 的唯一修复线。

标签: bug / scope/ui / p2(面板美元数字算错——缺陷、界面域、能用但数字失真,有绕行即忽略 $ 卡)。

已开始独立审核:已拉取分支 2026-10-27_saved-panel-cache-write-price(单 commit b398c3365,与 master c499b1450 零漂移),四个文件的 diff 全部通读完毕,正在本地做定向验证(billing-web 套件 + typecheck/build)并核对 CI 状态。结论稍后按八问体例给出。

@ranxianglei ranxianglei added bug Something isn't working p2 scope/ui labels Oct 27, 2026
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

Review 结论:可合。 独立审核完成(未复读 #4956 线程结论),代码、测试、CI 全部亲自核验。

审核过程(独立重做)

  • 逐行通读全部 diff(4 文件:sessions-data ±45 / client ±12 / i18n ±12 / billing-web.test ±39);单 commit b398c33,与 master(c499b14)零漂移。
  • 独立确认根因判断:savedUsdProfileForSummary live 分支喂给折叠公式的 w 是 input 价,而其余所有 w 消费方——kernel computeFoldEconomics(cache-report)、priceProfileFromRow(src/registry.ts:472,cache_write ?? input)、savedUsdFromFolds docstring(src/billing.ts)、同一函数的 stamped 分支——全用 cache-write。同一函数两分支不一致 = slip,不是设计;契约方(registry + kernel)明确。
  • 独立验证「无写溢价 provider 不变」保证:finalize()(src/billing.ts:177)cacheWrite ?? input ⇒ 无写溢价时修复前后 w 都等于 input,数字逐字节一致。
  • 清点 client.ts 全部 .w/.r/.q 消费点(gross_formula / at_read / at_output / payback_rates / 折叠表 / 输入卡 / miss 行):没有任何消费方在 .w 上期待 input 语义;miss 行与输入卡改挂新 i 字段——这两处真按 input 计费,若留在 w 上本修复会引入新错标(issue 没列的第三个消费方,处理正确)。
  • 确认被删「第二分支」确为死代码:sessions-data.ts:820-821,livePrice 有定义则 usdProf 必有定义(:685 live 分支恒返回)。
  • Test Blind Spot Retrospective: Reinforcing Negative Assertion Discipline, Tightening Fake Upstream Strictness, Thin Inst | 测试盲区复盘:补反向断言纪律、假上游严格化、薄安装冒烟、形态矩阵与生命周期覆盖 #3617 双向门是真门:正腿 fixture cache_write 3.75 ≠ input 3 ⇒ w 必须 3.75;负腿 override 行不带 cache_write ⇒ w 回落 6——负腿证明正腿读的是 cache_write 而非硬编码。
  • 本地定向验证:billing-web 7/7、billing-prices 10/10、web-sessions+web-i18n 38/38、typecheck + build 干净。
  • CI(b398c33 全量回归):全绿 —— test shards 11/11(ubuntu 22×3、ubuntu 24×3、windows 22×5)success,kernel-guard / version-guard / config-surface-guard / docs-sync / lock-sync / lane-guard / pi-subagents-guard / static-gates×2 / 其余 gate 全过;e2e zero-token 车道按设计默认 skip。

结构化八问

  1. 是什么问题:面板「省了多少钱」镜像把折叠回放成本按输入价算,而 kernel 折叠契约是 (写价−读价)·T——Anthropic 型价档(3/3.75/0.3/15 $/Mt)上回放项算了 2.7·T 而非 3.45·T,savings 系统性高估 ~28%,且与缓存报告、stamped 定价路径(后者一直用写价)自相矛盾。
  2. 什么原因导致的:savedUsdProfileForSummary live 分支写成 w: live.input,与其余全部 w 消费方(kernel cache-report / registry priceProfileFromRow / 同函数 stamped 分支)背离。属 slip:同一函数两个分支口径不一致,而契约侧(registry + kernel)是明确的。
  3. 影响范围与严重程度:仅面板展示面——用写溢价 provider 的用户看 savedUsd / ≈$ 卡 / break-even turns 时数字偏高;无数据丢失、无请求线影响、无功能停摆,绕行 = 忽略 $ 卡。p2。
  4. 怎么修复的:live 分支改返 {w: cacheWrite};input 价以增量可选字段 i 暴露给真正按 input 计费的展示面(miss 行、输入卡);标签措辞与实际算术对齐(net/payback 说写价−读价,miss 说 input);顺带删除不可达的第二分支。anchored 无量纲比例兜底分支刻意不动(用户比例约定,无价格行时的最后手段)。
  5. 是否有回归问题:逐项审过——无写溢价 provider 数字逐字节一致(finalize 回落已验证);client.ts 既有 .w 消费方全部要的就是写价;fleet 一致性判定对 w/r/q 保持原语义,i 仅在存在时参与判定、stamped-only 会话不阻塞 fleet 行;无 fail-fast 变吞错、无阈值/时序漂移;wire / 配置 / kernel 零触碰,两种压缩模式均不受影响。无意回归:无。有意行为变更已在 PR 披露:写溢价 provider 的 savedUsd / replayUsd / break-even 下移(fixture 0.0669 → 0.0647,replay 项 2.7 → 3.45 $/Mt)。
  6. 是否破坏缓存:不涉及——纯展示端计算,不触碰任何缓存 / 重试 / 增量游标逻辑。
  7. 是否改了设计方向:不涉及——把面板拉回既有 kernel 折叠契约,无新机制、无边界变化。
  8. 是否引入了新的配置:无。仅增量可选 API 字段 i(WebSessionSummary.rates / WebOverview.moneyRates,stamped-only 会话缺省),客户端已处理缺省(隐藏对应标签),无需迁移。

收工判定:可合。 修到根因(生产错误 w 的那一行),双向门钉死,行为变更披露完整,CI 全绿。未发现需要顺手小修或立项的遗留问题。

# Conflicts:
#	src/web/i18n.ts
#	src/web/sessions-data.ts
#	tests/billing-web.test.ts
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

Synced origin/master (7f2e119) into the branch — new head 7a3f4fd. Three conflicts (i18n.ts / sessions-data.ts / billing-web.test.ts) resolved by taking this PR's superset design: master's 058da0498 live-path fix is fully subsumed by #4963 (identical w=cacheWrite change + the added input-rate i leg), so no behavior was dropped from either side. Local validation on the merged head: typecheck ✓, build ✓, tests/billing-web.test.ts 7/7 ✓. Branch is no longer behind master; full-suite verdict with CI on the new head.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

CI 修复完成,新头 cbb31bd 已推送(merge ci-fixes 进 PR 分支)。八问:

  1. 是什么问题:三个红分片(ubu22-3/ubu24-3/win22-4)全是同一个失败——tests/plugin-fork.test.ts 的 [Bug][fork] Cold restore cannot use an intact unified raw tail for a non-retained parent (#4266 item 4) #5140 cold-tail 用例断言 200 收到 409(SNAPSHOT_UNAVAILABLE)。与本 PR 改动无关:本 PR 只动 src/web/sessions-data.ts/client.ts/i18n.ts + tests/billing-web.test.ts(面板 saved $ 计价),完全不碰存储/fork 路径。
  2. 什么原因导致的:不是 flake,是确定性环境错配——CI 的 preload-storage-baseline.mjs 给整个测试语料设了 BILI_STORAGE_UNIFIED=legacy,legacy 模式下没有 unified 行,forkSnapshot 冷 raw-tail 重建无源可取、fail-closed 返回 409;该用例自身没钉存储模式。本地双向复现钉死:legacy+未钉=409(与 CI 逐字一致)、legacy+钉=过、默认模式=过。
  3. 影响范围与严重程度:仅 CI 红挡合并;生产行为零影响(纯测试内 env 钉,finally 恢复 ambient 值)。
  4. 怎么修复的:merge origin/ci-fixes(含哨兵 commit 67f8e8940:该用例内钉 BILI_STORAGE_UNIFIED="full" + finally 恢复)进 PR 分支,同时带入最新 master 与 guard 修复。
  5. 是否有回归问题:无。本次 merge 对源码零改动(PR diff 仍是原 4 文件);typecheck/build 绿;定向验证 plugin-fork 55/55(在 legacy 基线下)、billing-web 9/9。
  6. 是否破坏缓存:不涉及。
  7. 是否改了设计方向:不涉及。
  8. 是否引入新配置:不涉及(BILI_STORAGE_UNIFIED 是既有 knob,只在单个测试进程内钉)。

重跑结果(cbb31bd):

判定:本 PR 自身范围可合;剩余 2 红为继承性 master 环境 flake,非本 PR 变更引入,不阻塞本 PR 审查结论。auto-lane 2/2 已用完,不再自动重试;若下轮重跑这两个 Windows 片仍红,走 #4599 收敛。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

Re-synced origin/master (44067a5) into the branch on top of the ci-fixes merge another lane had already landed (cbb31bd) — clean merge, zero conflicts; new head 2863394. The delta was disjoint from this PR's files (only src/persist.ts, src/plugin.ts, src/storage/shadow.ts + #5188's new test files). Local validation on merged head: typecheck ✓, build ✓, tests/billing-web.test.ts 9/9 ✓. PR state after push: open, mergeable=true (no conflicts), mergeable_state=blocked solely for CI on the new head.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 (ai: vllm-qwen/qwen3.8-27b)

Wrap-up for this merge-guard round: synced origin/master (44067a5) into the PR branch on top of the ci-fixes merge another lane had already landed — clean merge, zero conflicts, new head 2863394. Local validation green (typecheck ✓, build ✓, billing-web 9/9). PR state after push: open, no conflicts, mergeable_state=blocked only for CI running on the new head. Full details in the comment above.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

CI 修复完成,新头 7afc599 已推送。本轮 4 个红分片(win22-1/2/4 + ubu22-3)全部是继承性 master 红/环境 flake,与本 PR 改动无关(本 PR 只动 src/web/* 面板计价 4 个文件,不碰存储/fork/session 路径)。八问:

  1. 是什么问题:4 个红分片 = 4 个已知继承家族 + 1 个 runner flake,无一由本 PR diff 引入。
  2. 什么原因导致的:① issue4788-resident-minimal (a)-(d)(ubu22-3、win22-2):unref 的 debounced-save settle 后事件循环空转,父测试 hang、子测试 cancelledByParent 级联——根因修复([Performance] v0.1.208 long sessions exceed 2 GiB memory and spend 14–22 seconds in local processing #4788 phase 2,persist.ts ref-tracking)在 master@30ec63b55;② issue5103 win32 db-path(win22-2):shadow.ts 用 ${dir}/index.db 而 Windows 期望反斜杠 join;③ issue4739 EBUSY ×2(win22-4):teardown 时 Windows 无法 unlink 仍持有 sqlite handle 的目录——②③ 的修复来自外部贡献 PR [PR] ci-fixes convergence: port the four remaining master-red lanes (win32 db path, teardown handles, #5155 settle, #4788 timer host) #5262,哨兵已折进 ci-fixes 并合入 master;④ inc-canonical-pointers cold rebuild 409(ubu22-3):[Bug][fork] Cold restore cannot use an intact unified raw tail for a non-retained parent (#4266 item 4) #5140 瞬态竞争家族 flake(CI Control Center: Centralized CI Failure Handling & Status Sync (Comment all CI issues here; do not open new issues) | CI 总控: CI 失败集中处理与状态同步(所有 CI 问题在此评论, 勿开新 issue) #4599 有档);⑤ side-lane-invariants (B)fetch failed@76s(win22-1):Windows runner 资源耗尽——同文件兄弟子测试 (C)(D)(E)(E2) 紧随其后全部秒过,非逻辑回归。本头 2863394 只同步到 master@44067a5bc,恰好不含上述任何修复。
  3. 影响范围与严重程度:仅 CI 红挡合并;生产行为零影响(带入的全部是已合入 master 的提交)。
  4. 怎么修复的:merge origin/master@30ec63b55(该 tip 已含全部 ci-fixes@06ad804ac:[PR] ci-fixes convergence: port the four remaining master-red lanes (win32 db path, teardown handles, #5155 settle, #4788 timer host) #5262 两项修复 + [Performance] v0.1.208 long sessions exceed 2 GiB memory and spend 14–22 seconds in local processing #4788 测试适配 + 哨兵收敛)进 PR 分支,零冲突;新头 7afc599。
  5. 是否有回归问题:无。本次 merge 对本 PR 源码零改动(diff 仍是原 4 个 web 文件);typecheck/build 绿;在 CI 同款 legacy 存储基线(BILI_STORAGE_UNIFIED=legacy)下本地定向验证受影响的 7 套全绿共 95/95:billing-web 9/9(PR 自身)、issue4788 (a)-(d)、issue5103 首 ingest 警告、issue4739 full-mode ×2、plugin-fork 55/55(含 [Bug][fork] Cold restore cannot use an intact unified raw tail for a non-retained parent (#4266 item 4) #5140 pin)、inc-canonical-pointers、side-lane-invariants。
  6. 是否破坏缓存:不涉及。
  7. 是否改了设计方向:不涉及。
  8. 是否引入新配置:不涉及。

判定:本 PR 自身范围可合;本轮 4 红均为继承性失败,修复已随 master 同步进入分支,等重跑验证。无需 owner 决策(无设计取舍),故不开 decision request。auto-lane 1/1 已用完;若重跑仍有 Windows flake 残留,按 CI 协调政策走 #4599 收敛(已留一行结论)。

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working p2 scope/ui

Projects

None yet

1 participant