- 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 之后;不接真实计费
139 lines
9.6 KiB
Markdown
139 lines
9.6 KiB
Markdown
# 对齐 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`(超限回 402 `quota_exceeded`,
|
||
查询异常 fail-closed 回 503 `quota_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 改动清单(本轨)
|
||
|
||
1. `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_records` JOIN `tasks`,与
|
||
`_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"` 去重)。
|
||
2. 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 数,让用户看得见估算占比。
|
||
3. `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`。
|
||
4. `cloud/tests/test_usage_quota.py`(新):档位数值钉住提案、非法档位
|
||
拒绝、无档位行不限档位门、token actual/estimated 口径、消息固定
|
||
UTC 日窗口、并发门、存储门与清理指引、账本哈希链与篡改发现、提醒
|
||
只发一次、准入纯判定不碰在跑任务、服务端点(`/users/me/usage`、
|
||
`/admin/tiers`、档位门 402)。
|
||
5. `docs/chv-production-readiness.md`:补 P11 一节。
|
||
|
||
## §4 真机待验证清单(未做,排队在 round-11 与 P4~P9 之后)
|
||
|
||
- 真实 token 回传下的月度累计与 402(actual 行累计、无价模型走
|
||
既有 cap 不走美元门)。
|
||
- 并发门在真实多任务下(建第 N+1 个任务被拒,在跑任务不受影响)。
|
||
- 存储门在真实 worktree 下(本机任务目录求和、cloud 任务不计入)。
|
||
- 80% 提醒在真实使用下只发一次、跨窗口重置。
|
||
- 账本在真实写入压力下的链完整性(并发写不丢链不断)。
|
||
|
||
## §5 诚实边界(本轨内不解决,写清不冒充)
|
||
|
||
1. **进行中回合的语义不一致(已知待决)**:设计文档 §6.2 与本轨
|
||
任务书说“进行中的回合不中途掐断”;但基线 `_check_quota` 的
|
||
docstring 与 worker 实现是另一套——Local popen 与 Docker 路径的
|
||
worker 轮询每 30 秒查一次 USD 配额,超限杀进程组/容器(掐断粒度
|
||
是轮次边界 + 30 秒检查)。本轨新增的四项档位门**只做准入**,
|
||
不改既有 USD 路径的轮询掐断;两处语义不一致是已知待决项,
|
||
不在本轨内悄悄统一,须由父级另行裁决。
|
||
2. **并发超限的处理与设计文档不同**:设计文档 §6.2 说并发超限
|
||
“新任务排队,不立即拒绝”;本轨任务书(父级指令)说“即拒并
|
||
给出可读原因”。本轨按任务书即拒,差异记在此。
|
||
3. **存储计量不完整**:cloud / cloud-hypervisor 任务的 worktree
|
||
不在本机,量不到;本机也只能按任务 worktree 求和,用户在
|
||
VM 内或其它路径的占用不在计量内。payload 标明实测范围,
|
||
不冒充全量。
|
||
4. **Heavy 消息/天提案未给**:提案原文只给了 Heavy 的 tokens /
|
||
并发 / 存储,未给消息/天。本轨定为不限,并标注为**本项目决定**,
|
||
不是提案原文、不是官方口径。
|
||
5. **窗口口径**:token 按 UTC 自然月(与既有 USD 配额一致);
|
||
消息按 UTC 自然日(固定窗口,非滑动);并发与存储是瞬时值。
|
||
固定窗口边界存在少量跨窗毛刺,文档写清,不冒充滑动窗口。
|
||
6. **价格与计费**:档位价格是助手提案(用户委托按市场定,未确认),
|
||
不是用户确认定价,更不是 Meta 官方定价;payload 与文档都带
|
||
`proposal` 标注。真实计费(Stripe/支付/开票/充值)不在本轨,
|
||
待用户另行批准;任何把“记账”等同于“收费”的说法都是错的。
|
||
7. **token 价格**:USD 换算沿用 `cost.py` 的 OpenAI 挂牌价表,
|
||
注释明言不是 relay 账单;无价模型(无价格表项)的 token 只
|
||
计量、不折算美元,仍走既有无价 token cap。
|