Skip to content
Back to skills

Comp Compile Zh

BSecurity

数学建模竞赛中文论文编译与合规检查。编译 PDF 并检查页数、匿名、格式等竞赛要求。Use when user says \"编译竞赛论文\", \"compile competition paper\".

  • 10 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 24, 2026
ai-agentspythonbashsqlexpress

Works with

  • cli

Security analysis

B75/100
  • criticalPipes output to a shell interpreter
  • criticalSends environment variables or credentials to an external URL

Pro scans all 2 files and shows the line behind each finding

Scanned September 29, 2026

npx -y skills add FOURTEEN1416/academic-agent-toolkit --skill comp-compile-zh --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Comp Compile Zh?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Comp Compile Zh
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/fourteen1416-comp-compile-zh/badge)](https://www.skillsdirectory.com/skills/fourteen1416-comp-compile-zh)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---

name: comp-compile-zh

description: "数学建模竞赛中文论文编译与合规检查。编译 PDF 并检查页数、匿名、格式等竞赛要求。Use when user says \"编译竞赛论文\", \"compile competition paper\"."

argument-hint: [paper-directory]

allowed-tools: Bash(*), Read, Write, Edit, Grep, Glob

---

# Competition Paper Compile & Compliance (Chinese)

Compile and validate: **$ARGUMENTS**

## Constants

- **ENGINE = `xelatex`**

- **MAX_COMPILE_ATTEMPTS = 3**

- **PAPER_DIR = `paper/`**

- **PAGE_CAP / PAGE_SCOPE / PAGE_CAP_STATUS** — 与写作步、打包步消费**同一份 bound 赛事快照**:`gate_page_cap`(本任务 operative 口径)+ `gate_page_scope`(`body`/`total` 两种计数口径,绝不折叠成一个数)+ `page_cap_status`(来源性质)。逐字转录自下发的 `contest_profile`;无默认、无下限;**不直读档案原始页数字段**、不自行猜生效值与计数范围。

- **CONTEST_ID** — 逐字转录自 `contest_profile.contest_id`(规范 `comp_*` 键;不从自由文本或文件名猜)。

## Workflow

### Step 1: Verify environment

```bash

if ! which xelatex 2>/dev/null; then

    echo "xelatex not found, attempting install..."

    if which miktex 2>/dev/null; then

        miktex packages install xetex ctex xecjk gbt7714 fontspec

        miktex fndb refresh

    elif which initexmf 2>/dev/null; then

        initexmf --set-config-value=[MPM]AutoInstall=1

    fi

fi

which xelatex && which bibtex && echo "ready" || echo "xelatex/bibtex not found"

fc-list :lang=zh | head -5

kpsewhich gbt7714.sty 2>/dev/null || echo "gbt7714.sty not found (will auto-install on first compile)"

```

### Step 2: Pre-compile cleanup

```bash

if [ -f "_utils/compile_utils.sh" ]; then

    bash _utils/compile_utils.sh paper/

elif [ -f "skills/shared-scripts/compile_utils.sh" ]; then

    bash skills/shared-scripts/compile_utils.sh paper/

else

    echo "compile_utils.sh not found, manual cleanup needed"

fi

```

The script auto-handles: special chars cleanup, table format fixes, includegraphics path correction (`figures/` → `../figures/`), hidelinks, figures/figures/ nesting, math_commands conflicts, wide table resizebox wrapping, narrow table resizebox removal, light-color text fixes, TikZ library injection.

If script not found, perform these steps manually.

**⛔ 表格行结束符修复(Misplaced \noalign 的根因):**

```bash

# 检测并修复 tabular/longtable 中的单 \ 行结束符(应该是 \\)

# 这是 heredoc 不加引号导致 \\ 被转义为 \ 的常见问题

for f in paper/sections/*.tex; do

    [ -f "$f" ] || continue

    # 检测:tabular 环境内,行末只有单个 \ 后跟换行(应该是 \\)

    if grep -P '(?<!\\)\\(?!\\)(?=\s*$)' "$f" | grep -v '\\begin\|\\end\|\\hline\|\\toprule\|\\midrule\|\\bottomrule\|\\caption\|\\label\|\\centering\|\\input\|\\include\|\\usepackage\|\\section\|\\subsection' > /dev/null 2>&1; then

        echo "⚠ $(basename $f): 可能有表格行结束符问题(单 \\ 应为 \\\\)"

        # 在 tabular/longtable 环境内,把行末的单 \ 替换为 \\

        python3 -c "

import re

with open('$f', 'r', encoding='utf-8') as fh:

    content = fh.read()

# 只在 tabular/longtable 环境内修复

def fix_table_endings(match):

    table = match.group(0)

    # 把数据行末尾的单 \ (后跟换行) 替换为 \\\\

    fixed = re.sub(r'(?<=&[^&\n]*)\\\s*\n', r'\\\\\\\\\n', table)

    return fixed

for env in ['tabular', 'longtable']:

    pattern = r'(\\\\begin\{' + env + r'[*]?\}.*?\\\\end\{' + env + r'[*]?\})'

    content = re.sub(pattern, fix_table_endings, content, flags=re.DOTALL)

with open('$f', 'w', encoding='utf-8') as fh:

    fh.write(content)

" 2>/dev/null

    fi

done

```

Also check ref/label matching and embed missing figures:

```bash

mkdir -p _tmp

grep -oh '\\ref{[^}]*}' paper/sections/*.tex paper/main.tex 2>/dev/null | sort -u > _tmp/_refs.txt

grep -oh '\\label{[^}]*}' paper/sections/*.tex paper/main.tex 2>/dev/null | sort -u > _tmp/_labels.txt

comm -23 <(sed 's/\\ref/\\label/g' _tmp/_refs.txt) _tmp/_labels.txt > _tmp/_missing_labels.txt

cat _tmp/_missing_labels.txt

```

**⛔ 中文引号统一为全角引号(避免 PDF 出现 ''乱码或两个堆叠反引号):**

中文论文用 xeCJK,全角引号 `"..."` 会自动渲染为漂亮的对称弯引号。

LaTeX 风格 `` ``...'' `` 在中文字体下会显示成两个堆叠的反引号,很丑。

ASCII 直引号 `"..."` 在 LaTeX 中渲染为右右引号 `''...''`。

统一替换为全角引号。

```bash

# 把所有错误引号统一为全角引号

for f in paper/sections/*.tex; do

    [ -f "$f" ] || continue

    python3 -c "

import re

content = open('$f', 'r', encoding='utf-8').read()

# 保护数学环境

placeholders = []

def stash(m):

    placeholders.append(m.group(0)); return f'\\x00M{len(placeholders)-1}\\x00'

content = re.sub(r'\\\$[^\\\$]*\\\$', stash, content)

content = re.sub(r'\\\\\\[.*?\\\\\\]', stash, content, flags=re.DOTALL)

# 保护 \begin{verbatim}/lstlisting 等代码环境

content = re.sub(r'\\\\begin\{(verbatim|lstlisting|minted)\}.*?\\\\end\{\\1\}', stash, content, flags=re.DOTALL)

# 1. LaTeX 风格 ``...'' → 全角双引号

content = re.sub(r\"\`\`([^\`'\\\\n]+?)''\", '\u201c\\\\g<1>\u201d', content)

# 2. ASCII 直引号 \"...\" → 全角双引号(成对处理)

parts = content.split('\"')

if len(parts) > 2:

    result = parts[0]

    for i, p in enumerate(parts[1:], 1):

        result += ('\u201c' if i % 2 == 1 else '\u201d') + p

    content = result

# 还原

for i, ph in enumerate(placeholders):

    content = content.replace(f'\\x00M{i}\\x00', ph)

open('$f', 'w', encoding='utf-8').write(content)

" 2>/dev/null

done

```

If labels are missing, find corresponding figure/table code in `figures/*.tex` and embed into the correct section file.

Also check compile_utils.sh output for "UNEMBEDDED" warnings — each one means a figure or table from `figures/` is not in any section.

**MANDATORY FIX LOOP — do NOT proceed to compilation until all figures AND tables are embedded:**

```bash

UNEMBED=0

# Check PDF figures

for pdf in figures/*.pdf; do

    [ -f "$pdf" ] || continue

    bn=$(basename "$pdf")

    grep -rq "$bn" paper/sections/*.tex paper/main.tex 2>/dev/null || { echo "UNEMBEDDED PDF: $bn"; UNEMBED=$((UNEMBED+1)); }

done

# Check TABLE_*.tex files

for tbl in figures/TABLE_*.tex; do

    [ -f "$tbl" ] || continue

    bn=$(basename "$tbl")

    # Check if any label from this table file appears in sections

    for lbl in $(grep -oh '\\label{[^}]*}' "$tbl" 2>/dev/null); do

        grep -rq "$lbl" paper/sections/*.tex paper/main.tex 2>/dev/null || { echo "UNEMBEDDED TABLE: $lbl (from $bn)"; UNEMBED=$((UNEMBED+1)); }

    done

done

# Check latex_includes.tex labels

if [ -f figures/latex_includes.tex ]; then

    for lbl in $(grep -oh '\\label{[^}]*}' figures/latex_includes.tex 2>/dev/null); do

        grep -rq "$lbl" paper/sections/*.tex paper/main.tex 2>/dev/null || { echo "UNEMBEDDED: $lbl (from latex_includes.tex)"; UNEMBED=$((UNEMBED+1)); }

    done

fi

echo "Total unembedded: $UNEMBED"

```

If UNEMBED > 0, you MUST fix ALL of them before compiling. For each unembedded item:

- **PDF figure**: copy the `\begin{figure}...\end{figure}` block from `figures/latex_includes.tex` into the target section

- **TABLE_*.tex**: copy the `\begin{table}...\end{table}` block from `figures/TABLE_*.tex` into the target section (use `\input{../figures/TABLE_xxx.tex}` or paste the tabular code directly)

- Add 1-2 sentences of lead-in text before and 3-5 sentences of analysis after each embedded item

- Re-run the count check above — repeat until UNEMBED = 0

**Do NOT compile with unembedded figures or tables — the PDF will have missing content.**

```bash

# Check all figures/*.pdf are referenced in body

for pdf in figures/*.pdf; do

    [ -f "$pdf" ] || continue

    bn=$(basename "$pdf")

    grep -rq "$bn" paper/sections/*.tex paper/main.tex 2>/dev/null || echo "⚠ $bn not referenced"

done

```

### Step 3: Compile (manual steps, no latexmk)

```bash

cd paper/

xelatex -interaction=nonstopmode main.tex

bibtex main

xelatex -interaction=nonstopmode main.tex

xelatex -interaction=nonstopmode main.tex

```

### Step 4: Error fix loop (MANDATORY — do NOT skip)

After each compilation, check `main.log` for CRITICAL errors. **You MUST fix ALL errors before declaring compilation complete.**

```bash

# Count critical errors

MATH_ERR=$(grep -c 'Bad math environment delimiter\|Missing \$ inserted\|begin{document} ended by' paper/main.log 2>/dev/null)

LR_ERR=$(grep -c 'Not allowed in LR mode' paper/main.log 2>/dev/null)

UNDEF_CS=$(grep -c 'Undefined control sequence' paper/main.log 2>/dev/null)

TOTAL_ERR=$((MATH_ERR + LR_ERR))

echo "Math errors: $MATH_ERR, LR mode errors: $LR_ERR, Undefined CS: $UNDEF_CS"

if [ "$TOTAL_ERR" -gt 0 ]; then

    echo "CRITICAL: $TOTAL_ERR errors — MUST FIX before proceeding"

    # Show error locations

    grep -B2 'Bad math\|Missing \$ inserted\|begin{document} ended\|Not allowed in LR mode' paper/main.log | grep -E '^\./|^l\.' | head -20

fi

```

**Error fix rules (iterate up to 5 times, not 3):**

1. **Math environment errors** (`Bad math environment delimiter`, `Missing $ inserted`, `\begin{document} ended by \end{equation}`):

   - Read the error location from main.log (e.g., `./sections/3_model_theory.tex:42`)

   - Open the file and find the broken math: usually `\X(t)$` should be `$X(t)$`, or `\mu$` should be `$\mu$`

   - Common cause: a sed/cleanup script stripped the opening `$` but left the closing `$`

   - Fix: ensure every math expression has matching `$...$` or `\[...\]` delimiters

   - **Do NOT use broad sed patterns to fix math** — read each error location and fix individually

2. **LR mode errors** (`Not allowed in LR mode`):

   - Usually caused by `\begin{figure}` or `\begin{table}` inside a paragraph without proper separation

   - Fix: add `\par` or blank line before the float environment

3. **Undefined control sequence**:

   - Missing package → add `\usepackage{xxx}` to main.tex preamble

   - Typo in command → fix the command name

4. **BibTeX failures**:

   - If BibTeX fails because of earlier LaTeX errors, fix the LaTeX errors first, then recompile

   - Check that `\bibliography{references}` and `\bibliographystyle{plainnat}` exist in main.tex

   - Check that references.bib has no syntax errors (unmatched braces, missing commas)

**After each fix, recompile and recheck:**

```bash

cd paper/

xelatex -interaction=nonstopmode main.tex

bibtex main 2>&1 | tail -5

xelatex -interaction=nonstopmode main.tex

xelatex -interaction=nonstopmode main.tex

cd ..

# Recheck

MATH_ERR=$(grep -c 'Bad math environment delimiter\|Missing \$ inserted' paper/main.log 2>/dev/null)

echo "Remaining math errors: $MATH_ERR"

```

**⛔ Do NOT proceed to Step 5 until MATH_ERR = 0 and LR_ERR = 0.** BibTeX will also fail if there are LaTeX errors upstream — fix LaTeX first.

When fixing errors in main.tex, only fix the specific error (e.g., add a missing package, fix a typo). Do not rewrite or restructure main.tex — the template's preamble, cover page, page margins, section numbering format, and header/footer settings must remain unchanged.

### Step 5: Post-compile checks

```bash

bash _utils/compile_check.sh paper/ 2>/dev/null || bash skills/shared-scripts/compile_check.sh paper/

```

The script checks: PDF existence/size, undefined references, overfull hbox, TOC, abstracts, bibliography entries, citation count, citation format (上标/顺序/合并), unused figures, figure stacking, TikZ diagram presence.

**⛔ MANDATORY: 引用格式问题必须修复(不可忽略):**

compile_check.sh 会检查 3 类引用格式问题,任何一类 FAIL/WARN 都必须修复:

1. **上标格式 FAIL** → 如果 bibliographystyle 是 `plain/plainnat/unsrt` 但 `\cite{}` 没有上标

   - 修复方法A:改 bibliographystyle 为 `gbt7714-numerical` 或 `plainnat` + `\usepackage[numbers,square,super]{natbib}`

   - 修复方法B:把正文里所有 `\cite{x}` 改为 `\upcite{x}` 或 `\textsuperscript{\cite{x}}`

2. **多引用顺序 WARN** → `\cite{c,a,b}` 但全文 a 先出现

   - 修复方法:改成 `\cite{a,b,c}`(按全文首次出现顺序)

   - 用以下 bash 找出所有需修复的位置:

     ```bash

     grep -rnP '\\(up)?cite\{[^}]+\}' paper/sections/*.tex paper/main.tex

     ```

3. **连续引用未合并 WARN** → `\cite{a}\cite{b}` 或 `\cite{a} \cite{b}`

   - 修复方法:合并为 `\cite{a,b}`

   - 批量修复:

     ```bash

     # 找出所有需合并的位置

     grep -rnoP '\\(up)?cite\{[^}]+\}\s*\\(up)?cite\{[^}]+\}' paper/sections/*.tex paper/main.tex

     ```

**⛔ 修复后必须重新编译验证:** `xelatex → bibtex → xelatex → xelatex`,然后重新运行 compile_check.sh 确认无 FAIL。

Additionally check:

```bash

# List of figures / list of tables (stats competition requirement)

[ -s paper/main.lof ] && echo "✅ 插图清单已生成" || echo "⚠ 插图清单为空"

[ -s paper/main.lot ] && echo "✅ 表格清单已生成" || echo "⚠ 表格清单为空"

```

**Template format verification (stats competition)**:

```bash

echo "=== 模板格式验证 ==="

if [ "$CONTEST_ID" = "comp_stats" ]; then

    # Check page margins (should be 2.54cm top/bottom, 3.17cm left/right)

    grep -q '2.54cm' paper/main.tex && echo "✅ 页边距正确" || echo "⚠ 页边距可能不对(应为上下2.54cm,左右3.17cm)"

    # Check Chinese section numbering

    grep -q 'chinese{section}' paper/main.tex && echo "✅ 中文章节编号" || echo "⚠ 缺少中文章节编号(一、二、三...)"

    # Check cover page

    grep -q '参赛学校\|参赛作品\|作品编号' paper/main.tex && echo "✅ 封面存在" || echo "⚠ 缺少封面"

    # Check abstract format (should be \section*{摘要}, not \begin{abstract})

    grep -q 'section\*.*摘要' paper/main.tex && echo "✅ 摘要格式正确" || echo "⚠ 摘要格式可能不对"

    # Check natbib (stats uses natbib, not gbt7714)

    grep -q 'natbib' paper/main.tex && echo "✅ natbib 引用格式" || echo "⚠ 缺少 natbib(统计建模应用 natbib)"

    # Check no header line

    grep -q 'headrulewidth.*0pt' paper/main.tex && echo "✅ 无页眉线" || echo "⚠ 可能有页眉线"

    # Check listoffigures / listoftables

    grep -q 'listoffigures' paper/main.tex && echo "✅ 插图清单命令" || echo "⚠ 缺少 \\listoffigures"

    grep -q 'listoftables' paper/main.tex && echo "✅ 表格清单命令" || echo "⚠ 缺少 \\listoftables"

fi

```

If any format checks fail, 执行 Agent should fix main.tex to match the template format before recompiling.

### Step 6: Competition compliance

Check items:

1. **Page count**: 上限与**计数口径**来自与写作步消费的同一份 bound 赛事快照——`gate_page_cap` + `gate_page_scope`(`body` = 章节 1 至结论、不含摘要/目录/参考文献/附录;`total` = 整本 PDF 计)。两种口径绝不折叠成一个数,本步不直读档案原始字段、不猜生效值。状态为 `official_verified` 或显式任务授权时**不得超过该上限**;`unverified` 口径不产生默认硬页限——如实上报数值、口径与性质;没有下发时如实报告缺口,不自行设限。**没有页数下限,不为凑页数扩写。**

2. **Anonymous**: no team info (队号, 队员, 指导老师)

3. **Abstract exists** (数模竞赛: at least Chinese; 统计建模: both Chinese and English)

4. **TOC exists** (required by MathorCup etc.)

5. **Code appendix exists**

6. **No undefined cross-references or citations**

<page_diagnosis>

#### Page count principles

**没有页数下限:页数少不是合规失败,不为凑页扩写。** 章节内容完整性由写作步骤自身的合同保证;编译步只对「超出赛事档案上限」负责瘦身(见 page_overflow),不对「未达某个目标页数」做任何扩写或充数。

</page_diagnosis>

<page_overflow>

#### ⛔⛔ 页数超限时的铁律(图小问题的根治约束)

**页数上限来自赛事档案**(`comp_rules.json` compliance 页数字段,由引擎下发),不是本步自造的目标。历史教训的实质是「为页数目标而压图变形」:无论是把上限当凑页目标反向压图,还是为塞进超限内容压图,都是同一类错误。本段是硬约束。

**图的尺寸由写作规则 + `compile_utils.sh` 兜底唯一决定:单图恒 `width=0.85\textwidth`(并排双栏才 `0.48`),高度兜底为 `height=0.9\textheight`(防单图独占整页)。编译期绝不许因为页数去改图宽或压小图高。**

**⛔ 特别警告——压小 `height` 是最隐蔽的压页手段:** 给图加 `height=0.20\textheight` 这类小限高,在 `keepaspectratio` 下会先于 width 生效,把近方图/竖图卡成一小块(图又小又挤成一堆)。这和压图宽同样恶劣,同样禁止。`compile_utils.sh` 会自动剥离 `<0.5\textheight` 的限高并补回 `0.9\textheight`,编译期不得反向再压。

页数超出赛事档案上限时,**只能**按下列优先级瘦身,**从上往下试,图和正文字号永远不动**:

1. 精简附录代码(节选核心片段、删冗余注释),附录不计正文页数但占篇幅;

2. 合并/删除稀薄的重复过渡段、把 enumerate 冗述改紧凑叙述;

3. 收紧浮动间距参数(`\setlength{\intextsep}` 等),不动图本身尺寸;

4. 删除非必要的重复图/表(一张图重复出现多次时)。

**⛔ 绝对禁止的凑页手段(出现即判不合格,必须回退):**

- ❌ 把 `\includegraphics` 的 width 从 `0.85` 改小(如 `0.6/0.5/0.48/0.46\textwidth`)来省空间;

- ❌ 给 `\includegraphics` 加 `height=0.NN\textheight` 小限高(如 `0.20/0.22/0.3\textheight`)压小图来省空间;

- ❌ 在 `\begin{document}` 后注入全局 `\small` / `\footnotesize` 等正文降字号;

- ❌ 给正文(非表格)套任何全局缩字号命令。

**上游细化(modex-3 同源吸收,2026-09-22)——自适应图尺寸,反凑页双向成立**:上述 `0.85\textwidth` 是本仓统一口径的**默认档**,不是"合格证明"。真正的判据是**最终印刷可读性**:诊断实际裁切、缩后文字是否 <8pt、重叠与异常空白,必要时重排信息密度。同理**禁止反向操作**——不得为了"满足图宽规范"把所有图无脑放大到 `0.85\textwidth`;一张可读的紧凑小图与一张设计良好的多面板大图都合法,`0.48\textwidth`、绝对尺寸、有意控制的高度都**不构成缺陷证据**。字号与尺寸永远不由页数目标驱动(无论压缩还是撑大)。

**自检(Step 7 质量门禁前必跑):**

```bash

echo "=== 图宽合规自检(禁凑页压图)==="

# 只看 includegraphics 的 width 系数;<0.70 视为被凑页压小。合规域 0.70~0.98 内一律不误报:
# 正则兼容一位/两位小数(fig_include_size.py 以 %g 写出 0.7/0.8/0.9 一位小数形态,其密度感知
# 推荐域 0.80~0.98;drawio 窄图 0.7 同域)——0.7/0.8/0.9/0.85/0.98 等全部放行,仅抓 <0.70 的压图值
# (真正并排双栏请写 0.48 并用 subfigure/minipage,本检测会提示、人工确认即可)

BAD_W=$(grep -rhoE 'includegraphics\[[^]]*width=0\.[0-9]+' paper/sections/*.tex paper/main.tex 2>/dev/null | grep -oE 'width=0\.[0-9]+' | grep -vE 'width=0\.(7|8|9)[0-9]*' | wc -l)

[ "$BAD_W" -eq 0 ] && echo "OK 无过小图宽" || echo "FAIL 有 $BAD_W 处图宽<0.70(疑似凑页压图,除真正并排双栏外必须改回 0.85)"

echo "=== 图高合规自检(禁压小图高凑页)==="

# <0.5\textheight 的限高视为凑页压图;compile_utils.sh 本应剥离,若仍残留说明预处理没跑或被反向压回

BAD_H=$(grep -rhoE 'includegraphics\[[^]]*height=0?\.[0-9]+' paper/sections/*.tex paper/main.tex 2>/dev/null | grep -oE 'height=0?\.[0-9]+' | grep -vE 'height=0?\.([5-9][0-9]*)' | wc -l)

[ "$BAD_H" -eq 0 ] && echo "OK 无过小限高" || echo "FAIL 有 $BAD_H 处 height<0.5\\textheight(凑页压图,须删该限高让 compile_utils.sh 补回 0.9)"

echo "=== 全局 small 自检(禁正文降字号)==="

# \begin{document} 到 \maketitle 之间若单独出现 \small/\footnotesize/\scriptsize,即全局降字号

AFTER_DOC=$(awk '/begin\{document\}/,/maketitle/' paper/main.tex 2>/dev/null | grep -cE '^[[:space:]]*[\](small|footnotesize|scriptsize)([[:space:]]|$)')

[ "$AFTER_DOC" -eq 0 ] && echo "OK document 后无全局降字号" || echo "FAIL document 后有全局 small/footnotesize(凑页降字号,必须删)"

```

三项都必须 OK;任一 FAIL 都要先修回(图宽改回 0.85、删过小限高、删全局 small),再重编译。

</page_overflow>

### Step 7: ⛔ FINAL QUALITY GATE (must ALL pass before finishing)

Run all checks and verify every item passes. **Do NOT output the report until all CRITICAL items are resolved.**

```bash

echo "=========================================="

echo "  FINAL QUALITY GATE"

echo "=========================================="

GATE_FAIL=0

# ⛔⛔ 两阶段执行总则(省重编,必读):本门 22 项分两类,改完的重编需求完全不同——

#   【源码类】(19项):只扫 .tex/.json/.md 文本(grep/awk/python),与已编译 PDF 无关。

#      改完直接 grep 就能重判,【绝不需要重编】。含:#4图嵌入 #8模板完整 #9图对账 #10TikZ

#      #12占位符 #17摘要 #19符号longtable #21babel #22数值一致 #22.4声称↔代码 #22.5方法凭证

#      #22.5太完美 #22.6合理性 #22.8长表格 #23AI列表 #24meta #25过度声称 + #18的writing_check

#      (图注超长/引用格式/figure stacking)。

#   【产物类】(少数):读 main.log/main.toc/PDF,改完【必须重编】才能重判。含:#16TOC、

#      #5页数、#18的compile_check内部(overfull hbox/vbox、未定义引用)。

#   ⛔ 正确修复顺序见本门末尾指令:先把所有【源码类】❌ 批量改完(期间禁止重编)→ 统一重编

#      一次 → 再判【产物类】。禁止每修一个源码类问题就重编 57 页(那是"卡很久"的根因)。

# 4. No unembedded figures

UNEMBED=0

for pdf in figures/*.pdf; do

    [ -f "$pdf" ] || continue

    bn=$(basename "$pdf")

    grep -rq "$bn" paper/sections/*.tex paper/main.tex 2>/dev/null || UNEMBED=$((UNEMBED+1))

done

[ "$UNEMBED" -eq 0 ] && echo "✅ All figures embedded" || { echo "❌ $UNEMBED figures not embedded in paper"; GATE_FAIL=$((GATE_FAIL+1)); }

# 5. Page count

PAGE_EST=0

for f in paper/sections/*.tex; do [ -f "$f" ] || continue; c=$(wc -c < "$f"); PAGE_EST=$((PAGE_EST + c)); done

PAGE_EST=$((PAGE_EST / 900))

echo "  Page estimate: ~$PAGE_EST pages (ceiling: engine-dispatched competition page limit)"

# 8. Template integrity — compare preamble against original template

echo "--- Template integrity ---"

TMPL=""

# TMPL 用工作区动态探测:真源是 comp-paper-zh 落进 paper/ 的同名原始模板(若用户/流程保存过)与仓库 _templates/*/main.tex;
# 禁止硬编码单一赛事模板列表(工作区恒不存在 → 检查静默空转)。
for t in paper/_original_main.tex _templates/*/main.tex _templates/*_main.tex; do
    [ -f "$t" ] && TMPL="$t" && break
done

if [ -z "$TMPL" ]; then
    echo "ℹ 未找到可对比的原始模板 main.tex(paper/_original_main.tex 或 _templates/*/main.tex),跳过 preamble 对比——如需此保护,写作前将官方原模板存一份为 paper/_original_main.tex"
fi

if [ -n "$TMPL" ] && [ -f paper/main.tex ]; then

    # Extract preamble (before \begin{document}) from both files

    TMPL_PRE=$(sed -n '1,/\\begin{document}/p' "$TMPL" | grep '\\usepackage\|\\documentclass\|\\ctexset\|\\pagestyle\|\\renewcommand.*headrulewidth\|\\listoftables\|\\listoffigures\|\\cline\|\\bibliography' | sort)

    MAIN_PRE=$(sed -n '1,/\\begin{document}/p' paper/main.tex | grep '\\usepackage\|\\documentclass\|\\ctexset\|\\pagestyle\|\\renewcommand.*headrulewidth\|\\listoftables\|\\listoffigures\|\\cline\|\\bibliography' | sort)

    MISSING=$(comm -23 <(echo "$TMPL_PRE") <(echo "$MAIN_PRE") 2>/dev/null | head -5)

    if [ -z "$MISSING" ]; then

        echo "✅ Template preamble intact"

    else

        echo "❌ Template preamble was modified — these lines from template are missing in main.tex:"

        echo "$MISSING" | sed 's/^/    /'

        GATE_FAIL=$((GATE_FAIL+1))

    fi

    # Check cover page structure (if template has one)

    if grep -q '参赛学校\|参赛作品' "$TMPL" 2>/dev/null; then

        grep -q '参赛学校\|参赛作品' paper/main.tex 2>/dev/null && echo "✅ Cover page present" || { echo "❌ Cover page missing/rewritten"; GATE_FAIL=$((GATE_FAIL+1)); }

        grep -q 'cline{2-2}' paper/main.tex 2>/dev/null && echo "✅ Cover underlines (cline)" || { echo "❌ Cover cline missing"; GATE_FAIL=$((GATE_FAIL+1)); }

    fi

    # Check bracket placeholders not remaining

    if grep -q '\[论文标题\]\|\[学校名称\]\|\[队员1\]\|\[指导老师\]\|\[竞赛年份\]\|\[届数\]\|\[中文摘要内容\]' paper/main.tex 2>/dev/null; then

        echo "❌ Unreplaced bracket placeholders in main.tex"; GATE_FAIL=$((GATE_FAIL+1))

    else

        echo "✅ All placeholders replaced"

    fi

    # Check hand-written figure/table list (anti-pattern)

    if grep -P '^(表|图)\d+\.' paper/main.tex 2>/dev/null | head -1 | grep -q '.'; then

        echo "❌ Hand-written figure/table list (use \\listoftables/\\listoffigures)"; GATE_FAIL=$((GATE_FAIL+1))

    fi

else

    echo "  (no template found for comparison, skipping)"

fi

# 9. Figure plan reconciliation (check planning docs)

echo "--- Figure plan check ---"

PLAN_FIGS=0; ACTUAL_FIGS=$(ls figures/*.pdf 2>/dev/null | wc -l)

for plan in TOPIC_PLAN.md PAPER_PLAN.md PROBLEM_ANALYSIS.md; do

    [ -f "$plan" ] || continue

    pf=$(grep -ci 'fig_\|图.*:\|figure.*:' "$plan" 2>/dev/null || echo 0)

    [ "$pf" -gt "$PLAN_FIGS" ] && PLAN_FIGS=$pf

done

if [ "$PLAN_FIGS" -gt 0 ]; then

    echo "  Planned: ~$PLAN_FIGS figures, Actual: $ACTUAL_FIGS PDFs"

    [ "$ACTUAL_FIGS" -ge "$PLAN_FIGS" ] && echo "✅ Figure count meets plan" || { echo "❌ Fewer figures than planned ($ACTUAL_FIGS < $PLAN_FIGS)"; GATE_FAIL=$((GATE_FAIL+1)); }

else

    echo "  No figure plan found, actual: $ACTUAL_FIGS PDFs"

fi

# 10. TikZ 几何/算法/架构图

# TikZ 由 paper-figure-drawio 编译成 figures/tikz_diagrams.pdf, 通过 \includegraphics 嵌入

# (不是 sections 里的裸 tikzpicture 代码)。两种形态都算已嵌入。

TIKZ_IN_PAPER=$(grep -rl 'tikzpicture\|tikz_diagrams\|tikz_' paper/sections/*.tex paper/main.tex 2>/dev/null | wc -l)

# ⛔ 只在"实际生成了 tikz_*.pdf 产物"时才硬核对(避免规划提了但用 DrawIO 替代时误报失败)

TIKZ_PDF_TOTAL=0; TIKZ_PDF_MISSING=0

for tpdf in figures/tikz_diagrams.pdf figures/tikz_diagrams_*.pdf figures/tikz_*.pdf; do

    [ -f "$tpdf" ] || continue

    TIKZ_PDF_TOTAL=$((TIKZ_PDF_TOTAL+1))

    grep -rq "$(basename "$tpdf")" paper/sections/*.tex paper/main.tex 2>/dev/null || TIKZ_PDF_MISSING=$((TIKZ_PDF_MISSING+1))

done

if [ "$TIKZ_PDF_TOTAL" -gt 0 ]; then

    # 有真实 TikZ 产物 → 必须全部嵌入

    if [ "$TIKZ_PDF_MISSING" -gt 0 ]; then

        echo "❌ $TIKZ_PDF_MISSING 张 TikZ PDF 未嵌入任何章节"; GATE_FAIL=$((GATE_FAIL+1))

    else

        echo "✅ TikZ diagrams embedded ($TIKZ_PDF_TOTAL)"

    fi

elif grep -qi 'tikz\|架构\|路线图\|几何示意\|算法流程' PAPER_PLAN.md PROBLEM_ANALYSIS.md 2>/dev/null; then

    # 规划提到 TikZ 但没生成 tikz_*.pdf(可能已用 DrawIO 替代) → 仅提醒, 不判失败

    [ "$TIKZ_IN_PAPER" -gt 0 ] && echo "✅ TikZ embedded" || echo "  ⚠ 规划提到 TikZ 但未发现 tikz_*.pdf(可能已用 DrawIO 替代, 不阻塞)"

else

    [ "$TIKZ_IN_PAPER" -gt 0 ] && echo "✅ TikZ diagrams embedded ($TIKZ_IN_PAPER)" || echo "  (no TikZ planned)"

fi

# 12. No placeholders remaining

PLACEHOLDERS=$(grep -rl 'PLACEHOLDER\|待补充\|TODO\|\[论文标题\]\|\[中文摘要内容\]' paper/sections/*.tex paper/main.tex 2>/dev/null | wc -l)

[ "$PLACEHOLDERS" -eq 0 ] && echo "✅ No placeholders" || { echo "❌ $PLACEHOLDERS files have placeholders"; GATE_FAIL=$((GATE_FAIL+1)); }

# 16. TOC 【产物类】——⛔ 唯一在本门主体内会重编的项,但仅当 main.toc 真空时才触发兜底重编。

#     正常情况 Step 3/4 已编够 3-4 遍、TOC 早已生成,此分支不进、不重编。不要误以为每轮都要走这里。

if grep -q 'tableofcontents' paper/main.tex 2>/dev/null; then

    [ -s paper/main.toc ] && echo "✅ TOC generated" || {

        echo "❌ TOC empty — running extra compile pass..."

        cd paper/

        xelatex -interaction=nonstopmode main.tex > /dev/null 2>&1

        xelatex -interaction=nonstopmode main.tex > /dev/null 2>&1

        cd ..

        [ -s paper/main.toc ] && echo "✅ TOC generated after extra compile" || { echo "❌ TOC still empty"; GATE_FAIL=$((GATE_FAIL+1)); }

    }

fi

# 17. Abstracts (Chinese papers)

if grep -q 'ctex' paper/main.tex 2>/dev/null; then

    grep -rq '摘.*要' paper/sections/*.tex paper/main.tex 2>/dev/null && echo "✅ Chinese abstract" || { echo "❌ No Chinese abstract"; GATE_FAIL=$((GATE_FAIL+1)); }

    grep -rq 'Abstract' paper/sections/*.tex paper/main.tex 2>/dev/null && echo "✅ English abstract" || { echo "❌ No English abstract"; GATE_FAIL=$((GATE_FAIL+1)); }

fi

# 18. Run compile_check.sh + writing_check.sh for full details

echo ""

echo "--- Full check scripts ---"

# ⛔ 必须分别捕获两个脚本的退出码:`WC_EXIT=$?` 只能接到 writing_check 的,

#    compile_check 的退出码会被覆盖丢弃 → 它 506 行的检查白跑、FAIL 不计分。

#    两者都计入 GATE_FAIL 后,本项是「引用格式/未定义引用/hbox/vbox/未用图/

#    图堆叠/模板包冲突…」等一大批检查的权威裁判,手工项不得重复查同一项。

bash _utils/compile_check.sh paper/ 2>/dev/null || bash skills/shared-scripts/compile_check.sh paper/ 2>/dev/null

CC_EXIT=$?

bash _utils/writing_check.sh paper/ 2>/dev/null || bash skills/shared-scripts/writing_check.sh paper/ 2>/dev/null

WC_EXIT=$?

[ "$CC_EXIT" -eq 0 ] && echo "✅ compile_check passed" || { echo "❌ compile_check failed (exit=$CC_EXIT) — 看上方明细逐条修"; GATE_FAIL=$((GATE_FAIL+1)); }

[ "$WC_EXIT" -eq 0 ] && echo "✅ writing_check passed" || { echo "❌ writing_check failed (exit=$WC_EXIT) — 看上方明细逐条修"; GATE_FAIL=$((GATE_FAIL+1)); }

# 19. 符号说明 longtable 检查

echo "--- Symbol table format ---"

for f in paper/sections/*.tex; do

    [ -f "$f" ] || continue

    if grep -q '\\section{符号说明}\|\\section.*符号' "$f" 2>/dev/null; then

        if grep -q '\\begin{longtable}' "$f" 2>/dev/null; then

            echo "✅ 符号说明使用 longtable"

        elif grep -q '\\begin{table}' "$f" 2>/dev/null; then

            echo "❌ 符号说明仍用 table(应转 longtable 防分页)"; GATE_FAIL=$((GATE_FAIL+1))

        fi

    fi

done

# 21. babel[english] 冲突

echo "--- babel check ---"

if grep -q 'ctex\|cumcmthesis\|gmcmthesis' paper/main.tex 2>/dev/null; then

    grep -q 'babel.*english' paper/main.tex 2>/dev/null && { echo "❌ 中文论文有 babel[english]"; GATE_FAIL=$((GATE_FAIL+1)); } || echo "✅ 无 babel 冲突"

fi

# 22. 数值一致性(JSON vs 论文)

echo "--- Numerical consistency ---"

if [ -f figures/all_results.json ]; then

    python3 -c "

import json, re, os

with open('figures/all_results.json','r',encoding='utf-8') as f: results=json.load(f)

def extract(obj,p=''):

    n={}

    if isinstance(obj,dict):

        for k,v in obj.items(): n.update(extract(v,f'{p}.{k}'))

    elif isinstance(obj,(int,float)) and not isinstance(obj,bool):

        if 0.001<abs(obj)<1e10: n[p]=obj

    return n

jn=extract(results); pn=set()

for tf in sorted(os.listdir('paper/sections')):

    if not tf.endswith('.tex'): continue

    with open(f'paper/sections/{tf}','r',encoding='utf-8',errors='ignore') as f: t=f.read()

    for m in re.finditer(r'(?<![a-zA-Z])(\d+\.?\d+)(?![a-zA-Z_{}])',t):

        try: pn.add(float(m.group(1)))

        except: pass

miss=sum(1 for k,v in jn.items() if not any(abs(p-v)<abs(v)*0.01+0.001 for p in pn) and any(w in k.lower() for w in ['rmse','r2','accuracy','f1','objective','optimal','best']))

print(f'❌ {miss} key values missing in paper' if miss else '✅ Key values consistent')

import sys; sys.exit(1 if miss>3 else 0)

" 2>/dev/null

    [ $? -ne 0 ] && GATE_FAIL=$((GATE_FAIL+1))

fi

# 22.4 声称↔代码 确定性静态扫描(⛔ 两个模式都跑,零额度;数值一致 ≠ 结论成立)

# 编译阶段 paper/sections 已存在,这里再跑一次能把"正文声称"也纳入扫描,比 comp-code 阶段更全。

echo "--- 声称↔代码 静态扫描(第 3 道闸)---"

CC_SCRIPT=""

for f in _utils/claim_code_check.py skills/shared-scripts/claim_code_check.py; do

    [ -f "$f" ] && { CC_SCRIPT="$f"; break; }

done

if [ -n "$CC_SCRIPT" ] && [ -d code ]; then

    python "$CC_SCRIPT" --modeling MODELING_REPORT.md --codedir code

    CC=$?

    if [ "$CC" -eq 1 ]; then

        echo "❌ 静态扫描发现'声称的方法代码没实现'(整数规划实为连续 / 仿真实为加噪声等)— 回 comp-code 修"

        GATE_FAIL=$((GATE_FAIL+1))

    fi

    # CC=2(缺文件)不阻断

else

    echo "ℹ 无 claim_code_check.py 或无 code/,跳过静态扫描"

fi

# 22.5 方法实现对账凭证核对(严格模式 comp-code 会写 METHOD_CHECK 凭证)

echo "--- Method-implementation credential(凭证核对)---"

if [ -f RESULTS.md ]; then

    MC=$(grep -oE 'METHOD_CHECK[^>]*' RESULTS.md | tail -1)

    if [ -z "$MC" ]; then

        echo "⚠ RESULTS.md 无 METHOD_CHECK 凭证(应回 comp-code 补方法实现对账)"

    elif echo "$MC" | grep -q 'skipped_anchor=1'; then

        echo "ℹ 锚定式对账快速模式跳过;静态扫描已在上面独立跑过"

    else

        NC=$(echo "$MC" | grep -oE 'n_claims=[0-9]+' | grep -oE '[0-9]+'); NI=$(echo "$MC" | grep -oE 'n_implemented=[0-9]+' | grep -oE '[0-9]+')

        if [ -n "$NC" ] && [ "$NC" = "$NI" ]; then echo "✅ 方法声称全部有代码实现($NI/$NC)"

        elif [ -n "$NC" ]; then echo "❌ 方法声称未全实现($NI/$NC)— 回 comp-code 补实现或改正文声称"; GATE_FAIL=$((GATE_FAIL+1)); fi

    fi

fi

# 22.5 "太完美"结果检测(AI 编造或过拟合特征)

echo "--- Unrealistic values check ---"

if [ -f figures/all_results.json ]; then

    python3 -c "

import json

with open('figures/all_results.json','r',encoding='utf-8') as f: data=json.load(f)

suspicious = []

def check(name, val):

    if not isinstance(val,(int,float)) or isinstance(val,bool): return

    key = name.lower()

    if any(w in key for w in ['r2','r_squared','accuracy','acc','precision','recall','f1','auc']) and val > 0.999:

        suspicious.append(f'{name}={val:.4f} 过于完美(>0.999)')

    if any(w in key for w in ['rmse','mae','mse','loss']) and val == 0:

        suspicious.append(f'{name}=0 完美误差')

    if ('p_value' in key or 'pvalue' in key) and val == 0:

        suspicious.append(f'{name}=0 完美显著')

    if any(w in key for w in ['improvement','speedup','gain','提升']) and val > 10:

        suspicious.append(f'{name}={val} 提升过大({val*100:.0f}%)')

def walk(obj, path=''):

    if isinstance(obj,dict):

        for k,v in obj.items(): walk(v, f'{path}.{k}')

    elif isinstance(obj,list):

        for i,v in enumerate(obj): walk(v, f'{path}[{i}]')

    else: check(path, obj)

walk(data)

if suspicious:

    print(f'🚩 {len(suspicious)} 处可疑的完美结果(可能过拟合或数值编造):')

    for s in suspicious[:5]: print(f'    {s}')

    print('  需在论文中说明合理性,或回到 comp-code 检查数据泄漏')

else:

    print('✅ 数值合理性通过')

" 2>/dev/null

fi

# 22.6 合理性审查章节是否存在(必须)

echo "--- 合理性审查章节检查 ---"

if [ -f RESULTS.md ]; then

    if grep -q '合理性审查\|数值合理\|背景对照\|sanity.*check' RESULTS.md 2>/dev/null; then

        echo "✅ RESULTS.md 包含合理性审查章节"

    else

        echo "❌ RESULTS.md 缺少合理性审查章节 — 回到 comp-code Step 1.7 补充"

        GATE_FAIL=$((GATE_FAIL+1))

    fi

fi

# 22.7 数据源时间戳一致性(代码 vs 图表 vs 论文)

echo "--- 数据源时间戳一致性 ---"

if [ -f figures/all_results.json ]; then

    JSON_TIME=$(stat -c %Y figures/all_results.json 2>/dev/null || stat -f %m figures/all_results.json 2>/dev/null || echo 0)

    # 检查是否有 PDF 图表比 JSON 旧(说明代码重跑了但图没更新)

    STALE_FIGS=0

    for pdf in figures/*.pdf; do

        [ -f "$pdf" ] || continue

        PDF_TIME=$(stat -c %Y "$pdf" 2>/dev/null || stat -f %m "$pdf" 2>/dev/null || echo 0)

        if [ "$JSON_TIME" -gt "$PDF_TIME" ] && [ "$((JSON_TIME - PDF_TIME))" -gt 60 ]; then

            echo "  ⚠ $(basename $pdf) 比 all_results.json 旧 — 图表数据可能过期"

            STALE_FIGS=$((STALE_FIGS+1))

        fi

    done

    if [ "$STALE_FIGS" -gt 0 ]; then

        echo "  ❌ $STALE_FIGS 张图表可能使用了旧数据(JSON 更新后图表未重新生成)"

        echo "  → 建议重跑 paper-figure 步骤更新图表"

        GATE_FAIL=$((GATE_FAIL+1))

    else

        echo "✅ 数据源时间戳一致"

    fi

fi

# 22.8 正文长表格检测(>12 行的表格不应在正文中完整展开)

echo "--- 正文长表格检测 ---"

LONG_TABLES=0

for f in paper/sections/*.tex; do

    [ -f "$f" ] || continue

    # 跳过附录文件

    echo "$(basename $f)" | grep -qi 'appendix\|附录\|A_code' && continue

    # 统计每个 tabular/longtable 环境内的数据行数(\\ 的数量)

    python3 -c "

import re

with open('$f', 'r', encoding='utf-8', errors='ignore') as fh:

    content = fh.read()

# 找所有 tabular/longtable 环境

for env in ['tabular', 'longtable', 'tabular*']:

    pattern = r'\\\\begin\{' + env + r'[*]?\}.*?\\\\end\{' + env + r'[*]?\}'

    for match in re.finditer(pattern, content, re.DOTALL):

        table_text = match.group()

        row_count = table_text.count('\\\\\\\\') - table_text.count('\\\\hline') // 2

        if row_count > 12:

            print(f'$(basename $f): {env} 有 {row_count} 行(>12)')

" 2>/dev/null | while read line; do

        echo "  ❌ $line — 正文表格超过 12 行,应截断(前3+后3+省略),完整版放附录"

        LONG_TABLES=$((LONG_TABLES+1))

    done

done

[ "$LONG_TABLES" -eq 0 ] && echo "✅ 正文无超长表格" || GATE_FAIL=$((GATE_FAIL+1))

# 22.9 图注超长检测已集中到 writing_check.sh(见第 18 项,其 EXIT_CODE→WC_EXIT→GATE_FAIL),此处不再重复。

# 23. AI 写作痕迹(列表环境)

echo "--- AI writing patterns ---"

AI_LISTS=0

for f in paper/sections/*.tex; do

    [ -f "$f" ] || continue

    echo "$(basename $f)" | grep -qi 'appendix\|A_code' && continue

    c=$(grep -c '\\begin{itemize}\|\\begin{enumerate}' "$f" 2>/dev/null || echo 0)

    AI_LISTS=$((AI_LISTS+c))

done

[ "$AI_LISTS" -le 3 ] && echo "✅ AI patterns: $AI_LISTS lists" || { echo "❌ $AI_LISTS lists in body — convert to prose"; GATE_FAIL=$((GATE_FAIL+1)); }

# 24. 元叙述泄露

echo "--- Meta content leak ---"

META=0

for f in paper/sections/*.tex; do

    [ -f "$f" ] || continue

    l=$(grep -ci 'RESULTS\.md\|AGENTS\.md\|MODELING_REPORT\|PROBLEM_ANALYSIS\|latex_includes' "$f" 2>/dev/null || echo 0)

    META=$((META+l))

done

[ "$META" -eq 0 ] && echo "✅ No meta leaks" || { echo "❌ $META meta content leaks"; GATE_FAIL=$((GATE_FAIL+1)); }

# 25. 过度声称

echo "--- Overclaiming ---"

OC=0

for f in paper/sections/*.tex; do

    [ -f "$f" ] || continue

    for w in "首次提出" "首次发现" "完美" "最优的" "无可比拟" "前所未有" "开创性" "革命性"; do

        c=$(grep -c "$w" "$f" 2>/dev/null || echo 0); OC=$((OC+c))

    done

done

[ "$OC" -eq 0 ] && echo "✅ No overclaiming" || echo "⚠ $OC overclaiming instances"

echo ""

echo "=========================================="

if [ "$GATE_FAIL" -eq 0 ]; then

    echo "  ✅ ALL CRITICAL CHECKS PASSED — ready to submit"

else

    echo "  ❌ $GATE_FAIL CRITICAL FAILURES — MUST FIX before finishing"

    echo "  按下方「省重编修复顺序」修:先批量改完源码类,再统一重编一次。"

fi

echo "=========================================="

```

**⛔ If GATE_FAIL > 0, you MUST fix every ❌ before finishing. Repeat until GATE_FAIL = 0. 但修复顺序按下面来,别每修一项就重编:**

**⛔⛔ 省重编修复顺序(治"编译卡很久"的关键——大多数 ❌ 是源码类,改完不必重编):**

1. **先批量修完所有【源码类】❌**(见本门开头总则的清单:图注超长 / 引用格式 / 占位符 / meta / AI列表 / 长表格 / 数值一致 / 模板完整 …)。这些只改 `paper/sections/*.tex` 或 `main.tex` 文本,**期间一次都不要重编**——它们和已编译 PDF 的 hbox/页数/TOC 无关,改完直接 grep 就能重判。

2. **所有源码类改完后 → 统一重编一次**:`cd paper/ && xelatex→bibtex→xelatex→xelatex`。

3. **重编后只重跑【产物类】检查**(#16 TOC / #5 页数 / #18 compile_check 的 hbox·vbox·未定义引用)。

4. **仅当【产物类】还有 ❌ 时**(通常是页数不足或 hbox),才针对性修 + 再重编一次。

5. **重复直到 GATE_FAIL=0**,但每一轮都遵循"源码类批量改→只重编一次",**严禁每修一个源码类问题就重编 57 页**。

> 为什么这样能省时间:一篇 57 页论文 xelatex 单遍就要几十秒,×4 遍一轮就 1-2 分钟。过去把"图注改短""表格内联"这类纯文本修改也各自触发一轮重编,多轮累积就是十几分钟。按上面顺序,源码类问题无论多少个都只在末尾重编一次,重编轮数从"问题分几批就编几轮"压到 1-2 轮。

**上游证据优先规约(modex-3 同源吸收,2026-09-22,与 `_utils/quality_gate_contract.md` 同一口径)**:

- 只修**具体失败项**,批量修完后编译一次、只对改动的最终快照复查。绝不为让步骤通过而压制真实失败。
- **工具失败/超时/缺依赖不是论文内容缺陷**。停下给出可恢复诊断;不得为此消耗模型调用去重写无关文本。检查器故障先修检查器。
- **提示性警告(advisory)也不是已证实的证据**。其来源与适用性在既有的语义复核中一并解决;无法解决的如实保留为局限,不升级成硬失败。
- 不要用对 `sections/` 全目录的大范围 `grep` 自行重实现检查器——只有 `main.tex` 实际包含的源与最终稿实际引用的图参与判定。
- 不得把 PDF 字节数、固定公式显示数、表格行数、列表数、计划图名的提及、缺失的字面算法关键词、或单条 caption 长度本身当作硬失败判据。`fig_size_consistency_check.py` 只比对草稿规划,陈旧规划不判成品错。
- 检查脚本区分两类退出:`GATE_FAIL`(内容失败,必修)与 `GATE_UNAVAILABLE`(检查不可用,如实报告、不判通过也不判论文错)。

### Step 8: Output report

Competition name, status, PDF path, total pages, body pages, compliance pass/fail.


## 执行与产出

使用当前执行会话完成本步工作;产物路径按当前步骤合同。程序采集真实操作、输入输出、版本与运行清单,模型只负责实质成果和领域质量。

建议额外记录:LaTeX 引擎版本、页数、编译警告数。

## Key Rules

- ⛔ **写稿/图表质量闸全家桶(按需选跑,双副本同 shared-scripts/)**:编译侧 `latex_typography_check.py`(排版精细检查)/`normalize_cjk_quotes.py`(中文引号规范);图表侧 `tikz_structure_check.py <file>` + `tikz_palette_check.py`(TikZ 结构/配色)/`fig_include_size.py` + `fig_size_consistency_check.py`(插图尺寸与一致性)/`figure_pdf_quality_check.py` + `pdf_page_density_check.py` + `pdf_snapshot_report.py`(PDF 成品质量/页密度/快照)/`figure_text_budget.py` + `figure_narrative_check.py`(图内文字预算与叙事)/`fig_bucket_doc_sync_check.py`(图桶-文档同步);写作侧 `abstract_emphasis_check.py`(摘要重点)/`symbol_layout_check.py` + `assumption_layout_check.py`(符号表/假设排版)/`writing_source_check.py` + `compile_source_check.py`(写稿/编译源一致性)/`paper_source_scope.py`(正文范围)。计算侧 `compute_checkpoint.py`/`run_compute.py`/`modeling_tex_policy.py`/`recipe_audit.py` 归 comp-code 侧按需。合同规范:`modeling_paper_contract.md`(建模-论文合同)/`abstract_writing_contract.md`(摘要合同)/`quality_gate_contract.md`(验证证据复用)/`cumcm_2026_format.md`(2026 国赛格式)/`tikz_style_families.md`(TikZ 风格族)。

- No latexmk — manual step-by-step compilation

- Do not delete .bbl file after compilation (bibliography data)

- Figure paths auto-corrected by compile_utils.sh: `figures/` → `../figures/`

- 正文页数不超过引擎下发的赛事档案页数上限(无下限,不为凑页扩写)

- Anonymous: no team info in body

- Primary output: `paper/main.pdf`, temp files: `_tmp/`

**⛔ 国赛提交包打包规则(强制)**:

1. **所有提交文件必须以中文命名**:
   - `论文.pdf`(正文 PDF)
   - `代码说明.txt`(程序说明,**仅使用 TXT 格式**)
   - `支撑材料.pdf`(含 AI工具使用详情.pdf 等)
   - `代码/`(代码文件夹,中文命名)

2. **程序说明仅使用 TXT 文件**(`代码说明.txt`),不使用 Markdown、Word 或其他格式。内容包括:
   - 代码功能说明
   - 运行环境要求
   - 核心算法简述
   - 输入输出说明

3. **压缩包命名**:`参赛编号+队号.zip`(如 `20260001_A01.zip`)

4. **禁止在提交包中包含**:
   - `.env` 文件
   - `.sqlite` 数据库文件
   - `__pycache__` 目录
   - 任何包含真实竞赛题面的文件(题面由组委会单独分发)


产出结构、存在性和最低完整性由 `finish` 按模板中的 `output_contract` 自动核验;修复返回的具体问题,不复制执行验证脚本。

## 退出判据(Verification)

本步完成前逐项自检(不达标即视为未完成):

- [ ] 0 编译错误、0 未定义引用
- [ ] 图表公式编号连续且与正文引用一致
- [ ] 页数与页边距符合规则
- [ ] 编译日志已留档(可复现)

## 常见合理化(Common Rationalizations)

| 合理化 | 现实 |
|---|---|
| "能出 PDF 就算编译通过" | 带警告的编译可能藏着断引用与错编号,需按日志逐项清。 |
| "引用警告无视即可" | 未定义引用即正文存在断链,评审一眼可见。 |
| "重新编译一下就好" | 无留档的编译不可复现;日志是产物的一部分。 |

> 本段与 `skills/_utils/anti_rationalization.md`(全局版)配套:本表是本步专属,
> 全局版覆盖跨步骤通用借口。新增借口时优先落到本表(更贴岗位),能泛化再上升。

Files in this skill

  • SKILL.md47.6 KB
  • references/UPSTREAM.md604 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…