Skip to content

IR-0006 AC-9 GAP — human_minutes 预算维度无账本源且被 BUDGET_KEYS[:3] 静默排除(四元组预算实际只对 usd/tokens 生效) #472

Description

@randypanding

背景(独立验收发现,2026-08-30 第二轮独立核对)

IR-0006 spec specs/IR-0006/spec.md AC-9 / BEH-07 / BUDGET-03 / IFACE-03 要求:

conductor/cost-check 消费波次级预算(usd/tokens/wallclock/human_minutes)按 subject 聚合自统一账本;超限硬停+熔断标记。

即四元组预算的四维都应参与超限判定。本轮对 governance/wave_schema.py 做代码级逐维复算,结论:
四元组实际只有 usd / tokens 两维生效,另外两维一个崩溃、一个静默空转。

维度 声明侧 账本侧 执法结果
usd BUDGET_KEYS[0] cost.usdagg["usd"] ✅ 生效
tokens BUDGET_KEYS[1] cost.tokensagg["tokens"] ✅ 生效
wallclock_sec BUDGET_KEYS[2] 账本只有 cost.wall_sec ❌ KeyError → 整卡崩溃(见 #470
human_minutes BUDGET_KEYS[3] 无任何账本源 ❌ 静默 no-op(本 issue)

#470 已覆盖 wallclock_sec 崩溃面;本 issue 只报 human_minutes 维度——它与 #470 是同一段代码的两个独立缺陷,#470 的修复方案(键名映射 + rc 兜底)不覆盖本条,需单独处置。

代码证据

证据 1:BUDGET_KEYS[:3] 硬切片把第四维剔除在比较之外

governance/wave_schema.py L54、L191-192:

BUDGET_KEYS = ("usd", "tokens", "wallclock_sec", "human_minutes")
...
exceeded_dims = [k for k in BUDGET_KEYS[:3]          # ← 只取前三维
                 if k in budget and agg[k] > float(budget[k])]

[:3] 依赖元组书写顺序——这是 #470 崩溃的直接成因,也是本条的成因:第四维永不进入比较。

证据 2:human_minutes 无账本源,且 docstring 声称的「备注承载」并不存在

governance/wave_schema.py L154 与 L160-171:

cost.{usd,tokens,wall_sec} 求和 cost 字段记 0)。human_minutes 无账本源
——报告不判定备注承载)。
...
u = usage.setdefault(card, {}).setdefault(tenant, {"usd": 0.0, "tokens": 0, "wall_sec": 0.0})
u["usd"]     += float(cost.get("usd") or 0)
u["tokens"]  += int(cost.get("tokens") or 0)
u["wall_sec"] += float(cost.get("wall_sec") or 0)      # ← 无 human_minutes 聚合键

全仓检索 human_minutes 仅命中:模板/校验(wave_schema.py L11/L24/L54/L98)、宪法 specs/IR-0003/constitution.md L365、spec/落位表文本。没有任何账本字段或采集点产生 human_minutes 用量
且 L154 声称「备注承载」,但 rows append(L193-196)只输出 budget / usage_by_tenant / usage_total / exceeded_dims / on_exceed没有任何 human_minutes 备注字段——docstring 与实现不符。

证据 3:实测静默通过(独立沙箱,非 CI 快照)

卡 budget: human_minutes: 1 / on_exceed: hard-stop
账本实耗:  usd=99.0, tokens=900000, wall_sec=8000.0
期望:      human_minutes 超限 → exceeded_dims 非空 → exit 4(BEH-07 熔断三件套)
实际:      exceeded_dims=[] → exit 0 → cost-check 打 "WAVE-OK 预算卡 1 张对账无 hard-stop 超限"

复现命令:

mkdir -p /tmp/hm/ledger
cat > /tmp/hm/cards.json <<'EOF'
[{"number": 602, "body": "## budget(波次预算)\nhuman_minutes: 1\non_exceed: hard-stop"}]
EOF
cat > /tmp/hm/ledger/shadow-evidence-3.jsonl <<'EOF'
{"ts":"2026-08-29T02:00:00Z","kind":"cost","action":"cost.dispatch","verdict":"pass","subject":{"card":"Cloudbird-Software/.github#602","tenant":"t1"},"actor":{"identity":"x","role":"bot","model":null},"cost":{"tokens":900000,"usd":99.0,"wall_sec":8000.0},"seq":1,"prev_hash":null,"hash":"aa"}
EOF
python3 governance/wave_schema.py wave-check --cards /tmp/hm/cards.json --ledger-dir /tmp/hm/ledger; echo "rc=$?"

证据 4:现有回归套件不覆盖本面

governance/tests/test-wave-schema.sh L109-116 的四张测试卡分别声明 usd+tokenstokens、无预算、非法键——没有任何一张卡声明 human_minutes(也没有声明 wallclock_sec,这是 #470 漏网同源)。套件 15/15 PASS 但对本面零覆盖。

违反的条款

条款 影响
AC-9 / BUDGET-03 四元组预算第四维(human_minutes)零执法——注意力预算承诺未落地
absorption-map.md 第二部分 / 词汇归并表「收件箱」行 明写「human_minutes 入卡补全」注意力硬预算——字段入卡了,执法没接上
宪法 §5 / INV-01 fail-closed 声明了预算却不判定 = 静默放行,与「宁红勿假」方向相反(虽非崩溃级,但属承诺落空)

建议处置(三选一,按成本排序)

方案 1(推荐,最小变更·诚实声明):把不可执法改为显式可见,而不是假装判定。

# wave_schema.py:去掉 [:3] 魔法切片,改为显式可执法集合
ENFORCEABLE = {"usd": "usd", "tokens": "tokens", "wallclock_sec": "wall_sec"}  # 与 #470 方案 A 合并
for k, agg_key in ENFORCEABLE.items():
    if k in budget and agg[agg_key] > float(budget[k]): exceeded_dims.append(k)
# human_minutes:账本无源 → 行级声明字段,供 cost-check 摘要输出,不静默
if "human_minutes" in budget:
    row["unenforced_dims"] = ["human_minutes(账本无源,AC-9 未执法)"]

并在 cost-check.sh 波次通道摘要里把 unenforced_dims 打出来——让缺口可见,而不是让预算看起来在跑

方案 2(补源,完整落地 AC-9):新增 human_minutes 采集点(如 needs-human 停留时长 / owner 人工介入时长,来源可为 metrics 注意力会计或飞书投影停留时长列),写入统一账本 cost 段(扩展 record@1 或新增 human_minutes 字段),再纳入 ENFORCEABLE。成本较高,建议作为独立卡立项。

方案 3(降级声明):若确认本 IR 不做 human_minutes 执法,则应走 C1 治理变更——在 specs/IR-0006/spec.md AC-9/BUDGET-03 与 absorption-map.md 明确降级为「入卡不执法,执法另行立项」,并同步修正 acceptance.md 第 8 条回探行的 ✅ 结论。

补测(无论选哪个方案都建议加):

关联

验收对账基准(修完必须实测)

  1. 声明 human_minutes: 1 且实际消耗巨大 → 输出中必须出现可视缺口标记(方案 1)或 exit 4(方案 2)
  2. 声明 usd+wallclock_sec 且 usd 超限 → exit 4,不得再因 KeyError 吞掉(与 IR-0006 AC-9 SEV:HIGH — wave_schema wallclock_sec/wall_sec 键名不匹配→KeyError→cost-check fail-open 绕过(BEH-07 预算硬停失效) #470 联合回归)
  3. test-wave-schema.sh 新增断言实测绿

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1P1 级重要问题bugSomething isn't workinggovernance治理体系相关

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions