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
104 lines
8.1 KiB
Markdown
104 lines
8.1 KiB
Markdown
# TASK · 补漏单:把绑定排除集钉成字面量 + 记录 timezone 环境缺口 — 2026-09-15
|
||
|
||
- 基线:`origin/staging` @ `1d2aeffa`(BUG-693/694 实现已合入并**已由我验收通过**)。
|
||
- 分支:`codex/report-binding-scope-lock-20260915`,worktree `.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.py`、`scripts/full_report_quality_gate.py`、`scripts/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.md` 的 **BUG-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_yoga` 的 `list(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. 开工前置命令
|
||
|
||
```bash
|
||
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 failed(timezone)
|
||
```
|
||
|
||
## 8. BUG 编号起点
|
||
|
||
**本单不新增编号**(D5)。`docs/BUG_HISTORY.md` 当前最大号 BUG-694;只更新 BUG-694,不要占 695。若执行中发现真实回归,再按当时最大号 +1 新开。
|