From a4017ad44d0c52a1fca8f6d222cd8297790ec5b6 Mon Sep 17 00:00:00 2001 From: dela Date: Mon, 17 Aug 2026 09:41:42 +0800 Subject: [PATCH] feat: make SuperPaper the family parent of superfig and supertensor House the two figure toolkits as git submodules under SuperPaper. The parent owns paper-note orchestration; children keep their own history, macros, and lint. DESIGN.md is the family contract. --- .gitignore | 8 + .gitmodules | 6 + DESIGN.md | 1824 ++++++++++++++++++++++++++++++++++++++++++++ README.md | 50 ++ SKILL.md | 68 ++ agents/openai.yaml | 8 + superfig | 1 + supertensor | 1 + 8 files changed, 1966 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 DESIGN.md create mode 100644 README.md create mode 100644 SKILL.md create mode 100644 agents/openai.yaml create mode 160000 superfig create mode 160000 supertensor diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f68865e --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +work/ +*.aux +*.log +*.out +*.fls +*.fdb_latexmk +*.synctex.gz +.DS_Store diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..3b775c1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "superfig"] + path = superfig + url = ssh://git@ssh.gitea.mygoband.com:2222/carrydela/SuperFig.git +[submodule "supertensor"] + path = supertensor + url = ssh://git@ssh.gitea.mygoband.com:2222/carrydela/SuperTensor.git diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000..449cc81 --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,1824 @@ +# Superpaper Family:论文笔记编排层与推导图工具包 + +| 字段 | 值 | +|---|---| +| **Title** | Superpaper Family:论文脉络 / 推导 / 出图分层设计 | +| **Author** | TBD | +| **Date** | 2026-08-17 | +| **Status** | Final | +| **Audience** | 将在 `/home/carry/myprj/tools/skills/` 落地 `superpaper/`(及后续 `superderive/`)的工程师与 agent | +| **Companion** | `superfig/`、`supertensor/`、`wdkns-skills/skills/youtube-render-pdf/` | + +--- + +## Overview + +用户要的三件事——**文章脉络梳理**、**公式推导**、**抽象公式图像化**——不是「再画一种图」,而是一层**读论文 / 写讲义**的编排问题,外加一类尚未存在的**逐步代数图**。现有 `superfig` 的契约是「一条 paper claim → 一张 dense、slide-ready 的节点/边图」(见 `superfig/SKILL.md`);`supertensor` 的契约是「一条张量计算路径 → 一张形状对齐的 face 图」(见 `supertensor/SKILL.md`)。把笔记编排、符号表、引理依赖、逐步改写塞进 `superfig.sty`,会同时破坏两边已经用 lint-on-warning 钉死的图尺度不变量(一图一个 `\sfcallout`、`\sftopformula` 必须在最后 `\sfrowend` 之后、每图 ≤4 个活跃色相)。 + +本设计按 **superfig / supertensor 已经验证过的 sibling 分层** 落一套 family,而不是升级某一个 `.sty`: + +``` +superpaper NEW(v1):读论文 / 笔记编排 skill(文档层) + ├─ 脉络: claims, definitions, assumptions, lemma dependencies, symbol table + ├─ 推导链: 哪些代数步骤必须在笔记里展开 + └─ 委派出图 + ├─ superfig EXISTING:architecture / pipeline / state / dependency + ├─ supertensor EXISTING:shape-aligned tensor formula figures + └─ superderive NEW(phase 2):stepwise algebraic derivation figures +``` + +`superpaper` 是论文侧的 `youtube-render-pdf`:输入一篇论文,输出结构化中文 `.tex` 笔记 + 编译 PDF。它**不**生长 `superfig.sty`。所谓「抽象公式图像化」在 v1 是一个 **figure router**(决策表 + 委派契约),不是第三套绘图引擎。逐步改写图留给 phase 2 的 `superderive`;v1 笔记用 `align` / `aligned` 顶上。 + +--- + +## Background & Motivation + +### 当前状态 + +仓库里已经有两套 **figure toolkit** sibling,形状几乎同构: + +| | `superfig/` | `supertensor/` | +|---|---|---| +| 入口 | `SKILL.md`(瘦;细节在 `references/`) | 同 | +| 宏包 | `assets/superfig.sty`,`\sf*` | `assets/supertensor.sty`,`\st*` | +| 原语 | `\sfnode` `\sfconn` `\sfarrow` `\sfgroup` `\sfcallout` `\sfmeaningbox` | `\stface` `\stdim` `\ststack` `\stindexface` `\stlink` `\stcomm` | +| 工作流 | preflight → 收成一条 claim → **semantics ledger** → 选最小语法 → `build.sh` | 同,但 ledger 是 **shape & semantics + geometry** | +| 构建纪律 | `Missing character` / overfull / `Package superfig Warning` = 失败 | 同,包名换成 `supertensor` | +| 交付物 | PNG 预览 + 一段 mechanism 说明 + `.tex` + PDF/SVG | 同 | +| 明确不做 | 张量形状、数值绘图 | 无形状的架构框图、数值绘图 | + +House style 是**复制**而非抽取的:muted palette `#4F8FA5 / #EE995B / #C95B5B / #8A74B5 / #85898F`,一 role 一色,≤4 活跃色相 + gray。`supertensor/README.md` Provenance 写明它抽自 `wdkns-skills/skills/tensor-formula-viz/`,后者保持不动。 + +文档/编排层的现成类比是 `wdkns-skills/skills/youtube-render-pdf/`(及 `bilibili-render-pdf/`): + +- 教学序列:动机 → 想法 → 机制 → 证据 → takeaway +- 公式规则:先中文讲清楚 → display math → 扁平符号表 +- 盒子:`importantbox` / `knowledgebox` / `warningbox`(定义在 `assets/notes-template.tex`) +- 可视化委派:TikZ 或 matplotlib,**skill 自己不拥有图原语** +- 长视频切段 + outline / writers / figure / consistency 多 agent(见 `wdkns-skills/README.md`「subagents 的触发」) +- 召回不足的缓解:独立 reviewer 对照源材料查漏 + +`wdkns-skills/templates/writing/readme.md` 把写作当成 structure(骨架)+ contents(血肉),并指向 paper-slides 前作。这和「先 ledger 再写笔记」是同一条纪律。 + +### 痛点 + +1. **图层错位。** 脉络是跨章节的 claim / 假设 / 符号生命周期问题;`superfig` 的 lint(`scripts/lint.py`:一图一个 callout、formula 不得出现在最后一行之前、禁止 raw `\draw`)是为 **standalone 一页图** 写的。把 15 页笔记塞进这套规则,只可能有两种结果:要么放松 lint(明确非目标),要么笔记根本编不过。 +2. **原语错位。** 「逐步消去 / 代入」不是 node/edge,也不是 tensor face。硬用 `\sfnode` 表示一行等式,会画出一张**编译干净、看起来整齐、教错东西**的图——这正是 `superfig/references/antipatterns.md` 和 `supertensor` 存在的理由。 +3. **出图引擎错位。** 「把抽象公式变成图」在本仓库里已经分裂成两种合法引擎。缺的是**路由**,不是第三种「什么都能画」的宏。 +4. **没有论文侧的 ledger。** `superfig` 要求画之前先有 nodes/edges/groups ledger;`supertensor` 要求 shape & geometry ledger。论文笔记今天没有对应物,于是符号漂移、漏 claim、图和正文各说各话——这是 `youtube-render-pdf` 用 consistency agent + 事后 reviewer 在视频域打过的同一类仗。 + +### 为何现在做 + +产品决策已定:**不要塞进 superfig;按层拆,对齐现有 sibling 模式。** 仓库里 `superfig/` 与 `supertensor/` 的目录形状、`SKILL.md` 瘦身方式、`scripts/{preflight.sh,lint.py,build.sh,test.sh}` 四件套已经足够当脚手架模板。`youtube-render-pdf` 提供文档层教学契约。缺的是一份足够具体、第一张 PR 不用再发明产品决策的设计。 + +--- + +## Goals & Non-Goals + +### Goals + +- **v1 落地 `superpaper/`**:agent skill + 笔记模板 + ledger schema + 可执行 figure router + 笔记构建/一致性 lint。输入一篇论文(PDF / arXiv / 本地 tex / 摘录),输出结构化中文笔记 `.tex` + PDF。 +- **Ledger-first**:先写 claims / definitions / assumptions / symbols / derivation chains / figure plan,再写正文、再委派出图。Ledger 是 machine-checkable 的单一事实源。 +- **路由而非绘制**:按决策表把每张计划中的图交给 `superfig`、`supertensor`、(v2)`superderive`、screenshot / matplotlib,或 `none`(纯公式)。 +- **委派契约可执行**:figure agent 收到的 request 文件能直接当 sibling skill 的输入;交付物与 `superfig/SKILL.md`「Output」一节同构。 +- **零改动 sibling 契约(v1)**:不改 `superfig.sty` / `supertensor.sty` / 它们的 lint 规则 / `wdkns-skills/`。 +- **v2 规格写清**:`superderive` 的视觉语法、宏草图、与 `align` 的分界,足以单独开 PR,不必再做产品讨论。 + +### Non-Goals + +- 不把 `superfig` 变成笔记器、证明助手或厨房水槽宏包。 +- 不合并 `superfig` 与 `supertensor`。 +- v1 **不**抽取共享 `superstyle` 包。现有两套已经复制 palette;现在抽取比再复制一次更贵。 +- 不实现数值绘图引擎(loss / bar / scatter 出家族,见路由表)。 +- 不原地改 `wdkns-skills`;新工作只出现在 `/home/carry/myprj/tools/skills/` 的 sibling 目录。 +- 不把 `superfig` 的图尺度 lint(一 callout、formula 顺序、4 色相)「升级」成文档尺度规则。 +- 不做多篇论文对比、文献综述自动生成、论文 PDF 重排版、或论文原文的 TeX 再发布。 +- 不做交互式证明助手(Lean/Isabelle);推导链是教学展开,不是形式化核验。 +- 不把 arXiv 源码拿来 **编译**(可读、可抄符号,不执行)。 + +--- + +## Proposed Design + +### 家族分层与数据流 + +```mermaid +flowchart TB + subgraph sources [Input] + PDF[Local PDF] + ARX[arXiv id] + TEX[Local tex] + EX[Excerpt / markdown] + end + + subgraph sp [superpaper — document layer] + ING[ingest.sh] + LED[ledger.yaml] + OUTL[outline.md] + NOTES[notes.tex] + REQ[figures/Fid.request.md] + LINT[lint.py] + NBUILD[scripts/build.sh] + end + + subgraph fig [figure siblings — standalone layer] + SF[superfig] + ST[supertensor] + SD[superderive v2] + SC[screenshot / matplotlib] + end + + PDF --> ING + ARX --> ING + TEX --> ING + EX --> ING + ING --> LED + LED --> OUTL + LED --> NOTES + LED --> REQ + REQ --> SF + REQ --> ST + REQ --> SD + REQ --> SC + SF -->|PDF vector| NOTES + ST -->|PDF vector| NOTES + SD -->|PDF vector| NOTES + SC -->|PDF/PNG + 出处脚注| NOTES + NOTES --> LINT + LED --> LINT + LINT --> NBUILD + NBUILD --> PDFN[notes.pdf] +``` + +两条硬边界: + +1. **笔记文档不 `\usepackage{superfig}` / `supertensor`。** 它们的 `\documentclass{standalone}` + 图尺度 lint 与 `article` 笔记互斥。委派产物以 **PDF 向量** `\includegraphics` 嵌入(与 `youtube-render-pdf` 对外生图「export pdf, include」的约定一致,见该 SKILL「Visualization」)。 +2. **图尺度不变量仍由 sibling `build.sh` 执行。** `superpaper` 的 `lint.py` 管 ledger 完整性、claim 覆盖、符号表、toolkit 枚举、禁止把 `.sty` 拉进笔记;不管 callout 预算和 4 色相。 + +--- + +### Layer 1 — `superpaper`(先做) + +#### 1. 输入契约 + +**v1 范围内的源(按信息质量降序):** + +| `source.kind` | 用户怎么给 | ingest 做什么 | 质量含义 | +|---|---|---|---| +| `tex` | 本地 `.tex` / 工程目录 | 复制到 `source/tex/`;不编译 | 符号与公式最佳 | +| `arxiv` | `1706.03762` 或 `arxiv.org/abs/...` | 校验 id;拉 PDF;**尽力**拉 e-print(tar),只解包阅读 | PDF 保底 + 可能有源码 | +| `pdf` | 本地 PDF 路径 | 复制到 `source/paper.pdf` | 正文靠 `pdftotext` + 页渲染 | +| `excerpt` | 粘贴 / `.md` / 选段 | 写入 `source/excerpt.md` | `coverage.mode = excerpt`,不假装读完全文 | +| `markdown` | 已有笔记 / HTML dump | 复制为 `source/excerpt.md` | 同 excerpt | + +arXiv id 校验(防 shell 注入): + +```text +^(ar[Xx]iv:)?(\d{4}\.\d{4,5}(v\d+)?|[a-z-]+/\d{7})$ +``` + +下载: + +- PDF:`https://arxiv.org/pdf/.pdf`(失败则 `export.arxiv.org`) +- e-print(可选、best-effort):`https://arxiv.org/e-print/` → `source/eprint/`。**禁止**对解出的 TeX 跑 `latex`。只当符号/公式的高信息文本。 + +**明确不在 v1:** 付费出版社 HTML 抓取、扫描件 OCR 当主路径、视频论文(走 `youtube-render-pdf`)、ar5iv HTML。扫描件若 `pdftotext` 几乎为空:标 `degraded: scanned`,进入页渲染视觉模式(对标 `bilibili-render-pdf` 的 visual-only),并在交付里说出口。 + +**论文里已有图/表怎么处理(相对重绘):** + +ingest 后 outline agent 必须给**每一张源图 / 主表**打标签,写入 `ledger.yaml` 的 `source_assets[]` 与/或 `figures[]`: + +| `handling` | 何时 | 笔记里长什么样 | +|---|---|---| +| `redraw-superfig` | 架构、流水线、数据流、状态、依赖、「谁吃谁」 | 委派 `superfig`;caption 写「重绘自论文 Figure N」 | +| `redraw-supertensor` | 轴、形状、转置、broadcast、gather、shard、收缩 | 委派 `supertensor` | +| `redraw-superderive` | 必须被**看见**的逐步改写(v2;v1 降级为 `align`) | v1:`align`;v2:委派 `superderive` | +| `screenshot` | 数值曲线、照片、复杂实验装置、UI | `pdftoppm -r 200` 该页(+ 可选 `crop_bbox`);出处脚注 | +| `matplotlib` | 用户明确要求重画数值图 | 族外脚本;导出 PDF 再嵌入 | +| `omit` | 装饰、重复、无教学价值 | ledger 记原因,不进笔记 | + +规则: + +- **不要**把论文每一张图都截进笔记。按教学需要选,对标 `youtube-render-pdf`「Select figures by necessity」。 +- 架构类图**优先重绘**,不要截原图——原图常常违反 house style,且无法进入 sibling 的语义审计。 +- 数值图**不要**用 `superfig` 假装;路由到 `screenshot` 或 `matplotlib`,并在笔记里说「本家族不出数值图」。 +- 出处脚注是视频时间戳的论文对应物:`论文 Figure 2,§4.1,p.7`。重绘图同样要写源 Figure 编号。 +- 理解源图必须**看页渲染**(`pdftoppm`),不要只靠 caption 文本猜内容。对标 youtube skill 的 `view image` 纪律,禁止用 tesseract 代替看图。 + +**页预算与切段(对标长视频策略;与 §7 单/多 agent 表同一套谓词):** + +| 条件 | 策略 | +|---|---| +| **必须拆** writer/figure agent:正文 **> 12 页**,或论文顶层节 **> 4**,或计划重绘图 **≥ 2**,或用户显式 spawn | 按 `outline.md` 的**讲义节**并行(不是按 PDF 页序) | +| **否则单 agent**(含 excerpt、以及 9–12 页 ∧ 顶层节 ≤ 4 ∧ 重绘图 ≤ 1) | 一遍写完 | +| 正文 > 40 页(综述 / 教材) | 默认 **只做用户点名的节 + 引言/结论**;否则先问范围。禁止单次塞完整 40 页 | + +附录默认跳过,写入 `coverage.sections_skipped`。用户点名再纳入。 + +**工作目录(唯一根;所有脚本吃 `--work `):** + +```text +/ # 默认 ./work// + source/ + meta.yaml # kind, arxiv, pages, sha256 + paper.pdf + paper.txt # pdftotext -layout + pages/pg-001.png # 一律三位:ingest 把 pdftoppm 输出重命名为 pg-%03d.png + eprint/ # 可选 + tex/ # 可选 + excerpt.md # excerpt / markdown + ledger.yaml # SSOT(始终在 / 根,不在 notes/) + outline.md + notes/ + notes.tex # 主文件;cwd 编译;\input{sections/sec-01.tex} + sections/sec-01.tex + sections/symbols.tex # render_ledger.py --work 写入此处 + figures/ + F1/ + F1.request.md + F1.tex + F1-mechanism.md + build/F1.{pdf,svg,png} # sibling 向量产物 + orig.png # 仅 screenshot + plot.py # 仅 matplotlib + run.log + out/notes.pdf +``` + +**路径约定(三处必须同形,相对 `notes/`):** + +| 位置 | 向量图 | 截图 | +|---|---|---| +| `figures[].include` | `figures/F1/build/F1.pdf` | `figures/F2/orig.png` | +| `\spfig` / `\spscreenshot` | `figures/#2/build/#2.pdf` | `figures/#2/orig.png` | +| 磁盘 | `/notes/figures/F1/build/F1.pdf` | `/notes/figures/F2/orig.png` | +| `figures[].request` | `figures/F1/F1.request.md` | `null`(截图不写 request) | + +禁止再写 `notes/figures/...` 进 ledger(那是相对 `/` 的另一套根)。API 层只承诺「相对 `notes/` 的 `figures/F/...`」。 + +`paper-id`:arXiv id **原样保留点号**(`1706.03762` → 目录 `1706.03762`)。非 arXiv:NFKC → 小写 → 非 `[a-z0-9.]` 换成 `-` → 压缩连字符 → 截断 40 字符 → 必须以字母或数字开头结尾;空则用 `paper`。仓库内 `examples/` 只放 **自造 fixture**,不提交受版权保护的 PDF。 + +存储量级(单篇 12 页 ML 论文):PDF 1–15 MB + 页渲染约 8–20 MB + 笔记/图 2–8 MB ≈ **20–50 MB**。运行时 `/` 默认在调用方 cwd 下的 `work/`,gitignore,不进 skill 仓库。 + +--- + +#### 2. Ledger-first 工作流 + +对标 `superfig/SKILL.md` 步骤 3「Build a semantics ledger before drawing」和 `supertensor/SKILL.md` 步骤 3 的双 ledger。`superpaper` 的 ledger 在**文档层**: + +1. `preflight.sh`(笔记工具链,不是图工具链)。 +2. `ingest.sh` 落 `source/`。 +3. **先写 `ledger.yaml`**,再写 `outline.md`,再写任何 `sections/*.tex`。 +4. figure plan 填完才能开 figure agent。 +5. 改图或改术语:先改 ledger,再改那一处正文或那一张 request——对标 sibling 的「Iterating:不要重画整张图」。 + +**格式选 YAML,不选 Markdown。** 理由:claim 覆盖、toolkit 枚举、`retired_ids` 交叠检查必须机器可解析;figure plan 是带 enum 的分发表。Markdown 标题约定会逼 lint 写第二套解析器。数学用字面块 `|` 或单引号标量。`assets/ledger.example.yaml` 既是 schema 样例,也是 outline agent 的**空模板**(复制到 `/ledger.yaml` 再填)。不要用 `agents/openai.yaml` 当「agent 会写 YAML」的证据——那只是 4 行 `interface:` 块。 + +Markdown 只作为**投影**:`render_ledger.py --work ` 写入 `notes/sections/symbols.tex`(附录 `\input`)和可选的 `/claims.md`。投影只读。 + +**id 规则:** + +- 前缀 + **正整数**:`C1`、`Q1`、`D1`、`A1`、`L1`、`E1`、`DER1`、`F1`、`SA1`。正则:`^(C|Q|D|A|L|E|DER|F|SA)[1-9][0-9]*$`。 +- **禁止** `F1a` / `F1b`。跨类拆分时删掉(或 retire)混信号行,用**下一个整数**建新行(见 §4)。 +- 同一 ledger 内 id 唯一(含已 `status: dropped` 的行)。引用只用 id。 +- 删除或永久废弃一个 id 时:把它写入顶层 `retired_ids`,并从对应数组移除**或**保留为 `status: dropped` 且不再改语义。新对象只许拿下一个未用整数。 +- 笔记用 `\splabel{C1}` 把段落钉到 id 上(PR 4 起强制 core claim)。 + +--- + +#### 3. Ledger schema(`superpaper.ledger/v1`) + +权威副本:`superpaper/assets/ledger.schema.yaml`(JSON Schema draft-07)。`lint.py` 顺序固定,禁止「先 validate 再认别名」: + +1. **Normalize(写回内存副本,不改磁盘):** 把每个 `symbols[].kind` 按下面别名表收到 canonical。`kind: activation` → `value`,`kind: shape-parameter` / `shape_parameter` → `shape parameter`。不在别名表且不在 canonical 的值原样留下,下一步会 `SP001`。 +2. **硬失败 `SP001`:** 对**已经 normalize** 的对象跑 `jsonschema.validate`(依赖 **`jsonschema`**)。schema 的 `kind` / `steps[].rule` enum **只含 canonical**。未知 `rule`(如 `foo`)是 `SP001`,不是警告。`additionalProperties: true`,未知键不因此失败。 +3. **警告(不失败):** validate 通过后,扫顶层与一层嵌套的未知键、`coverage.mode=full` 且 `sections_in` 空、符号从未在笔记出现。**不要**再对 `steps[].rule` 发警告——那条路径已被 schema enum 关掉。 + +excerpt-toy 必须带齐 **required 数组**(可空):`claims: []` 合法。缺 `paper.id` 不合法。 + +**Required:** + +| 对象 | required | +|---|---| +| 根 | `schema`, `paper`, `coverage` | +| `paper` | `id`, `title`, `source` | +| `paper.source` | `kind` | +| `coverage` | `mode` | +| `questions[]` | `id`, `text` | +| `claims[]` | `id`, `text`, `kind`, `status` | +| `definitions[]` | `id`, `name`, `text` | +| `assumptions[]` | `id`, `text` | +| `lemmas[]` | `id`, `text` | +| `symbols[]` | `name`, `latex`, `meaning`, `kind` | +| `derivations[]` | `id`, `claim`, `title`, `expand` | +| `derivations[].steps[]` | `id`, `from`, `to`, `rule` | +| `figures[]` | `id`, `claim`, `title`, `grammar`, `toolkit`, `signals`, `status` | +| `evidence[]` | `id`, `kind`, `source`, `supports`, `handling` | +| `terms[]` | `canonical` | +| `source_assets[]` | `id`, `kind`, `handling` | +| `skip_reasons[]` | `section`, `reason` | + +未列的数组键缺省视为 `[]`;schema 仍把它们标为 optional。`retired_ids` 缺省 `[]`。 + +**类型与可空:** + +- `paper.year`:integer 或省略。 +- `paper.source.pages`:integer ≥ 1 或省略。 +- `paper.degraded`:string 数组,enum `scanned | no-eprint | no-pdftotext`。 +- `figures[].source_pages`:integer 数组(页码,从 1)。 +- `figures[].include` / `request` / `drop_reason` / `derivations[].figure`:`string` **或** `null`。路径/空值与 `status`/`toolkit` 的组合**不**写进 draft-07 `if`/`then`(避免和 `additionalProperties: true` 扭在一起);由 `check_row` 的 `SP013–SP016` 执行,见 §4 / §10。 +- `figures[].crop_bbox`:`null` 或恰好 4 个 number `[x0,y0,x1,y1]`(200 dpi 页像素,左上原点)。仅 screenshot。 +- `figures[].signals`:非空 string 数组(`toolkit: none` 的 bookkeeping 行允许 `["notation"]` 或空数组)。 + +**Enums(闭集;写进 schema):** + +| 字段 | enum | +|---|---| +| `schema` | `superpaper.ledger/v1` | +| `source.kind` | `arxiv \| pdf \| tex \| excerpt \| markdown` | +| `coverage.mode` | `full \| excerpt \| body-only` | +| `claims[].kind` | `contribution \| theoretical \| empirical \| methodological` | +| `claims[].status` | `core \| supporting \| dropped` | +| `figures[].toolkit` | `superfig \| supertensor \| superderive \| screenshot \| matplotlib \| none \| align` | +| `figures[].status` | `planned \| delegated \| built \| included \| dropped` | +| `figures[].grammar` | `architecture \| pipeline \| data-flow \| state \| time \| dependency \| argument-map \| tensor-face \| derivation \| screenshot \| plot \| notation \| none` | +| `evidence[].kind` | `table \| plot \| ablation \| theorem \| example` | +| `evidence[].handling` / `source_assets[].handling` | `redraw-superfig \| redraw-supertensor \| redraw-superderive \| screenshot \| matplotlib \| omit` | +| `source_assets[].kind` | `figure \| table` | +| `steps[].rule` | `definition \| substitute \| cancel \| factor \| scale \| take-limit \| approx \| cite \| rearrange \| introduce` | +| `symbols[].kind` | 见下表 | + +**`symbols[].kind`:** 权威左列抄 `supertensor/references/semantics.md`「Kinds worth separating」。canonical 取斜杠左侧(`shape parameter` 保留空格,与原文一致)。schema enum **只列 canonical**。别名合法当且仅当走第 1 步 normalize;`SP001` 在 normalize **之后**跑。这是有文档的扩展,不是「零新增类型学」——`scalar` / `set` 只用于文档层、不进张量图。 + +| canonical(schema enum) | lint 接受的别名 | 例 | +|---|---|---| +| `value` | `activation`, `value / activation` | `X`, `H` | +| `score` | `logit`, `score / logit` | `S = QK^T/√d_h` | +| `probability` | | `A = softmax(S)` | +| `index` | `coordinate`, `index / coordinate` | `I` | +| `rank` | `order`, `rank / order` | 选中槽轴 `r` | +| `count` | | `n_e` | +| `id` | | token / device id | +| `mask` | `support`, `mask / support` | 因果 `M` | +| `permutation` | | gather 序 | +| `shape parameter` | `shape-parameter`, `shape_parameter` | `d_k`, `h`, `p`(**不是** `scalar`) | +| `scalar`(文档层扩展) | | 损失 `L`、温度 `τ` 这类 0 维量,且不是轴长 | +| `set`(文档层扩展) | | 词表 `V` | + +draft-07 正文(检入 `assets/ledger.schema.yaml`;实现不得再猜 required/enum): + +```yaml +$schema: "http://json-schema.org/draft-07/schema#" +$id: "https://local/superpaper.ledger/v1" +type: object +required: [schema, paper, coverage] +additionalProperties: true +properties: + schema: {const: superpaper.ledger/v1} + retired_ids: + type: array + items: {type: string, pattern: "^(C|Q|D|A|L|E|DER|F|SA)[1-9][0-9]*$"} + paper: + type: object + required: [id, title, source] + additionalProperties: true + properties: + id: {type: string, minLength: 1} + title: {type: string} + authors: {type: array, items: {type: string}} + year: {type: integer} + venue: {type: string} + notes_language: {type: string, enum: [zh, en]} + degraded: + type: array + items: {type: string, enum: [scanned, no-eprint, no-pdftotext]} + source: + type: object + required: [kind] + additionalProperties: true + properties: + kind: {enum: [arxiv, pdf, tex, excerpt, markdown]} + arxiv: {type: string} + local_pdf: {type: string} + pages: {type: integer, minimum: 1} + language: {type: string} + coverage: + type: object + required: [mode] + additionalProperties: true + properties: + mode: {enum: [full, excerpt, body-only]} + sections_in: {type: array, items: {type: string}} + sections_skipped: {type: array, items: {type: string}} + skip_reasons: + type: array + items: + type: object + required: [section, reason] + properties: + section: {type: string} + reason: {type: string} + questions: + type: array + items: + type: object + required: [id, text] + properties: + id: {type: string, pattern: "^Q[1-9][0-9]*$"} + text: {type: string} + source: {type: string} + claims: + type: array + items: + type: object + required: [id, text, kind, status] + properties: + id: {type: string, pattern: "^C[1-9][0-9]*$"} + text: {type: string} + kind: {enum: [contribution, theoretical, empirical, methodological]} + status: {enum: [core, supporting, dropped]} + supports: {type: array, items: {type: string}} + depends_on: {type: array, items: {type: string}} + evidence: {type: array, items: {type: string}} + source: {type: string} + definitions: + type: array + items: + type: object + required: [id, name, text] + properties: + id: {type: string, pattern: "^D[1-9][0-9]*$"} + name: {type: string} + text: {type: string} + source: {type: string} + assumptions: + type: array + items: + type: object + required: [id, text] + properties: + id: {type: string, pattern: "^A[1-9][0-9]*$"} + text: {type: string} + source: {type: string} + used_by: {type: array, items: {type: string}} + lemmas: + type: array + items: + type: object + required: [id, text] + properties: + id: {type: string, pattern: "^L[1-9][0-9]*$"} + text: {type: string} + depends_on: {type: array, items: {type: string}} + used_by: {type: array, items: {type: string}} + source: {type: string} + symbols: + type: array + items: + type: object + required: [name, latex, meaning, kind] + properties: + name: {type: string} + latex: {type: string} + meaning: {type: string} + domain: {type: string} + kind: + enum: [value, score, probability, index, rank, count, id, mask, + permutation, "shape parameter", scalar, set] + introduced: {type: string} + used: {type: array, items: {type: string}} + aliases: {type: array, items: {type: string}} + derivations: + type: array + items: + type: object + required: [id, claim, title, expand] + properties: + id: {type: string, pattern: "^DER[1-9][0-9]*$"} + claim: {type: string} + title: {type: string} + source: {type: string} + expand: {type: boolean} + figure: {type: ["string", "null"]} + steps: + type: array + items: + type: object + required: [id, from, to, rule] + properties: + id: {type: string} + from: {type: string} + to: {type: string} + rule: + enum: [definition, substitute, cancel, factor, scale, + take-limit, approx, cite, rearrange, introduce] + cite: {type: string} + justify: {type: string} + figures: + type: array + items: + type: object + required: [id, claim, title, grammar, toolkit, signals, status] + properties: + id: {type: string, pattern: "^F[1-9][0-9]*$"} + claim: {type: string} + title: {type: string} + grammar: + enum: [architecture, pipeline, data-flow, state, time, dependency, + argument-map, tensor-face, derivation, screenshot, plot, + notation, none] + toolkit: + enum: [superfig, supertensor, superderive, screenshot, + matplotlib, none, align] + signals: {type: array, items: {type: string}} + source_fig: {type: string} + source_pages: {type: array, items: {type: integer, minimum: 1}} + crop_bbox: + type: ["array", "null"] + minItems: 4 + maxItems: 4 + items: {type: number} + request: {type: ["string", "null"]} + include: {type: ["string", "null"]} + status: {enum: [planned, delegated, built, included, dropped]} + drop_reason: {type: ["string", "null"]} + evidence: + type: array + items: + type: object + required: [id, kind, source, supports, handling] + properties: + id: {type: string, pattern: "^E[1-9][0-9]*$"} + kind: {enum: [table, plot, ablation, theorem, example]} + source: {type: string} + supports: {type: array, items: {type: string}} + handling: + enum: [redraw-superfig, redraw-supertensor, redraw-superderive, + screenshot, matplotlib, omit] + terms: + type: array + items: + type: object + required: [canonical] + properties: + canonical: {type: string} + aliases: {type: array, items: {type: string}} + first_defined: {type: string} + source_assets: + type: array + items: + type: object + required: [id, kind, handling] + properties: + id: {type: string, pattern: "^SA[1-9][0-9]*$"} + kind: {enum: [figure, table]} + paper_ref: {type: string} + handling: + enum: [redraw-superfig, redraw-supertensor, redraw-superderive, + screenshot, matplotlib, omit] + pages: {type: array, items: {type: integer}} + note: {type: string} +``` + +**样例(字段合法;`include`/`request` 已改为相对 `notes/`):** + +```yaml +schema: superpaper.ledger/v1 +retired_ids: [] +paper: + id: "1706.03762" + title: "Attention Is All You Need" + authors: ["Vaswani et al."] + year: 2017 + venue: "NeurIPS" + source: {kind: arxiv, arxiv: "1706.03762", local_pdf: "source/paper.pdf", pages: 15, language: en} + notes_language: zh + degraded: [] +coverage: + mode: full + sections_in: ["1", "2", "3", "4", "5"] + sections_skipped: ["6", "appendix"] + skip_reasons: + - {section: "6", reason: "default skip appendix-like extras"} +questions: + - {id: Q1, text: "能否去掉 recurrence / convolution,只用注意力做序列转导?", source: "§1"} +claims: + - id: C1 + text: "多头自注意力可以替代循环与卷积作为序列转导的主模块" + kind: contribution + status: core + supports: [Q1] + depends_on: [A1, D1] + evidence: [E1] + source: "§1, §3.2.2, §5" +definitions: + - {id: D1, name: "scaled dot-product attention", + text: "Attention(Q,K,V) = softmax(QK^T / sqrt(d_k)) V", source: "§3.2.1, Eq.(1)"} +assumptions: + - {id: A1, text: "位置信息由显式 positional encoding 注入", source: "§3.5", used_by: [C1]} +lemmas: [] +symbols: + - {name: Q, latex: "Q", meaning: "query 矩阵", domain: "R^{n x d_k}", + kind: value, introduced: "§3.2.1, Eq.(1)", used: ["§3.2.1", "§3.2.2"]} + - {name: d_k, latex: "d_k", meaning: "key 维", kind: "shape parameter"} +derivations: + - id: DER1 + claim: C1 + title: "scaled dot-product 的缩放从何而来" + source: "§3.2.1" + expand: true + figure: null # v1:笔记 align;见 §4 + steps: + - {id: S1, from: "QK^T", to: "QK^T / sqrt(d_k)", rule: scale, + cite: "§3.2.1", justify: "点积方差随 d_k 增长"} +figures: + - id: F1 + claim: C1 + title: "Encoder–decoder 块" + grammar: architecture + toolkit: superfig + signals: [architecture, what-eats-what] + source_fig: "Figure 1" + source_pages: [3] + crop_bbox: null + request: "figures/F1/F1.request.md" + include: "figures/F1/build/F1.pdf" + status: planned + drop_reason: null +evidence: + - {id: E1, kind: table, source: "Table 2", supports: [C1], handling: screenshot} +terms: + - {canonical: "multi-head attention", aliases: ["MHA", "多头注意力"], first_defined: "§3.2.2"} +source_assets: + - {id: SA1, kind: table, paper_ref: "Table 2", handling: screenshot, pages: [6], + note: "BLEU 表;数值结果走 screenshot,signals 用 table 不是 loss-curve"} +``` + +**PR 1 起就必须存在的 schema fixture 与期望码**(只测本 PR 已实现的检查;完整码表见 §10): + +| 文件 | 期望 | +|---|---| +| `tests/ledger-valid.yaml` | 退出 0 | +| `tests/ledger-invalid/missing-paper-id.yaml` | `SP001` | +| `tests/ledger-invalid/bad-toolkit.yaml` | `SP001`(enum) | +| `tests/ledger-invalid/duplicate-id.yaml` | `SP002` | +| `tests/notes-loads-sty.tex` + 最小 ledger | `SP003` | + +--- + +#### 4. Figure router(「抽象公式图像化」= 路由) + +权威规则在 `references/router.md`;可执行副本在 `scripts/router.py`(**PR 1 即完整实现**,含单测;lint 接线分 PR,见 §10 / PR Plan)。 + +`suggest()` 返回的是 **class**,不是 toolkit。lint(PR 2+)检查 `figures[].toolkit ∈ ACCEPTED[class]`。 + +**信号 → class:** + +| class | 若 `signals` 与下列集合相交 | +|---|---| +| `numeric` | `{loss-curve, bar, scatter, histogram, numeric-plot}` | +| `raster` | `{table, photo, apparatus, ui}` | +| `tensor` | `{axis, shape, transpose, broadcast, gather, shard, contraction, face}` | +| `derive` | `{rewrite-figure, cancel-visual, subst-visual}` | +| `fig` | `{architecture, pipeline, data-flow, state, time, dependency, what-eats-what, argument-map}` | +| `none` | 不相交(含仅 `notation` 或 `[]`) | + +**class → 合法 toolkit 集合:** + +| class | `ACCEPTED[class]` | 笔记呈现 | +|---|---|---| +| `numeric` | `{screenshot, matplotlib}` | agent 选:原图截图或族外 PDF;正文声明「本家族不画数值图」 | +| `raster` | `{screenshot}` | 表 / 照片 / 装置 / UI;**不能**选 matplotlib | +| `tensor` | `{supertensor}` | 委派 sibling | +| `fig` | `{superfig}` | 委派 sibling | +| `derive` | phase 1:`{align}`;phase 2:`{align, superderive}` | 见下 | +| `none` | `{none}` | 散文 + display math + 符号表 | + +`toolkit: matplotlib` + `signals: [loss-curve]` ⇒ class `numeric` ⇒ **合法**。`toolkit: screenshot` + `signals: [table]` ⇒ class `raster` ⇒ **合法**。原先草图把 `suggest` 直接返回 `"screenshot"`,会误杀这两条。 + +**`align` 与 `derivations[].figure`:** + +| 情况 | `derivations[].figure` | 是否需要 `figures[]` 行 | +|---|---|---| +| 默认(v1 几乎全部):笔记里 `align` | **必须 `null`** | **不需要**。推导不是图 | +| 可选 bookkeeping:想在 figure plan 里留下「已路由到 align」 | 可填该 `F*` | 一行 `toolkit: align`,`include: null`,`request: null`,`signals` ⊆ derive;`status: included` 表示 writer 已把 `align` 写进讲义节 | +| v2 且必须看见取消/代入,或 >4 步 | 填 `F*` | `toolkit: superderive`,走 sibling 委派 | + +v1:任何 derive-class 行的 toolkit 必须是 `align`;`toolkit: superderive` → `SP022`(PR 4 起;PR 1–3 的 schema 虽允许该枚举值,但 example 不得使用)。phase 2 仍遵守 ≤4 步且无 `cancel-visual`/`subst-visual` ⇒ **必须** `align`(即使包已存在)。 + +`toolkit: none` 只用于「考虑过、决定不出图」:`status: dropped`,`include: null`。这些组合**不是** `SP010`(`SP010` 只表示 toolkit ∉ `ACCEPTED[class]`)。由下面 `check_row(..., status, include, fig_id)` 给出独立码。 + +**冲突拆分(硬规则,禁 `F1a`):** + +- **任何一行** `classify(signals)` 不得返回多个 class。混类 → `SP011`,消息列出 class 集合并要求 outline 用**下一个整数 id** 拆成 N 行。 +- 拆分算法:retire(写入 `retired_ids`)或删除混类行;新建 `F{max+1}`、`F{max+2}`、…;每子行 `signals` 是**单类子集**;每子行 `toolkit ∈ ACCEPTED[class]`。三路(`numeric+tensor+fig`)就是三个新整数。不保留 parent 行。 +- 子行 `signals` 必须 ⊆ 该类的信号集合。 + +```python +# scripts/router.py — PR 1 检入的完整实现(不是草图) +from __future__ import annotations + +NUMERIC = frozenset({"loss-curve", "bar", "scatter", "histogram", "numeric-plot"}) +RASTER = frozenset({"table", "photo", "apparatus", "ui"}) +TENSOR = frozenset({"axis", "shape", "transpose", "broadcast", "gather", + "shard", "contraction", "face"}) +DERIVE = frozenset({"rewrite-figure", "cancel-visual", "subst-visual"}) +FIG = frozenset({"architecture", "pipeline", "data-flow", "state", "time", + "dependency", "what-eats-what", "argument-map"}) + +CLASS_SIGNALS = { + "numeric": NUMERIC, "raster": RASTER, "tensor": TENSOR, + "derive": DERIVE, "fig": FIG, +} + +def classify(signals: set[str]) -> list[str]: + s = set(signals) + hit = [c for c, vocab in CLASS_SIGNALS.items() if s & vocab] + return hit or ["none"] + +def suggest(signals: set[str], *, phase: int = 1) -> str: + """Return a class name, or 'SPLIT:a+b+...' in CLASS_SIGNALS order.""" + classes = classify(signals) + if len(classes) > 1: + return "SPLIT:" + "+".join(classes) + return classes[0] + +def accepted(cls: str, *, phase: int = 1) -> frozenset[str]: + if cls == "numeric": + return frozenset({"screenshot", "matplotlib"}) + if cls == "raster": + return frozenset({"screenshot"}) + if cls == "tensor": + return frozenset({"supertensor"}) + if cls == "fig": + return frozenset({"superfig"}) + if cls == "derive": + return frozenset({"align", "superderive"} if phase >= 2 else {"align"}) + if cls == "none": + return frozenset({"none"}) + raise KeyError(cls) + +VECTOR = frozenset({"superfig", "supertensor", "superderive", "matplotlib"}) + +def include_pdf(fig_id: str) -> str: + return f"figures/{fig_id}/build/{fig_id}.pdf" + +def include_png(fig_id: str) -> str: + return f"figures/{fig_id}/orig.png" + +def check_row( + signals: set[str], + toolkit: str, + *, + status: str = "planned", + include: str | None = None, + fig_id: str = "F1", + phase: int = 1, +) -> str | None: + """First matching code, or None. SP010 ≠ include/status rules.""" + classes = classify(signals) + if len(classes) > 1: + return "SP011" + if toolkit not in accepted(classes[0], phase=phase): + return "SP010" + if toolkit == "none" and status != "dropped": + return "SP013" + if toolkit in {"align", "none"} and include is not None: + return "SP014" + if status == "included" and toolkit in VECTOR and include != include_pdf(fig_id): + return "SP015" + if status == "included" and toolkit == "screenshot" and include != include_png(fig_id): + return "SP016" + return None +``` + +谓词(lint-only;不写进 draft-07 `if`/`then`): + +| 码 | 条件 | +|---|---| +| `SP010` | 单类,但 `toolkit ∉ ACCEPTED[class]` | +| `SP011` | `classify` 返回多个 class | +| `SP013` | `toolkit=none` ∧ `status ≠ dropped` | +| `SP014` | `toolkit ∈ {align,none}` ∧ `include is not None` | +| `SP015` | `status=included` ∧ 向量 toolkit ∧ `include ≠ figures/{id}/build/{id}.pdf`(含 `include` 为 null) | +| `SP016` | `status=included` ∧ `toolkit=screenshot` ∧ `include ≠ figures/{id}/orig.png` | + +`status=included` ∧ `toolkit=align` ∧ `include=null` 合法(bookkeeping)。`SP021`(PR 4)只检查「`include` 已是非空字符串但文件不存在」,不再兼职这些结构规则。 + +`router_test.py`(PR 1 必须绿)至少覆盖: + +- `[loss-curve] → numeric`;`accepted` 含 `matplotlib` 与 `screenshot` +- `[table] → raster`;`matplotlib` 不在 `accepted` +- `[axis, architecture] → SPLIT:tensor+fig` 且 `check_row` = `SP011` +- `[rewrite-figure]` phase 1:`align` ok,`superderive` → `SP010` +- `[]` 或 `[notation] → none` +- `none` + `status=included` → `SP013`;`align` + `include="figures/F1/build/F1.pdf"` → `SP014` +- `superfig` + `included` + `include=null` → `SP015`;`screenshot` + `included` + 错路径 → `SP016` + +**默认偏向 `none`。** 公式不是图。只有「机制靠空间关系才能一次看清」才出图。 + +--- + +#### 5. 笔记教学法 + +**直接复用** `youtube-render-pdf/SKILL.md`「Pedagogical Standard」+「Writing Rules」1–2、5–11,论文侧改下列几处(写在 `references/pedagogy.md`,不要在 SKILL.md 复述 youtube 全文): + +| youtube | superpaper | +|---|---| +| 时间戳 / 章节 | **§ / Eq.(n) / Figure n / Table n / p.** | +| 片头封面图 | **书目卡片**(题名、作者、年份、venue、arXiv、本地 PDF)。不做论文首页截图当封面 | +| `$$...$$` | **`\[` / `align` / `aligned`**(多步推导是一等公民;不沿用 `$$`) | +| `dialoguebox` | **`quotebox`**:短原文 + `§/Eq` 出处。禁止大段粘贴 PDF | +| 关键帧截图 | 源图 screenshot **或** sibling 重绘;重绘优先于架构类原图 | +| `\subsection{本章小结}` | 保留 | +| `\section{总结与延伸}` | 保留:论文 limitations / future work + 笔记作者的压缩与追问 | +| 默认中文 | 保留;用户明确要求才英文 | +| 禁止 `[cite]` 占位 | 保留;出处写进 `\spsource{...}` 或正文 | + +公式三拍(不可拆): + +1. 先用中文讲这式子在主张什么、为什么在这里出现; +2. display math(`\[` 或 `align`); +3. 立刻跟扁平符号表(`itemize`,每个符号一行:符号 — 含义 — 定义处)。 + +盒子语义与 youtube 相同,定义抄进 `assets/notes-template.tex`(颜色也抄:蓝/黄/红。**不要**把笔记盒子改成 figure 的 muted palette——笔记是文档层,图是图层次;v1 不统一)。图必须留在盒子外面(youtube Writing Rule 9 原句)。 + +每节内部顺序:动机 → 想法 → 机制 → 证据 → takeaway(本章小结)。不要按 PDF 页序复述。 + +建议顶层骨架(模板注释里写死;outline agent 可增删中间节,不可删首尾): + +```tex +\section{这篇论文在问什么} % questions[] + 动机 +\section{主张与贡献} % claims[status=core],\splabel{C*} +\section{预备:定义、假设、符号} % D* / A* / 符号表摘要 +% --- 中间节由 outline 按论文机制切 --- +\section{实验与证据} % 若有 E*;可 omit +\section{总结与延伸} +\appendix +\section{符号表} % render_ledger.py 投影 +\section{推导链一览} +\section{图表清单} +``` + +主张依赖图(argument map)**默认不出**。仅当 `claims + assumptions + lemmas + evidence` 的节点 ≥ 6 且用户没反对时,加一条 `figures[]`:`grammar: argument-map`,`toolkit: superfig`,用现有 `\sfnode`/`\sfarrow`(见 §「Argument-map figures」)。 + +--- + +#### 6. 委派时的 figure request 与嵌入约定 + +**谁画什么:** + +| toolkit | 谁做 | 输入 | 输出 | +|---|---|---|---| +| `superfig` / `supertensor` / `superderive` | **figure agent**(每图一个) | 仅 `figures/F*/F*.request.md` + sibling `SKILL.md` | standalone `.tex` + sibling `build.sh` 产物 | +| `screenshot` | **主 agent**(不是 sibling figure agent) | `scripts/screenshot.sh --work --id F*` | `figures/F*/orig.png` | +| `matplotlib` | **主 agent** 跑 `figures/F*/plot.py` | cwd = `/notes/figures/F*` | `build/F*.pdf` | +| `align` / `none` | writer / 不画 | 无 request | 无 PDF | + +lint `SP012`(PR 2):`toolkit ∈ {superfig,supertensor,superderive}` ∧ `status != dropped` ⇒ `/notes/` + `figures[].request` 指向的文件必须存在。 + +Sibling skill **不**读 `ledger.yaml`。request 字段必须能 1:1 译成真实宏(`\sfnode` keys 只有 `role, level, gap, bracket, at=`;`\sfconn{name}{label}` 是 cursor 对象,**没有** from/to)。 + +**`allow-raw-tikz`:** sibling lint 只认源码注释 `% superfig-lint: allow-raw-tikz`(`superfig/scripts/lint.py` `directives()`)。request 里写 true 而不把该注释抄进 `.tex`,`build.sh` 仍失败。figure agent 必须两者一起写。 + +**superfig request(PR 2 example;与 `superfig/examples/pipeline.tex` 逐宏对应):** + +```markdown +# Figure request F1 +toolkit: superfig +language: cjk +claim: 一次前向是 x → f_θ → ŷ;损失不在主路上。 +grammar: pipeline +# 以下路径一律相对 notes/ +work_rel_dir: figures/F1 +# 主 agent 必须这样调 sibling(第二个参数是 outdir,不要丢 PDF 在 work_rel_dir 根上): +# superfig/scripts/build.sh /notes/figures/F1/F1.tex \ +# /notes/figures/F1/build + +## Roles # \sfsetrole;宏吃 ROLE 不吃颜色 +- {role: input, color: sfTeal} +- {role: model, color: sfOrange} +- {role: loss, color: sfCoral} +- {role: output, color: sfViolet} + +## Flow (cursor). \sfconn 没有 endpoints。 +stage: {name: SA, text: "推理流程:一次前向"} +row: {name: R1, height: 16mm} +in_row: + - {macro: sfnode, name: x, role: input, label: "输入 $x$", w: 16mm, h: 12mm} + - {macro: sfconn, name: e1, label: 预处理} + - {macro: sfnode, name: f, role: model, label: "模型 $f_\\theta$", w: 18mm, h: 12mm} + - {macro: sfconn, name: e2, label: logits} + - {macro: sfnode, name: y, role: output, label: "预测 $\\hat y$", w: 16mm, h: 12mm} + +## Fixed topology(非线性才用;at= 必须是带 ($…$) 的 calc 坐标) +# 译成 \sfnode[..., at={($(y.south)+(0,-22mm)$)}]{s}{...} +- {macro: sfnode, name: s, role: loss, label: "损失 $L$", w: 14mm, h: 12mm, + at: "($(y.south)+(0,-22mm)$)"} +- {macro: sfarrowlabel, from: "y.south", to: "s.north", label: "$L(\\hat y, y)$"} + +## After row +lane: R1 +captions: + - {on: x, symbol: "$x$", detail: 原始输入} + - {on: f, symbol: "$f_\\theta$", detail: 可学习参数} +nolane: true +extra_captions: + - {on: s, symbol: "$L$", detail: 与真值比较} +topformula: "$x \\xrightarrow{f_\\theta} \\hat y,\\quad \\min_\\theta L(f_\\theta(x), y)$" +meaning: + idea: 一次从输入到预测的前向;损失在预测之后单独计算 + objects: 数据、模型参数、预测、损失 + mechanism: 预处理后送入模型;模型产生 logits 得到预测;损失比较预测与真值 + +## Lint +allow-raw-tikz: false +# 若为 true:F1.tex 顶部必须有 `% superfig-lint: allow-raw-tikz` +``` + +译出的 `.tex` 必须能被现有 `superfig/scripts/build.sh` 编过。`at` 字段是 **TikZ `calc` 表达式**,必须含外层 `($…$)`(与 `superfig/examples/pipeline.tex` 的 `at={($(y.south)+(0,-22mm)$)}` 一致)。禁止 `at: "below y"`,也禁止漏掉括号写成 `$(y.south)+(0,-22mm)$`。 + +**supertensor request(PR 3;字段对齐 `semantics.md` + `geometry.md` + `mha-causal.tex` 的 ledger,图可裁到 stage A 以免 example 过大):** + +```markdown +# Figure request F2 +toolkit: supertensor +language: cjk +claim: 每头打分沿 d_h 收缩;K^T 必须物理换面。 +grammar: tensor-face +work_rel_dir: figures/F2 +# build.sh /notes/figures/F2/F2.tex /notes/figures/F2/build + +## Roles # \stsetrole +- {role: q, color: stTeal} +- {role: k, color: stOrange} +- {role: s, color: stCoral} + +## Geometry # \stdim{axis}{cells} +- {axis: T, cells: 6} +- {axis: dh, cells: 3} + +## Symbols # semantics.md 每条 +- {name: Q, kind: value, dtype: R, shape: "h x T x d_h", + axes: {h: heads, T: time, dh: head dim}, producer: "linear_q"} +- {name: KT, kind: value, dtype: R, shape: "h x d_h x T", + note: "physical transpose of K; contracted axis dh matches Q width"} +- {name: S, kind: score, dtype: R, shape: "h x T x T"} + +## Flow +stage: {name: SA, text: "每头打分:沿 $d_h$ 收缩"} +row: {name: rowA, height: T} +# coord: "" 必填。译码器对 ststack/stface/stglyph/stindexface +# 永远输出空坐标参数:\ststack[role=q, bracket=true]{Q}{}{T}{dh}{3} +# 丢掉 {} 会把 T 当成 coord,编出来的图与 stage A 对不上。 +in_row: + - {macro: ststack, name: Q, role: q, coord: "", rows: T, cols: dh, sheets: 3, bracket: true} + - {macro: stglyph, name: mA, coord: "", glyph: "$\\times$"} + - {macro: ststack, name: KT, role: k, coord: "", rows: dh, cols: T, sheets: 3, bracket: true} + - {macro: stglyph, name: eA, coord: "", glyph: "$=$"} + - {macro: ststack, name: S, role: s, coord: "", rows: T, cols: T, sheets: 3} +captions: + - {on: Q, symbol: "$\\mathbf Q^{(i)}$", shape: "$h\\times T\\times d_h$"} + - {on: KT, symbol: "$\\mathbf K^{(i)\\top}$", shape: "$h\\times d_h\\times T$"} + - {on: S, symbol: "$\\mathbf S^{(i)}$", shape: "$h\\times T\\times T$"} +topformula: "$S^{(i)} = Q^{(i)} K^{(i)\\top}$" +meaning: + axes: "T 时间;d_h 头维;h 头数画成 stack 深度" + objects: "Q/K 是 value;S 是 score,不是 mask" + mechanism: "沿 d_h 收缩;K^T 换面,收缩边等长" + +## Lint +# 源码若需要豁免,写 `% supertensor-lint: ...`,不要只写在本文件 +``` + +不要在 supertensor request 里发明 `\sf*`。 + +**Figure agent 交付(与 `superfig/SKILL.md` Output 对齐):** PNG 预览、`F-mechanism.md` 一段、`.tex` + `build/` 下 PDF/SVG/PNG。 + +```bash +/home/carry/myprj/tools/skills/superfig/scripts/build.sh \ + "/notes/figures/F1/F1.tex" \ + "/notes/figures/F1/build" +``` + +`F1.tex` 头与 golden 相同:`\documentclass[border=10pt]{standalone}` + `\usepackage[cjk]{superfig}`。 + +**Screenshot CLI(主 agent):** + +```bash +./scripts/screenshot.sh --work --id F2 +``` + +算法(**页渲染是唯一主路径**;`crop_bbox` 的坐标系只对它有定义): + +1. 读 `figures[F2]`。`source_pages` 必填,取**第一个**页码 `N`(多页截图拆成多行 `F*`,不在一页脚本里拼)。 +2. 主路径:`pdftoppm -png -r 200 -f N -l N /source/paper.pdf /pg` → 得到一张 200 dpi 整页 PNG。这与 `crop_bbox`「200 dpi 页像素、左上原点」同一空间。 +3. 若 `crop_bbox` 非 null:必须有 `magick`。没有 → `screenshot.sh` 非零退出(不要 silently 交整页)。有则 `magick .png -crop WxH+X+Y +repage` 写出 `orig.png`(`W=x1-x0` 等)。 +4. 若 `crop_bbox` 为 null:把整页复制为 `orig.png`。 +5. **不要**用 `pdfimages -all` 当默认。它无页码、分辨率不是 200 dpi 页像素,无法实现「Table 2 on p.6 + crop_bbox」。v1 不提供 `raster_backend: embedded`。 + +`source_pages` 缺失或 `N` 越界 → 非零退出。 + +**Matplotlib:** `/notes/figures/F3/plot.py` 必须在 cwd=`.../F3` 下接受 `--out build/F3.pdf` 并写出向量 PDF。主 agent:`python3 plot.py --out build/F3.pdf`。`include` 仍是 `figures/F3/build/F3.pdf`,用 `\spfig` 不是 `\spscreenshot`。 + +**笔记嵌入:** + +```tex +\spfig{F1}{一次前向与侧路损失。}{重绘自论文 Figure~1(§3.1);toolkit: \texttt{superfig};ledger id: F1。} +\spscreenshot{F2}{WMT 2014 BLEU。}{论文 Table~2,p.6;toolkit: screenshot。} +``` + +宏签名见 API 节。禁止:`\input`/`\includestandalone` sibling 源;向量图用 PNG 当主嵌入;图进盒子;笔记 `\usepackage{superfig|supertensor|superderive}`(`SP003`)。 + +--- + +#### 7. Agent 拆分 + +对标 `wdkns-skills/README.md` 里 youtube 的四类角色,论文侧改成 **ledger 先行**。`references/agents.md` 是权威;SKILL.md 只留触发阈值和一份可粘贴 spawn 配方。 + +```mermaid +sequenceDiagram + participant U as User + participant M as Main / integrator + participant O as Outline agent + participant W as Writer agents + participant F as Figure agents + participant C as Consistency agent + participant R as Reviewer (optional follow-up) + + U->>M: paper source + 范围 + M->>M: preflight + ingest + M->>O: source/ + assets/ledger.example.yaml + O-->>M: ledger.yaml + outline.md + notes 骨架 + alt 用户要求确认 ledger + M->>U: 展示 claims / figure plan + U-->>M: 修订 + end + par 按节 + M->>W: ledger + 本节边界 + 邻节 overlap + W-->>M: sections/sec-XX.tex + end + par 每张计划图一张 agent + M->>F: F*.request.md + 对应 sibling SKILL + F-->>M: tex + build/ + mechanism.md + end + M->>M: 核对 notes.tex 的 \\input 与 outline map;更新 figures[].status + M->>C: ledger + notes + figure 产物 + C-->>M: consistency.yaml(id 列表) + M->>M: lint.py --work + build.sh --work → notes.pdf + opt 用户显式要求查漏 + M->>R: 对照 source/paper.txt 与页渲染 + R-->>M: 仅反馈,不改(与 youtube reviewer 相同) + end + M->>U: notes.pdf + ledger + 图产物 +``` + +**单遍 vs 多 agent(闭合 9–12 页空洞;与 §1 表同一谓词):** + +| 必须拆 | 单 agent(其余一切,含 9–12 页 ∧ 顶层节 ≤ 4 ∧ 重绘 ≤ 1) | +|---|---| +| 正文 **> 12** 页 | excerpt,或用户只要 ledger | +| 论文顶层节 **> 4** | 上列三个「必须拆」都不成立 | +| 计划重绘图 **≥ 2**(每图一个 figure agent) | | +| 用户 query **显式**要求 spawn | | + +**Codex / 部分 runtime 的硬约束**(抄 `wdkns-skills/README.md`):只有用户 query **显式**要求 sub-agent / 并行时才会 spawn。因此 `SKILL.md` 必须附一份可粘贴配方,而不是假设运行时总会拆: + +```text +$superpaper <源> 请 spawn 多 sub agents,隔离上下文: + - 1 个 outline agent:ingest 之后写 ledger.yaml + outline.md + 节边界 + - N 个 writer agents:各写 sections/sec-XX.tex,引用 ledger id + - 每个计划重绘图 1 个 figure agent:只读 F*.request.md,调用对应 sibling skill + - 1 个 consistency agent:符号、术语、claim 覆盖、路由一致性 +完成后用 superpaper/scripts/lint.py 与 build.sh 收口。 +``` + +**Writer 工作单元 = `outline.md` 里的讲义节,不是 `coverage.sections_in`。** +`coverage.sections_in` 只限制**可以引用的论文节**(防 writer 去写被 skip 的附录)。切段、文件名、并行度全部看讲义 map。 + +`outline.md` **必须**含下列标题(否则 consistency 视为未完成): + +```markdown +# Outline: + +## Lecture map + +| file | lecture_title | paper_sections | ledger_ids | +|---|---|---|---| +| sec-01.tex | 这篇论文在问什么 | 1 | Q1 | +| sec-02.tex | 主张与贡献 | 1, 3 | C1 | +| sec-03.tex | 预备:定义、假设、符号 | 2, 3.1 | D1, A1 | +| sec-04.tex | | 3.2 | C1, DER1, F1 | +| sec-05.tex | 实验与证据 | 5 | E1, F2 | +| sec-06.tex | 总结与延伸 | 6, 7 | C1 | +| sec-app-a.tex | 符号表 | — | (generated) | +| sec-app-b.tex | 推导链一览 | — | DER* | +| sec-app-c.tex | 图表清单 | — | F* | + +## Locked +- 首节标题必须是「这篇论文在问什么」 +- 末节(appendix 前)必须是「总结与延伸」 +- 三个 appendix 行必须存在;`sec-app-a.tex` 只 `\input{sections/symbols.tex}` +``` + +`sec-XX` 的 XX 是**讲义序号**(01, 02, …),不是论文节号。不要按 PDF 页序复述;map 的 `paper_sections` 只是引用许可。 + +**谁写哪份文件:** + +| 文件 | 作者 | 之后谁可以改 | +|---|---|---| +| `ledger.yaml` | outline(从 `assets/ledger.example.yaml` 复制) | 仅 outline / 主 agent(writer **禁止**) | +| `outline.md` | outline | 仅 outline | +| `notes/notes.tex` | outline:填元数据 + 按 map `\input{sections/sec-XX.tex}` | 仅当 map 增删行时由 outline 改。主 agent「缝合」= **核对 `\input` 列表与 map 一致**,不是重写正文 | +| `notes/sections/sec-XX.tex` | 每个文件 **一个 writer**(含首节、总结) | 该 writer | +| `notes/sections/symbols.tex` | `render_ledger.py` | 无人手改 | +| `notes/figures/F*/F*.request.md` | outline | figure agent 只读 | + +首节/末节不由 outline 代写正文:outline 只落 `\section{...}` 空壳,writer 填。 + +**handoff:** + +- Outline 输入:`source/` + `assets/ledger.example.yaml`。输出:磁盘上的 `ledger.yaml` + `outline.md` + `notes.tex` 骨架 + 空 `sec-XX.tex` + 各 `F*.request.md`。 +- Writer 输入:`ledger.yaml` + 本行 map(file / lecture_title / paper_sections / ledger_ids)+ 邻接讲义节最后一段 overlap + `references/pedagogy.md`。不得新增 `status: core` claim。 +- Figure 输入:仅 request + sibling SKILL。不读 `source/`。 +- Consistency 输入:ledger + 全部 `sec-*.tex` + 各 `F*-mechanism.md`。输出 `/consistency.yaml`: + +```yaml +schema: superpaper.consistency/v1 +unlabeled_core_claims: [] # C* +symbol_drift: [] # {name, ledger_kind, notes_hint} +term_mismatch: [] # {used, canonical} +router_mismatches: [] # F* +missing_artifacts: [] # F* +missing_requests: [] # F* +orphan_labels: [] # \splabel 指向不存在的 id +``` + +主 agent 按该文件改磁盘,再跑 `lint.py`。 + +**并发度:** 典型 12 页 = 1 outline + 3–5 writers + 0–3 figures + 1 consistency。Figure 目录互不共享。Writer 不改 ledger。 + +--- + +#### 8. 仓库布局(v1 第一张 PR 就必须按此建目录) + +**Git 拓扑(已落地):** SuperPaper 是母仓库。`superfig/` 与 `supertensor/` 是 +git submodule,远程分别为 `carrydela/SuperFig` 与 `carrydela/SuperTensor`。 +`superderive/` 以后同样以子仓库加入。本地 `skills/superfig` 与 +`skills/supertensor` 是指进本仓库的符号链接。子仓库的 `.sty` / lint 契约不变。 + +v1 笔记脚手架仍落在母仓库根下(与子仓库并列),不是塞进某一个 child: + +```text +/home/carry/myprj/tools/skills/superpaper/ + SKILL.md + README.md + agents/openai.yaml + assets/ + notes-template.tex + ledger.schema.yaml + ledger.example.yaml + references/ + input.md # 源类型、ingest、原图 vs 重绘 + ledger.md # schema、id、retired_ids、kind 别名表 + router.md # class / ACCEPTED / SPLIT 整数 id + figure-request.md # 两套 request 全文、screenshot.sh + pedagogy.md # 教学序列、公式三拍、盒子、骨架 + agents.md # 讲义 map、阈值、spawn、consistency.yaml + api.md # 全部 \sp* / quotebox 签名 + checklist.md # 笔记交付清单(不是图清单) + antipatterns.md # 编译干净但教错的笔记 + fallback.md # 无 LaTeX / 扫描件 / sibling 缺失 + scripts/ + preflight.sh + ingest.sh + screenshot.sh # PR 2 + lint.py + router.py # PR 1 完整实现 + render_ledger.py + build.sh + test.sh + examples/ + excerpt-toy/ # 就是一个 --work 树(见下) + pipeline-delegate/ + tensor-delegate/ + tests/ + ledger-valid.yaml # --ledger only + ledger-invalid/ # --ledger only;按 PR 切片 + loads-sty/ # 迷你 --work 树,专测 SP003 + notes-smoke/ # 迷你 --work 树,只编过 + router_test.py +``` + +对标 `superfig/README.md` 的「目录即契约」:`SKILL.md` 瘦、`references/` 按需加载、`scripts/{preflight.sh,lint.py,build.sh,test.sh}` + `ingest` / `router` / `render_ledger` / `screenshot`。 + +**不出现:** `assets/superpaper.sty`(v1 盒子和宏都放进 `notes-template.tex`,避免再长一个包)、`work/`、真实论文 PDF。 + +`agents/openai.yaml`: + +```yaml +interface: + display_name: "Superpaper" + short_description: "把论文编成带 ledger 与路由出图的中文讲义" + default_prompt: >- + Use $superpaper to reconstruct this paper's argument thread, + expand the key derivations, and produce structured Chinese notes. + Build ledger.yaml first. Route figures to superfig / supertensor / align; + do not draw inside superpaper and do not \usepackage{superfig} in the notes. +``` + +--- + +#### 9. `SKILL.md` 形态(给第一张 PR 的正文大纲) + +遵守 `~/.grok/bundled/skills/create-skill/SKILL.md` 的 frontmatter,以及 `skill-design-principles`:一事一处、SKILL 是 agent 提示词不是文档、细节指针到 `references/`。对标 `superfig/SKILL.md` 的瘦身程度(约 80 行),**不要**写成 youtube 那样 260 行的全抄。 + +建议 frontmatter(触发词必须能自动召回): + +```yaml +--- +name: superpaper +description: >- + Reconstruct a paper's argument thread and write structured Chinese + lecture notes with a claims/symbols/derivation ledger, then route + figures to superfig, supertensor, or (later) superderive. Use when + the user asks for 读论文, 论文笔记, 脉络梳理, 公式推导, 抽象公式图像化, + arXiv notes, paper notes, or $superpaper. Not for drawing a single + architecture figure (use superfig) or a tensor-shape figure (use + supertensor) or for turning a lecture video into notes + (use youtube-render-pdf / bilibili-render-pdf). +--- +``` + +正文只保留: + +1. 一句话定位:论文侧的 `youtube-render-pdf`,**不是** figure 包。 +2. When to use / When not(指向 sibling 与视频 skill)。 +3. 编号工作流:preflight → ingest → **ledger** → outline → writers → router/delegate → consistency → build。 +4. Non-negotiables:ledger SSOT;笔记不加载 figure `.sty`;公式三拍;路由表;不发明 superfig 原语。 +5. Output:`ledger.yaml` + `notes.tex` + `notes.pdf` + 各图产物。 +6. Iterating:改 ledger 再改一处。 +7. 指针:`references/*.md`。 +8. 可粘贴 spawn 配方。 + +--- + +#### 10. 脚本契约 + +所有面向工作副本的脚本统一: + +```bash +./scripts/ingest.sh --work --arxiv 1706.03762 +./scripts/ingest.sh --work --pdf /path/p.pdf +./scripts/ingest.sh --work --tex /path/main.tex +./scripts/ingest.sh --work --excerpt /path/clip.md +./scripts/lint.py --work +./scripts/lint.py --ledger tests/ledger-valid.yaml + # YAML-only:SP001/SP002,以及已启用的 + # SP010/SP011/SP013–SP016/SP022/SP023/SP024 + # 跳过必须看见笔记或磁盘文件的码:SP003、SP012、SP020、SP021 +./scripts/lint.py --ledger X.yaml --notes path/to/notes.tex + # 另加 SP003(及已启用的 SP020);仍无 --work 则跳过 + # SP012 / SP021(它们解析 /notes/ 下的文件) +./scripts/render_ledger.py --work # 写 notes/sections/symbols.tex +./scripts/build.sh --work +./scripts/screenshot.sh --work --id F2 +``` + +兼容别名:`--out` = `--work`(ingest 文档里两名同义,实现只保留 `--work`)。 + +**每个 `examples/*` 目录就是一棵 `--work` 树**,不是扁的 `notes.tex`: + +```text +examples/excerpt-toy/ + ledger.yaml + outline.md + source/excerpt.md + notes/notes.tex + notes/sections/sec-01.tex +``` + +`test.sh` 对 example / `tests/notes-smoke` / `tests/loads-sty` 一律 `build.sh --work ` 或 `lint.py --work `。`tests/ledger-invalid/*.yaml` 继续 `--ledger`(无笔记)。 + +**`preflight.sh`** — 0 完整 / 1 降级 / 2 无引擎。对标 sibling:缺 CJK 是 1 不是 2。 + +| 档 | 检查 | 缺了 | +|---|---|---| +| 引擎 | `xelatex`、`article.cls` | **exit 2**(「无 LaTeX」只用于这一档) | +| 模板/CJK(exit 1) | `ctex.sty`、`FandolSong-Regular.otf`、`amsmath.sty`、`amssymb.sty`、`tcolorbox.sty`、`graphicx.sty`、`hyperref.sty`、`geometry.sty`、`listings.sty`、`booktabs.sty`、`subcaption.sty`、`float.sty`(`figure[H]`)、`tikz.sty`、`etoolbox.sty` | 降级:无 Fandol 则英文笔记或稍后 Missing character | +| Python(exit 1) | `python3`、`import yaml`、`import jsonschema` | 不能 lint | +| ingest(exit 1) | `pdftotext`、`pdftoppm` | 只吃 tex/excerpt | +| 可选 | `magick`、`pdftocairo`、`curl`/`wget`、sibling 目录 | 无 `magick` 时 `crop_bbox` 必须失败(见 `screenshot.sh`),不是静默整页;不升到 2 | + +不要求 `standalone.cls`。 + +**`ingest.sh`:** 写 `source/meta.yaml`。`pdftoppm -png -r 120` 之后**重命名**为 `pages/pg-%03d.png`(永远三位数,避免 8 页 `pg-1` vs 15 页 `pg-01`)。网络失败可重入。 + +**`lint.py` 码表(按 PR 启用;未启用的码不跑、对应 fixture 不进 `test.sh`):** + +| 码 | PR | 失败条件 | +|---|---|---| +| `SP001` | 1 | `jsonschema` 失败(缺 required、坏 enum、坏类型) | +| `SP002` | 1 | 任意数组内 id 重复 | +| `SP003` | 1 | 笔记源 `\usepackage` 匹配 `superfig\|supertensor\|superderive` | +| `SP010` | 2 | 单类但 toolkit ∉ `ACCEPTED[class]`(**不含** include/status) | +| `SP011` | 2 | 单行 `classify` 返回多个 class | +| `SP012` | 2 | sibling toolkit ∧ `status != dropped` ∧ request 文件不存在 | +| `SP013` | 2 | `toolkit=none` ∧ `status ≠ dropped` | +| `SP014` | 2 | `toolkit ∈ {align,none}` ∧ `include is not None` | +| `SP015` | 2 | `included` ∧ 向量 toolkit ∧ `include ≠ figures/{id}/build/{id}.pdf` | +| `SP016` | 2 | `included` ∧ `screenshot` ∧ `include ≠ figures/{id}/orig.png` | +| `SP020` | 4 | `status: core` 的 claim 在 `notes/**/*.tex` 无 `\splabel{C*}`(`coverage.mode=excerpt` 同样查 ledger 里列出的 core) | +| `SP021` | 4 | `include` 已是非空路径但 `/notes/` 不存在 | +| `SP022` | 4 | v1(`SUPERPAPER_PHASE` 缺省 1)出现 `toolkit: superderive` | +| `SP023` | 4 | 非 dropped 的新 id ∈ `retired_ids` | +| `SP024` | 4 | `figures[].claim` / `derivations[].claim` 不是已有 `C*` | + +stderr 格式**抄** `superfig/scripts/lint.py`:先 `!! {path}`,随后缩进行 ` line N: SP00X message`(无行号则 ` SP00X message`)。 + +警告(不失败):未知顶层键、`coverage.mode=full` 且 `sections_in` 空、符号从未在笔记出现。未知 `steps[].rule` **不是**警告(`SP001`)。 + +**禁止**复制 superfig 的 raw-tikz / callout / 4-hue 规则。 + +**`build.sh --work `:** + +1. `lint.py --work ` +2. `render_ledger.py --work ` +3. `cd /notes && xelatex -halt-on-error notes.tex` 两遍(`\includegraphics` 相对 `notes/`) +4. `Missing character` / undefined references / multiply-defined = 失败 +5. **Overfull/Underfull 不失败** +6. 复制 PDF 到 `/out/notes.pdf` + +**`test.sh`:** 只跑**当前已启用码**对应的 fixture。example 与 `tests/{notes-smoke,loads-sty}` 按 `--work` 调。PR 2/3 example 的图 PDF 预构建并提交;`test.sh` 编笔记,不重跑 sibling `build.sh`。 + +**`render_ledger.py --work`:** 写 `notes/sections/symbols.tex`;可选 `/claims.md`。 + +**`screenshot.sh`:** 见 §6。 + +--- + +#### 11. Argument-map figures(本设计允许的**唯一** superfig「扩展」,且是后置 PR) + +v1 **零改** `superfig/`。主张图先用现有原语 + 文档化 role 约定: + +```tex +\sfsetrole{claim}{sfTeal} +\sfsetrole{assumption}{sfOrange} +\sfsetrole{lemma}{sfViolet} +\sfsetrole{evidence}{sfCoral} +% 然后 \sfnode / \sfarrow;边语义只能是 dependency 或 causality +% (superfig/references/grammar.md:data | control | dependency | causality) +``` + +四点约束: + +- **不新增原语。** 不需要 `\sfclaim`。role 名只是 `\sfsetrole` 字符串。 +- **不改 lint。** 4 色相预算刚好够这四个 role + gray。第五种节点用 `level=` 或拆图。 +- **后置、可加性。** PR 5 最多:`superfig/examples/argument-map.tex` 一张 golden + `references/grammar.md` 表格加一行「argument map = 现有 node/edge + 上述 role」。`SKILL.md`「When to use」可加半句。不改 `.sty`。 +- 推荐 **不要** 为 argument map 改 `superfig` 的 description 触发词;路由由 `superpaper` 拥有。 + +--- + +### Layer 2 — `superderive`(现在写清,以后再实现) + +新的 sibling **figure** toolkit:逐步代数推导图。视觉语法既不是 node/edge,也不是 tensor face。 + +**不要**往 `superfig.sty` 加 `align` 风格宏。 + +#### 视觉语法 + +三区仍对齐家族(顶 claim / 中结构 / 底 meaning),但中区是 **改写行** 不是流水线: + +| 要暴露的事实 | 语法 | 宏(草图) | +|---|---|---| +| 一行合法改写 | step | `\sdstep{name}{lhs}{rhs}` | +| 为何合法 | 右轨 justification | `\sdreason{name}{text}` | +| 消去 | strike + cancel 色 | `\sdcancel{name}{subterm}` | +| 代入 | 源/目标高亮 | `\sdsubst{name}{from}{to}` | +| 焦点子式 | 不改变项的框 | `\sdbox{name}{subterm}` | +| 非法 vs 合法对照 | 两列,非法列 role=warn | `\sdcol` … `\sdcolend` | +| 底注 | 三行 meaning | `\sdmeaningbox`(idea / rewrite / caveat) | + +House style **复制** `superfig` 骨架(palette 名改为 `sdTeal` 等,HEX 相同;一 role 一色;≤4 色相;lint-on-warning;`scripts/{preflight.sh,lint.py,build.sh,test.sh}`)。v1/v2 都不抽 `superstyle`。 + +Role 建议:`keep`(保留项)、`rewrite`(本步触碰)、`cancel`、`intro`(新引入)。不要把每一步换成新色相。 + +#### 何时由 superpaper 调用 + +见上表。额外:若 `derivations[].expand: true` 且步数 ≤ 4 且没有任何 `cancel-visual` / `subst-visual`,即使以后有 `superderive` 也 **仍用 `align`**。图是为「必须看见」服务的,不是为「有包就用」服务的。 + +#### API 草图(实现时可以微调名字,但前缀锁定 `\sd`) + +```tex +\documentclass[border=10pt]{standalone} +\usepackage[cjk]{superderive} + +\sdsetrole{keep}{sdTeal} +\sdsetrole{rewrite}{sdOrange} +\sdsetrole{cancel}{sdCoral} + +\begin{document}\begin{tikzpicture} +\sdstage{D1}{缩放来自方差,不是装饰} +\sdrow{R1} + \sdstep{s1}{QK^{\top}}{QK^{\top}/\sqrt{d_k}} + \sdreason{s1}{§3.2.1,避免 softmax 饱和} +\sdrowend +\sdbbox{all} +\sdtopformula{F}{\mathrm{Attention}(Q,K,V)=\mathrm{softmax}(QK^{\top}/\sqrt{d_k})V} +\sdmeaningbox{mb}{120mm}{all} + {点积方差随 $d_k$ 线性涨} + {缩放是改写,不是新算子} + {没有缩放,softmax 进饱和区,梯度消失} +\end{tikzpicture}\end{document} +``` + +Lint(v2,对标 `superfig/scripts/lint.py` 的职责切分):未声明 role、>4 色相、raw `\draw`、`\sdtopformula` 出现在最后 `\sdrowend` 之前、一图多个「非法对照」列(预算:一列对照)。**不要**把「公式必须在最后一行之后」理解成禁止中间出现数学——数学就是 step 的内容;禁的是**顶栏 claim** 提前居中。 + +#### `superderive/` 目录(phase 2 才建,形状抄 `superfig/`) + +```text +/home/carry/myprj/tools/skills/superderive/ + SKILL.md + README.md + agents/openai.yaml + assets/superderive.sty + references/{grammar,layout,style,api,checklist,antipatterns,fallback}.md + scripts/{preflight.sh,lint.py,build.sh,test.sh} + examples/{rewrite-cancel.tex,subst-chain.tex,antipatterns.tex} + tests/{smoke.tex,lint-invalid/,invalid/} +``` + +Provenance 写:「第三 sibling;不是从 superfig 长出来的。superpaper router 在 phase≥2 才发出 `toolkit: superderive`。」`tensor-formula-viz` 与 `superfig` 都不动。 + +`agents/openai.yaml`:`Use $superderive to turn a rewrite sequence into a step/justification figure. Not for architecture (superfig) or tensor faces (supertensor).` + +--- + +## API / Interface Changes + +### 新建 + +| 接口 | 消费者 | 稳定承诺 | +|---|---|---| +| `superpaper` skill | 用户 / 主 agent | 见 SKILL description | +| `ledger.yaml` `superpaper.ledger/v1` | outline / writers / lint | §3 schema;未知键警告 | +| `router.classify` / `suggest` / `accepted` / `check_row` | lint + agent | class 或 `SPLIT:a+b`;不是 toolkit | +| `--work ` CLI | 全部 scripts | ledger 在 `/ledger.yaml` | +| `\sp*` / `\quotebox` | 笔记源 | 下方签名 | +| `F*.request.md` | figure agent | §6 两套模板 | +| `superderive` `\sd*`(v2) | figure agent | v1 不存在 | + +### 笔记宏(检入 `assets/notes-template.tex` 与 `references/api.md`) + +```tex +% 锚:hypertarget + label,供 PR 4 用正则 \\splabel\{C1\} 扫描 +\newcommand{\splabel}[1]{\hypertarget{sp:#1}{}\label{sp:#1}} +% 可点击引用;排版为等宽 id +\newcommand{\spref}[1]{\hyperlink{sp:#1}{\texttt{#1}}} +% 出处脚注 +\newcommand{\spsource}[1]{\footnote{来源:#1}} +% 向量图:读 figures/#2/build/#2.pdf +\newcommand{\spfig}[4][0.92\textwidth]{% + \begin{figure}[H]\centering + \includegraphics[width=#1]{figures/#2/build/#2.pdf}% + \caption{#3\protect\footnotemark}\end{figure} + \footnotetext{#4}} +% 截图:读 figures/#2/orig.png +\newcommand{\spscreenshot}[4][0.92\textwidth]{% + \begin{figure}[H]\centering + \includegraphics[width=#1]{figures/#2/orig.png}% + \caption{#3\protect\footnotemark}\end{figure} + \footnotetext{#4}} +% 短原文;#1 = 标题(含 §/Eq) +\newtcolorbox{quotebox}[1]{ + enhanced, breakable, + colback=black!3!white, colframe=black!55, colbacktitle=black!55, + coltitle=white, fonttitle=\bfseries, title=#1, sharp corners} +``` + +用法:`\splabel{C1}` 放在陈述该 claim 的段首;`\spref{C1}` 在后文回指;`\spsource{§3.2, Eq.(4)}` 作句末脚注。`quotebox` 正文禁止超过约 8 行。图不得放入任何盒子。需要 `float`(`[H]`)和 `hyperref`(`\hypertarget`)。 + +### 对现有包 + +| 包 | v1 | 后置 | +|---|---|---| +| `superfig` | **零改动** | PR 5:additive example + grammar 一行。不改 `.sty`、不改 lint | +| `supertensor` | **零改动** | 无 | +| `tensor-formula-viz` | **不动**(与 `supertensor/README.md` Provenance 一致) | 无 | +| `youtube-render-pdf` / `bilibili-render-pdf` | **不动**;盒子定义复制进 superpaper 模板 | 不抽共享模板 | + +无 before/after 宏变更。笔记与图的唯一运行时耦合是 **相对 `notes/` 的路径** `figures/F/build/F.pdf`(截图为 `figures/F/orig.png`)。 + +--- + +## Data Model Changes + +无数据库。磁盘上的 SSOT 是 `ledger.yaml`。 + +**迁移:** `schema: superpaper.ledger/v1`。破坏性变更加 `v2`。`render_ledger.py` 投影随时可删可再生。 + +**id 稳定性:** 顶层 `retired_ids: [C1, F2, …]`。废弃时把 id 写入该数组,并从工作数组删除或保留为不可变的 `status: dropped` 行。新对象只用下一个未占用整数。lint `SP023`:非 dropped id ∩ `retired_ids` ⇒ 失败。不存在「两条同 id(一条 dropped 一条新)」的检查——那已经是 `SP002`。 + +--- + +## Alternatives Considered + +### A. 做大 `superfig` + +把笔记宏、`align` 推导、主张 role、甚至「文档模式」option 塞进 `superfig.sty`。 + +| 利 | 弊 | +|---|---| +| 一个 skill 名 | 图尺度 lint 与文档尺度互相污染(一 callout、4 色相、formula 顺序、raw tikz) | +| | `standalone` 与 `article` 的构建失败语义不同(`build.sh` 对 overfull 零容忍,中文 article 做不到) | +| | 逐步改写会逼出与 `\sfnode` 无关的宏,包变成厨房水槽 | +| | 与「为何从 tensor-formula-viz 拆出 supertensor」的理由直接相反 | + +**否决。** 产品决策已定;仓库证据也支持:`superfig.sty` 文件头自称 “A smaller sibling of `supertensor.sty`… primitives are generic nodes and edges, not tensor faces.” 它的价值就是小。 + +### B. 一个 mega-skill(读论文 + 两种图 + 推导 + 视频?) + +| 利 | 弊 | +|---|---| +| 用户只记一个名字 | SKILL.md 无法保持「瘦 + 按需 references」;与 skill-design-principles 冲突 | +| | youtube 的帧召回纪律和 superfig 的 4 色相纪律写在同一提示词里,agent 会串规则 | +| | 无法对「只画一张架构图」保持 `superfig` 的短 description 触发 | + +**否决。** 触发词污染:用户说「画一张 pipeline」不应拉起读论文流水线。 + +### C. Sibling family(采纳) + +与 `superfig` / `supertensor` 的拆分理由相同,再加一层文档: + +- **失败模式不同。** 图的失败是「编译干净但几何/语义在撒谎」(shards 没铺满、未转置却标 \(K^\top\))。笔记的失败是「编译干净但漏 claim、符号漂移、路由错引擎」。推导图的失败是「把改写画成假拓扑」。三种失败要三套不变量、三套 lint。 +- **原语不同。** nodes/edges ≠ faces/axes ≠ steps/justification。共用宏包只会让最小语法选择失效。 +- **构建目标不同。** standalone 一页图 vs article 讲义 vs(v2)又一页 standalone 图。 +- **风格复制可接受。** 两套包已经复制 palette;第三套 figure 包(`superderive`)继续复制。文档层连 palette 都不共享(youtube 盒子颜色)。抽取 `superstyle` 的时机是第四个 **figure** 包出现之后,不是现在。 + +`superpaper` 这个名字放文档层,避免 `paper-render-pdf` 暗示它是 youtube 的克隆(源、出处、公式规则都不同)。 + +### 曾短暂考虑、已丢弃的小方案 + +- **Markdown ledger:** 对人友好,对 PR 4 的 lint 不友好。改为 YAML + 只读 Markdown 投影。 +- **`\input` standalone TikZ 进笔记:** 省一次 PDF。会把 `Package superfig Warning` 打进笔记 log,并迫使笔记 `build.sh` 解释图尺度警告。否决。 +- **v1 就抽 notes 模板共享包:** 要改 `wdkns-skills`,违反 non-goal。复制盒子。 + +--- + +## Security & Privacy Considerations + +本 skill 是**本地、单用户、不可信 PDF** 的批处理,不是服务。威胁模型小但具体: + +| 威胁 | 严重度 | 缓解 | +|---|---|---| +| arXiv id / 路径注入 `ingest.sh` | 高 | id 正则;路径不当作 shell 拼接;用数组传参 | +| 解包 e-print 后编译/执行 | 高 | **禁止**对 e-print 跑 latex/make;只当文本读 | +| 恶意 PDF 的工具链漏洞(poppler) | 中 | 本地可信用户假设;不把 ingest 暴露成网络服务 | +| 把受版权论文提交进 git | 中 | `work/` gitignore;`examples/` 只用自造 fixture | +| ledger / 笔记里粘贴隐私批注 | 低 | 不上传;无遥测 | +| figure agent 读整篇论文导致提示词膨胀 / 数据扩散 | 低 | request 文件隔离;figure agent 禁止读 `source/` | + +无认证、无多租户、无密钥。`ingest.sh` 只访问用户给出的本地路径与 arXiv。 + +--- + +## Observability + +不是线上服务。可观察性 = **本地构建纪律**(抄 sibling,但指标不同): + +| 信号 | 来源 | 处理 | +|---|---|---| +| preflight 0/1/2 | `preflight.sh` | 1/2 必须在交付中说出口(对标 `superfig/references/fallback.md`) | +| ingest 页数、`sha256`、是否拿到 e-print | `source/meta.yaml` + `run.log` | 主 agent 写进笔记书目卡片 | +| lint 失败列表 | `!! {path}` 后跟缩进 ` line N: SP00X …`(与 `superfig/scripts/lint.py` 相同) | `build.sh` 非零退出 | +| 路由冲突 | `SPLIT:` / toolkit mismatch | 失败,不静默改 toolkit | +| 笔记 TeX | `Missing character`、undefined ref | 失败 | +| 笔记 TeX | Overfull | **记录在 `run.log`,不失败** | +| 图 TeX | sibling `build.sh` | 图目录内失败;主笔记 build 若 `status: included` 缺 PDF 再失败 | +| claim 覆盖 | core 缺 `\splabel` | 失败 | +| 耗时 | `run.log` 时间戳 | 人工;目标见下 | + +**量级目标(单用户,12 页、2 张重绘图):** + +- ingest(已有 PDF):< 30 s(`pdftotext` + 120 dpi 页渲染) +- ingest(arXiv 冷下载):受网络限制,60–120 s 可接受 +- 单张 sibling 图:`build.sh` 5–20 s(与现仓库 `superfig/examples/pipeline.tex` 同量级) +- 笔记两遍 xelatex:10–40 s +- Agent 墙钟(多 agent):15–40 min,主要在模型,不在脚本 + +无 metrics backend、无 alerting。CI 就是 `scripts/test.sh`。 + +--- + +## Rollout Plan + +本地 skill。开关是 **lint 码启用表 + `SUPERPAPER_PHASE`(缺省 1)**。依赖链是 **1 → 2 → 3 → 4**;PR 5 与 PR 6 可与该链并行;**只有 PR 7** 把 phase 默认改为 2。 + +1. PR 1:skill 可跑无委派笔记。`router.py` **完整**(class / `ACCEPTED` / `SPLIT` / `check_row`),但 lint **不**跑 `SP010–SP016`。SKILL 写「委派是后续 PR」。 +2. PR 2:启用 `SP010–SP016`;superfig 委派 example(出生即带 `\splabel`)。 +3. PR 3:supertensor 委派 example(同样自带 `\splabel`)。 +4. PR 4:启用 `SP020–SP024`。example 不得返工。 +5. PR 5:optional,只动 `superfig/examples` + grammar 一行。 +6. PR 6:落地 `superderive/` 宏包与测试。**不改** router 缺省 phase,不改 `SP022`。 +7. PR 7:`SUPERPAPER_PHASE` 缺省 2;关掉 `SP022`;加 derive-delegate example。 + +**回滚:** 删/回退对应目录即可。v1 对 sibling 零改动,回滚 superpaper **不会**留下 sty 垃圾。PR 5 回滚只删 example 与 grammar 那一行。PR 7 回滚即回到 phase 1,宏包可留。 + +**降级路径**(`references/fallback.md`): + +- 无 XeLaTeX:仍交 `ledger.yaml` + Markdown 笔记;声明 PDF 未产出。 +- 无 `pdftotext`:只接受 `tex` / `excerpt`。 +- sibling 缺失或 figure `build.sh` 失败:该图降级为 `align` 或 screenshot,ledger 写 `status: dropped` + 原因;笔记仍须能编过。 + +--- + +## Risks + +| 风险 | 严重度 | 机制 | 缓解 | +|---|---|---|---| +| 选错 toolkit(框图当 tensor 画,或反过来) | 高 | 图「看起来对」但撒谎;正是 sibling 存在的理由 | 可执行 `router.py`;跨类强制拆图;request 里写死 grammar | +| 符号漂移(正文、符号表、图 caption 三套名字) | 高 | 长论文 + 多 writer | YAML SSOT;`\splabel`;consistency agent;lint;`terms[].aliases` | +| 长论文召回失败 | 高 | youtube README 已承认的「AI extraction 漏召回」 | 切段 + overlap;页渲染召回;可选 reviewer **只反馈不改**;excerpt/body-only 默认 | +| superfig 契约被慢慢污染 | 高 | 「顺便加个宏吧」 | v1 零改动;本设计只允许 PR 5 加 example;评审检查表写明 | +| 笔记 build 误用图尺度失败条件 | 中 | 中文 article 全是 overfull | `build.sh` 明确不把 overfull 当失败;lint 禁止笔记加载 figure sty | +| standalone 嵌入方式选错 | 中 | class 冲突 / 警告泄漏 | 只 `\includegraphics` PDF | +| YAML 数学引号把公式写坏 | 中 | outline agent 产出非法 YAML | example + schema;lint 先解析;字面块 `|` | +| Codex 不 spawn,单上下文丢细节 | 中 | 平台约束 | SKILL 内可粘贴配方;单 agent 阈值写清 | +| 把论文原图当「已经可视化」 | 中 | 架构图截图无法审计语义 | 路由表:架构优先重绘 | +| `superderive` 延期导致推导体验差 | 低 | v1 用 `align` 是刻意的 | 公式三拍 + 展开规则已够教学;图是增强 | +| e-print 解包炸弹 | 低 | 恶意 tar | 限制解压大小/文件数(ingest.sh);永不编译 | +| 工作目录塞进 git | 低 | 大二进制 + 版权 | gitignore;CI 不跑 ingest 网络 | + +--- + +## What “done” looks like + +### v1(本设计的实现完成线) + +- 目录 `superpaper/` 按上文树存在,`./scripts/preflight.sh` 与 `./scripts/test.sh` 在干净 TeX 环境下绿。 +- Agent 仅读 `SKILL.md` + 按需 `references/` 能走通:摘录 → `ledger.yaml` → 中文 `notes.tex` → `notes.pdf`。 +- 公式三拍、`\splabel`、书目卡片、本章小结、总结与延伸,都在模板注释和 pedagogy 里写死。 +- Router 对决策表有单测;跨类 signals 必须拆图。 +- 至少一个 **superfig** 委派 example、一个 **supertensor** 委派 example(图 PDF 预构建)。 +- 笔记源加载 `superfig.sty` 会被 lint 拒绝。 +- `toolkit: superderive` 会被 lint 拒绝,并提示用 `align`。 +- `superfig/`、`supertensor/`、`wdkns-skills/` 的 diff 为空。 + +### v2 + +- `superderive/` 以 superfig 同构形状存在,一张 golden rewrite 图 + 负例 lint。 +- PR 7 把 `accepted("derive")` 扩为 `{align, superderive}` 并停掉 `SP022`;example 增补一个委派。`suggest()` 仍然返回 class `derive`,不是 toolkit 名。 +- PR 5 的 argument-map golden 可先于或后于 superderive 独立合并。 + +--- + +## Key Decisions + +1. **按层拆 sibling,不升级 `superfig`。** 文档失败模式、图失败模式、推导图失败模式需要三套不变量。这与 `superfig` 从「通用图」里把张量面拆给 `supertensor` 的理由相同。 +2. **`superpaper` 是编排 skill,不是 `.sty`。** 对标 `youtube-render-pdf`,不对标 `superfig.sty`。v1 不引入 `superpaper.sty`。 +3. **「抽象公式图像化」是 router,不是第三套画笔。** `suggest()` 返回 **class**(`numeric|raster|tensor|derive|fig|none|SPLIT:…`);`ACCEPTED[class]` 才是 toolkit 集合(`numeric → {screenshot, matplotlib}`,`raster → {screenshot}`)。 +4. **Ledger 用 YAML + draft-07 + `jsonschema`。** 未知键 lint 警告、schema 不 `additionalProperties: false`。不靠 `agents/openai.yaml` 当理由。 +5. **v1 对 `superfig` / `supertensor` / `wdkns-skills` 零改动。** 唯一允许的后续触碰是 PR 5 的可加性 example。 +6. **唯一工作根 `--work`;ledger 在 `/ledger.yaml`;笔记路径一律相对 `notes/`。** `\spfig` 与 `figures[].include` 同形。 +7. **House style:figure 包继续复制 muted palette;笔记盒子继续复制 youtube 的蓝/黄/红。** v1 不抽 `superstyle`。 +8. **v1 逐步推导用 `align`(`derivations[].figure = null`),不用假框图。** 可选 `toolkit: align` bookkeeping 行没有 PDF。 +9. **主张图用现有 `\sfnode`/`\sfarrow` + 四个 role 名。** 不改 `.sty`。 +10. **`symbols[].kind` 以 `semantics.md` 左列为 canonical;斜杠右侧是别名;`scalar`/`set` 是文档层扩展(`d_k` 是 `shape parameter`)。** +11. **必须拆 agent 当且仅当:页 > 12 ∨ 顶层节 > 4 ∨ 重绘 ≥ 2 ∨ 用户 spawn。** 9–12 页落在单 agent。Writer 按讲义节切,不按 `coverage.sections_in`。 +12. **examples 用自造 fixture,不提交论文 PDF。出生即带 `\splabel`。** +13. **笔记 `build.sh` 不因 overfull 失败;图的 `build.sh` 保持零容忍。** +14. **Figure agent 只看见 `F*.request.md`;截图走 `screenshot.sh`(主 agent)。** +15. **e-print 只读不编译。id 退役进 `retired_ids`。拆分只用下一个整数,不用 `F1a`。** +16. **PR 链 1→2→3→4 可审但后条依赖前条;phase 默认只在 PR 7 翻转。** +17. **`lint.py` 先 normalize `symbols[].kind` 再 `SP001`。** `check_row` 的 class/toolkit 失配是 `SP010`/`SP011`;include/status 是独立码 `SP013–SP016`。截图主路径是 `pdftoppm -r 200`,不是 `pdfimages`。 + +--- + +## Open Questions + +在已给产品决策和仓库约束下,实施所需的产品选择已经闭合。下列两项**不阻塞 v1**,有偏好再改: + +1. **PR 2/3 的委派 example 用哪条自造 claim?** 默认改编 `superfig/examples/pipeline.tex`(前向 + 侧路损失)和 `supertensor/examples/mha-causal.tex` 的教学点,写成「论文摘录 fixture」,避免引入新的科学内容。若希望 example 更「像一篇真论文」,再换。 +2. **`SUPERPAPER_PHASE` 升 2 的时机。** 已定为 PR 7(`superderive/scripts/test.sh` 全绿之后),不绑在 PR 6 的 sty。 + +无需用户在实现前回答即可开工 PR 1。 + +--- + +## References + +- `/home/carry/myprj/tools/skills/superfig/SKILL.md` — 文档层对标的「瘦 skill + ledger-before-draw + Output 三件套」 +- `/home/carry/myprj/tools/skills/superfig/README.md` — sibling 目录契约、lint-on-warning 哲学 +- `/home/carry/myprj/tools/skills/superfig/references/{grammar,api,style,checklist,layout,antipatterns,fallback}.md` +- `/home/carry/myprj/tools/skills/superfig/assets/superfig.sty` — `\sf*`、palette、role registry +- `/home/carry/myprj/tools/skills/superfig/scripts/{preflight.sh,lint.py,build.sh,test.sh}` +- `/home/carry/myprj/tools/skills/superfig/examples/{pipeline,branch-architecture,state-flow,dependency-graph}.tex` +- `/home/carry/myprj/tools/skills/supertensor/SKILL.md`、`README.md`(含 Provenance) +- `/home/carry/myprj/tools/skills/supertensor/references/semantics.md` — 符号 kind 的单一来源 +- `/home/carry/myprj/tools/skills/supertensor/references/api.md` — `\st*` / `\stdim` / `\stsetrole` +- `/home/carry/myprj/tools/skills/wdkns-skills/skills/youtube-render-pdf/SKILL.md` +- `/home/carry/myprj/tools/skills/wdkns-skills/skills/youtube-render-pdf/assets/notes-template.tex` — 盒子与书目页 +- `/home/carry/myprj/tools/skills/wdkns-skills/skills/bilibili-render-pdf/SKILL.md` — 降级阶梯 +- `/home/carry/myprj/tools/skills/wdkns-skills/README.md` — 多 agent 配方与 reviewer 查漏 +- `/home/carry/myprj/tools/skills/wdkns-skills/skills/tensor-formula-viz/` — 保持原地不动 +- `/home/carry/myprj/tools/skills/wdkns-skills/templates/writing/readme.md` +- `/home/carry/.grok/bundled/skills/skill-design-principles/SKILL.md` +- `/home/carry/.grok/bundled/skills/create-skill/SKILL.md` + +--- + +## PR Plan + +**1→2→3→4 是依赖链**:每条可单独审查,但 2/3/4/7 **不能**在没有前驱的情况下合并。5 与 6 可并行。不要再说「每条独立可合并」。 + +### PR 1 — `superpaper` 脚手架 + SKILL + ledger + 笔记模板(无出图委派) + +- **Title:** `superpaper: scaffold skill, ledger schema, and notes template` +- **Files/components:** + - 新建 `superpaper/SKILL.md`、`README.md`、`agents/openai.yaml` + - `assets/{notes-template.tex,ledger.schema.yaml,ledger.example.yaml}`(schema = §3 全文;模板含全部 `\sp*` / `\quotebox`) + - `references/{input,ledger,router,pedagogy,api,checklist,antipatterns,fallback}.md`;`figure-request.md` / `agents.md` 可先骨架 + - `scripts/{preflight.sh,ingest.sh,lint.py,router.py,render_ledger.py,build.sh,test.sh}` + - `examples/excerpt-toy/`(一棵 `--work` 树:`ledger.yaml` + `notes/notes.tex` + `notes/sections/`;**每个 core claim 已有 `\splabel`**;`align` 推导;无 sibling) + - `tests/ledger-valid.yaml` + - `tests/ledger-invalid/{missing-paper-id.yaml,bad-toolkit.yaml,duplicate-id.yaml}` + - `tests/loads-sty/`、`tests/notes-smoke/`(迷你 `--work` 树,不是扁的 `.tex`)、`tests/router_test.py` +- **Lint 码启用:** 仅 `SP001 SP002 SP003` +- **`test.sh` 跑:** `--ledger` 测 schema/id;`lint.py --work tests/loads-sty` 测 `SP003`;`build.sh --work` 编 `notes-smoke` 与 excerpt-toy;再跑 `router_test.py`(含 `check_row` 的 `SP010–SP016` 单测,但 lint 进程不启用这些码)。**不**放跨类未拆分、缺 `\splabel`、缺 request 的 fixture。 +- **Dependencies:** 无 +- **Description:** `--work` 约定落地。`router.py` **完整**(`classify`/`suggest`/`accepted`/`check_row`),单测钉 class、`SPLIT` 与 include/status 谓词,但 lint 不调用 `check_row`。ingest 支持 `--arxiv/--pdf/--tex/--excerpt`,页渲染改名为 `pg-%03d.png`。preflight 按 §10 分档。`jsonschema` + PyYAML 是依赖。 + +### PR 2 — 路由 lint 接线 + 嵌入约定 + superfig 委派 example + +- **Title:** `superpaper: wire router lint and superfig include convention` +- **Files/components:** + - `references/{figure-request,agents}.md` 写满(§6 / §7) + - `scripts/lint.py`:启用 `SP010 SP011 SP012 SP013 SP014 SP015 SP016`(即开始调用 `check_row`) + - `scripts/screenshot.sh`(`pdftoppm -r 200` 主路径;`crop_bbox` 缺 `magick` 则失败) + - `examples/pipeline-delegate/`:一棵 `--work` 树;§6 的 F1.request(1:1 `pipeline.tex`,`at` 含 `($…$)`)+ 预构建 `notes/figures/F1/build/F1.pdf` + `\spfig` + **`\splabel` 已在** + - `tests/ledger-invalid/{mixed-signals.yaml,toolkit-mismatch.yaml,missing-request.yaml,none-not-dropped.yaml,align-has-include.yaml,included-null-include.yaml,screenshot-bad-include.yaml}` + - `SKILL.md` 补委派步骤 +- **不改:** `router.py` 决策表(已在 PR 1)。本 PR 只接线。 +- **Lint 码启用:** `SP001–SP003` + `SP010–SP016` +- **Dependencies:** PR 1 +- **Description:** 笔记相对路径 + sibling `build.sh` 命令行写进 example README。CI 编笔记,不重跑 superfig。零改 `superfig/`。 + +### PR 3 — `supertensor` 委派 example + +- **Title:** `superpaper: supertensor delegation example` +- **Files/components:** + - `examples/tensor-delegate/`(§6 的 F2 request + 预构建 PDF + `\splabel`) + - `references/figure-request.md` 挂上 supertensor 剖面(若 PR 2 已写入则本 PR 只加 example) + - 可选:再加一个 mixed-signals fixture 若 PR 2 已覆盖则不必 +- **新 lint 码:** 无 +- **Dependencies:** PR 2 +- **Description:** 证明 `axis` 只能配 `supertensor`。零改 `supertensor/`。 + +### PR 4 — 笔记一致性 lint(符号表、claim 覆盖) + +- **Title:** `superpaper: consistency lint for claims and symbols` +- **Files/components:** + - `lint.py`:启用 `SP020 SP021 SP022 SP023 SP024` + - `tests/ledger-invalid/{unlabeled-core.yaml, missing-include.yaml, superderive-v1.yaml, retired-reuse.yaml, dangling-claim.yaml}` + - `references/{checklist,antipatterns}.md` 补漏 claim / 符号漂移 +- **禁止:** 回头改 PR 1–3 example 补 `\splabel`(它们出生就必须带) +- **Lint 码启用:** 全表 `SP001–SP024`(v1) +- **Dependencies:** PR 3(链上;技术上只依赖 PR 1 的 example 已有 label,但按链合并以免测试矩阵分叉) +- **Description:** consistency 的机械部分变成 build 失败。符号未使用仍只警告。`render_ledger.py` 若 PR 1 已有则本 PR 不改。 + +### PR 5 —(可选)superfig argument-map golden(可加性) + +- **Title:** `superfig: additive argument-map example using existing primitives` +- **Files/components:** + - **仅** `superfig/examples/argument-map.tex`(+ 其 `build/` 产物若仓库习惯提交) + - `superfig/references/grammar.md` 表格加一行 + - 可选:`superfig/SKILL.md`「When to use」加半句 + - `superfig/scripts/test.sh` 会自动捡起 `examples/*.tex`(现有通配符)——必须让这张图 lint/build 干净 +- **Dependencies:** 无(可与 superpaper PR 并行)。若要在笔记 example 里引用,则依赖 PR 2 +- **Description:** 四个 role(`claim`/`assumption`/`lemma`/`evidence`)+ `\sfnode`/`\sfarrow`。不改 `.sty`,不改 lint 规则,不加原语。4 色相预算内。这是本设计允许的唯一 superfig 触碰。 + +### PR 6 — phase 2:`superderive` 脚手架 + +- **Title:** `superderive: scaffold stepwise derivation figure toolkit` +- **Files/components:** + - 新建 `superderive/` 整树(见 Layer 2 目录) + - `assets/superderive.sty` 最小:`\sdsetrole`、`\sdstep`、`\sdreason`、`\sdmeaningbox`、cursor 行、palette + - `examples/rewrite-cancel.tex` + `tests/smoke.tex` + lint 负例 + - `scripts/{preflight.sh,lint.py,build.sh,test.sh}`(复制 superfig 骨架,不抽库) + - `superpaper/scripts/router.py` **不**改缺省 phase;**不**动 `SP022` +- **Dependencies:** 无硬依赖。建议 PR 1–4 已合并 +- **Description:** 证明「取消一项」能被看见。不往 `superfig.sty` 加宏。phase 翻转留给 PR 7。 + +### PR 7 — router 打开 `superderive`(唯一改缺省 phase 的提交) + +- **Title:** `superpaper: route rewrite-figure to superderive` +- **Files/components:** + - `router.py`:`phase` 缺省 2;仍可读 `SUPERPAPER_PHASE` + - `lint.py`:停用 `SP022` + - `examples/derive-delegate/` + `references/router.md` +- **Dependencies:** PR 6、PR 4 +- **Description:** 单独一记,回滚路由不必回滚宏包。`suggest()` 仍返回 class `derive`。 + +--- + +*本文是实施规格。第一张 PR 按 PR 1 的文件列表脚手架即可开工,不必再做一次产品选型。* diff --git a/README.md b/README.md new file mode 100644 index 0000000..069cc73 --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# SuperPaper + +母仓库:把一篇论文编成带 ledger 的中文讲义,并把图路由到独立的子仓库。 + +子仓库各自保有自己的 git 历史、lint 和不变量。母仓库只编排,不往任何一个 `.sty` 里塞笔记宏。 + +``` +superpaper/ this repo (orchestration) +├── DESIGN.md family spec +├── SKILL.md document-layer skill +├── superfig/ submodule — architecture / pipeline / flow +├── supertensor/ submodule — tensor faces / axes / shards +└── superderive/ later — stepwise rewrite figures +``` + +| 子仓库 | 画什么 | 远程 | +|---|---|---| +| [`superfig`](superfig/) | 节点、边、分组、机制框图 | `carrydela/SuperFig` | +| [`supertensor`](supertensor/) | 形状对齐的张量公式图 | `carrydela/SuperTensor` | +| `superderive` | 逐步代数改写图 | 尚未建 | + +## Clone + +```bash +git clone --recurse-submodules \ + ssh://git@ssh.gitea.mygoband.com:2222/carrydela/SuperPaper.git +# 已有工作副本: +git submodule update --init --recursive +``` + +Each child is also a standalone skill. Point an agent at `superfig/` or +`supertensor/` when you only need that figure grammar. Point at this +directory when the job is 读论文 / 脉络 / 推导 / 出图路由. + +## Layout on disk + +Under `/home/carry/myprj/tools/skills/` the old sibling paths are +symlinks into this repo: + +``` +skills/superpaper/ SuperPaper +skills/superfig -> superpaper/superfig +skills/supertensor -> superpaper/supertensor +``` + +## Status + +The family contract lives in [`DESIGN.md`](DESIGN.md). Figure children +are usable now. The notes scaffold (`scripts/`, ledger, template) is +the SuperPaper v1 PR chain in that document — not in this commit. diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..3015761 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,68 @@ +--- +name: superpaper +description: >- + Reconstruct a paper's argument thread and write structured Chinese + lecture notes with a claims/symbols/derivation ledger, then route + figures to superfig, supertensor, or (later) superderive. Use when + the user asks for 读论文, 论文笔记, 脉络梳理, 公式推导, 抽象公式图像化, + arXiv notes, paper notes, or $superpaper. Not for drawing a single + architecture figure (use superfig) or a tensor-shape figure (use + supertensor) or for turning a lecture video into notes + (use youtube-render-pdf / bilibili-render-pdf). +--- + +# superpaper + +论文侧的 `youtube-render-pdf`:**编排层**,不是 figure 包。输入一篇论文,输出 +`ledger.yaml` + 结构化中文笔记。图一律委派给子仓库,不要在笔记里 +`\usepackage{superfig}` / `supertensor`。 + +本目录是家族母仓库。子仓库在 `superfig/` 与 `supertensor/`(git submodule)。 +完整合同见 `DESIGN.md`。笔记脚手架(`scripts/`、模板、schema)按 DESIGN 的 PR 1 落地;在此之前按下面路由手工委派。 + +## When to use + +- 读论文、梳理脉络、展开公式推导、把抽象公式变成图。 +- 需要一张以上的图,或需要符号表 / claim 覆盖。 + +Do **not** use when the user only wants one architecture figure (`superfig`) +or one tensor-shape figure (`supertensor`), or when the source is a lecture +video. + +## Route figures (do not draw here) + +| 信号 | toolkit | 子仓库 | +|---|---|---| +| 架构 / 流水线 / 数据流 / 状态 / 依赖 / 谁吃谁 | `superfig` | `superfig/SKILL.md` | +| 轴、形状、转置、broadcast、gather、分片、收缩 | `supertensor` | `supertensor/SKILL.md` | +| 必须被看见的逐步改写 | v1:笔记 `align`;v2:`superderive` | — | +| 数值曲线 / 柱状 / 散点 | screenshot 或 matplotlib | 本家族不画 | +| 表 / 照片 / 装置 / UI | screenshot | — | + +混类信号拆成下一整数 id,禁止 `F1a`。默认偏向不出图。 + +## Workflow + +1. 读 `DESIGN.md` 的输入契约与 ledger schema。 +2. 先写 `ledger.yaml`(claims / symbols / derivations / figure plan),再写笔记。 +3. 公式三拍:中文动机 → `\[` / `align` → 扁平符号表。 +4. 每张计划图写一份自包含 `F*.request.md`,开一个 figure agent,**只**把对应子仓库的 `SKILL.md` 给它。 +5. 笔记用 PDF `\includegraphics` 嵌入子仓库产物。禁止 `\input` standalone 源。 +6. 改术语或改图:先改 ledger,再改那一处。 + +## Spawn recipe + +``` +$superpaper <源> 请 spawn 多 sub agents,隔离上下文: + - 1 个 outline agent:写 ledger.yaml + outline.md + 节边界 + - N 个 writer agents:各写 sections/sec-XX.tex,引用 ledger id + - 每个计划重绘图 1 个 figure agent:只读 F*.request.md,调用对应子仓库 skill + - 1 个 consistency agent:符号、术语、claim 覆盖、路由一致性 +``` + +必须拆 agent 当且仅当:正文 > 12 页,或顶层节 > 4,或重绘图 ≥ 2,或用户显式要求 spawn。 + +## Output + +`ledger.yaml`、`notes.tex` / `notes.pdf`、各图的 PNG 预览 + `.tex` + 向量产物。 +交付时说明哪些图走了哪个子仓库。 diff --git a/agents/openai.yaml b/agents/openai.yaml new file mode 100644 index 0000000..187e8be --- /dev/null +++ b/agents/openai.yaml @@ -0,0 +1,8 @@ +interface: + display_name: "Superpaper" + short_description: "把论文编成带 ledger 与路由出图的中文讲义" + default_prompt: >- + Use $superpaper to reconstruct this paper's argument thread, + expand the key derivations, and produce structured Chinese notes. + Build ledger.yaml first. Route figures to superfig / supertensor / align; + do not draw inside superpaper and do not \usepackage{superfig} in the notes. diff --git a/superfig b/superfig new file mode 160000 index 0000000..db5598f --- /dev/null +++ b/superfig @@ -0,0 +1 @@ +Subproject commit db5598fbf77d284de7ff92a072ca7506e2296407 diff --git a/supertensor b/supertensor new file mode 160000 index 0000000..7d62e02 --- /dev/null +++ b/supertensor @@ -0,0 +1 @@ +Subproject commit 7d62e0279a0c19f0af969c4947760fe3649ecec5