本任务属于 Epic #23。共享上下文(整体目标、Agent Execution Contract、Non-goals、回归基线)见 #23。
依赖:无(可与 PR-1 并行)。
代码定位按当前仓库版本核对;若行号漂移,以函数名 / 字段名 / 挂载点语义为准。
完成本 PR 需遵守 Epic #23 的 Agent Execution Contract 与 Test Execution Protocol:先写失败测试与反例夹具 → 最小实现 → 跑里程碑测试 → 跑回归基线。PR 描述需列出:changed files / tests added / tests run / before-after / non-goals。
目标
四个确定性检查,输入 = 已渲染稿件文本 main_tex(+ ledger),输出 {passed: bool, hits: [{rule, location, snippet}]}。扩展现有 paper_completeness.py:829 latex_sanity_check(它已整篇 lower + 子串扫 FORBIDDEN_LATEX_TERMS),不另起一套。本 PR 只做检查本身;接入门禁、禁止出稿是 PR-4。
Allowed changes
latex_sanity_check 及其配置/词表
- M2 deterministic checks
- PR-3 fixtures
- PR-3 tests
Forbidden changes
- 不删除已有
FORBIDDEN_LATEX_TERMS
- 不把裸
{{ / }} 加入 forbidden substring 词表
- 不用相似度阈值判断跨 run 串台
- 不把正常单个问号
? 判为未解析引用
- 不扫描 verbatim / code block 内的
??
M2-a 未解析引用(新增)
- 命中任一即 fail:
\?\?(≥2 连续问号)、Table\s+\?\?、Figure\s+\?\?、源里残留 \\ref\{[^}]*\} / \\cite\{[^}]*\}。
- 不算命中(防误杀):正常单个问号
?;verbatim / 代码块内的 ??。
- 验收:
m2a_unresolved.tex(Table ??)→ fail 且 location 到行;m2a_clean.tex(含正常疑问句)→ pass。
M2-b 脚手架泄漏(扩展现有词表)
- delta(配置文件交付):新增
fixme、<scaffold、generate a figure that。不要加 TODO:(todo 已在词表)。
- 未渲染模板占位:不得把裸
{{ / }} 加进子串词表({{ 合法出现在 \frac{{a}}{{b}} 及 iclr/natbib .sty,会误伤);改用锚定正则 \{\{[a-z_][a-z0-9_]*\}\} 单独检。
- 验收:
m2b_scaffold.tex(caption 含 {{plot_cmd}})→ fail;m2b_clean.tex(含合法 \frac{{a}}{{b}})→ pass;另附一条证明现有 placeholder 检测未被破坏。
M2-c 跨 run 身份串台(纯集合判定)
- 事实源:本稿锁定方法名 =
state.get("method_name")(paper_completeness.py 里 state 是 dict,见 :561;不要写 state.method_name,会 AttributeError)。
- 规则:抽稿件 title / front-matter / 图注中"方法名样式 token"(驼峰 / 全大写缩写),若 token 既不属于锁定方法名集合、也不在缩写白名单 → fail。纯集合判定,无相似度阈值。
- 缩写白名单(配置文件交付):默认含
GSM8K, MuSiQue, MMLU, BLEU, GPU, CPU, LLM, LaTeX, JSON, API 等。
- 验收:
m2c_contaminated.json(锁定 CGGR,图注出现 OtherMethod)→ fail;m2c_clean.json(锁定 CGGR,正文提及 GSM8K)→ pass。
M2-d 模板复读(新增)
- 规则:同一规范化句子(去空白、小写、去标点)出现
≥ N 次即 fail;N 默认 3(可配);仅统计 ≥8 词的句子。
- 验收:
m2d_repeat.tex(同句 ×4)→ fail 并列出句与位置;m2d_clean.tex → pass。
DoD
四个检查各自 命中/干净 用例全绿;新增词表/阈值/白名单以配置文件交付;证明未破坏现有 latex_sanity_check;回归基线全绿。
完成本 PR 需遵守 Epic #23 的 Agent Execution Contract 与 Test Execution Protocol:先写失败测试与反例夹具 → 最小实现 → 跑里程碑测试 → 跑回归基线。PR 描述需列出:changed files / tests added / tests run / before-after / non-goals。
目标
四个确定性检查,输入 = 已渲染稿件文本
main_tex(+ ledger),输出{passed: bool, hits: [{rule, location, snippet}]}。扩展现有paper_completeness.py:829 latex_sanity_check(它已整篇 lower + 子串扫FORBIDDEN_LATEX_TERMS),不另起一套。本 PR 只做检查本身;接入门禁、禁止出稿是 PR-4。Allowed changes
latex_sanity_check及其配置/词表Forbidden changes
FORBIDDEN_LATEX_TERMS{{/}}加入 forbidden substring 词表?判为未解析引用??M2-a 未解析引用(新增)
\?\?(≥2 连续问号)、Table\s+\?\?、Figure\s+\?\?、源里残留\\ref\{[^}]*\}/\\cite\{[^}]*\}。?;verbatim/ 代码块内的??。m2a_unresolved.tex(Table ??)→ fail 且 location 到行;m2a_clean.tex(含正常疑问句)→ pass。M2-b 脚手架泄漏(扩展现有词表)
fixme、<scaffold、generate a figure that。不要加TODO:(todo已在词表)。{{/}}加进子串词表({{合法出现在\frac{{a}}{{b}}及 iclr/natbib.sty,会误伤);改用锚定正则\{\{[a-z_][a-z0-9_]*\}\}单独检。m2b_scaffold.tex(caption 含{{plot_cmd}})→ fail;m2b_clean.tex(含合法\frac{{a}}{{b}})→ pass;另附一条证明现有placeholder检测未被破坏。M2-c 跨 run 身份串台(纯集合判定)
state.get("method_name")(paper_completeness.py里state是 dict,见:561;不要写state.method_name,会 AttributeError)。GSM8K, MuSiQue, MMLU, BLEU, GPU, CPU, LLM, LaTeX, JSON, API等。m2c_contaminated.json(锁定 CGGR,图注出现OtherMethod)→ fail;m2c_clean.json(锁定 CGGR,正文提及GSM8K)→ pass。M2-d 模板复读(新增)
≥ N次即 fail;N默认3(可配);仅统计 ≥8 词的句子。m2d_repeat.tex(同句 ×4)→ fail 并列出句与位置;m2d_clean.tex→ pass。DoD
四个检查各自 命中/干净 用例全绿;新增词表/阈值/白名单以配置文件交付;证明未破坏现有
latex_sanity_check;回归基线全绿。