From 36a8c2f91032594787db94e205f1eaec3ec33360 Mon Sep 17 00:00:00 2001 From: shaofl <2899218482@qq.com> Date: Thu, 30 Jul 2026 13:59:44 -0700 Subject: [PATCH] docs: record the F1 residual-bucket fix and the D5 C5 close-out Two entries appended to docs/progress/07_factor_layer_refactor.md, plus the ledger rows for #111-#114 and the three moving parts of CLAUDE.md (status table, headline, roadmap). What is worth carrying forward from these two steps is not the fixes but what they revealed about the evidence base. C5's failure taxonomy was derived from a results table that recorded one factor's panels leg as passing while its log said ok=False; that factor turned out to be a third member of the F3 family, so the class boundaries had been fitted to an incomplete sample. The full C5 sweep also ran on pre-#109 code, so the bounded warmup cell ceiling never executed even though the audit skeleton described it as an active gate. And every "pass" in the reports column was an F5 FileNotFoundError rather than a verdict, which is why two drifts nobody had ever seen surfaced only now. Five times this round a piece of evidence did not hit the claim it was placed there to support, and not one was caught by a test. The .pyc case is the sharpest: CPython validates bytecode by (mtime, size), so an equal-length rewrite within the same second leaves the mutated bytecode in place after the source is "restored" - which means the harness had been reporting red/green that could not be trusted, and the fix had to include re-running the thirteen mutations already on file, not just repairing the harness. Two overclaims the review measured as false are recorded with their disproof rather than quietly replaced: a whitelist described as the enumeration of a density criterion that in fact admits 69x more pairs, and a C-B comparison presented as an engine-regression check that is tautological (scaling ic_mean in all three books leaves C-B exactly zero). --- AGENTS.md | 8 ++++---- CLAUDE.md | 8 ++++---- docs/progress/07_factor_layer_refactor.md | 10 ++++++++++ docs/progress/pr_ledger.md | 4 ++++ 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 7649359..8e7f61d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -66,15 +66,15 @@ data → universe → factors(特征) → alpha(合成/预测) → portfolio(+ri | 项 | 值 | |---|---| -| `main` | 下表全部 gate 实测于 `c9cc12e`(PR #109);此后只落过 docs-only 的 #110(文档瘦身,pytest 复跑同为 2537) | -| `pytest -p no:warnings` | **2537 passed**(⚠️ 不要再传 `-q`:`pyproject.toml` 已含 `addopts="-q"`,叠成 `-qq` 会吞掉摘要行) | +| `main` | 下表全部 gate 实测于 `a5bbbba`(PR #113,D5 C5 收口) | +| `pytest -p no:warnings` | **2606 passed**(⚠️ 不要再传 `-q`:`pyproject.toml` 已含 `addopts="-q"`,叠成 `-qq` 会吞掉摘要行) | | `ruff check .` | clean | | phase0 锚(`run-phase0 --config config/example.yaml`) | **ic 0.9600 / annual 0.8408**(自 P0 起从未变过,任何改动都不许动它) | | `qt.exec_baseline_freeze --verify` | **77/77 @ `45c14aa`** | | `validate-config` | 32/32 | | 唯一 OPEN 的 PR | #38(历史遗留,保持 OPEN) | -**当前主线 = 因子层深度重构(设计 v3.2,D0–D7),走到 D5 C5(四腿全量对账)。** 全量跑已完成并暴露五类失败 F1–F5,全部已根因定位并裁定,**修复代码尚未开始**。 +**当前主线 = 因子层深度重构(设计 v3.2,D0–D7)。D5 C5 已收口(PR #113):11 因子 × 3 模式 33 格全绿,C5 通过 ⇒ 满足 C6 前置条件之一。** F1 残桶前视缺陷另立 correctness PR #112 修复(panels `unclassified` 729,029 → 0)。**下一步 = Step 4 / C6:删 11 个旧 runner**(owner 2026-07-28 已裁定退役重生成能力;前置条件另有 R16 覆盖数非降的逐条核销,且改造 PR 与删除 PR 必须分开)。 > **接手必读(唯一入口)**:[`tmp/design/HANDOFF_2026-07-30_claude_code.md`](tmp/design/HANDOFF_2026-07-30_claude_code.md) > ——含当前截面、F1–F5 裁定速查表、六步路线、派发/评审/限额的具体操作法、陷阱清单。 @@ -146,6 +146,6 @@ data → universe → factors(特征) → alpha(合成/预测) → portfolio(+ri ## 路线图 -1. **因子层重构收尾(当前主线)**:F1 残桶 correctness PR → C5 audit PR(F2/F3/F4 扩类 + F5 修复 + 真实重跑 + 填审计报告)→ C5 进度文档 → C6 删 11 个旧 runner → D6a–d 存量收口 → D7 收官全量重评估(**exec-only**)。 +1. **因子层重构收尾(当前主线)**:~~F1 残桶 correctness PR (#112)~~ → ~~C5 audit PR (#113)~~ → ~~C5 进度文档~~ → **C6 删 11 个旧 runner(下一步)** → D6a–d 存量收口 → D7 收官全量重评估(**exec-only**)。 2. **因子研究**:十一因子无一到 Adopt ⇒ 下一步优先做**换手/成本敏感的组合层验证**与更长 holdout,而不是继续堆新因子;补 PR #79 的 review;修订 HTML compendium。 3. **可选、须单独显式 goal**:I5g(强制 partial-fill / volume-cap);数据层 D6(`PanelStore` append/partition,仅当因子研究需要可复用派生面板时才启动);schema 守卫接 live `data-update`。 diff --git a/CLAUDE.md b/CLAUDE.md index 7649359..8e7f61d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -66,15 +66,15 @@ data → universe → factors(特征) → alpha(合成/预测) → portfolio(+ri | 项 | 值 | |---|---| -| `main` | 下表全部 gate 实测于 `c9cc12e`(PR #109);此后只落过 docs-only 的 #110(文档瘦身,pytest 复跑同为 2537) | -| `pytest -p no:warnings` | **2537 passed**(⚠️ 不要再传 `-q`:`pyproject.toml` 已含 `addopts="-q"`,叠成 `-qq` 会吞掉摘要行) | +| `main` | 下表全部 gate 实测于 `a5bbbba`(PR #113,D5 C5 收口) | +| `pytest -p no:warnings` | **2606 passed**(⚠️ 不要再传 `-q`:`pyproject.toml` 已含 `addopts="-q"`,叠成 `-qq` 会吞掉摘要行) | | `ruff check .` | clean | | phase0 锚(`run-phase0 --config config/example.yaml`) | **ic 0.9600 / annual 0.8408**(自 P0 起从未变过,任何改动都不许动它) | | `qt.exec_baseline_freeze --verify` | **77/77 @ `45c14aa`** | | `validate-config` | 32/32 | | 唯一 OPEN 的 PR | #38(历史遗留,保持 OPEN) | -**当前主线 = 因子层深度重构(设计 v3.2,D0–D7),走到 D5 C5(四腿全量对账)。** 全量跑已完成并暴露五类失败 F1–F5,全部已根因定位并裁定,**修复代码尚未开始**。 +**当前主线 = 因子层深度重构(设计 v3.2,D0–D7)。D5 C5 已收口(PR #113):11 因子 × 3 模式 33 格全绿,C5 通过 ⇒ 满足 C6 前置条件之一。** F1 残桶前视缺陷另立 correctness PR #112 修复(panels `unclassified` 729,029 → 0)。**下一步 = Step 4 / C6:删 11 个旧 runner**(owner 2026-07-28 已裁定退役重生成能力;前置条件另有 R16 覆盖数非降的逐条核销,且改造 PR 与删除 PR 必须分开)。 > **接手必读(唯一入口)**:[`tmp/design/HANDOFF_2026-07-30_claude_code.md`](tmp/design/HANDOFF_2026-07-30_claude_code.md) > ——含当前截面、F1–F5 裁定速查表、六步路线、派发/评审/限额的具体操作法、陷阱清单。 @@ -146,6 +146,6 @@ data → universe → factors(特征) → alpha(合成/预测) → portfolio(+ri ## 路线图 -1. **因子层重构收尾(当前主线)**:F1 残桶 correctness PR → C5 audit PR(F2/F3/F4 扩类 + F5 修复 + 真实重跑 + 填审计报告)→ C5 进度文档 → C6 删 11 个旧 runner → D6a–d 存量收口 → D7 收官全量重评估(**exec-only**)。 +1. **因子层重构收尾(当前主线)**:~~F1 残桶 correctness PR (#112)~~ → ~~C5 audit PR (#113)~~ → ~~C5 进度文档~~ → **C6 删 11 个旧 runner(下一步)** → D6a–d 存量收口 → D7 收官全量重评估(**exec-only**)。 2. **因子研究**:十一因子无一到 Adopt ⇒ 下一步优先做**换手/成本敏感的组合层验证**与更长 holdout,而不是继续堆新因子;补 PR #79 的 review;修订 HTML compendium。 3. **可选、须单独显式 goal**:I5g(强制 partial-fill / volume-cap);数据层 D6(`PanelStore` append/partition,仅当因子研究需要可复用派生面板时才启动);schema 守卫接 live `data-update`。 diff --git a/docs/progress/07_factor_layer_refactor.md b/docs/progress/07_factor_layer_refactor.md index 9928263..4c115ff 100644 --- a/docs/progress/07_factor_layer_refactor.md +++ b/docs/progress/07_factor_layer_refactor.md @@ -37,3 +37,13 @@ - 评审两轮:APPROVE-WITH-NITS(LOW-1 位置性豁免可绕过 + NIT-1 静默钳位)→ 修复 → **delta 复核双双 CLOSED 可合并**(评审回退修复自证测试有牙)。 - gates(lead 独立重跑):pytest 2533 passed(node-ID 0 挤掉)、ruff clean、phase0 锚 0.9600/0.8408、32/32 configs、secret 0、exec_baseline --verify 77/77 @ 45c14aa。 - **D5a(PR #95,D5 的前三块——冻结/编目/探测;探测结论迫使插入新迁移步 D4b)**:**C1 冻结 exec 对账基线**(`qt/exec_baseline_freeze.py`)——22 份 exec artifact 是后续一切对账的参照,却 **gitignored 只存在于本机**,且设计假定的耐久副本 `scratchpad/baseline_reports/` **早已不存在**;新 runner 沿用同名输出路径,**跑一次就毁掉唯一基线**,随后的「对账」会比对刚被自己覆盖的文件(= 本仓在案的 `compare_postmerge.py` 空对账形态)。实冻 **77 个文件**(不是交办的 44——同族还有 11 份 `_exec_basis_sanity.md` + 22 张 dashboard,同样单份不可再生),**sha256 manifest 入 git**(字节留 gitignored,哈希只能经评审 diff 变动),每次读都验哈希,读取器结构性拒绝 live 路径(直连/symlink 别名/`..` 三种绕过全拒)。**provenance 按证据强度分级**:观察到的是 77 文件共享毫秒级 mtime(批量拷贝签名),对照 44 份 close 基准的 11 个递进 mtime 与 #74 重跑窗口吻合;「字节出自 #79 run」标注为**推断非观察**,字段名故意叫 `frozen_at_git_head` 而非 `producing_sha`。**C2 编目 11 runner 差异**(§六.5「未编目的差异算失败」)——用 **AST 级比对**而非抽读证明完整性(`_build_book_factors`/`_write_report`/`_section_payload` 11 份逐字符相同;其余 helper 剥掉字符串常量后坍缩成 1 组),另记 **7 个既有 bug**(只标不修)与 `FactorSpec` 16→20 键漂移(来自 #86/#91,须预登记否则对账时会被当 D5 回归去追)。**探测(`qt/saturation_probe.py`,可复跑工具非一次性脚本):D4 的 materializer 在真实评估面上跑不了**——995 票中 **84 票**首根 1min bar ≥ emit_start ⇒ pooled 饱和**永远无法提前终止、必打到 floor**(D4 已披露的代价在全规模是**构造性**兑现);磁盘 8.18/16.43 GB,名义内存 52.7/122.2 GB,而 **frame:峰值RSS 实测 2.2–2.45×**(`minute_bars` 逐票读完 `pd.concat`,parts 与结果同时在内存)⇒ 评估窗真实峰值 **≈115 GB vs 可用 56 GB**;**不止 pooled**——bounded 路径同样整 universe 单帧(`materialize.py:262`),光评估窗就超可用内存约一倍。**三条更便宜的出路全部证否**:按票分批会因 `service._ensure_coverage` 的缺口判定**只按日期不按 (date,symbol)** 而**静默丢名**(I5a 红线);按时间分块只救 3 个 bounded 因子;缩短窗口不动 pooled 加载左端(锚在 floor)。**关门的是 `intraday_amp_cut`**(**同时 pooled × 截面**)——按票分批毁其截面、按时间分块管不住其深度,两轴都绕不开。切口位置已实测:纯因子逐票 ≡ 整 universe **逐位相同**(728/1524 个可比 cell `max|diff|=0.0`),`intraday_amp_cut` 逐票 **1860 finite → 0** ⇒ **切口必须落在截面 combine 之前**。**暴露的设计层缺口(照实记)**:§八只给**决策热路径**(20 日尾窗)定过规模预算,**从未给评估路径定规模**,所以「整 universe 单帧」在设计评审里没人拦;而旧 runner docstring 白纸黑字写着 "the multi-year all-symbol minute panel is NEVER materialized"——**D4 的加载几何相对被替换对象是回归**,只是 D4 验收跑在 40 票 smoke 上看不见。lead 提的「复用 `panel_freeze.py` 的加载形态代替 D4b」**已证否**:它没有自己的加载形态,是 import 11 个 runner 调其私有 `_load_*_panel`——「复用」等于保留决策③要杀的第二条取数路径;可复用的是**形状**不是调用路径。⇒ **插入迁移步 D4b(per-symbol 流式物化)**,设计文档记为实施期修订 A1;C3–C6 刻意未开始(修 materializer 是改取值路径,须自带四腿验收,混进 D5 当「让 run 跑起来」正是本项目反复抓到的形态)。**评审两轮**:首轮 BLOCK 1 HIGH——被文档称作「幂等」的再冻结命令**静默销毁 provenance**(未改动树上跑,输出 `copied: 0 / already ok: 77` 报纯成功,git 里却清空 `source_note` 并把 `frozen_at_git_head` 改指向重跑者 = **主动的假声明**,而 **16 个测试全程绿灯**)→ 改为 provenance 继承 + 内容不变则一个字节不写 + **恒跑断言**(`source_note` 非空 / head ^[0-9a-f]{40}$ / sha256 合法 hex(原只验长度)/ `size_bytes`>0),评审逐条 mutation 四条全红;另修 2 MEDIUM(**本 PR 自己 suite 里的空 mutation**——那条 git-tracking 测试全程不碰 git,注释掉 `.gitignore` 仍通过 → 改查 **git 索引** `git ls-files -- `;**C6 爆炸半径漏编目 3 个 runner importer**,含**生产 D1 冻结基线的 `panel_freeze.py` 本身**,其重跑流程是「旧 SHA + 当前分支文件」的混合式、两种 C6 处置下都会失效)。**方法论(三个空 mutation,全部照实记)**:实现方两次(tamper 测试替换了文件里**不存在**的字节串;git 索引 mutation 用 `git add -f` 被 symlink 拒绝执行 → 什么也没改、测试**为错误的理由通过**),评审一次(它建议的 `git ls-files --error-unmatch` 对「未跟踪」与「路径不存在」**返回相同 rc=1**,据此的断言会在**最需要它的机器上空过**)——**三次都不是被测试抓住的,而是被「与预期矛盾的观察」抓住的;评审建议本身也需要 mutation 证据**。**顺带更正一条长期误诊**:「本机 pytest 摘要行被环境吞掉」是假的——`pyproject.toml:53` 已有 `addopts="-q"`,我们再传 `-q` 就是 `-qq`;去掉即出现 `N passed` 摘要行(点计数仍是有用的交叉校验,本轮就抓到 2113 vs 2114 之差,但它从来不是因为摘要不可得才必须存在)。gates:**2117 collected**(2116 passed + 1 skipped——跳的是字节绑定测试,其字节 gitignored;manifest 自洽测试**无 skipif 恒跑**)/ ruff / 31 configs / phase0 锚不变 / secret 0 / `--verify` 77/77 且 head 仍 `45c14aa` / 冻结面板 mtime 未变。 +- ✅ **`amp_marginal_anomaly_vol` 残桶 correctness fix(PR #112,单独成 PR、非重构一部分,照 #103 jump 先例)**:`amp_marginal_anomaly_vol_20` 是 11 个分钟因子里**唯一派生 5min bar 的**。新引擎路径先把 1min 预截到 `available_time ≤ 14:50`、compute 再 resample ⇒ `resample_intraday_bars` **emit 残桶**,每天多出一根**只有 4 个成分**的"5min bar"(振幅/收益类统计对 bar 长度敏感 ⇒ **系统性偏小、有方向**);旧 runner 先取整日 bar 再派生,14:50 那桶成分齐全但 `avail=14:51 > cutoff` 被整桶丢弃、当天最后一根是 14:45 完整桶。**因子定义是"5min bars 截断于 14:50"⇒ 14:45–14:50 那个完整桶在 14:50 根本不可得,旧路径才是定义忠实的那个**。修法 `_complete_grid_bars(coarse, freq)`、判据 `bar_end == bar_end.dt.ceil(freq)`,在 **compute 内**(不在 materializer 打补丁——那正是本缺陷的形状;`resample_intraday_bars` 未改,它是通用 data-layer 原语)。**结果**:panels `unclassified` **729,029 → 0**,`float_tail/threshold_flip/flip_contamination` 全 0(未靠任何容差类兜底);anchors 此前 FAIL 的 3 行现为 **rel = 0.00e+00 精确**;reports **首次真正跑起对比**。**verdict Reject/Reject 未变**(真跑出来的,不由相关系数推定),微小位移全部来自已登记的 `warmup_left_extension` 聚合效应(评估日 1199→1209),`_bookclose` 增量 ICIR **逐位复现冻结的 −0.311985**。**不 bump `spec.version`、不加 `FactorCorrection`**:#103 的 jump 是**已发布 artifact 本身脏**,而 F1 的缺陷由重构中的新引擎引入、**从未发布**,修复是让引擎**回到**已发布值——声明一次没发生的 supersession 等于往每份 artifact 写一句假话。"已发布值不移动"**直接测得**(评审用 `git show main:` 把修复前后两模块载入同一进程喂逐字节相同输入,5 只真实 symbol **整日几何 5/5 BITWISE-EQ**)。**缺陷足迹不小**:`600000.SH` 完整评估窗口(1,213 日)修复前 **567/1,213 日不同、max rel `1.456776e-01`**,修复后 0/1,213——聚合看着动得小是**稀释不是无害**。**评审三处文档缺陷**:①普查射程被夸大(初版写"评估窗内 591 只",实为在 **5,782 个缓存目录**上随机抽 600、与 995 只评估 universe 交集**仅 102 只 = 10.3%**,而它是论证链的**承重前提**)→ 补成全量普查(995/995、1,159,263 对 = `rows_frozen`、残桶 0,实现方与评审两个独立脚本逐项一致),初版错误**如实记录在案**;②判据放行 **09:30 集合竞价 bar**(`ceil(09:30,5min)=09:30` ⇒ 自成一桶、恰 1 个成分、算"完整"),与 docstring 给的理由不符 → 点名它、**行为不改**(两种几何与冻结基线都保留它,丢掉会移动已发布值 ⇒ 另开 PR),编目明写「已知且刻意不改,后人别顺手修」;③守卫射程写进自己的 docstring(`{1,5,15,30}min` 对齐、**`60min` 不对齐** ⇒ 11:01–11:30 每天被静默丢弃,实测 coarse 100 → dropped 20 全是 `bar_end=11:30`)。**mutation 四组各有红/绿见证,实现方与评审各自独立写了一套**(其中把 ceil 网格硬编码成 15min 使两条 whole-day 测试**变红** ⇒ 它们确实有牙,此前"它们不区分修复"的怀疑被证否)。gates:pytest **2546 passed**(node-ID 差分 0 挤掉)/ ruff / 锚 0.9600·0.8408 / 32 configs / `--verify` 77/77 / secret 0。 +- ✅ **D5 C5(PR #113,四腿全量对账收口——11 因子 × 3 模式 33 格全绿,C5 通过 ⇒ 满足 C6 前置条件之一)**:F2/F3/F4 扩类 + F5 修复 + NIT-1,配以「A 阶段做完停下等裁定、再花三小时重跑」的分段——**边界参数一旦烤进一次三小时的全量跑,改起来就是重跑一次**。 + - **F2**(bars-only 臂):600623.SH 那根整数成交量 bar 压在 same-slot μ+σ 阈值上、pandas rolling 浮点累加**路径依赖加载起点**(thr 差 ~4e-13)⇒ `vol > thr` 翻转,**输入侧零变化**。窗口/symbol 未动,按因子设**相对**界(kurtosis ≤5e-3 / relative_vwap ≤1e-5,实测 2.904e-3 / 1.530e-6;沿用截面臂的 2e-4 绝对界会全数越界),cap 25。**F3**:`frozen_finite_new_nan` 进 warmup 方向集(限 pooled + 早区)+ 新类 `warmup_sparse_valid_day_tail`。**F4**:float-dust 谓词(abs ≤1e-12)**前移到 `_in_warmup` 分支之前**(按**机制**识别不按位置)⇒ 月计数 `{07:8198,08:11,09:3,10:9}` → `{07:8198}` 天然单调;实测对已绿因子无副作用,**被否决的方案②(月计数 ≤30 豁免单调链)未被启用**。**F5**:后缀传进写出层直接写 `_bookclose`、删掉事后 `os.replace`——此前 close 模式先用共享 stem 写再移动,**decision→close 顺序跑完会销毁 decision 的 with_book 三件套**。**NIT-1**:panels summary 加**逐类 max_rel**(headline 在任何分桶之前更新,与 `unclassified=0` 并排会诱导"容差没牙"的误读;本例那个 `9.03e-01` 经两方独立复算完全落在已登记 warmup 内)。 + - **三个证据基窟窿(比修复本身更重要——它们说明"跑绿"曾经只覆盖"我们看过的那部分")**:①交接文档的结果总表把 `peak_ridge_amount_ratio_20` 的 panels 记成通过,而**日志是 `unclassified=30 / ok=False`**,它是 F3 同族的**第三个**因子 ⇒ F2/F3/F4 的边界参数原本推自一个**残缺证据基**;据此做了 **11 因子 × 3 模式的「表所记 vs 日志实测」全量对照**(33 格只此 1 格记错,panels 一列**不依赖日志**、另用 dump 的 served 面板独立重算互证)。②**整轮 C5 全量跑用的是 PR #109 之前的判据**——`warmup_ceiling` 由 `35de346`(07-28 02:08)引入,而幸存的 8 条 07-28 日志行**没有一条带这个字段** ⇒ bounded warmup 的 cell ceiling **一次都没上过场**,而审计骨架把它写成生效中的闸门。措辞已改准:ceiling = `(w−1)×|symbols|` 是**结构上限**,只要日期边界判据没坏就**数学上不可能被超过** ⇒ 它是「日期边界判据自身有没有坏」的 **backstop,不是量级/密度闸门,只有在另一个守卫已失效时才会响**;91.5% 结构上本就该接近 1,**既非警报也非余量**;**C4a LOW-1 的量级缺口仍然敞着**。③**reports 腿的 11 个 `1` 全部是 F5 的 `FileNotFoundError`、不是判定结果** ⇒ 该腿此前只被真正观测过一个因子;本 PR 是它对其余 10 个因子的**首次**观测,两类此前无人见过的漂移因此第一次露面(诊断 sink 的**纯新增 section**;D2 迁移导致的 `spec.description` **provenance 改写**),均非数值差异、均已登记(前者补做了 PR #105 当初做过而这三个因子没做过的验证:12 个 grid 逐格 `old=None` / mandatory+verdict 逐位不变 / **自造索引位移实测会被检出**;后者**逐对精确枚举 old→new 字符串,不用谓词**——宽泛的"description 改写可接受"会把某天真正改了因子定义陈述的那次一起放行)。另:`_make_logger` 是 truncate 的(重跑会静默销毁同名日志唯一副本),**B 之前先把 pre-fix 数字誊进被提交的审计报告**——`tmp/` 快照被 gitignore、只在本机,而本项目已因 `/tmp` 被清理丢过一次全量跑总日志。 + - **评审证否的两处 overclaim**:**HIGH-1「白名单是该密度谓词的枚举」是假的**——谓词在窗口内允许 **1,250** 对而类实际覆盖 **18** 对,**69 倍差**。处置是**改措辞、不改谓词**(改谓词会把闸放宽约 69 倍):该类如实标为**「枚举类 + 必要条件守卫」而非机制类**(这个区别是操作性的——读"机制类"的人会以为**可以照机制推导着扩**),证伪门槛从"低于中位"(按定义约一半的票满足、近乎恒真)收紧到**低于 p25**(仍 18/18,最差百分位秩 21.7%),`600906.SH` 的不对称证据射程写准(**只有否定方向"稠密 ⇒ 不进簇"成立**,且它在对照因子上只高于中位 **1 天**、是**单点证据**),**反棘轮约束不放宽反而更要紧**(既然没有规则决定成员集,"再有新成员就停下上报"是这一类**唯一**的守卫,反向测试从配角升为主力)。**HIGH-2「若引擎回归藏在别的指标里,C−B 会在那些行非零」是恒真**——评审 mutation 直接证否:把 `ic_mean` 在 **A/B/C 三本书里同时 ×1.5**,**C−B 仍精确 0.0**(那四个指标对书**构造性免疫** 44/44,引擎回归会让三者一起动、在差里对消);已换成有信息量的版本(artifact 层 C−B 非零共 **174 叶,全部落在 `sections[3]` + `book_view` + verdict reasons ⇒ 书视图爆炸半径被限制住,174/174 通过**),并**明写真正检出引擎回归的是 `no_book`/`bookclose` 两格 strict 对冻结基线的逐叶子闸**;**这条被证否的推理连同其 mutation 证据留在报告里,没有悄悄换掉**(与 `compare_postmerge.py` 那次空对账处理一致)。 + - **贴边的边界(新增 §三之四)**:`jump` float_tail **101/101(0 格)**、sparse-tail 窗口右端 **2021-11-15(0 天)**、cap **19/20(1 格)**、p25 密度守卫 **35 天 vs 门槛 36(1 天)**。反棘轮使这种紧是**有意的牙**,但读者得知道有多紧;其中 p25 那道门**红了就是 STOP-AND-REPORT、不许把门槛放回中位**——**而它红的时候恰恰最诱人**(中位门会放行,于是"改一个数就绿了")。 + - **方法论:本轮出现 5 次「证据/清单打不中它要支持的那个主张」,无一是被测试抓住的**:①白名单参数化测试**读被测常量本身** ⇒ 删一只票只是少一个 case、两次都绿(本仓第 **10** 例"不可能失败的测试");②**`.pyc` 按 (mtime, size) 校验** ⇒ **等长**改写在同一秒内会让"还原"后的源码被**变异后的字节码顶替**,据此把先前 **13 条 mutation 全部重跑**(**只修 harness 不重跑等于把已污染的证据留在案上**;推荐解法是每次变异用 `PYTHONPYCACHEPREFIX` 指向独立目录);③位移测试**为错误的理由通过**(尾部多出的下标就足以满足断言);④MD 前缀漏了 `to_section` 加的两个计算属性,且其覆盖测试**两侧同源**故对该元组无牙(现钉到四个 coverage 类 `@property` 名字的并集);⑤「p25 严格更紧」在案的两条 mutation **打不中它**(那两只票在中位门下也会红),已换成真正的证人(`000031.SZ` 低于中位、高于 p25 ⇒ p25 下红、中位下放行;带内共 **151** 只票)。另有**两次**"同一主张写四遍、改准三遍漏一遍"(其中一处测试 banner 断言 median 而其**下方 15 行**的代码 docstring 写 p25,**同屏自相矛盾**);已把权威处收敛到参数所在的 docstring、其余改为指针,**两份 Markdown 与 Python docstring 无共享 prose 机制这个限制如实写明**,收敛后剩 4 处纯重复、**0 矛盾、0 悬空**。 + - **重跑射程是实测不是论证**:扰动 `qt/factor_eval_reconcile.py` 后重算 5 个因子 `code_hash` → **5/5 逐字不变**;**负对照**扰动 `factors/compute/minute/primitives.py`(在 shared set 内)→ **5/5 全变** ⇒ 探针非空、harness 在 code_hash 射程之外、store 不失效。 + - **已登记、本 PR 不改**:`_make_logger` truncate;jump 的 reports 腿对**值改动**实际不设闸(593 个 diff 里 **518** 个走既有更正承载登记 #11、`with_book(decision)` 是 report-only #13 ⇒ 值级依据应看 `no_book`/`bookclose` 两个 strict 格与 panels 腿,**结构性增删仍设闸**)。 + - gates(lead 独立重跑):pytest **2606 passed** / ruff clean / phase0 锚 **0.9600·0.8408** / **32/32** configs / `--verify` **77/77 @ 45c14aa** / secret **0** / 陈旧措辞 grep **0** / 审计报告 `TBD` **0** / 编目对 main **纯追加(0 删除行)** / 冻结基线**今日 0 个文件被写**。 diff --git a/docs/progress/pr_ledger.md b/docs/progress/pr_ledger.md index af70258..00b9688 100644 --- a/docs/progress/pr_ledger.md +++ b/docs/progress/pr_ledger.md @@ -17,3 +17,7 @@ | #108 | 进度文档(D5 C4b) | | #109 | D5 C5 prep:性质测试迁移映射表 + 审计报告骨架 | | #110 | 文档瘦身:进度日志从 `CLAUDE.md` 逐字搬进 `docs/progress/`(398 → 151 行) | +| #111 | 台账补记 #108–#110 + 状态表标明 gate 实测于哪个 commit | +| #112 | `amp_marginal_anomaly_vol` 残桶 correctness fix(单独成 PR,非重构一部分) | +| #113 | D5 C5 四腿全量对账收口(F2/F3/F4 扩类 + F5 修复 + NIT-1 + 审计报告) | +| #114 | 进度文档(F1 + D5 C5) |