Skip to content

fix: hexgen_multi_seed 第④行缩进归位到量测块内,--gen 只生成不再崩(Fixes dsh-bounty #1960) - #1127

Closed
zhtty67-rgb wants to merge 1 commit into
FuRongJun-1999:mainfrom
zhtty67-rgb:fix/issue1960
Closed

zhtty67-rgb wants to merge 1 commit into
FuRongJun-1999:mainfrom
zhtty67-rgb:fix/issue1960

Conversation

@zhtty67-rgb

@zhtty67-rgb zhtty67-rgb commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

缺陷

lingshu/gen/hexgen_multi_seed.py:405(--gen 只生成模式)抛 UnboundLocalError,且 JSON 报告一字节不写 —— 已渲染成果全丢。

锚定:FuRongJun-1999/lingshu@45b8359(复基点),修复 rebase 到 5b0bf2a。
缺陷报告:FuRongJun-1999/dsh-bounty#1960

根因

81f68ccc(fix(gen): F23-25 empty_rate 零样本记 None)在把第 ④ 行打印改为容忍 er is None 时,把该行缩进从 8 格改成了 4 格:

        er = s["empty_rate"]
-        print(f"    ④ 空读件 ...")     # 块内(81f68ccc 之前)
+    print(f"    ④ 空读件 ...")         # 块外(81f68ccc 之后,现 HEAD)

该行引用的 s(rep["summary"],:397)与 er(:404)只在 if a.measure or do_both: 块内赋值,于是:

  • --gen(模块 docstring 第 30 行承诺可单跑的入口):s 从未绑定 ⇒ UnboundLocalError,进程非零退出;写报告在 :406-409,位于崩溃点之后 ⇒ 报告不存在。
  • --measure / 无参:s 已赋值能跑过,但该行脱离了量测块,无条件执行 —— 语义上不再是「量测结果的第 ④ 项」(本次一并归位)。

81f68ccc 同时新增的 tests/test_issue942_f23_25_empty_rate_null.py 只做源码字符串匹配("无样本" in src)+ 把打印式复制一份再断言,从不调用 main(),故对缩进层级零判别力。

修复(最小)

只改 1 行缩进,把 :405 挪回 if a.measure or do_both: 块内。无新语义、docstring 契约未动、无无关重构:

--- a/lingshu/gen/hexgen_multi_seed.py
+++ b/lingshu/gen/hexgen_multi_seed.py
@@ -402,7 +402,7 @@
         print(f"    ③ 件内方差/类间差 中位比 **{w['median_ratio']}**"
               f"(最差 5 维 {w['worst_dims']})")
         er = s["empty_rate"]
-    print(f"    ④ 空读件 {s['n_img_empty']}/{s['n_img']}(" + (f"{er:.1%}" if er is not None else "无样本") + ")")
+        print(f"    ④ 空读件 {s['n_img_empty']}/{s['n_img']}(" + (f"{er:.1%}" if er is not None else "无样本") + ")")
     os.makedirs(os.path.dirname(a.out) or ".", exist_ok=True)

守卫测试

新增 tests/test_issue1960_multi_seed_gen_only.py(3 条用例)。与既有同族守卫不同,本件真跑 main(),不做源码字符串匹配:

用例 钉住什么
test_gen_only_writes_report_and_does_not_measure --gen 正常返回、--out 报告已写出且含 generation/rows、不含量测段;summarize 被调用即判红
test_gen_only_does_not_print_measure_line 反向对照:只生成模式不得打印 ④ 行 —— 挡住「把 s 预初始化成 {} 只消错、行仍留在块外」的假修复
test_measure_mode_still_prints_line_four 反向对照:--measure 必须照旧打印 ④ 空读件 0/0(无样本) —— 挡住「整行删掉迁就崩溃」的假修复

环境隔离:只替换 gen(需本地 Qwen-Image-2.1 权重 + torch)与量测三件(load_multi/measure/summarize,需标定语料)这两处环境依赖;argparse、分支判定、print、os.makedirs、json 写报告全走原样实现 —— 缺陷正落在这条原样链上。

测试输出(真实执行)

修复前(HEAD 45b8359,红):

$ python -X utf8 -m pytest tests/test_issue1960_multi_seed_gen_only.py -q --no-header
...
>       print(f"    ④ 空读件 {s['n_img_empty']}/{s['n_img']}(" + (f"{er:.1%}" if er is not None else "无样本") + ")")
                           ^
E       UnboundLocalError: cannot access local variable 's' where it is not associated with a value

lingshu\gen\hexgen_multi_seed.py:405: UnboundLocalError
---------------------------- Captured stdout call -----------------------------
[多 seed 语料] prompt 子集 1 条 × 2 seed = 2 张(seed=[11, 22])
  vs_s000_circle_red: flat vector illustration, one red circle(s) in the center…
  生成:新增 2/2 张(加载 0.0s、生成 0.0s)
=========================== short test summary info ============================
FAILED tests/test_issue1960_multi_seed_gen_only.py::test_gen_only_writes_report_and_does_not_measure
FAILED tests/test_issue1960_multi_seed_gen_only.py::test_gen_only_does_not_print_measure_line
2 failed, 1 passed in 5.85s
RC=1

崩溃点、异常类型与 issue 报告逐字一致;生成:新增 2/2 张 已打印,证明渲染阶段已完成、损失发生在写报告之前。

修复后(本分支,绿):

$ python -X utf8 -m pytest tests/test_issue1960_multi_seed_gen_only.py \
    tests/test_issue942_f23_25_empty_rate_null.py -q --no-header -p no:cacheprovider
......                                                                   [100%]
6 passed in 1.51s
RC=0

同族回归面(修复后):

$ python -X utf8 -m pytest tests/test_issue1960_multi_seed_gen_only.py \
    tests/test_issue942_f23_25_empty_rate_null.py tests/test_hexgen_multi_seed_p2_cli_within.py \
    tests/test_hexgen_multi_seed_metric.py tests/test_issue735_multi_seed_stability_order.py \
    tests/test_issue198_hexgen_multi_seed_stable_id.py tests/test_hexgen_multi_seed_honored_pattern.py \
    -q --no-header
..................................                                       [100%]
34 passed in 13.16s
RC=0

$ python -X utf8 -m pytest tests/test_hexgen*.py -q --no-header -p no:cacheprovider
.............................................................            [100%]
61 passed in 132.84s (0:02:12)
RC=0

环境:Windows 11 + Git Bash,Python 3.14.9,pytest 9.1.1(本机 venv 直跑;仓内 .venv 不存在,故用既有环境注入 PYTHONPATH 提供 pytest/numpy/Pillow,未联网安装、未改仓内依赖声明)。

追加提交(CI gate 修复):同步 intake 登记指纹

首版 PR 的 gate CI 红了 3 个 job(py3.12 / py3.12·依赖下界 / py3.13),失败断言是:

FAILED tests/test_manifest_integrity.py::test_4_tool_exits_zero_on_real_repo
  AssertionError: {'entries': 64, 'match': 63, 'mismatch': 1, ...}
FAILED tests/test_manifest_integrity.py::test_18_native_modules_are_registered_where_the_tool_parses_them
  AssertionError: {"exit_code": 3, ... "status": "MISMATCH", "path": "lingshu/gen/hexgen_multi_seed.py",
                   "recorded_sha256": "3a20abdf8f45bbd1",
                   "actual_sha256": "d02a60418da1385e820efbd5ea295b8e5b1e48ebb667f6663e82d7923fddb18c"}

根因属实且是本次改动的直接后果:docs/intake/body-export-v0.1/_export_manifest.json 登记了
hexgen_multi_seed.py 的 sha256 前缀,而本次修复动了该文件的字节(81f68ccc 当时也是
「改代码 + 同步登记」成对提交,见其 diff 的单行指纹更新)。因此按仓内既有约定补一个
只改一行的登记提交 87bb60a:

--- a/docs/intake/body-export-v0.1/_export_manifest.json
+++ b/docs/intake/body-export-v0.1/_export_manifest.json
@@ -601,7 +601,7 @@
      "file": "hexgen_multi_seed.py",
      "src": "experiments.hexgen_multi_seed",
-     "sha256": "3a20abdf8f45bbd1",
+     "sha256": "d02a60418da1385e",

指纹算法与工具一致(LF 归一后 sha256 取前 16 位):

$ python -X utf8 tools/verify_manifest.py --strict --json   # 修复后(含 87bb60a)
RC=0
{ "exit_code": 0, "manifests": [ { "bytes_mismatch": 0, "mismatch": 0, ...

改前(本分支 539f8fc 单独检出到临时 worktree 实测):

$ python -X utf8 -m pytest tests/test_manifest_integrity.py -q --no-header -p no:cacheprovider
FAILED tests/test_manifest_integrity.py::test_4_tool_exits_zero_on_real_repo
FAILED tests/test_manifest_integrity.py::test_18_native_modules_are_registered_where_the_tool_parses_them
2 failed, 18 passed in 4.30s   RC=1

改后(本分支 HEAD 87bb60a):

$ python -X utf8 -m pytest tests/test_manifest_integrity.py -q --no-header -p no:cacheprovider
....................                                                     [100%]
20 passed in 4.23s   RC=0

合并回归面(修复 + 守卫 + 指纹三件一起):

$ python -X utf8 -m pytest tests/test_manifest_integrity.py \
    tests/test_issue1960_multi_seed_gen_only.py tests/test_issue942_f23_25_empty_rate_null.py \
    tests/test_hexgen_multi_seed_p2_cli_within.py tests/test_hexgen_multi_seed_metric.py \
    tests/test_issue735_multi_seed_stability_order.py tests/test_issue198_hexgen_multi_seed_stable_id.py \
    tests/test_hexgen_multi_seed_honored_pattern.py -q --no-header -p no:cacheprovider
......................................................                   [100%]
54 passed in 7.93s   RC=0

hexgen 全族(加指纹修复后重跑):

$ python -X utf8 -m pytest tests/test_hexgen*.py -q --no-header -p no:cacheprovider
.............................................................            [100%]
61 passed in 31.11s   RC=0

说明:test_4 / test_18 是既有守卫,本次没有改它们任何一行;它们在本 PR 上先红后绿,
恰好证明这两条断言对「改了被登记文件却忘了重算指纹」有真实判别力。

未做 / 不承诺

  • 未跑全量 pytest tests/(599 个测试件,规模外)。但已按 CI 报红定位并修复了唯一与本改动相关的失败面;
    其余 job 侧失败请以本 PR 最新的 gate 结果为准(见 checks)。
  • 未改动 tests/test_issue942_f23_25_empty_rate_null.py(该件只钉 empty_rate 的 null 语义,职责不同;
    本次另立新件补 control-flow 面)。

Fixes FuRongJun-1999/dsh-bounty#1960

FuRongJun-1999 added a commit that referenced this pull request Oct 29, 2026
…1127

fix(gen): hexgen_multi_seed --gen 只生成模式缩进归位(lingshu bounty #1960,镜像 #1127 净增量)
@FuRongJun-1999

Copy link
Copy Markdown
Owner

已修复并合并(维护侧实测)

确认属实(最新 main 合并前原样复现:--gen 模式 rc=2、UnboundLocalError、JSON 报告零字节),已由 PR #1157(镜像自 #1127 净增量,合并提交 fbf3d62)收口:打印第④行的缩进回到量测块内(er 定义所在的作用域)。

合并后 main(fbf3d62)读数:--gen --n 2 直跑 rc=2 但 UnboundLocalError: False(渲染与 JSON 报告正常产出;rc=2 为该模式的既有无样本退出口径,非崩溃);守卫 tests/test_issue1960_multi_seed_gen_only.py 3 passed(基线 2 红/1 绿 ⇒ 鉴别力);定点变异(缩进还原)2 红后恢复;hexgen_multi_seed.py 指纹重登记 strict 64/64;CI 4/4 绿。

致谢与署名:修法与守卫的净增量来自 @zhtty67-rgb 的 PR #1127(原样保留);#1127 未直接合并的原因是其分支基线 9a47775 先于维护侧 #1138/#1143/#1146/#1153/#1154 系(直接合并会回退已合工作,净 diff -1948 行),已按净增量摘取重放。

感谢报告——「已渲染成果全丢」的严重度定级(渲染成果不可再生)准确。

@FuRongJun-1999

Copy link
Copy Markdown
Owner

净增量已镜像合并(PR #1157,fbf3d62)——本 PR 关闭以避免与已落地内容重复。感谢贡献。

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

Labels

None yet

Projects

None yet

2 participants