diff --git a/.agent/skills/science-video-pipeline/SKILL.md b/.agent/skills/science-video-pipeline/SKILL.md index 48aecc127..4fcf6f7da 100644 --- a/.agent/skills/science-video-pipeline/SKILL.md +++ b/.agent/skills/science-video-pipeline/SKILL.md @@ -1,35 +1,35 @@ --- name: science-video-pipeline -description: 把论文/综述做成动效图解科普视频的九阶段流水线(论文精读提取→策划→逐字稿 SSOT→双重校验→分镜→TTS 声音克隆→Remotion 场景实现→草渲抽帧 QA→终渲交付)。Use when producing or iterating a media/*-video/ episode: narration.md, storyboard.md, IndexTTS voice cloning, Remotion scenes, frame QA, or final render; or when scaffolding a new episode. +description: 把论文/综述做成动效图解科普视频的九阶段流水线(论文精读提取→策划→逐字稿 SSOT→双重校验→分镜→TTS 声音克隆→Remotion 场景实现→草渲抽帧 QA→终渲交付)。Use when producing or iterating an apps/negentropy-influence/episodes/*-video/ episode: narration.md, storyboard.md, IndexTTS voice cloning, Remotion scenes, frame QA, or final render; or when scaffolding a new episode. allowed-tools: Read, Write, Edit, Glob, Grep, Bash --- # 科普视频制作流水线(导航壳) -本 Skill 是路由层:内容 SSOT 在 `media/pipeline/skills/01–09.md`,工具 SSOT 在 -`media/pipeline/scripts/`,不在此复制任何正文(防第二事实源)。 +本 Skill 是路由层:内容 SSOT 在 `apps/negentropy-influence/pipeline/skills/01–09.md`,工具 SSOT 在 +`apps/negentropy-influence/pipeline/scripts/`,不在此复制任何正文(防第二事实源)。 ## 九阶段速查 | Stage | 做什么 | 规格链接 | 工具/命令(编排入口 `pipeline.py`) | 通过门 | |---|---|---|---|---| -| ① 信源精读取证 | **A 型论文**:并行子代理逐章 + 官方站点补充;**B 型文档/代码/课程站点**:固定提交取证 + 证据三级 | [01](../../../media/pipeline/skills/01-source-extraction.md) | A 型 `paper_extract.py`(map/text/captions/find/render);B 型 `source_ledger.py`(fetch/list/verify) | 全部断言可回溯;RISKY=0 | -| ② 策划 | 受众/结构/视觉契约(色彩语义) | [02](../../../media/pipeline/skills/02-planning.md) | — | planning.md 六节齐 | -| ③ 逐字稿 | narration.md ★单一事实源 | [03](../../../media/pipeline/skills/03-narration.md) | `pipeline.py build` | `build_narration.py` 通过 | -| ④⑤ 双重校验 + 分镜 | 真实性回溯 + 易懂性;beat 覆盖性 | [04](../../../media/pipeline/skills/04-verification.md) / [05](../../../media/pipeline/skills/05-storyboard.md) | `pipeline.py check`(+`--check-scenes`) | RISKY=0;覆盖率无缺句 | -| ⑥ TTS 配音 | 本人音色克隆(IndexTTS-2.5) | [07](../../../media/pipeline/skills/07-tts-voice.md) | `pipeline.py tts --plan` | refs 指纹门 + 试听 + ETA | -| ⑦ Remotion 场景 | 代码动画实现 | [06](../../../media/pipeline/skills/06-remotion-implementation.md) | `tsc --noEmit` | 七条渲染红线 | -| ⑧ 草渲 + 抽帧 QA | 半分辨率快速迭代 | [08](../../../media/pipeline/skills/08-render-qa.md) | `pipeline.py render` + `qa` | 自动体检零 FAIL | -| ⑨ 终渲 + 交付 | 1080p30 + srt/vtt | [09](../../../media/pipeline/skills/09-final-render.md) | `render --final` + `captions` | 实测时长在预算窗 | +| ① 信源精读取证 | **A 型论文**:并行子代理逐章 + 官方站点补充;**B 型文档/代码/课程站点**:固定提交取证 + 证据三级 | [01](../../../apps/negentropy-influence/pipeline/skills/01-source-extraction.md) | A 型 `paper_extract.py`(map/text/captions/find/render);B 型 `source_ledger.py`(fetch/list/verify) | 全部断言可回溯;RISKY=0 | +| ② 策划 | 受众/结构/视觉契约(色彩语义) | [02](../../../apps/negentropy-influence/pipeline/skills/02-planning.md) | — | planning.md 六节齐 | +| ③ 逐字稿 | narration.md ★单一事实源 | [03](../../../apps/negentropy-influence/pipeline/skills/03-narration.md) | `pipeline.py build` | `build_narration.py` 通过 | +| ④⑤ 双重校验 + 分镜 | 真实性回溯 + 易懂性;beat 覆盖性 | [04](../../../apps/negentropy-influence/pipeline/skills/04-verification.md) / [05](../../../apps/negentropy-influence/pipeline/skills/05-storyboard.md) | `pipeline.py check`(+`--check-scenes`) | RISKY=0;覆盖率无缺句 | +| ⑥ TTS 配音 | 本人音色克隆(IndexTTS-2.5) | [07](../../../apps/negentropy-influence/pipeline/skills/07-tts-voice.md) | `pipeline.py tts --plan` | refs 指纹门 + 试听 + ETA | +| ⑦ Remotion 场景 | 代码动画实现 | [06](../../../apps/negentropy-influence/pipeline/skills/06-remotion-implementation.md) | `tsc --noEmit` | 七条渲染红线 | +| ⑧ 草渲 + 抽帧 QA | 半分辨率快速迭代 | [08](../../../apps/negentropy-influence/pipeline/skills/08-render-qa.md) | `pipeline.py render` + `qa` | 自动体检零 FAIL | +| ⑨ 终渲 + 交付 | 1080p30 + srt/vtt | [09](../../../apps/negentropy-influence/pipeline/skills/09-final-render.md) | `render --final` + `captions` | 实测时长在预算窗 | ## 关键不变量 - 逐字稿只改 `narration.md`;`narration.json`/`manifest.json` 是派生物。 -- **口播永不出现他集标题与集数序号**——顺序只在视觉层与 [media/series.json](../../../media/series.json)(校验:`check_series.py`)。 +- **口播永不出现他集标题与集数序号**——顺序只在视觉层与 [series.json](../../../apps/negentropy-influence/series.json)(校验:`check_series.py`)。 多系列(顶层 `seriesList[]`)语义:反串线规则**跨系列全局**,顺序类规则**按系列内**判定。 - **证据分级**:B 型信源里「他人对闭源产品源码的分析」属三级证据,口播必须带归属句, 不得表述为产品既成事实;活数据(行数、总量、star 数)不进口播。 - 每集 `pipeline.toml` 是可执行参数的唯一来源;README 不复制命令行参数。 - 时序常数只在 `video/src/timing.json`(timing.ts 与 Python 共读)。 - 声音样本是生物特征:不入库(`voices/refs.toml` 只存指纹),试听后即删。 -- 新集脚手架与复用边界(Python 集中 SSOT / Remotion 复制不共享)见 [media/pipeline/README.md](../../../media/pipeline/README.md)。 +- 新集脚手架与复用边界(Python 集中 SSOT / Remotion 复制不共享)见 [pipeline/README.md](../../../apps/negentropy-influence/pipeline/README.md)。 diff --git a/.gitignore b/.gitignore index 2a9094884..9b5e62b8e 100644 --- a/.gitignore +++ b/.gitignore @@ -294,39 +294,21 @@ benchmarks/runs/ # 此条兜底 agent 路径漂移误在 worktree 写候选的极端场景,确保其永不进 commit/PR) patrol-candidate.md -# 科普视频工程(media/self-improving-agents-video)本地产物: +# 科普视频工程(apps/negentropy-influence/episodes/-video)本地产物: # tts.py 逐句音频 + manifest、Remotion 渲染产物均环境相关,不入 git。 # 注:工程内的 .gitignore 被上方根级裸 `.gitignore` 规则挡住无法提交,规则须维护在此处。 -media/self-improving-agents-video/video/public/audio/ -media/self-improving-agents-video/out/ -media/self-improving-agents-video/**/*.mp4 -media/self-improving-agents-video/**/*.mp3 -media/self-improving-agents-video/**/*.wav - -# 科普视频工程(media/experience-era-agents-video)本地产物:同上集规则。 -media/experience-era-agents-video/video/public/audio/ -media/experience-era-agents-video/out/ -media/experience-era-agents-video/**/*.mp4 -media/experience-era-agents-video/**/*.mp3 -media/experience-era-agents-video/**/*.wav - -# 声音克隆参考样本(media/pipeline/voices/):个人声音属生物特征信息,绝不入库。 -# 目录级忽略 + 白名单例外(README 与 refs.toml 指纹清单——后者只存哈希与生成参数, -# 不含音频字节),防漏网音频格式(ogg/opus/wma 等)。 -media/pipeline/voices/* -!media/pipeline/voices/README.md -!media/pipeline/voices/refs.toml - -# 科普视频工程(media/self-evolving-coding-agents-video)本地产物:同上集规则。 -media/self-evolving-coding-agents-video/video/public/audio/ -media/self-evolving-coding-agents-video/out/ -media/self-evolving-coding-agents-video/**/*.mp4 -media/self-evolving-coding-agents-video/**/*.mp3 -media/self-evolving-coding-agents-video/**/*.wav - -# 科普视频工程(media/claude-code-explained-video)本地产物:同上集规则。 -media/claude-code-explained-video/video/public/audio/ -media/claude-code-explained-video/out/ -media/claude-code-explained-video/**/*.mp4 -media/claude-code-explained-video/**/*.mp3 -media/claude-code-explained-video/**/*.wav +# 通配到集:`*` 只吃一级目录名(= 分集目录),故**新增分集无需再改本文件** +# —— 此前逐集枚举导致新集的音频产物在补齐 5 行前完全未被覆盖。 +# `out/` 已由上方通用规则(第 223 行 `out/`,非锚定)覆盖,此处不再逐集重复。 +apps/negentropy-influence/episodes/*/video/public/audio/ +apps/negentropy-influence/episodes/**/*.mp4 +apps/negentropy-influence/episodes/**/*.mp3 +apps/negentropy-influence/episodes/**/*.wav + +# 声音克隆参考样本(apps/negentropy-influence/pipeline/voices/):个人声音属生物 +# 特征信息,绝不入库。目录级忽略 + 白名单例外(README 与 refs.toml 指纹清单—— +# 后者只存哈希与生成参数,不含音频字节),防漏网音频格式(ogg/opus/wma 等)。 +# 注:必须写 `/*` 而非 `/` —— git 无法用 `!` 把被排除**目录**内的文件重新纳入。 +apps/negentropy-influence/pipeline/voices/* +!apps/negentropy-influence/pipeline/voices/README.md +!apps/negentropy-influence/pipeline/voices/refs.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 858dc0412..ddd2cf8ba 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -46,16 +46,16 @@ repos: files: ^apps/negentropy/ types_or: [python, pyi] - # ── Python: media/pipeline(科普视频公共管线) ───────────────────────── + # ── Python: negentropy-influence/pipeline(科普视频公共管线) ────────── # 与 negentropy 同一 ruff 修订版;此前仅覆盖 apps/negentropy/,管线脚本无 lint 门 - id: ruff - name: ruff lint (media-pipeline) + name: ruff lint (influence-pipeline) args: [--fix, --exit-non-zero-on-fix] - files: ^media/pipeline/ + files: ^apps/negentropy-influence/pipeline/ types_or: [python, pyi] - id: ruff-format - name: ruff format (media-pipeline) - files: ^media/pipeline/ + name: ruff format (influence-pipeline) + files: ^apps/negentropy-influence/pipeline/ types_or: [python, pyi] # ── Node.js: apps/negentropy-ui ────────────────────────────────────────── @@ -119,14 +119,18 @@ repos: files: ^(VERSION|scripts/sync_versions\.py|package\.json|apps/negentropy/(pyproject\.toml|uv\.lock)|apps/negentropy-ui/package\.json|apps/negentropy-wiki/package\.json|apps/negentropy-perceives/(pyproject\.toml|uv\.lock)|packages/agents-chat-core/package\.json)$ pass_filenames: false - # ── 科普视频系列一致性(media/series.json 执法) ───────────────────────── + # ── 科普视频系列一致性(series.json 执法) ─────────────────────────────── # 规则:口播反串线(自身标题排除)/多标题顺序/序号绑定/清单完整性/相对链接死链。 # 注意:挂在内容修复之后落地;顺序调整类变更须先改 series.json 再动散文。 + # ⚠️ files: 写错是**静默**失效(钩子直接跳过、不报错),entry 写错才会响。 + # 改动本条后须验证:暂存一处子项目内改动,确认钩子 Passed 而非 Skipped。 + # `.agent/skills/science-video-pipeline/` 亦须在列 —— 该路由壳有 13 条入树 + # 链接受规则 5 执法,只改它的提交必须能触发本钩子。 - repo: local hooks: - id: series-consistency-check - name: Series consistency (media/series.json) + name: Series consistency (series.json) language: system - entry: uv run --no-project media/pipeline/scripts/check_series.py - files: ^(media/|docs/\.agents/knowledge-map\.md|CHANGELOG\.md) + entry: uv run --no-project apps/negentropy-influence/pipeline/scripts/check_series.py + files: ^(apps/negentropy-influence/|\.agent/skills/science-video-pipeline/|docs/\.agents/knowledge-map\.md|CHANGELOG\.md) pass_filenames: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 96e026978..aae09549f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,20 +4,32 @@ ## [Unreleased] +### Changed + +- **`media/` 迁移为 `apps/negentropy-influence/`(分层布局)+ 公共层四项抽取**:子项目从仓库根迁入 `apps/` 约定位置,「机制」(`pipeline/`)与「内容」(`episodes/-video/`)边界显式化。迁移本身是 191 文件 R100 纯重命名(0 增 0 删),语义修复独立成提交。四项基建: + ① **路径锚点抽取**([paths.py](apps/negentropy-influence/pipeline/scripts/paths.py) + `.influence-root` 哨兵):替换三处「数目录层数」的 `parents[N]`——迁移已实证其脆弱(错位后 tts.ref 解析失败、check_series 门静默失效、生物特征小样写错位置,三种失败**都不报错**)。`tts.ref` 与 `series.json` 的 `path` 同步改为**子项目根相对**(缓存摘要只含字节 sha1 不含路径,零句缓存失效)。 + ② **产物 ignore 通配化**(根 `.gitignore` 28 行→16 行):迁移后实测 `voices/*.wav`、逐句 mp3、`.engine`、`*.wav` 全部会变为**可提交**(`check-added-large-files` 阈值 1024KB 拦不住 768KB 的声音样本);通配到分集级同时修掉既存漏洞——**新集在补齐那 5 行之前完全没有覆盖**,新集清单第 3 步随之删除。 + ③ **[stages.toml](apps/negentropy-influence/pipeline/stages.toml) 九阶段唯一声明**:杀掉「散文/子命令/mermaid/路由表」四处分裂脑;序号↔文件号错位(⑥↔07、⑦↔06)显式化 + `test_stages.py` 执法;9 篇 H1 统一为 `# Stage <序号> <名字>`。 + ④ **`pipeline.toml` schema 与默认值层**([config.py](apps/negentropy-influence/pipeline/scripts/config.py)):每集 11 键收缩到 6 键(机制常数进代码、`episode.title` 删除、`engine` 留作策略声明、`server` 走环境变量);**等价变换已证明**(解析填默认后全部 schema 键 4 集逐一相等);修掉一个**静默跳过的门**(缺 toml 时时长预算退化为 [0,999]——现在点名 WARN);`episode.slug` 升级为跨源身份校验;`doctor` 打印带来源标注的配置表。 + ⑤ **骨架模板三件套**([templates/video-skeleton/](apps/negentropy-influence/pipeline/templates/video-skeleton/skeleton.toml)):复制源头从「任一既有集」收敛为**命名模板**(scaffold.py 实例化 + verify_skeleton.py 按系列分组 md5 漂移门),把「改一处须同步」从纸面义务变成秒级判据——此前 391 行冻结基建有 4 个同权真理声明者且义务从未执行过(实测 Main.tsx/cards.tsx 均已漂移,3 处既存漂移登记在案)。README §四「复制适配不做共享包」的决策**不被推翻、而是被补完**(运行期仍是物理副本、仍 `--ignore-workspace` 独立可渲染)。 + ⑥ **`$I`/`$R`/`$P`/`$V` 路径变量约定 + skills 死链执法**:命令变量化,**位置字面量全仓只写在 `I=` 一行**、其余变量派生自它(定义只在 pipeline/README.md 一处,`test_docs_paths.py` 守围栏块/行内/脚本文件头三种形态);散文链接保持相对路径(规则 5 执法);`.agent/skills/science-video-pipeline` 路由壳的 13 条链接**此前完全无死链校验**,现入 `check_series` 受检面;4 集 README 的三种互不一致调用风格统一为 `./node_modules/.bin/` 直调。 + 评审加固(同轮):**锚点混用成门**——`$R + pipeline/voices/…` 这类「在任何 CWD 下都不成立」的命令一度散在 7 个文件里(不是 Markdown 链接,规则 5 看不到),样本路径统一走 `$V` 并加正控;**`[[drift]]` 豁免按指纹钉住**(不钉指纹 = 该文件此后永久免检,而 Main.tsx 每集都要动),偏离内容一变即报 `DRIFT-CHANGED`,且 I2 与 I1 共用逃逸口(否则单集系列登记后 `--strict` 永远红、登记者无路可走);**模板 Main.tsx 的 regioned 区清空**(此前带着某一集的 7 条 `./scenes/*` import,新集开箱即 7 个 module-not-found;归一化恰好剥掉这两段,故清空不动任何既有集指纹);**scaffold 占位符自身合规**(`ref_sha1` 11 位曾让新集连 Stage ③ `build` 都跑不起来——`load_config` 对每个子命令都以 `scope=None` 全节校验);**`pipeline.py qa --video` 改为工程相对**(本入口以 `cwd=<工程>` 启动 qa_frames,`$P/out/…` 必落空——与直调 `qa_frames.py` 的写法**不可互抄**,两处均已成门);**漂移正控迁到 tmp_path 镜像子项目**(此前直接改写受版本控制的已发布分集文件,Ctrl-C 即留脏、并行跑测试互踩;沿用 `test_check_series.py` 的 `.influence-root` 假子项目做法)。 + 测试全绿(每条新守卫均做正控:注入漂移必红、还原转绿);4 集内容门/主题对比度与迁移前基线逐项一致;`pnpm ls -r` 仍恰 5 项目、根 lockfile 零变更、4 集 `tsc --noEmit` 全过、全仓 `media/` 引用归零(`--text --hidden --no-ignore` 三旗扫描)。⚠️ 各兄弟 worktree 的 gitignored TTS 产物(canberra 187 mp3 / philadelphia-v2 170 mp3)**留在旧路径**,须按 README runbook 在各 worktree 内搬迁,全程禁 `git clean -xdf`。 + ### Added -- **新系列「Claude Code 通俗全解」首集 + 管线多系列化与 B 型信源取证基建**:新增 [《拆开 Claude Code:让 AI 动手的四层机制》](media/claude-code-explained-video/README.md)(陶土橙 `#D97757` 内核 / 石青 `#64C4C0` 外挂机制 / 警示红 `#EF6461` 拒绝闸门,三色对 `#0E1116` 实测 6.06 / 9.18 / 6.00 : 1;170 句 4048 字 7 幕 39 镜;配音 `sunny-steady` + `me-bright.wav`),选题为开源课程 [Learn Claude Code](https://learn.shareai.run/zh/s01/) 的工具与执行四章(s01 Agent Loop / s02 Tool Use / s03 Permission / s04 Hooks)。为此做三件基建: - ① **`media/series.json` 多系列化**:顶层由单 `series` 对象改为 `seriesList[]`,`check_series.py` 相应分层——**反串线规则(1)跨系列全局生效**(两系列口播互不引用),**顺序类规则(2/3/4)按系列内判定**(`episode` 的 `1..N` 连续性只在系列内成立,slug 仍全局唯一);`test_check_series.py` 增 6 例多系列语义用例(各系列各有第 1 集不误报、跨系列标题不比顺序、跨系列反串线仍 FAIL、跨系列 slug 重复 FAIL)。 - ② **Stage ① 泛化为两类信源**:`skills/01-paper-extraction.md` → [`01-source-extraction.md`](media/pipeline/skills/01-source-extraction.md),A 型论文正文原样保留,新增 **B 型(文档/代码/课程站点)** 大节——双轨取证(仓库 @ **固定 commit** + 站点正文)、**证据三级**(一级仓库实测可断言 / 二级站点正文 / 三级「他人对闭源产品源码的分析」**必须带归属句**,不得说成产品既成事实)、数字纪律(口径须可复算、复算不出就只说趋势、活数据不进口播)、二次信源分歧清单必备。配套新工具 [`source_ledger.py`](media/pipeline/scripts/source_ledger.py)(fetch/list/verify,仿 `refs.py` 的清单+指纹设计;`repo` 类校验 `--pinned-ref` 出现在 URL 中且 raw 指纹漂移即 FAIL,`site` 类只比**剥标签归一后的正文**指纹、漂移报 WARN——构建产物哈希天天变,比 raw 毫无信噪比)+ `test_source_ledger.py` 11 例;`media/pipeline/tests/` 由 46 → **130 项**全绿(含合并 #1109 带入的 pron_marks / prospect_ref / tts_bench / digest 参数化用例)。 +- **新系列「Claude Code 通俗全解」首集 + 管线多系列化与 B 型信源取证基建**:新增 [《拆开 Claude Code:让 AI 动手的四层机制》](apps/negentropy-influence/episodes/claude-code-explained-video/README.md)(陶土橙 `#D97757` 内核 / 石青 `#64C4C0` 外挂机制 / 警示红 `#EF6461` 拒绝闸门,三色对 `#0E1116` 实测 6.06 / 9.18 / 6.00 : 1;170 句 4048 字 7 幕 39 镜;配音 `sunny-steady` + `me-bright.wav`),选题为开源课程 [Learn Claude Code](https://learn.shareai.run/zh/s01/) 的工具与执行四章(s01 Agent Loop / s02 Tool Use / s03 Permission / s04 Hooks)。为此做三件基建: + ① **`apps/negentropy-influence/series.json` 多系列化**:顶层由单 `series` 对象改为 `seriesList[]`,`check_series.py` 相应分层——**反串线规则(1)跨系列全局生效**(两系列口播互不引用),**顺序类规则(2/3/4)按系列内判定**(`episode` 的 `1..N` 连续性只在系列内成立,slug 仍全局唯一);`test_check_series.py` 增 6 例多系列语义用例(各系列各有第 1 集不误报、跨系列标题不比顺序、跨系列反串线仍 FAIL、跨系列 slug 重复 FAIL)。 + ② **Stage ① 泛化为两类信源**:`skills/01-paper-extraction.md` → [`01-source-extraction.md`](apps/negentropy-influence/pipeline/skills/01-source-extraction.md),A 型论文正文原样保留,新增 **B 型(文档/代码/课程站点)** 大节——双轨取证(仓库 @ **固定 commit** + 站点正文)、**证据三级**(一级仓库实测可断言 / 二级站点正文 / 三级「他人对闭源产品源码的分析」**必须带归属句**,不得说成产品既成事实)、数字纪律(口径须可复算、复算不出就只说趋势、活数据不进口播)、二次信源分歧清单必备。配套新工具 [`source_ledger.py`](apps/negentropy-influence/pipeline/scripts/source_ledger.py)(fetch/list/verify,仿 `refs.py` 的清单+指纹设计;`repo` 类校验 `--pinned-ref` 出现在 URL 中且 raw 指纹漂移即 FAIL,`site` 类只比**剥标签归一后的正文**指纹、漂移报 WARN——构建产物哈希天天变,比 raw 毫无信噪比)+ `test_source_ledger.py` 11 例;`apps/negentropy-influence/pipeline/tests/` 由 46 → **130 项**全绿(含合并 #1109 带入的 pron_marks / prospect_ref / tts_bench / digest 参数化用例)。 ③ **两条实测口径沉淀**:`skills/02` 写明 **`chars_per_min = 280` 不是纯语速而是含停顿的等效口径**(EP1 实测纯语速 301 字/分 + 停顿开销 68 s,两者抵消使「字数 ÷ 280」对全片时长误差仅 1%),并给出推论「**字数是硬约束,句数不是**」(本集实测:263 句合并到 229 句,字数只从 5054 掉到 4909,时长几乎没动——压时长必须真删内容);`skills/06` 新增**可复用视觉母题库**(终端打字 / 恒定视觉锚 / 字典分发表 / 闸门路由 / 插槽注册板 / 反枚举并列项)并显式化一条此前隐含的边界:**A 档冻结清单的同步义务限于同系列内**,新系列首集建立自己的基线(否则「复制不共享」的隔离初衷会被跨系列同步义务反向击穿)。 内容侧的两处校准值得单列:课程站点标注的章节行数(102/135/180/232)在固定提交上**用任何口径都复算不出**(s04 声称 232 而实测非空仅 213),判定为早期提交遗留值 → 口播只说趋势、画面给实测值 + 口径 + 取数日期;课程反复说的「循环里只改了一行」经逐章 diff 实测**只在 s02 成立**(s03 是插入 5 行门、s04 另长出 Stop 钩子续跑分支),故口播改用更准也更有力的口径——「**骨架四章一字未改,变的只有『执行』那一步怎么写**」(实测支撑:程序总行 141 → 255 增 81%,而 `agent_loop` 恒在 20–28 行)。另实测确认 pnpm ≥ 11 的 `ERR_PNPM_IGNORED_BUILDS: esbuild`(ISSUE-076)**对本工程无害**——平台二进制是 optionalDependency、不依赖 postinstall,旧写法下 `remotion bundle` 端到端通过,故刻意不改 A 档冻结文件去消音。 -- **科普视频公共管线基建升级**:`pipeline.py` 单入口编排(status/doctor/build/check/tts/captions/render/qa/all/clean-samples,阶段契约与派生式新鲜度——零状态文件防第二事实源)+ 每集 `pipeline.toml` 声明式配置(可执行参数不再散落 README,治 ISSUE-161 类漂移)+ `timing.json` 时序常数 SSOT(timing.ts 同步 import、Python 侧 timeline.py 共读,双语言镜像漂移结构性消灭)+ 七件新工具:`check_script`(④⑤门:分镜覆盖性/时长预算双口径/淡入不变式/--check-scenes 分镜↔代码互比——当场抓出两集既存分镜漂移)、`check_series`(系列顺序五规则执法 [media/series.json](media/series.json),自身标题排除使纯 grep 不可能做到的反串线 lint 成为可能)、`captions`(srt/vtt,cue 终点不含停顿)、`qa_frames --check/--check-theme`(黑帧/字幕带侵入[连通亮段法]/冻帧/字幕缺失 + WCAG 对比度)、`paper_extract`(Stage ① 取证五子命令)、`refs.py` + `voices/refs.toml`(参考样本指纹清单,只存哈希不存音频)、`tts.py --expect-ref-sha1` 指纹硬校验与 `.engine` 音色签名护栏 + `--allow-voice-switch` 显式放行(ISSUE-163 的拦截层);`media/pipeline/tests/` 45 项(digest 黄金哈希守「缓存零失效」)全绿 2s;pre-commit ruff 扩至 `^media/pipeline/`;技能规格补齐 skills/07–09 并挂载路由型真 Skill [.agent/skills/science-video-pipeline](.agent/skills/science-video-pipeline/SKILL.md)(零正文复制)。 -- **系列发布顺序 SSOT 与 Remotion 最佳实践三集落地**:新增 `media/series.json`/`series.md`(三集顺序 + 「序号不进口播」系列纪律——发布顺序变更的 TTS 代价恒为零);`@remotion/media` `