- cloud/usage.py(新):TIER_LIMITS 三档提案(Free $0/Paid $19/Heavy $99, 提案非定价,payload 带 proposal 标注)、TierStore(无档位行不受档位门 约束)、UsageLedger(追加写哈希链,篡改可发现)、UsageMeter(token 读 cost_records、消息读账本、并发/存储注入实测)、QuotaGate(纯准入判定, 402,不碰在跑任务)、80% 提醒每维度每窗口一次 - cloud/server.py:_reject_if_over_quota 内加档位门(同一漏斗,双人门 自动覆盖;查询异常 fail-closed 503)、GET /users/me/usage、 GET/POST /admin/tiers、存储实测复用 _task_worktree_for_files - docs/chv-muse-p11-gap.md:差距表(先写表再动手)+ 诚实边界(USD 路径 30 秒轮询掐断与“不掐断”语义不一致是已知待决;并发即拒与设计文档 排队不同;cloud 任务存储量不到;Heavy 消息/天提案未给,本轨定不限) - 测试 22/22,全量 1889 OK(skipped=8);mypy 在 usage.py 上干净, server.py 5 错均为基线旧错(marker_tools/sub2api/_row_get,与本轨无关) - 真机验证排队在 round-11 与 P4~P9 之后;不接真实计费
9.6 KiB
9.6 KiB
对齐 Muse P11 差距表:用量计量与配额执行
依据:~/workspace/research_notes/meta-muse-ai-architecture-20261101-0755/report.md
(官方帮助中心 / 新闻室 2026-09-08 为准;第三方转述只作参考,不得把
第三方转述的价格写成官方定价)。基线:06c3e17。先写表再动手。
§1 要求(官方 + 本项目提案)
| # | 要求 | 来源 |
|---|---|---|
| 1 | 免费但有使用上限;达到上限可升级付费订阅,或等免费额度刷新 | 官方帮助中心(报告 §1.5/§6) |
| 2 | 免费额度具体数字、付费档价格未出现在首发新闻稿中;Power/Maximum 等价格是第三方转述的帮助中心内容,不得写成官方定价 | 报告 §1.5、§5 表 |
| 3 | 三档档位与价格沿用本项目提案(用户 2026-11-06 委托“按市场定”,未确认为定价):Free $0 / Paid $19/月 / Heavy $99/月 | 本项目提案,见 §2 |
| 4 | 四项计量:token 数、消息数、并发任务数、存储量 | 本轨任务书 + 设计文档 §6.2 |
| 5 | 超限回 402;进行中回合不掐断,跑完才拦下一回合 | 本轨任务书 + 设计文档 §6.2 |
| 6 | 用量展示:用户可查当期用量与剩余额度;接近上限提醒一次(阈值默认 80%,本项目自定) | 本轨任务书 |
| 7 | 账本追加写、不可篡改;账本里绝不含对话原文、文件内容、密钥 | 本轨任务书 |
| 8 | 不接真实计费、不碰真实钱;计费对接(Stripe 等)待用户另行批准 | 本轨任务书 |
档位提案数值(提案,非用户确认定价,非官方定价):
| 档位 | 价格 | 消息/天 | tokens/月 | 并发任务 | 存储 |
|---|---|---|---|---|---|
| Free | $0 | 50 | 200,000 | 1 | 1 GB |
| Paid | $19/月 | 500 | 2,000,000 | 5 | 10 GB |
| Heavy | $99/月 | 不限(见 §5 第 4 条) | 20,000,000 | 20 | 100 GB |
§2 现状(基线 06c3e17 已有,可复用)
cloud/cost.py:CostStore:cost_records(task_id, project_id, model, tokens, usd_micros, source, day),actual(模型真实用量事件)与estimated(字符估算)永不混算;价格表是 OpenAI 挂牌价,注释明言 “不是 relay 的账单”;report_by_task/project/day,无report_by_user。cloud/db.py:user_quotas(user_id PK, quota_usd_micros, updated_at)。cloud/server.py:_quota_status(USD 月度配额,UTC 自然月)、_check_quota/_reject_if_over_quota(超限回 402quota_exceeded, 查询异常 fail-closed 回 503quota_check_unavailable)、_check_unpriced_token_cap(无价 token 上限,默认 20M/月,可配)、GET /users/me/quota、GET/POST /admin/quotas。 准入点是建任务 / 分支 / 重试 / 续跑 / goal-resume,均为权限校验通过后、 写库之前;_reject_if_over_quota_for_task双人门(触发人 + 原任务创建人)。- 全仓 grep 确认:
cost_records没有任何 UPDATE / DELETE 路径, token 账本已是追加写;本轨不再为 token 另建一套账本(见 §3 第 2 条)。
缺失:消息数计量、并发任务门、存储门、三档档位表、用量展示端点、
80% 提醒、账本防篡改校验、report_by_user。
§3 改动清单(本轨)
cloud/usage.py(新,标准库 +cloud.db/cloud.cost的常量口径, 不引 server):TIER_LIMITS:三档提案数值,模块 docstring 与每个返回 payload 都标注proposal: true(提案,非定价)。TierStore:user_tiers(user_id PK, tier, updated_at),get_tier/set_tier(非法档位名拒绝);无档位行的用户不受档位门约束, 只受既有 USD 配额约束——定档是管理员显式操作,不给存量用户 默认套 Free(否则上线即拦住所有人)。UsageLedger:usage_ledger追加写哈希链账本(prev_hash+entry_hash = sha256(规范 JSON)),record/sum_kind/verify_chain(篡改返回首个坏行 id)。记消息、任务起止、存储 快照、提醒事件;token 事件不重复记(见第 2 条)。UsageMeter:月度 token(读cost_recordsJOINtasks,与_quota_status同款查询,actual / estimated 分开列)、当日消息 (读账本)、并发(注入running_task_count,状态queued/running)、存储(注入storage_bytes,磁盘实测)。summary(user_id):四项 used / limit / remaining + 提醒 + 账本 校验结果。QuotaGate:check_task_admission(token + 并发 + 存储)、check_message_admission(消息/天 + token/月)。返回 None 放行, 否则否决 dict(error: quota_exceeded+dimension+limit/used+ 可读detail);纯准入判定,无任何终止在跑任务的 API(进行中回合不掐断,见 §5 第 1 条)。disk_usage_bytes(path):递归求和,不跟随符号链接,读错跳过 (尽力而为,调用方在 payload 里标明实测范围)。- 提醒阈值默认 0.8,环境变量
CLOUD_USAGE_WARN_RATIO可配; 每维度每窗口只记一次提醒(账本kind="warning"去重)。
- token 计量口径:以模型方返回为准(
source="actual");无返回时 字符估算(source="estimated",payload 标注为估算)。档位门只计 actual——与cost.py的 P1 决定一致(“Estimated rows are never real spend and must not trip the cap”);estimated 只展示、不拦人。 但 payload 同时列出 estimated 数,让用户看得见估算占比。 cloud/server.py接线(只动配额漏斗,不新增调用点):_reject_if_over_quota内、USD 门与无价 cap 通过后,加档位门 (同一quota_user_id);档位查询异常同样 fail-closed 回 503。_reject_if_over_quota_for_task不动(它已委托给前者,双人门 自动覆盖)。GET /users/me/usage(_user_usage_self):当期用量与剩余额度- USD 配额合并返回 + 提醒 + 账本校验结果。
GET/POST /admin/tiers(_admin_tiers_get/set,_is_global_admin同款鉴权):管理员定档 / 查档。- 存储实测:复用
_task_worktree_for_files逐任务解析本机 worktree 求和;cloud / cloud-hypervisor 任务不在本机,量不到,计 0 并在 payload 里标明storage_measured_tasks/storage_total_tasks。
cloud/tests/test_usage_quota.py(新):档位数值钉住提案、非法档位 拒绝、无档位行不限档位门、token actual/estimated 口径、消息固定 UTC 日窗口、并发门、存储门与清理指引、账本哈希链与篡改发现、提醒 只发一次、准入纯判定不碰在跑任务、服务端点(/users/me/usage、/admin/tiers、档位门 402)。docs/chv-production-readiness.md:补 P11 一节。
§4 真机待验证清单(未做,排队在 round-11 与 P4~P9 之后)
- 真实 token 回传下的月度累计与 402(actual 行累计、无价模型走 既有 cap 不走美元门)。
- 并发门在真实多任务下(建第 N+1 个任务被拒,在跑任务不受影响)。
- 存储门在真实 worktree 下(本机任务目录求和、cloud 任务不计入)。
- 80% 提醒在真实使用下只发一次、跨窗口重置。
- 账本在真实写入压力下的链完整性(并发写不丢链不断)。
§5 诚实边界(本轨内不解决,写清不冒充)
- 进行中回合的语义不一致(已知待决):设计文档 §6.2 与本轨
任务书说“进行中的回合不中途掐断”;但基线
_check_quota的 docstring 与 worker 实现是另一套——Local popen 与 Docker 路径的 worker 轮询每 30 秒查一次 USD 配额,超限杀进程组/容器(掐断粒度 是轮次边界 + 30 秒检查)。本轨新增的四项档位门只做准入, 不改既有 USD 路径的轮询掐断;两处语义不一致是已知待决项, 不在本轨内悄悄统一,须由父级另行裁决。 - 并发超限的处理与设计文档不同:设计文档 §6.2 说并发超限 “新任务排队,不立即拒绝”;本轨任务书(父级指令)说“即拒并 给出可读原因”。本轨按任务书即拒,差异记在此。
- 存储计量不完整:cloud / cloud-hypervisor 任务的 worktree 不在本机,量不到;本机也只能按任务 worktree 求和,用户在 VM 内或其它路径的占用不在计量内。payload 标明实测范围, 不冒充全量。
- Heavy 消息/天提案未给:提案原文只给了 Heavy 的 tokens / 并发 / 存储,未给消息/天。本轨定为不限,并标注为本项目决定, 不是提案原文、不是官方口径。
- 窗口口径:token 按 UTC 自然月(与既有 USD 配额一致); 消息按 UTC 自然日(固定窗口,非滑动);并发与存储是瞬时值。 固定窗口边界存在少量跨窗毛刺,文档写清,不冒充滑动窗口。
- 价格与计费:档位价格是助手提案(用户委托按市场定,未确认),
不是用户确认定价,更不是 Meta 官方定价;payload 与文档都带
proposal标注。真实计费(Stripe/支付/开票/充值)不在本轨, 待用户另行批准;任何把“记账”等同于“收费”的说法都是错的。 - token 价格:USD 换算沿用
cost.py的 OpenAI 挂牌价表, 注释明言不是 relay 账单;无价模型(无价格表项)的 token 只 计量、不折算美元,仍走既有无价 token cap。