Files
Jyotisha/docs/tasks/TASK-report-binding-scope-lock-20260915.md
T
Jesse_ChenandClaude Opus 5 10b463b9e8 docs(tasks): lock the binding exclusion list and record the timezone gap
BUG-693/694 实现(1d2aeffa)验收通过:三次 CLI 加三个 PYTHONHASHSEED 哈希
全同,变异法验证覆盖 33/40 顶层键,耗时中位数 2737 ms(修复前 2769 ms)。
补漏单处理两个没被机制挡住的洞:排除集的「只能三类」靠的是生产者、质量门、
测试引用同一对常量,加第四类会自动放行,改为把字面量钉进合同测试;快速门
必红的 timezone inference 依赖缺口记进 BLOCKED.md(修复前同样红,非回归)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-15 02:34:37 +00:00

8.1 KiB
Raw Blame History

TASK · 补漏单:把绑定排除集钉成字面量 + 记录 timezone 环境缺口 — 2026-09-15

  • 基线:origin/staging @ 1d2aeffaBUG-693/694 实现已合入并已由我验收通过)。
  • 分支:codex/report-binding-scope-lock-20260915worktree .worktrees/report-binding-scope-lock-20260915
  • 关联:TASK-report-provenance-binding-20260915.md(本单是它的验收补漏)、BUG-694(本单补它的防复发条)。
  • 串行:只加一个合同测试 + 改 BLOCKED.md不改任何生产代码行为,与在途分支无重叠。

1. 缘起(验收实证)

BUG-693/694 的实现验收通过:三次 CLI 加三个 PYTHONHASHSEED 哈希全同(784cdda5…),变异法独立验证覆盖 33/40 顶层键,耗时中位数 2737 ms(修复前 2769 ms)。本单不推翻其中任何一条。

验收时发现两个没有被任何机制挡住的洞:

1.1 排除集的"只能三类"目前是纸面规矩

BUG-694 的防复发条写的是「排除集只能是自引用 / 生成时刻 / 墙钟三类……加第四类要改任务书」。实际约束链是:

  • 生产者:scripts/calculation_profile_contract.py:81 / :86 定义 ALLOWED_BINDING_EXCLUDED_TOP_KEYS / ALLOWED_BINDING_EXCLUDED_PATHS:458 / :459 把它们原样写进回执。
  • 质量门:scripts/full_report_quality_gate.py:14-21 import 同一对常量:197 / :200 拿回执里的排除集减去这对常量判「意外排除」。
  • 测试:tests/test_calculation_profile_contract.py:585-586 断言 set(scope[...]) == set(ALLOWED_...)

三处引用的是同一个常量,所以谁往常量里再加一条,门自动放行、测试自动变绿。这条防复发现在只能挡住外来或手工篡改的包,挡不住它真正想挡的那件事(排除集悄悄变宽)。

本轮那次扩集就是例证:D2 原文只批了 ai_and_audit.summary.elapsed_seconds 一条墙钟路径,落地扩成了 **.elapsed_seconds 通配并新增 **.called_at / **.cache_created_at / **.cache_expires_at。理由(跨进程可复现)成立、也写进了 BUG-694,但任务书没有被改,也没有任何东西要求改。

1.2 --profile quick 在本机必红一条,没人记

FAILED tests/test_api_server_security.py::test_shadbala_endpoint_returns_ranked_planet_strength
WARNING [api_server] shadbala advanced layer failed: timezone inference dependency unavailable
E       assert ['core_sixfold'] == ['core_sixfold', 'advanced_evidence']

739 passed, 1 failed。同一条在修复前的 039b0a26同样红,与 BUG-693/694 无关。BLOCKED.md 里没有这条;实现方进度记录里写的是自己机器缺 mcp,也没进 BLOCKED.md。结果是下一个人跑快速门会重新查一遍同一个环境问题。

2. 决策记录

决策 内容
D1 不动现有排除集的内容。 四条墙钟/时间戳路径按 BUG-694 的记录保留,本单不重新开会讨论它们该不该在里面。
D2 把当前允许集的字面量钉进合同测试:常量被改动(增、删、改名)即测试红,由人决定放不放行,而不是自动通过。这是本单唯一的行为约束。
D3 不把这条做成运行时校验(不在生产代码里再写死一份清单)——两份清单会漂移,且门在运行期要挡的是外来包,语义不同。锁在测试层。
D4 BLOCKED.md 如实记录 timezone 缺口,写明失败的测试名、warning 原文、以及"修复前同样红"这个对照证据。不得写成通过,也不得为了让门变绿去改那条断言。
D5 不新增 BUG 编号。本单是 BUG-694 防复发条的补强,落在原记录上。

3. 硬红线

  1. 不改生产代码。 scripts/calculation_profile_contract.pyscripts/full_report_quality_gate.pyscripts/jyotish_engine.py 一行不动。若发现不改生产代码就锁不住,停下来写进度记录说明,不要自行改。
  2. 不得放宽或删除 BUG-693/694 的既有判据与断言。
  3. tests/test_calculation_profile_contract.py + tests/test_full_report_quality_gate.py 保持全绿;--profile quick 除 §1.2 那条 timezone 缺口外不得新增失败。
  4. 不改 .gitea/workflows/**,不提升 main

4. 任务分解

任务 1 · 允许集字面量锁(P1

  • tests/test_calculation_profile_contract.py 新增一条合同测试,断言两个常量的完整字面量与顺序等于当前值:
    • ALLOWED_BINDING_EXCLUDED_TOP_KEYS == ("generated_at", "report_quality_gate", "shared_full_report_authority")
    • ALLOWED_BINDING_EXCLUDED_PATHS == ("ai_and_audit.summary.elapsed_seconds", "**.elapsed_seconds", "**.called_at", "**.cache_created_at", "**.cache_expires_at")
  • 测试里写明三类归属与"改这里要先改任务书并在 BUG-694 补记"的注释,不要只留一行断言。
  • 验收标准:本地把常量任意加一条(例如 **.generated_by)→ 该测试红;恢复后绿。进度记录贴这两次的输出。

任务 2 · 环境缺口入账(P1

  • BLOCKED.md 新增一节,按 D4 写清:失败测试名、warning 原文、739 passed, 1 failed 的数字、以及"在 039b0a26(修复前)上同样红"这条对照证据,并注明这不是 BUG-693/694 的回归
  • 同时写明它对验收的影响:本机 --profile quick 的通过口径是"除这一条外全绿",谁要宣称快速门全绿,必须先补上 timezone 推断依赖。
  • 验收标准:条目里能直接复制出复现命令;不出现"通过"字样。

任务 3 · 记录(P2

  • docs/BUG_HISTORY.mdBUG-694:更新「最近更新」日期,防复发条补一句——允许集有字面量合同测试守门,改动必须先过测试再改任务书。不新增编号、不改原有的现象/根因/修复正文。
  • docs/tasks/PROGRESS-report-binding-scope-lock-20260915.md:贴任务 1 的红/绿两次输出与 --profile quick 的失败清单。
  • CHANGELOG.md 不写(对用户不可感知)。

5. 不在本单范围(验收时记下的观察项,不要顺手改)

  • report_quality_gate / shared_full_report_authority 现在挂在 sanitize_professional_report_reference 之后,不再过脱敏。实测差异只有 limitation_reference: null 这类空值被保留,无路径或内部字段泄漏,前端不消费这两个键。本单不动;要改需单独一单并说明"交付对象最后必过一遍 sanitize"这条保证要不要恢复。
  • cmd_yogalist(set(...))sorted(...) 是 BUG-694 的第二根因修复,已记录在案,不要回退
  • BUG-692 那条线:候选数 = 1 时会出现「还剩 … 里 1 个候选。按现有信息分不开。」自相矛盾(修复前说「这两分钟」,同样错,不是回归)。属于 TASK-rectification-invite-copy-and-assertions-fix-20260915.md 的后续,不在本单。

6. 让步顺序

  1. 若字面量锁与将来某次合法扩集冲突:先改任务书/BUG 记录,再改测试字面量,顺序不得颠倒。
  2. 若 timezone 依赖能在本机装上(需要联网或系统包),优先装上并让那条测试真绿BLOCKED.md 只保留"曾经缺、现在已补"的一行说明;装不上再按任务 2 入账。
  3. 任何情况下不得通过修改 test_shadbala_endpoint_returns_ranked_planet_strength 的断言来让门变绿。

7. 开工前置命令

git -C /workspace/Jyotisha status -sb | head -1
git -C /workspace/Jyotisha fetch origin --prune
git -C /workspace/Jyotisha worktree add -b codex/report-binding-scope-lock-20260915 \
  .worktrees/report-binding-scope-lock-20260915 origin/staging

cd .worktrees/report-binding-scope-lock-20260915
/workspace/Jyotisha/.venv/bin/python -m pytest \
  tests/test_calculation_profile_contract.py tests/test_full_report_quality_gate.py
/workspace/Jyotisha/.venv/bin/python scripts/run_quality_gate.py --profile quick   # 预期:739 passed, 1 failedtimezone

8. BUG 编号起点

本单不新增编号D5)。docs/BUG_HISTORY.md 当前最大号 BUG-694;只更新 BUG-694,不要占 695。若执行中发现真实回归,再按当时最大号 +1 新开。