Files
Jyotisha/PROGRESS-billing-pricing-20260830.md
T

7.1 KiB
Raw Blame History

计费闭环与功能级定价进度(2026-08-30)

任务 0 · 真实单位成本门控

已完成只读聚合端点:frontend/src/app/api/admin/usage/aggregate/route.ts

  • 权限:billing.orders.read
  • 窗口:最近 30 天
  • 输出:每个预留功能的 runsavgp50p95max,覆盖 cost_microusdinput_tokensoutput_tokensduration_ms
  • 无数据:hasData=false,统计值为 null,不会静默伪造为 0
  • report.full:当前账本 0 行,这是报告接入计费前的已知空缺

当前可见数据库观测

本机 jyotisha-local-preview-postgres-1(不是 staging/production)截至 2026-08-30 的最近 30 天账本:

feature_key runs cost p50 cost p95 input p50 output p50 duration p50
chat.standard 0 无实测数据 无实测数据 无实测数据 无实测数据 无实测数据
rectification 3 0 0 110566 5835 52879
report.full 0 无实测数据 无实测数据 无实测数据 无实测数据 无实测数据

上述 3 条校正账本行的 request_id 都是 rectification:case:<caseId>,每个 case 只有 1 行。代码链路确认 runV9AgentTurn 在一次 agent run 结束时调用 billing.complete({ ...outcome.usage, durationMs }),而 outcome.usage 来自该次 run 的 result.totalUsage;它不是跨 case 多轮累计值。当前本机发布模型的 input/output 单价也都是 0,因此这组本地 cost=0 不能作为生产定价依据。

门控结论:未取得 staging/production 的非零真实单位成本,禁止写入任何新价格数字、会员公平使用数字或价格种子。

尚未执行

任务 1–6 依赖任务 0 的真实成本口径;在取得可审计的 staging/production 聚合数据前,不接入会导致线上默认失败的空定价配置,也不修改商品售价或公平使用参数。

任务 3 · 功能级定价服务端配置

已完成结构与后台管理接线:

  • 新增 public.feature_pricing,按 feature_key × model_tier × version 保存草稿、发布、退休状态;迁移事务化、幂等、RLS 与 service/admin runtime 权限均已配置。
  • 新增 resolve_feature_pricing(feature_key, model_id):只解析 published/enabled 模型与价格;模型或价格缺失时分别 fail-closed 为 feature_pricing_model_unavailable / feature_pricing_missing
  • 新增 security-definer 管理函数 admin_save_feature_pricing_draftadmin_publish_feature_pricing,均要求既有权限、原因与 request id,并写入 admin 审计日志。
  • 新增 /admin/feature-pricing/api/admin/feature-pricing,前端不携带默认价格数字;价格只来自服务端配置。
  • 已为 profile.extra / report.export 预留 feature key,未接入业务路径。

本轮必要地更新了 database-local-business.test.ts 的 schema 表清单:原断言锁定基线表集合,本迁移有意新增 feature_pricing,因此仅补入该表并在断言旁注明原因。

验证:

  • ./node_modules/.bin/tsc --noEmit:通过
  • ./node_modules/.bin/tsx --test tests/feature-pricing-contract.test.ts2 通过
  • npm run test:db34 通过,0 失败;Docker 中 migration apply 与业务 schema 检查通过

价格门控仍生效:没有 staging/production 非零真实成本前,migration 未写入任何价格 seed。

任务 1 · 报告生成计费

已接入 report.full 的完整 reserve → complete/release 闭环:

  • 日限检查之后、创建报告之前 reserve;创建或入队失败立即 release。
  • inline 成功 completedurable worker 成功 complete,终态失败 releaseretryable failure 在重试耗尽前不 release。
  • request id 使用既有 payload.requestId,保持幂等。
  • token 按 plan、章节、summary、repair 的实际调用累计后 complete;不使用伪造的固定 token 数。

任务 2 · 校正按功能定价

已接入 resolveFeaturePricing(accounting, "rectification", selectedModel.id),不再把模型 creditCost 当作校正价格。继续使用既有 case 级幂等键 rectification:case:<caseId>,未修改公平使用、配额或 model_not_included SQL 校验。错误响应区分点数不足、分钟/日/月公平使用限制与 billing denied。

任务 3 · 对话按功能定价

已接入 resolveFeaturePricing(accounting, "chat.standard", model.id),仍使用既有 reserve_consultation_usage RPC,仅替换 p_credit_cost 的来源为服务端已发布功能价格。

任务 4 · 上下文缓存

Blocked/skipped:当前没有 staging/production 的真实成本与 provider 缓存能力证据;本轮不接缓存,也不引入 provider 特殊降级逻辑。待有真实成本与 provider 级缓存计价/兼容性数据后再单独评估。

任务 5 · 会员档参数与权益

Blocked:未取得 staging/production 非零真实单位成本,不能重设 minuteLimitdayLimitbillingLimit,不能移除 rectification / report.full 现有权益行,也不修改商品售价。保持现有公平使用与配额配置不变。

任务 6 · 管理端定价测算页

已完成只读 /admin/pricing-simulator

  • 数据来自模型价格、功能定价、商品/权益与账本聚合端点;页面仅调用 GET,未提供保存价格入口。
  • 单功能、会员平均/打满、盈亏平衡与 21 秒串行日吞吐/会员承载量均由纯函数实时计算。
  • 权重不为 1 时自动归一化;billingLimit=null 显示不限;账本无数据显示“无实测数据”,不转成 0。
  • 模型价格为 0、账本无数据、权重归一化与不限配额均有单测。
  • 空数据、分布权重、汇率固定规则之外的固定成本与用户画像均保持“假设/待填”语义;未写入任何价格 seed。固定换算规则为 1 元人民币 = 10 积分。

验证与剩余环境缺口

已通过:

  • ./node_modules/.bin/tsc --noEmit
  • ./node_modules/.bin/tsx --test tests/personal-report-api.test.ts tests/personal-report-worker.test.ts tests/feature-pricing-contract.test.ts tests/application-billing-contract.test.ts tests/pricing-simulation.test.ts72 passed
  • npm run lint0 errors23 个既有 warnings
  • npm run test:db34 passed0 failedDocker migration/schema tests
  • npm run build(成功;仅既有 Turbopack dynamic filesystem tracing warnings

npm run db:migrate:check 尚未能执行有效检查:环境未提供 SCHEMA_DATABASE_URL,命令会 fail-closed 为 SCHEMA_DATABASE_URL is required。补充 schema database 连接串后需连续运行三次;当前不因该环境缺口修改迁移内容。

本轮不 push、不 merge、不 rebase;主工作树保持不变。

全量测试补充

./node_modules/.bin/tsx --test tests/*.test.ts2369 passed1 failed。唯一失败为既有的 tests/staging-backend-workflows.test.ts YAML 语法检查,失败原因是运行环境的 Python 缺少 yaml 模块(ModuleNotFoundError: No module named 'yaml');本轮未修改 .gitea/workflows/**,因此不是本轮回归。该环境缺口未通过新增依赖绕过。