# Teacher Paper

> 教师智能出题技能 - 覆盖小学一年级到高三全科目（语文、英语、政治/道德与法治、历史、地理、数学、物理、化学、生物），全题型，按用户提供的材料/真题样卷/题型分值分布参数化出卷；结合本地资料（Word/PDF/PPT/Excel/MD/TXT/图片）与在线真实素材（新闻/科普/公版古籍/英语分级读物等）生成学生试卷，产出可直接打印的 Word 试卷 + Word 参考答案及解析。默认九年级语文·长沙中考。理科含图题须用户提供图片，本技能不自动配图。触发时机：用户要求出题、组卷、制作试卷、生成练习题、制作考试卷，或提到'出题''组卷''试卷''考试卷''练习题'等关键词。

- Skill: `wsxwj123/teacher-paper` (Agent Skill, multi-file: 53 files)
- Install (CLI): `npx skillmds@latest add wsxwj123/teacher-paper`
- Raw SKILL.md: https://api.skillmd.com/api/skills/wsxwj123/teacher-paper/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- Author: wsxwj123 (https://skillmd.com/u/wsxwj123)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/wsxwj123/teacher-paper

---


# Teacher-Paper 教师智能出题技能

> 🔴🔴🔴 **第一铁律：阅读材料禁止编造** 🔴🔴🔴
> 非连续性文本、现代文（小说/散文）、古诗词、文言文、名著的**选文与材料，必须取自真实来源**：
> - **非连续性文本 → 必须摘自真实新闻报道/科普文章**（来源见 `references/material-sources.md`），用 `fetch_web.py` 抓取，**原文落盘到 工程/materials/**。
> - **古诗文/名著 → 必须是真实存在的作品**，用 `fetch_web.py` 从古诗文网/ctext 核验原文，落盘 materials/。
> - **现代文 → 优先选《读者》《意林》等真实美文**；教师自创文（需有真实创作背景，非 AI 生成）须在 meta.source 显式写 `原创-已声明`，并在 meta.json 补注 `"origin_note": "教师原创，YYYY年作"`。
>
> **`assemble.py build` 有硬门禁**：任何含选文的材料文件，meta 缺 `source`+`source_file`（或 source_file 指向的 materials/ 文件不存在），**直接拒绝出卷**。
> **严禁先编造内容再补一个假来源**——这是命题的红线，宁可流程慢，不可凭空捏造选文。
>
> 🔴 **忠实节选铁律（保真：可删减，禁造假）**：选文**可删掉与命题无关的部分（含中间段落），但保留的每段文字必须逐字取自真实原文**——禁止改字、禁止编造、禁止打乱原文顺序。卷面出处一律标 **"节选自《X》"**，禁用"改编自/整理自/编写自/原创"等字样。build 有 `_check_faithful_excerpt` 硬门禁：material 每段须为 source_file 原文的逐字子串且按原文先后顺序，否则 exit 2 拒绝出卷。
>
> 🔴 **关于 `--allow-unsourced`（强制绕过门禁，慎用）**：build 提供 `--allow-unsourced` 可跳过溯源/完整性门禁强制出卷。**默认绝不使用**；仅在用户**明确知情并要求**时才加，且**一旦使用必须显式告知用户"本卷已绕过真实性门禁，选文未经溯源校验，请自行核对来源"**。**不得为图省事自行加此参数**。

## 核心命题理念

> "以命题促教学，用原创提素养"

本技能以**自包含脚本作为稳定底座**，同时会优先复用当前电脑/当前 AI agent 已有的 Office、MCP、Pandoc、OCR 等能力。任何 AI agent、任何电脑上，都先扫描能力，再选择最稳路径；只有没有稳定 Word 生成后端时，才安装最小兜底依赖。

六个自包含脚本：`setup.py`（环境自检/装依赖）、`read_material.py`（读文档）、`fetch_web.py`（抓网页）、`ocr_image.py`（图片OCR兜底，无识图能力时用）、`assemble.py`（原子化组卷·init/build）、`make_paper.py`（生成 Word）。

> **关于脚本路径（重要，跨工具通用）**：下文命令里的 `<SKILL_DIR>` 代表**本 skill 的实际所在目录**，不是固定路径。不同 AI 工具/电脑上 skill 位置不同，**不要写死**。开始前先确定它：本 SKILL.md 文件所在目录就是 `<SKILL_DIR>`；脚本在 `<SKILL_DIR>/scripts/`。`setup.py` 运行时会用自身位置自动解析并打印出 `skill 目录`，照此替换即可。

**默认场景**：未指定时按**初三/九年级·语文·中考模拟**、长沙中考标准（21题/120分/120分钟）出卷。

### 适用范围（重要）

**支持全科目**：语文、英语、政治/道德与法治、历史、地理、数学、物理、化学、生物（小学一年级到高三）。

> ⚠️ **理科/文综（数物化生·地理）配图能力分级（全技能唯一锚点，v3.18.0 更新）**：本技能 `make_figure.py` **可生成 11 种图**：function/geometry/number_line/bar/line/pie/scatter/vector/climate/pyramid/**svg**（AI 直写 SVG 入 `figure.kind="svg"` 渲染）。**分级处理**：
> - ✅ **AI 直接生成**：函数图、几何示意（含简单受力/光路/简单装置示意）、数轴、柱/折/饼/散点图、向量图、气候柱状叠折线、人口金字塔、**简单 SVG 装置/电路/分子结构/细胞结构示意**。
> - ⚠️ **用户提供**：复杂装置图、真实照片、地理等高线/卫星/地形图、复杂电路、复杂分子三维结构、文物图、历史地图——`figure.src` 指向用户提供的图片。
> - 🛑 **占位**：临时无图但确认人工补图时，留 `［图：…］` 占位（`--allow-missing-figure` 降级）。
>
> **build 缺图硬门禁**：题干写了"如图/图中"却没有 figure 块 → 拒绝出卷；仅在用户知情同意走"占位"时加 `--allow-missing-figure` 降级。各科具体分级见 `references/subjects/<科目>.md` 第 2 节。

> 文科里的少量图（历史地图、地理图表）同样不自动生成；处理方式同上。

### 全学段：结构从哪来（核心机制）

本技能可出**小学一年级到高三、上述文科科目**的卷。试卷结构按以下优先级解析（`assemble.py` 自动处理）：

1. **样卷蓝图（最优先）**：用户给一份本地真题/样卷 → 你读它（`read_material.py`/识图）→ 解析出"大题/题型/分值/时长"写成结构 JSON → `init --blueprint-file <结构.json>`。**中小学无统一标准卷，本地样卷最贴合,优先走这条。**
2. **内置预设**：`presets/` 下已备 17 个预设文件，按 `学段_科目[_地区].json` 命中即用；科目别名（政治/道法→思想政治）与地区缺省自动回退基名。

   | 学段 | 科目（共17文件） | 文件名（可直接核查 `presets/` 目录）|
   |------|------|--------|
   | 九年级 | 思想政治 | `九年级_思想政治.json` |
   | 九年级 | 历史 | `九年级_历史.json` |
   | 九年级 | 地理 | `九年级_地理.json` |
   | 九年级 | 英语 | `九年级_英语.json` |
   | 九年级 | 数学 | `九年级_数学.json` |
   | 九年级 | 物理 | `九年级_物理.json` |
   | 九年级 | 化学 | `九年级_化学.json` |
   | 九年级 | 生物 | `九年级_生物.json` |
   | 高三 | 语文 | `高三_语文.json` |
   | 高三 | 英语 | `高三_英语.json` |
   | 高三 | 历史 | `高三_历史.json` |
   | 高三 | 地理 | `高三_地理.json` |
   | 高三 | 思想政治 | `高三_思想政治.json` |
   | 高三 | 数学 | `高三_数学.json` |
   | 高三 | 物理 | `高三_物理.json` |
   | 高三 | 化学 | `高三_化学.json` |
   | 高三 | 生物 | `高三_生物.json` |
   | 九年级语文 | 内置（长沙中考 21 题/120 分） | 无文件，硬编码默认 |

   > 若预设文件不存在（如高中文科无 `高三_历史.json`）→ 自动回退通用兜底并提示用户。**CLI 参数（`--total`/`--duration`/`--questions`）优先级高于预设默认值**，用户给了具体数字直接覆盖预设，无需额外确认；但**题量/总分覆盖后，预设的大题骨架与 manifest 不会自动重分配**——你须同步调整各大题题量分值，并在 Phase 1 出口把修订后的分布表展示给用户。另外预设按 `学段_科目` 命中、**不区分考试类型**（如"期末"会命中按中考/高考骨架写的预设），类型不同时须告知用户"结构基于 X 类型预设，建议提供本地样卷"。
3. **内置默认**：九年级语文 → 长沙中考标准（不传任何参数即此）。
4. **通用兜底**：以上都没有时，按科目给通用大题骨架（选择/填空/解答…），并提示按样卷补全。

> ⚠️ **不要硬背分值**：同一"七年级数学期末"在不同区县满分题型都不同。**有样卷一定先解析样卷**，预设/兜底只是没有样卷时的近似。

> 大资料量、需增量修改时，**务必走原子化工作流**（每题一个 json 文件，最后合并），详见 `references/authoring-workflow.md`。这能防止上下文丢失、让改一题不动全卷。

### 命题原则与特征

**命题五原则（仿得像·有根·依标·适度·有据）与四特征（情境/跨学科/不确定性/素养立意）**——长沙九年级语文的完整表述见 `references/exam-templates.md`「命题原则与特征」；其它学段科目对标对应样卷/课标，原则同构（结构仿真题、选材紧扣教材、考点锚课标、创新适度、考查点优先于题型表象）。

### 底线要求（全学段全科目通用）

1. **原创性（操作定义：原创 = 真实选文 + 全新设问）**——这条和第一铁律的边界必须分清：**选文是抓来的**（必须真实、可溯源、忠实节选，禁编造）；**设问是新写的**（题干、设问角度、干扰项、采分点必须全新原创）。具体禁区：
   - 禁止复用已有真题的题干句式、设问措辞、选项内容（哪怕换了选文）；
   - 禁止"换皮改编"——把真题换个数字、换个人名、换篇选文就当新题；
   - 真题只能用于分析命题规律与难度梯度（见"历年真题参考"），不能作为题目素材。
2. **规范性**：遵循课标，难度适中，无政治性和知识性错误
3. **去AI感**：严禁AI高频套话和模板化表述（详见 `references/anti-ai-guidelines.md`）
4. **人情味**：题目措辞自然亲切，贴近学生真实生活，像教了10年书的教师出的

---

## 启动第一步：环境自检（每次开始前必做）

不要假设依赖齐全、不要假设有任何特定工具。**开始任何出卷工作前，先完成两层能力探测**：

1. **Agent 工具探测**：检查当前 AI 客户端是否暴露 Word/Document/Office/Pandoc/Markdown/Spreadsheet/PPT/OCR 相关 MCP、插件或内置工具。
2. **本机能力探测**：运行 `setup.py`，扫描多个 Python 解释器、Python 包、Pandoc、LibreOffice/Office/WPS、OCR、macOS/Windows 系统转换工具。

> MCP / 插件是当前 agent 的会话能力，Python 脚本无法可靠枚举；因此先由 agent 看自己当前有哪些工具，再用 `setup.py` 看本机有什么。

```bash
# 体检（只看不装）：
python3 "<SKILL_DIR>/scripts/setup.py"
# 机器可读体检报告（推荐）：
python3 "<SKILL_DIR>/scripts/setup.py" --json
# 仅当报告显示没有稳定 DOCX 后端，且用户同意时，安装最小兜底依赖：
python3 "<SKILL_DIR>/scripts/setup.py" --install
```

处理规则：
- **不要把当前 `python3` 缺包等同于整台电脑没有能力**：`setup.py` 会扫描多个 Python 解释器；agent 也可能有 Word/Pandoc/文档 MCP。
- **python-docx 是最小稳定兜底，不是唯一方案**：已有可用 `docx` Python 后端时，优先用 `make_paper.py`；没有时再看 Pandoc、Office/MCP、系统转换工具。
- **可选依赖**（PDF/PPT/Excel 读取、网页提取增强、图片OCR）缺哪个、只在用到对应素材类型时才需，按需安装。
- **外部工具**（Pandoc、LibreOffice、Word/WPS、OCR、系统转换工具）有就用、没有不强求。
- **git（强烈建议，且 build 有硬门禁）**：`setup.py` 会扫描 git。有 git 时 `assemble.py init` 自动把工程纳入版本管理，**每完成一题/一部分必须 `assemble.py commit` 存档**。🔴 **build 时若 `items/` 有未提交改动 → 直接拒绝出卷（`--allow-uncommitted` 逃生）**，强制逐题存档可回滚。无 git 或工程嵌在父仓库内 → 该门禁自动不适用（出卷不受影响，但失去逐题回滚保护，建议提示用户装 git）。
- 自带脚本若缺失 → 说明 skill 文件不完整，请用户重新获取完整 skill。
- **命令一律按 bash 语法书写，禁止 cmd 风格的 `>NUL` / `2>NUL` 重定向**——Windows 上命令实际由 Git Bash 执行，`NUL` 不是空设备而是普通文件名，会在目录里留下一个名为 `NUL` 的垃圾文件。脚本输出本就必须如实转告用户，不要静默丢弃；确需丢弃用 `/dev/null`。

### DOCX 后端选择顺序

| 顺序 | 后端 | 使用条件 | 定位 |
|------|------|----------|------|
| 1 | `python-docx` + `make_paper.py` | 任一 Python 解释器可 import `docx` | 最稳定、离线、版式可控的主路径 |
| 2 | Pandoc + `build/content.md` | 有 Pandoc CLI 或 Pandoc MCP | Markdown 中间产物转 DOCX，可配 reference.docx |
| 3 | Word/Document/Office MCP 或内置文档插件 | 当前 agent 暴露相关工具 | 后处理、局部编辑、补图片、转 PDF、复杂文档操作 |
| 4 | LibreOffice / Microsoft Word / WPS | 本机安装且可被 agent 调用 | 格式转换、渲染校验、PDF 输出 |
| 5 | macOS `textutil` / Windows PowerShell | 只有系统自带工具可用 | 低保真 DOCX 兜底 |
| 6 | 安装 `python-docx` | 上述稳定路径都不可用 | 经用户确认后安装最小兜底依赖 |

> 输出仍以 `assemble.py build` 生成的 `build/content.json` 为唯一结构源；`build/content.md` 是给 Pandoc/MCP/Office 后端复用的中间产物。不要让不同后端各自重新组织题目内容。

---

## 启动第二步：确定工作模式与工程位置（开工前必做）

环境就绪后，**在出题前先问清两件事并写入工程**，避免中途反复打断或自作主张：

> 🔴 **STOP·开工前必须问清以下 1/2，模式二还须问清 3；未问清不得进入 Phase 1。**

### 1. 工作模式（🔴必问·二选一，不得默认）

用 AskUserQuestion 问用户遇到问题时怎么处理：

- **模式一·全程确认**：遇到任何不确定（选哪篇素材、某题难度、补题方向、抓不到内容如何替代等）都**停下来问用户**，不自行决定。
- **模式二·全自动**：除非触及硬门禁（如素材抓不到、依赖装不上），否则**全程自主完成**，最后一次性交付，中途不打断。

> 选模式二时，**必须在开工前把可预见的决策点一次性问清并定好**（见下"决策点预填"），写入工程的 `meta.json`，之后严格据此自动执行，不再逐题打扰。

### 2. 工程位置（🔴必问）

用 AskUserQuestion 问用户：**这份试卷的工程放在哪个文件夹？**
- 用户给了路径 → 在该路径下新建 `<试卷名>_工程` 子文件夹。
- **用户没指定 / 选"默认" → 自动在桌面新建子文件夹**（跨平台：脚本会自动探测真实桌面，兼容 Windows 中文"桌面"、OneDrive 重定向、Linux XDG）。
- 用纯工程名调用 `assemble.py init "<试卷名>_工程"`（不带路径）即触发桌面默认；给绝对路径则建在指定位置。

> 工程是一个独立子文件夹，所有素材、原子题、成卷都在里面，不污染其它位置；断点续作也回到这个文件夹。

### 3. 决策点预填（🔴模式二·STOP：开工前一次性问清，否则不得自动出题）

模式二的决策点 = **Phase 1「参数确认总表」全部 17 项 + 对应科目文档第 5 节的科目特有参数**，开工前一次性问清并写入 `<工程>/meta.json` 的 `decisions` 字段，之后严格据此自动执行，不再逐题打扰。

> 模式一则无需预填，逐项发生时再问。这些选择连同工作模式一并存入 `<工程>/meta.json`，作为本卷的"作业指导书"，断点续作也据此进行。

---

## 执行流程

### Phase 0：资料收集与读取

按资料类型分流处理，**不遗漏任何一份资料/链接**：

**本地文档**（.docx/.pdf/.pptx/.xlsx/.csv/.txt/.md）：
```bash
python3 <SKILL_DIR>/scripts/read_material.py "文件1" "文件2" ...
```
脚本统一输出文本（表格转 `|` 分隔）。若 docx/pdf 内含图片型阅读材料，脚本会提示，需解压后按下方"图片"三级策略识别。

**图片**（截图/拍照/.png/.jpg）——**三级识别策略，兼容不同模型**：
1. **你（模型）本身支持多模态识图** → 直接看图识别（凡支持识图的多模态模型，用其原生识图能力即可）。
2. **你是纯文本模型、无法识图** → 调本地 OCR 兜底：
   ```bash
   python3 <SKILL_DIR>/scripts/ocr_image.py "<图片>" --save "<工程>/materials/截图_XX.md"
   ```
   （脚本自动降级 RapidOCR→PaddleOCR→tesseract；都没装会提示 `pip3 install rapidocr-onnxruntime`）
3. **两者都不行** → 请用户手动誊录图中文字成 .md 放进 `materials/`。

> **无论哪种方式，识别结果都必须存成 markdown 落盘到 `工程/materials/`**，按规律命名（见下"素材命名规范"），不要只在对话里识别完就丢。这样图片素材和网页素材一样可回看、可溯源、可被门禁校验。

**在线链接**（含历年真题网页、新闻、科普文）：
```bash
python3 <SKILL_DIR>/scripts/fetch_web.py "<url>" ...
```
多策略降级抓取，输出 Markdown 正文。小红书/B站短链自动跟随重定向。
已内置 fetch-everything 引擎（多在线服务分流 + Scrapling 浏览器降级 + 质量门），**不要调用外部抓取技能/工具替代**——只有 `fetch_web.py --save` 会写抓取凭证头，外部工具抓的内容过不了溯源门禁。`requests`/`scrapling` 未安装时引擎自动跳过对应路线，退回 jina 直连。

**联网选材来源**（文言文/现代文/作文素材的具体站点与检索方法）见 `references/material-sources.md`。核心：文言文走古诗文网/ctext 公版古籍（《世说新语》《古文观止》节选）；现代文、作文素材按主题检索《意林》《读者》《作文周刊》《意林·作文素材》美文；非连文本取《科学之友》等科普+数据图表。**抓到的素材一律落盘到工程的 `materials/` 目录**（命题时只读当前题相关素材，避免上下文膨胀）；抓不到一律请用户截图或提供 PDF，绝不臆造拼凑选文。

**反爬站点**（学科网、组卷网、希沃白板、需登录的小红书等）：
脚本抓取失败会明确提示。此时立即告知用户："该网站有访问限制，请截图相关内容，我来识别提取。"

**素材命名规范（所有落盘到 `materials/` 的文件统一遵守）**：

```
<板块>_<来源>-<简述>.md
例：非连_中新网-种子库.md   现代文_意林-补碗.md   文言_古诗文网-世说新语德行.md
    截图_用户-真题第3页.md   作文素材_作文周刊-成长.md
```
- 板块前缀：`非连 / 现代文 / 文言 / 诗词 / 名著 / 作文素材 / 截图 / 真题`
- 手工誊录/截图识别的素材文件，开头**必须写**两行元信息：`来源：<URL或出处>` 和 `抓取日期：<YYYY-MM-DD>`——门禁回填 `source/source_file` 依赖它（`fetch_web.py --save` 抓取的文件已自动带凭证头，无需手写）。

**资料读取后**，提取整理：
- 知识点清单（按课标章节归类）
- 可用素材（文段、诗词、图表、数据、新闻）
- 对应教材单元与语文要素
- 可命题方向（哪些素材适合做什么题型）

> **Phase 0 → Phase 1 依赖**：Phase 0 读完资料后，样卷结构 JSON 和 materials/ 文件才就绪，Phase 1 的"样卷优先"解析和总表第 15 项（阅读素材逐块确认）才能做完整确认。无资料时可直接进 Phase 1，样卷/素材在 Phase 2 出题时再补。

### Phase 1：参数确认（一张总表问完，写入 meta.json 后才出题）

> **先问一句**：用户有没有"参考样卷/本地真题"？**有 → 先走下方"样卷优先"路径解析定结构**，总表中结构类参数（总分/时长/大题分值）直接取自样卷，不再重复问；没有 → 按总表确认。已明确的跳过；用户答"按默认"即用默认列。

用 AskUserQuestion 按总表**分组确认**（三组三问，不要拆成十几轮，也不要不问就动笔）：**组①定位 = 第 1-4 项 + 第 16 项科目特有参数**（确认科目的同一轮就处理听力/配图，不要等到表尾）；**组②规格 = 第 5-10 项**；**组③工程与素材 = 第 11-15、17 项**。

**参数确认总表**：

| # | 参数 | 默认值 | 写入 | 何时必问 |
|---|------|--------|------|----------|
| 1 | 学段年级 | 九年级 | `--stage` | 总是 |
| 2 | 科目 | 语文 | `--subject` | 总是 |
| 3 | 考试类型 | 中考模拟 | `--type` | 总是 |
| 4 | 地区 | 长沙 | `--region` | 影响满分/是否开卷/折算时 |
| 5 | 总分·时长·大题结构与分值分布 | 样卷 > 预设 > 内置默认 | `--total` `--duration` `--questions` / `--blueprint-file` | 无样卷且预设未命中时 |
| 6 | 难度系数 | 小学0.8 / 初中0.7 / 中考0.65-0.70 / 高考0.55-0.65 | meta | 用户有偏好时 |
| 7 | **考试范围**（单元/课次/书目）| 不限（按学段全册）| `--scope` / meta.exam_scope | **总是（极易漏，直接决定考点覆盖）** |
| 8 | **教材版本/册次** | 不限 | `--textbook` / meta.textbook | **政史地必问**，其它科也应问（不问则考点锚定无依据）|
| 9 | 作答方式 | 卷面作答（**不生成答题卡**，别写"答题卡上作答"）| `--answer-method` | 总是 |
| 10 | 作文规格 | 字数下限按学段缩放（见下注）| 作文题 json + essay_grid | 含作文的卷 |
| 11 | 卷面工程项（页码/密封线·座位号）| 页码开 / 密封线关 | `--sealing-line` `--page-number` | 用默认即可，不必专门问 |
| 12 | 输出格式 | 仅 docx | build `--pdf` | 用默认即可 |
| 13 | 答案解析详略 | 详细（含采分点）| `--answer-detail` | 用默认即可 |
| 14 | 素材来源方向 | A·全自动联网抓真实素材（B·用户提供为主，缺口用 A 补）| meta.decisions | 总是；无论 A/B 选文都必须真实可溯源落盘 materials/ |
| 15 | 各阅读板块·字数/题材/来源 | 按对应科目文档第 2 节区间表 | meta.decisions（build 据此校验字数）| 含阅读选文的卷：**动笔写任何阅读题前逐块确认** |
| 16 | 🔴 科目特有参数 | 无默认，必问 | meta.decisions | **英语 listening_plan、理科 figure_plan（确认科目时即问）**；清单见对应科目文档第 5 节 |
| 17 | 抓不到素材时 | 自动换源重试 | meta.decisions | 模式二必问 |

> **作文规格·字数下限默认**（不要一律写600）：小学中年级 300-400 / 小学高年级 400-500 / 初中 500-600 / 中考·高中 ≥600 / 英语作文按词（见 `subjects/英语.md`）。`essay_grid` 的 `rows×cols` 应与字数下限匹配（20列×行数≈格数）。
> 理科配图限制须在确认科目时即告知用户（锚点见"适用范围⚠️"）。

**样卷优先（中小学无统一卷，有样卷必须先走此路径）**：用户给了样卷时——
1. 用 `read_material.py`/识图读样卷全文；
2. 解析出结构写成 JSON：`{"stage","subject","total","duration","questions","subtitle","skeleton":[["100_sec_x","一、..."],...],"manifest":[["101","q01","题型",分值,"考点","难度"],...]}`（字段见 `make_paper.py`/`authoring-workflow.md`）。`stage/subject/region/exam_type` 写进蓝图即生效（CLI 未显式指定时以蓝图为准）；选文字数区间可加 `"novel_len":[下限,上限]`（默认九年级小说 1000-1500）；
3. 存为 `工程父目录/结构.json`，`init` 时 `--blueprint-file 结构.json` 即按样卷出卷。
4. 这样满分/题型/分值完全贴合用户的本地卷，不依赖内置默认。

🔴 **STOP·Phase 1 出口（唯一确认门禁）**：总表参数确认完并写入 meta.json（模式二含 decisions 全量预填）后，展示题型分布表（manifest），**用户确认或调整后才进入 Phase 2 出题**。

### Phase 2：组卷出题

**科目路由（按需加载：先读本节①通用命题规则，再 Read 对应科目文档，不读无关科目）**：

| 科目 | Phase 2 动笔前必读 |
|------|-----------------|
| 语文 | ① 通用命题规则 → Read `references/subjects/语文.md` + `references/exam-templates.md`（21题逐题命题工艺） |
| 英语 | ① 通用命题规则 → Read `references/subjects/英语.md`（387行，覆盖听力/完形/阅读/七选五/语法填空/读后续写/书面表达/短文改错） |
| 政治·道法 | ① 通用命题规则 → Read `references/subjects/政治.md`（含时政时效门禁规则） |
| 历史 | ① 通用命题规则 → Read `references/subjects/历史.md`（含史料软门禁规则） |
| 地理 | ① 通用命题规则 → Read `references/subjects/地理.md`（含SVG/用户提供图源分级） |
| 数学 | ① 通用命题规则 → Read `references/subjects/数学.md` |
| 物理 | ① 通用命题规则 → Read `references/subjects/物理.md` |
| 化学 | ① 通用命题规则 → Read `references/subjects/化学.md` |
| 生物 | ① 通用命题规则 → Read `references/subjects/生物.md` |

> 旧版 `subjects/理科.md` 和 `subjects/政史地.md` 已拆分（v3.18.0），保留为兼容入口（仅提示导向新文档），新出卷请按上表读对应单科文档。
>
> 🔴 **地理特别说明（W-3）**：高考地理 75%+ 题依赖图表（等高线/气候图/区位/分布）。**Phase 1 确认"地理"科目时第一问必须问图源**——`figure_plan` 三选一：①用户提供等高线/卫星/复杂图（推荐）②AI 写 SVG（仅适用简单柱状图/饼图情境）③降级为"非读图题专项卷"（避开等高线题型，但出题灵活度大幅受限）。**未问清不得进入 Phase 2**，否则成卷可能整套无法作答。

> 科目文档统一含 5 节：命题规则 / 选材规格与字数区间 / 排版要求 / 科目反模式 / Phase 1 额外参数。含阅读选文的科目（语/英/政史地材料题）还须读 `references/authoring-workflow.md` 的 material 块排版铁律（build 硬门禁）。
>
> **自洽说明**：①通用命题规则（去AI感、难度控制、能力层次）已完整内嵌在本节；科目专属要求在 `references/subjects/`，**对应科目文档缺失 → 说明 skill 文件不完整，提示用户重新获取，不要凭记忆脑补科目规则**。

---

#### ① 通用命题规则（所有科目）

##### 去AI感策略
```
【绝对禁止】
× “同学们，让我们一起来...” / “请认真阅读下面的材料...”（直接给材料）
× “综合以上材料，谈谈你的看法”（太泛，给具体角度和锚点）
× 选项结构完全一致（如四个“XX的精神/品质/品格/态度”）
× 阅读材料是“鸡汤文”或说教文
× 作文题假大空（“以‘坚持’为话题”）
× 干扰项随便凑，一眼看出答案

【务必做到】
✓ 题干简洁直接，不废话
✓ 选项长短参差，表述方式各异
✓ 干扰项反映学生真实常见错误（偷换概念、绝对化、强加因果）
✓ 阅读材料有生活质感（家书、采访、新闻特写、真实故事、科普）
✓ 全卷语言风格统一
```

##### 难度控制（数字为参考基线，各科目按学段/卷型调整）
```
基础题（记忆/识别类）：≥0.8，“必得分”
中等题（理解/应用类）：0.6-0.8
拔高题（分析/探究/综合计算）：0.4-0.6
每板块内部由易到难；设送分题与优生拉分题
全卷难度系数：小学 0.8 / 初中 0.7 / 中考 0.65-0.70 / 高考 0.55-0.65
```

##### 能力层次递进
```
识记积累 → 理解感悟 → 分析综合 → 运用表达 → 鉴赏评价 → 探究
```

---

### Phase 3：原子化组卷 → 生成 Word 试卷 + Word 答案解析

**原子化工作流（大资料量/多轮迭代时必须走此路径）**（完整流程见 `references/authoring-workflow.md`）。每题独立成 json 文件，最后合并，避免上下文丢失、便于增量改题。

```bash
# 1) 建工程脚手架（目录+meta+manifest+大题分隔文件 + 复制脚本副本到 工程/scripts/）
#    纯工程名→自动建到桌面（跨平台探测）；给绝对路径则建在指定位置；--mode 写入工作模式
#    默认(不传参)=九年级语文长沙；其它学段科目用 --stage/--subject/--region/--type/--total/--duration/--questions
python3 <SKILL_DIR>/scripts/assemble.py init "<试卷名>_工程" --stage 九年级 --subject 语文 --type 中考模拟 --mode 全自动
#    文科示例：--stage 高三 --subject 英语 --type 高考   （命中 presets/高三_英语.json）
#    卷面/范围可选参数：--answer-method 卷面作答|答题卡  --sealing-line true  --page-number false
#                       --scope "第一~三单元"  --textbook 统编版  --answer-detail 详细|简略
#    样卷驱动：先把样卷解析成结构 JSON，再 --blueprint-file "<工程父目录>/结构.json"

# 1b) 决策点写入：跨平台稳妥做法 —— 直接用 Write/Edit 把决策写进 <工程>/meta.json 的 "decisions" 字段，
#     不要靠命令行传 JSON（Windows 的 cmd/PowerShell 对引号处理不同，易出错）。
#     mac/Linux 也可用 --decisions-file <json文件> 传入。

# 2) 抓素材入 materials/，逐题写 items/NN_qXX.json（paper+answer+解析+命题意图）
#    🔴 每写完一题/一部分立即存档（init 已自动 git init；无 git 自动跳过）：
#    这是硬要求——build 会检查 items/ 是否全部提交，有未提交改动直接拒绝出卷。
python3 "<工程>/scripts/assemble.py" commit "<工程>" "题7完成：动能定理计算题"

# 3) 合并校验并出卷 —— init 后改用【工程内脚本副本】，不再碰技能本体脚本！
#    自动校验题量/分值、选文完整性、溯源凭证、缺图、各板块选文字数；生成两个 Word 到 build/（默认带页码）
#    需同时出 PDF 加 --pdf（需本机 LibreOffice，否则提示手动导出）
python3 "<工程>/scripts/assemble.py" build "<工程>" [--pdf]
```

**自检/盲检发现问题 → 处理与回滚（适用 Phase 3.5/3.8/3.9，精确区分勿混）**：
- **标准动作＝定点修复**：只改对应 `items/NN_qXX.json` → `commit` → 重 build。**自检失败不回滚**——回滚会丢掉同批其他正确的题。
- **单题回滚**（仅当某题越改越坏/改出 JSON 错误，不影响其他题）：
  - 改动未存档：`git -C "<工程>" checkout -- items/NN_qXX.json`（弃未 commit 改动）
  - 已存档退上一版：`git -C "<工程>" checkout HEAD~1 -- items/NN_qXX.json`（只回退该题）
- 🔴 **禁用 `git reset --hard`**（波及整仓、丢未存档工作，属危险操作）。

> **务必把 build 的所有 `[校验告警]`/`[PDF]`/`[后端]`/figure 降级等输出如实转告用户**——
> 例如小说字数偏短、题量分值不符、抓取替代源、配图降级为占位、用了 `--allow-unsourced` 等，
> 不要只看到"已生成"就报喜，告警与降级都要让用户知情。

> **为什么用工程内副本（重要）**：`init` 会把脚本复制一份到 `<工程>/scripts/`。之后的 build 一律用这份副本，
> 这样即便临场要调脚本，改的也是工程内副本，**永不污染技能本体**，多份试卷工程互不影响。

**出卷后必做（告知位置，不要替用户打开文件）**：build 末尾会打印两个 Word 的**绝对路径**与所在文件夹。
你要把这两个路径清楚转告用户，然后用 AskUserQuestion 问：**"是否帮你打开成卷所在文件夹？"**
- 用户同意 → 执行打开**文件夹**的命令（macOS `open "<build目录>"` / Windows `explorer "<build目录>"` / Linux `xdg-open "<build目录>"`）。
- **只打开文件夹，绝不直接打开 docx 文件**——用户关掉文件后仍能在文件夹里找到，避免"文件在哪"的困惑。

🔴 **STOP · 出卷前确认门禁（必做，不可跳过）**：在运行第3步 `build` 之前，必须先把 `00_manifest.md` 的题目清单（题号·题型·考点·分值·难度·选材）完整展示给用户，逐题让用户确认或指出要改的题。**用户明确说"可以出卷"后才运行 build**。避免未经确认直接产出成卷。

**原子题文件最小格式（与 `authoring-workflow.md`、`make_paper.py` 顶部 block 列表一致；这是 build 唯一认的格式）**：

> 🔴 **只有「块格式」生效**：assemble.py 只读 `atom.get("paper")` / `atom.get("answer")` / `atom.get("meta")` 三个键，**没有扁平格式转换**。题干/选项/选文/图都是 `paper` 数组里的 **block**（`{"type":...}`），不是顶层字段。**`num`/`score` 写在 `meta`**（供总分聚合与 manifest 对账；缺 score 不崩但 warn「未计入总分」），`paper` 的 question/answer 块里再写一份 `score` 字符串（如 `（2分）`）供卷面显示。

```json
{
  "meta": {
    "num": "7", "score": 2, "difficulty": 0.7,
    "type": "选择|填空|简答|材料分析|解答|作文",
    "knowledge_point": "考点标签",
    "source": "https://… 或 节选自《X》 或 原创-已声明",
    "source_file": "materials/xxx.md",
    "status": "已出"
  },
  "paper": [
    {"type": "material", "title": "选文标题", "author": "作者/朝代",
     "paras": ["第一段全文", "第二段全文"], "source": "（节选自《X》）",
     "layout": "prose|verse",
     "block": "非连|小说|散文|文言|名著（可选；不写按小标题推断，字数门禁按此归板块）"},
    {"type": "question", "num": "7", "score": "（2分）", "text": "题干正文"},
    {"type": "options", "items": ["A. …", "B. …", "C. …", "D. …"]}
  ],
  "answer": [
    {"type": "answer", "num": "7", "score": "（2分）", "text": "C"},
    {"type": "analysis", "text": "【解析】…"}
  ]
}
```
> 含图题：在 `paper` 数组加 figure 块 `{"type":"figure","src":"materials/图.png","alt":"图注"}`（用户提供图）或 `{"type":"figure","kind":"svg","svg":"<svg…>","alt":"…"}`（AI 直绘）。
> 大题分隔/纯材料文件：`meta.status="-"`，`paper` 只放 `section`/`sub`/`material` 块、无 question，`answer` 留 `[]`。完整 block 类型见 `make_paper.py` 顶部文档。

规则：① **每道小题一个独立文件，文件名前缀须全局唯一且递增**——如一选 7 题写 `101_q01.json / 102_q02.json / … / 107_q07.json`（不是全用 `101_` 前缀！同前缀会被去重，v3.24.0 起按"完整基名去版本号"判重，`101_q01` 与 `101_q02` 不再误判，但仍建议前缀递增唯一最清晰；只有 `101_q01` + `101_q01_v2` 这种同名带版本号才会判为同题）；前缀数字对应 manifest 大题编号区段（1xx→一大题/2xx→二大题…）；② 含选文题必须有 `material` 块且 `paras` 写全文，缺 `source`+`source_file` 则 build 拒绝；③ `material.layout="verse"` 让古诗词逐句居中；④ 含图题：用户提供图片填 `{"type":"figure","src":"materials/图.png","alt":"…"}`；AI 自动渲染填 `{"type":"figure","kind":"svg","svg":"<svg …>…</svg>","alt":"…"}` 或 `kind":"function"/"climate"` 等（**svg 内容写在顶层 `svg` 字段，切勿写成 `"spec":"<svg>"`**，否则降级占位、图丢失；详见 `物理.md` 第 2 节）；缺 src 又无可渲染内容时 build 末尾按占位比例 warn；⑤ `options` 仅选择题需要；⑥ `answer` 客观题填选项字母，主观题填采分点列表；⑦ **JSON 字符串内的中文引述一律直接写全角 `“”`**——未转义的 ASCII 双引号会让整个文件解析失败、该题被完整性门禁拦下（不要用 `\"` 转义绕行，渲染时反正会规范成全角）。**⚠️ 英语题例外**：英语题干/选项/原文里的引号、撇号**一律保留 ASCII 半角，不准用全角 `“”`**（全角引号在英文里是排版错误，且 build 会 warn）。唯一正确写法：**双引号写 `\"` 转义**（JSON 字符串本就以双引号定界，内部双引号只能转义，没有"改用单引号"的替代——JSON 不接受单引号定界字符串），**撇号 `'` 直接写**（JSON 字符串内单引号无需转义）。引号撇号混用的正例：`"text": "He said, \"I'm fine.\""`。完整 block 类型扩展见 `make_paper.py` 顶部文档（存在时参照）。

##### 🔴 排版铁律（写 items JSON 前必读 · build 有 lint 软提醒兜底）

版式由 **block type 自动决定，AI 只负责写对内容、选对 block，禁止手设字体/字号/居中**。AI 把排版搞错，几乎都是越权手设版式、或把该用 Unicode/全角的字符写成了半角/markdown。分工边界与必守规则：

| # | 维度 | 谁负责 | AI 必须怎么做 |
|---|------|--------|--------------|
| ① | 居中·对齐·层级·字体·字号·行距 | make_paper 按 block 自动 | 大题用 section 块、小标题用 sub 块、题干用 question、选文用 material；古诗词 `material.layout="verse"` 逐句居中，篇名/作者居中、出处自动右对齐。**禁止**：用空格/全角空格手动居中；用空行手动撑行距（行距 1.5 倍已固定）；把"一、""（一）"塞进 text 充当层级；在 JSON 里写任何字体名/字号（写了也不生效，正文宋体五号、选文楷体、标题宋体加粗已固定） |
| ② | 上标·下标 | 简单：AI 写 Unicode；复杂：写 `_{}`/`^{}` 脚本渲染 | **单数字优先 Unicode**：化学式 `H₂O`/`CO₂`/`C₆H₁₂O₆`、幂 `x²`/`10⁻³`、单位 `m/s²`/`cm³`（禁写 ASCII 的 `H2O`/`x^2`/`m/s2`；下标 `₀₁₂₃₄₅₆₇₈₉`、上标 `⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻`）。**Unicode 表达不了的多字符/中文下标**（合力 `F_{合}`、最大速度 `v_{max}`、表面积 `S_{表}`）写 **`_{...}` 下标、`^{...}` 上标**，make_paper 渲染成真上下标。**花括号不能省**：`F_{合}` ✓，写成 `F_合`（漏花括号）会原样印出下划线 ✗ |
| ③ | 全角·半角 | AI 写文本 | **中文正文标点一律全角**（`，。；：？！""''（）《》—…`）；**英文、英语整题、纯数字一律半角**；不在中文里夹全角字母数字（写 `2025` 不写 `２０２５`、写 `ABC` 不写 `ＡＢＣ`） |
| ④ | 富文本标记 | 渲染器**只认 `_{}`/`^{}`** | **唯一支持的标记是②的 `_{...}`/`^{...}` 上下标**；其余 markdown/HTML 一律禁写：`**粗**` `*斜*` `~~删~~` `^x^`（成对脱字号）`# 标题` `[文](url)` `<i>` 都会原样印成符号。需要加粗改用 sub 块；**渲染器无斜体**，物理量/变量直接正体写，不要写 `*v*`/`<i>v</i>`；乘号用 `×` 不用 `*` |

> build 的 `_check_typography` 会对②③④的常见违例打 **warn（不阻断）**，英语整题误用全角引号另有专项 warn；**看到任何排版 warn 必须回改对应 items，别让符号/错宽标点原样印到卷上**。JSON 内引号的转义写法见上文规则⑦（与③不冲突：③管渲染出的成品标点，⑦管 JSON 源码里怎么写才合法）。

输出（缺一不可，落在 `build/`）：
1. **学生试卷.docx**——A4，可直接打印，默认带页脚页码「第X页 共Y页」；按 `meta.sealing_line` 可加密封线与座位号；排版按 `references/formatting-rules.md`（缺失时默认规范：A4纸/页边距2.54cm，试卷名黑体二号居中，正文宋体小四10.5磅，行距1.5倍，古诗词楷体居中）
2. **参考答案及解析.docx**——含每题答案 + 详细解析 + 评分标准/采分点
3. **content.json / content.md**——结构化源文件与 Markdown 镜像；当 python-docx 不可用时，供 Pandoc、Word MCP、Documents 插件或其它 Office 工具生成/修复 Word。
4. **（可选）PDF**——build 加 `--pdf` 且本机有 LibreOffice 时同时导出两份 PDF。

> 答案解析要包含：客观题答案+错因，主观题采分点（"答出X点给X分"），作文评分等级标准，命题意图与教材关联。
> 单题快速生成也可直接用 `make_paper.py content.json`（不走工程目录），但多资料/需迭代时一律用 assemble 原子化流程。

### Phase 3.5：审题磨题（v3.21.0 机器化 + v3.22.0 扩展）

**目标**：在交给用户审之前，机器自动产出整卷质量自审表。

🟢 **build 自动生成 `build/Phase3.5_自审表.md`**（Batch6-L3 机器化，AI 无需手工统计）：

1. **考点覆盖统计**：依据 items meta `knowledge_point` 字段统计；任一考点重复 ≥3 次 → 🔴 自审 issue。
2. **难度梯度统计**：依据 items meta `difficulty` 字段（0-1）统计均值/范围/跨度；跨度 <0.25 → 🔴 自审 issue（全卷难度均匀，缺分层）。
3. **题干长度分布**：统计每题 question.text 长度；>3 题超均值 2.5 倍 → 🔴 自审 issue（前后风格突变）。
4. **干扰项同质性**（v3.22.0 新增）：扫描单选题 options，若多个选项前缀相同（如"加速度为 5/加速度为 2"）→ 🔴 自审 issue（学生可二选一秒杀；多选题不触发）。
5. **同源考点聚合**（v3.23.0 新增）：按"主类·子类前缀"语义聚合（如"力学·牛顿第二定律"+"力学·牛顿定律"+"力学·牛顿运动定律"），≥3 次 → 🔴 issue。精确匹配漏过的同源考点由此识别。
6. **物理量合理性**（v3.23.0 新增·理科类专用）：扫描答案的偏转角/摩擦因数等数值，偏转角<1° / 摩擦因数>1 → warn（参数不合理或现象不显著）。

build 末尾还会打印**卷头常数使用率与数值规约 warn**（不阻断，仅提醒）：

- **P1-2 卷头声明三角值/g/π 无引用** → warn"sin37° 全卷无题引用，属冗余条件"
- **P1-3 答案残留 π 符号未数值化**（卷头声明π取值时）→ warn"E=100π V 应补 ≈314 V"

**v3.22.0 新增的硬门禁**（exit 2 阻断）：

- **P0-1 figure 字段显式声明**：理科电磁/光学/电路/受力/装置等含图题型，`items/NN_*.json` 的 meta 必须写 `"figure": "required"`；build 校验缺 figure block → exit 2。详见 `references/subjects/物理.md` 第 2 节"figure 字段硬声明"。
- **P0-2 连续 section/sub 去重**：build 末尾自动去除 paper/answers 数组中紧邻重复的大题标题（多个 atom 各自打同名 section 时，docx/md 不再出现"## 一、单项选择题"重复行）。

**v3.23.0 新增的题量范围门禁**：理科 preset（高三+九年级 物理/化学/生物）声明 `questions_range: [min, max]`（如高考物理 [14,18]）；build 时实得题量在范围内不打 warn，无需 `--allow-incomplete` 绕过；超出范围才 warn。同时 `references/subjects/物理.md` 第 5 节新增"难度系数锚定表"校准 AI 自评。

> **遇 🔴 自审 issue 必须返工对应 items 后重跑 build**——例如考点重复 → 改题改考点，难度均匀 → 重设难度系数。改完 build 自动重算自审表，全绿才能进 Phase 4。

🔴 **STOP·Phase 3.5 出口**：`Phase3.5_自审表.md` 全绿（无 issue）后，才进入 Phase 4。

---

### Phase 3.8：终审门禁（v3.25.0 新增·合并排版后整卷对账）

**两次自检分工**：Phase 3.5 查**原子层命题质量**（考点/难度/题干/同质/同源）；终审查**合并排版后才暴露的整卷结构问题**——单看一道题的 JSON 看不出，拼成整卷才发现。

🟢 **build 末尾自动产出 `build/终审表.md`**，并对以下做门禁/提醒：

**🔴 门禁级（exit 2 阻断，`--allow-final-audit` 可降级）**：
1. **试卷↔答案题号对账**：某些题有答案、另一些题漏答案 = 真残卷 → 拒绝。（全卷 0 答案＝分批预览，降为提醒不拦）
2. **客观题答案越界**：选择题答案字母超出实际选项范围（如只有 A/B/C 却答 D）→ 拒绝。

**⚠️ 提醒级（warn）**：
3. 试卷题号断号（1,2,4 跳 3）
4. 标题层级断层：孤立小标题无上级大题 / 空大题下无题
5. 大题中文编号不连续（一、三、… 跳"二"）
6. 解析疑似缺失（答案无 analysis 块且正文<15字，≥2 题时提示）
7. 答案有多余题号（试卷无此题）

> 图题对应由 P0-1（题干"如图"必有 figure）+ R2（占位率 warn）覆盖，终审不重复。
> 内容真实性由原子层硬门禁（溯源/忠实节选/措辞）覆盖，终审不重复。

🔴 **STOP·终审出口**：`终审表.md` 门禁级清零后才进入 Phase 4。

---

### Phase 3.9：独立subagent盲检（v3.26.0 新增·防自评偏差）

**为什么**：Phase 3.5/3.8 是**机器规则**（题号对账/字数/sha256），查不了"内容对不对"。而出题的主会话 AI 自己复核，有"自己出的题自己觉得没问题"的乐观偏差（darwin-skill 实证：同上下文自评不可信）。所以机器两表全绿后，**必须派独立subagent盲检**——机器管结构、subagent管内容、且独立于出题过程。

🔴 **强制协议**（不可主会话自己审了事）：

1. 用 **Agent 工具派一个 sonnet subagent**（全新上下文，**不告诉它出题过程/不复用主会话**），只给它：工程路径、`build/` 两份 Word（或 content.md）、`Phase3.5_自审表.md`、`终审表.md`。
2. subagent任务＝**站在审卷老师立场盲审**，复核机器查不出的内容层（每条给出题号 + 问题 + 修改建议）：
   - **答案/解析正确性**：逐题核对答案对不对、解析推理有无错误、采分点是否合理（机器只查"有没有答案"，查不了"答案对不对"）
   - **题目科学性**：题干表述有无歧义/科学性错误、选项是否严谨、是否有多解或无解
   - **材料真实性内容核验**：选文是否断章取义、是否曲解原意（机器只校验 sha256/来源，判不了内容是否被歪曲）
   - **难度名实**：标注的 difficulty 与题目实际难度是否相符
   - **学段适配**：是否超纲/欠缺该学段该科目命题规范（术语、题型、赋分习惯）
3. subagent回报问题清单 → 主 AI **只改对应 `items/NN_qXX.json`** → `commit` 存档 → 重 build → **重新派盲检**，直到subagent无实质异议。

> subagent是"独立第二双眼睛"，不是橡皮图章。它报的问题主 AI 不得擅自忽略，须逐条处理或向用户说明为何不改。

🔴 **STOP·盲检出口**：独立subagent确认无实质问题后，才进入 Phase 4。

---

### Phase 4：审题迭代

**输入**：Phase 3 产出的两份 Word + `items/` 原子文件 + `00_manifest.md` + Phase 3.5 自审表
**输出**：用户确认无需改动的最终版两份 Word

分板块展示成卷给用户，主动询问：
- "需要替换或修改哪道题？"
- "各板块难度是否合适？"
- "选文/素材是否满意？"

用户提意见后**只修改对应的 `items/NN_qXX.json`**，重跑 `assemble.py build`，其余题零改动、零风险，循环到满意为止。`00_manifest.md` 随时记录每题状态，支持中断续作。

🔴 **STOP·退出条件**：用户明确说"不用改了"或"定稿"后结束迭代，进入交付。

#### 交付时必须告知用户（免责与人工待办，逐条说清）

1. **文件位置**：两份 Word 的绝对路径 + 所在文件夹，并询问是否打开**文件夹**（不直接开文件）。
2. 🔴 **材料真实性自检表（build 自动生成，必须原样转发）**：build 成功时已自动打印并写入 `build/材料真实性自检表.md`（文件 | 选文标题 | meta.source | source_file | 溯源 | 标注措辞）。你必须把这张表**原样转发给用户**复核，不得省略、不得口头概括。表中出现 ❌ 说明用了 `--allow-*` 开关带病出卷——逐项向用户说明原因；标注含"改编/改写/整理自"或"原创"字样默认已被措辞门禁拒绝（exit 2），正确做法是回改标注为"节选自…"后重跑，而非加开关。
3. **触发的告警**：build 会把所有 warn 落盘到 `build/校验告警.md`（含「排版自检」分节：上下标/全半角/斜体/裸下标/英语引号，及题量分值/史料/降级开关等）。**原样转告用户**，包括选文字数越界、题量分值不符、抓取换源、配图降级占位、是否用了任何 `--allow-*` 开关（`--allow-unsourced`/`--allow-missing-figure`/`--allow-length`/`--allow-incomplete`/`--allow-wording`/`--allow-excerpt`/`--allow-stale`/`--allow-final-audit`/`--allow-uncommitted`）。
4. **需人工补的内容（待办清单）**：名著须**核对书目版本**；历史地图/地理图表需用户提供；figure 占位 `［图：…］` 处需补图；**英语听力**：录音稿已写入《参考答案及解析.docx》的 listening 板块，监考老师**按答案文档朗读两遍**（试卷上只有题号/题干/选项），或老师按脚本录制音频后让学生听。
5. **请用户终审**：真实素材经删改、AI 命题可能有疏漏，**事实/数据/出处/答案务必请用户人工校对**；难度系数为命题估计值（非实测）。
6. **版权提醒**：选用的真实新闻/美文仅供课堂测评，正式公开使用请用户自行确认版权。
7. **引号已自动规范**（单引号误用→中文双引号），如与原文有别属正常。

---

## 异常与兜底

遇到异常**先告知用户，再按以下规则处理；绝不静默跳过**。

🔴 **门禁拒绝 = 返工信号，不是停止信号**：build 被任何门禁拒绝（溯源/措辞/字数/缺图/完整性）时，任务**没有完成**，绝不把报错当最终结果停下来等用户。标准返工循环：

1. 读报错，定位违规的 items/materials 文件；
2. 素材不真实/无来源 → 用 `fetch_web.py` **重新检索真实素材**（换来源站/换文章均可），落盘 materials/；
3. 据新的真实素材**重新命题**，替换对应原子文件（设问全新写，不沿用旧题）；
4. 重跑 build → 仍被拒则回到第 1 步，**循环直到通过，把成卷交给用户**。

`--allow-*` 开关不是修复手段——仅当用户主动要求、或确属误伤（如选文书名本身含"改编"二字）才可使用，且必须告知用户。连续 3 轮返工仍无法获得真实素材时，才停下来向用户说明卡点（如请用户提供截图/PDF）。

| 触发条件 | 一线修复 | 仍失败兜底 |
|----------|----------|-----------|
| `read_material.py` 读本地文件报错（格式不支持/权限/损坏）| 尝试切换解析器（docx→LibreOffice转txt；pdf→pdfplumber→pdftotext）| 请用户另存为 .txt 或截图，走图片三级识别路径；不跳过该文件 |
| `fetch_web.py` 抓取返回空/报错 | 换 `material-sources.md` 备用站点重试一次 | 告知用户"该站点无法抓取"，请用户截图/提供 PDF；**绝不臆造选文** |
| `build` 门禁拒绝（材料文件缺 `source` 或 `source_file`）| 仅字段缺漏 → 补填重跑；素材本身无真实来源 → **重新抓取真实素材并据此重新出题**（见上方返工循环）| 连续 3 轮抓不到 → 请用户提供截图/PDF；`--allow-unsourced` 仅限用户主动要求 |
| DOCX 后端全部不可用（python-docx/Pandoc/Office 均无） | `setup.py --install` 安装 python-docx（须征得用户同意）| 输出 `build/content.md`，告知用户用 Word 手动打开 Markdown 中间产物 |
| `ocr_image.py` 识别失败（所有 OCR 引擎均报错）| 用模型自身原生识图能力直接读图 | 请用户手动誊录图中文字为 .md 放入 `materials/` |
| `assemble.py init` 失败（路径权限/磁盘问题）| 改为桌面默认路径重试（不传绝对路径）| 手动建目录后重试；若仍失败告知用户手动创建工程文件夹 |
| 用户给 URL 无法访问（403/超时/反爬）| 换同主题备用站抓取一次 | 请用户截图/PDF；不使用无法核实来源的内容 |
| build 字数门禁拒绝（选文越板块区间，区间见科目文档第2节）| 补充/精简选文后重写 materials/ 对应文件再 build | 征得用户知情同意后加 `--allow-length` 降级为告警（不要用 `--allow-unsourced`，那是溯源开关）|
| build 完整性门禁拒绝（items JSON 非法 / 题量≠期望）| 修复报错指出的 items/*.json（最常见：字符串内 ASCII 双引号改全角 `“”`）后重跑 | 仅分批预览等明确场景加 `--allow-incomplete` 降级为告警，**必须告知用户缺了哪些题** |
| build 措辞门禁拒绝（选文标注含"改编/改写/整理自"或"原创"字样）| 只是标注写错 → 改为"节选自…"重跑；**正文确实被改写过 → 重新抓原文忠实节选并重新出题**（教师原创只写 meta.source='原创-已声明'）| 仅选文标题/书名本身含这些词的误伤场景加 `--allow-wording`，并向用户说明 |
| build 忠实节选门禁拒绝（选文段落非原文逐字/顺序颠倒=疑似改字/编造/重排）| 材料**可删减无关部分（含中间段），但每段须逐字取自原文、按原文顺序**；重抓原文、逐字节选后重跑 | 仅原文有合理格式差异（OCR/换行噪声）误伤时加 `--allow-excerpt`，并向用户说明 |
| 断点续作时工程路径找不到 | 让用户重新指定工程路径 | 在**新路径**建新工程并把旧 `items/`、`materials/` 复制进来；**绝不在旧工程上重跑 init**（会重置 meta.json 的 decisions，见反模式 #10）|
| build git 存档门禁拒绝（items/ 有未提交改动）| 跑 `assemble.py commit "<工程>" "说明"` 把已写的题存档后重跑 build | 仅分批预览/确需未存档出卷时加 `--allow-uncommitted`（降级为告警）；无 git 环境该门禁自动不触发 |

---

## 特殊处理

### 小红书/社交媒体
提取教学相关内容（知识点、易错题、答题技巧），忽略营销，标注来源。

### 希沃白板课件
提取知识结构、重难点标注，利用课件逻辑辅助知识点覆盖。

### 历年真题参考
分析命题规律与考查重点；新题须区别于原题（换素材/换角度），严禁搬运；可模仿命题风格与难度梯度；避开学生过熟的经典片段。

---

## 命题反模式黑名单

> 每道题写完前过一遍本表。命中任何一条 → 必须返工，不得放行。

| # | 反模式 | 为什么不行 | 替代做法 |
|---|--------|-----------|----------|
| 1 | **编造选文来源** | 命题红线；build 门禁会拒绝，但伪造 source 字段更危险 | 抓不到 → 告知用户，请用户提供；绝不先编内容再补假来源 |
| 2 | **自行生成听力题而不告知用户** | 输出的 Word 没有音频，听力题成废题 | 开工前三选一（见 `subjects/英语.md` 第5节），写入 meta.decisions |
| 3 | **套用语文600字字数要求给英语作文** | 英语按词计，600字≈300词，严重超出学段要求 | 按学段词数（初中≥80词，高考≥100词）出英语作文 |
| 4 | **用过时时政材料出道法题** | 时政过期即错题；开卷考学生能现查反驳 | 抓近1-3个月真实报道，核对日期后再命题 |
| 5 | **高中政史地无样卷直接套内置预设** | 各省考纲不同，内置预设是近似值 | 强烈建议用户提供样卷；明确告知"本卷按通用兜底骨架，建议对照真题核查" |
| 6 | **选项四个结构完全一致** | 答题有规律可循，干扰项失效 | 选项表述方式各异，长短参差，反映学生真实常见错误 |
| 7 | **题干用AI套话开头** | "同学们""请认真阅读""综合以上材料谈谈你的看法" 暴露AI感 | 题干直接给任务，不废话寒暄 |
| 8 | **作文题"假大空"** | "以坚持为话题""谈谈你对梦想的理解" 写不出有内容的文章 | 从小切口进入，贴近学生真实生活场景 |
| 9 | **史料/数据未经核实** | 溯源门禁只查 material 选文，纯数据题由命题者自行把关 | 史料走 ctext/古诗文网核验原文；数据注明来源 |
| 10 | **断点续作覆盖已有 items/ 文件** | 重跑 init 会重置工程，已出好的题丢失 | 断点续作只跑 build，不重跑 init；需改结构时用 Edit 直接改 meta.json |
| 11 | **未展示 manifest 直接 build** | 用户无法在成卷前修改题目，造成反复重出 | build 前必须展示 00_manifest.md，等用户明确说"可以出卷"再执行 |
| 12 | **理科未告知配图能力分级就开始出题** | make_figure 可生成 11 种图（含 SVG）但有边界——复杂装置/真实照片/等高线/卫星图须用户提供；未问清就开始会出现"该 AI 画的没画+该用户提供的没要" | Phase 1 确认科目时必告知三级分级（AI 直绘 / 用户提供 / 占位），定 figure_plan 后再出题 |
| 13 | **为图省事自行加 `--allow-unsourced`** | 绕过溯源门禁让整卷选文真实性无法保证，学生可能拿到 AI 编造的阅读材料答题 | 只有用户明确知情并要求时才加；一旦使用必须显式告知"本卷已绕过真实性门禁，请自行核对来源" |
| 14 | **换皮改编真题**（换数字/换人名/换选文但沿用真题设问结构） | 违反原创底线；学生刷过原题即识破，且有版权风险 | 真题只用于分析命题规律；设问角度、干扰项、采分点全新设计（见"底线要求1"操作定义）|

---

## 质量检查清单

> **注意**：结构校验项仅适用于**长沙中考语文（九年级·语文·长沙）**。其它科目/学段/地区请对照用户提供的样卷或本地课标核查，不得用下列固定数字检查非语文科目。

### 结构校验（⚠️ 仅限长沙中考语文——其它科目/学段直接跳过本小节，按样卷或预设核对）
- [ ] 3大题、21题、分值20/50/50、总分120
- [ ] 全卷连续编号 1-21（不按大题重计）
- [ ] 文言文含断句选择题（第16题）

### 内容校验
- [ ] 知识点覆盖用户指定范围
- [ ] 难度梯度合理（基础≥0.8，全卷0.65-0.70）
- [ ] 无知识性/政治性错误
- [ ] 选择题答案分布均衡（避免连续3个相同）

### 原创性校验（操作定义见"底线要求1"）
- [ ] 选文真实可溯源（meta.source/source_file 齐全，URL 来源带抓取凭证头）
- [ ] 设问全新：未复用任何真题的题干句式/设问措辞/选项内容
- [ ] 无换皮改编：没有"真题换数字/换人名/换选文"的题
- [ ] 选段避开学生烂熟片段

### 去AI感校验
- [ ] 题干简洁、选项参差、材料有生活质感、默写有情境、作文贴近生活、全卷风格统一

### 完整性校验
- [ ] Word 试卷 + Word 答案解析齐全
- [ ] 答案解析含采分点说明与作文评分标准
- [ ] 排版无 warn（见 `build/校验告警.md` 的「排版自检」分节：②上下标 / ③全半角 / ④标记）
- [ ] 🔴 每题已 `commit` 存档（**build 硬门禁**：items/ 有未提交改动直接拒绝出卷；无 git 环境则不适用）

