refactor(influence): media/ 迁移为 apps/negentropy-influence/(分层布局)+ 公共层四项抽取 - #1111
Open
ThreeFish-AI wants to merge 6 commits into
Open
refactor(influence): media/ 迁移为 apps/negentropy-influence/(分层布局)+ 公共层四项抽取#1111ThreeFish-AI wants to merge 6 commits into
ThreeFish-AI wants to merge 6 commits into
Conversation
191 个文件全部 R100 纯重命名(0 增 0 删、无任何内容改动),并采用分层布局
把「机制」与「内容」的边界显式化:
- media/pipeline/ → apps/negentropy-influence/pipeline/
- media/series.{json,md} → apps/negentropy-influence/series.{json,md}
- media/<slug>-video/ ×4 → apps/negentropy-influence/episodes/<slug>-video/
分层只在成片侧加深一层,pipeline/ 相对子项目根的深度不变,因此 pipeline 内
全部 parents[1] 锚点(prepare_ref / refs / tts / conftest 及 13 个测试文件)
零改动;代价仅为 12 个薄包装的 parents[2]→[3] 与 series.json 的 4 个 path。
⚠️ 纯重命名,不可单独落地;语义修复见后继提交。本提交之后树是坏的:
3 处仓库根锚点(pipeline.py / check_series.py / tts_sample.py)错位一级、
pre-commit 两处 files: 正则静默失配、28 行 .gitignore 规则失配(逐句音频与
声音克隆样本会变为可提交)、16 条相对链接失效。
🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
承接前一提交的纯重命名,修完它造成的全部断裂,并把三处「数目录层数」的
脆弱锚点换成标记法。
## 路径锚点(治根)
新增 `pipeline/scripts/paths.py` + `.influence-root` 哨兵:向上搜索标记定位
子项目根,`REPO` 由「子项目位于 apps/<name>」派生。此前 `REPO` 一个名字混用
了「仓库根」与「子项目根」两个正交概念,迁移后三处 `parents[N]` 同时指向
`apps/`,且三种失败形态各不相同、**都不报错**:
- `pipeline.py` → tts.ref 解析失败,doctor 的告警与「样本本就不入库」无法区分
- `check_series.py` → series.json 找不到即 exit,pre-commit 门整体静默失效
- `tts_sample.py` → 生物特征小样写进 `apps/.temp/`,而 `.temp/` 非锚定,git 无感
不用 `.git` 作标记:本仓是 worktree,`.git` 是**文件**不是目录;且测试的 tmp
假仓库没有 `.git`,而 `~/tools/index-tts` 恰好是真 `.git`(tts_server.py 拷出去
跑时会误锚)。`tts.py` 刻意不依赖 paths.py,以保住它被拷出仓库运行的路径。
12 个薄包装 `parents[2]`→`[3]`(episodes/ 层),三名各自仍逐字节一致。
## 受检范围按根拆分(顺带补一个既存缺口)
`check_series.py` 的 COVERED_GLOBS 拆为 INFLUENCE / REPO 两组,子项目侧用相对
glob —— 路径字面量从脚本中**彻底消失**,「误把前缀写宽成 `apps/**`」结构性
不可能发生(实测宽化会炸出 12 条其他子项目的既存死链假 FAIL)。
新增 `.agent/skills/science-video-pipeline/**` 覆盖:该路由壳有 13 条入树链接,
此前**完全没有死链校验**,而它们正是整目录迁移会一次性打断的东西。刻意不收
`.agent/skills/**` 全量——会连带执法别的技能的既存债(pdf-reader 有示意占位链接)。
## 产物 ignore 通配化(治一个静默泄漏)
根 `.gitignore` 28 行逐集枚举 → 16 行通配到分集级。实测迁移后 voices/*.wav、
video/public/audio/*.mp3、.engine、*.wav 全部会变为**可提交**(仅 out/ 靠通用
规则幸存),而 check-added-large-files 阈值 1024KB 拦不住 768KB 的声音样本。
通配同时修掉一个既存漏洞:**新集在补齐那 5 行之前完全没有覆盖**——故
pipeline/README.md 新集清单第 3 步随之删除。
## 数据契约
- 4 个 `pipeline.toml` 的 `tts.ref` 改为**子项目根相对**。缓存安全已证明:
`digest_indextts` 的摘要含 `ref_sha1`(文件字节哈希)而**无任何路径成分**,
改拼法不会失效任何一句缓存,test_digest 黄金哈希不受影响。
- `series.json` 4 个 `path` → `episodes/<slug>-video`;规则 2/3 取 `split("/")[-1]`,
两处判定逻辑零改动。
## 其余
- 6 个仓库级文件的 69 处引用(.gitignore / .pre-commit-config.yaml / SKILL.md
含 frontmatter 发现 glob / knowledge-map / CHANGELOG / issue.md)
- 树内 151 处路径:命令走 `$R`/`$P` 变量(位置无关),散文走子项目相对链接
- 5 条爬出子项目的相对链接补层级;分集侧需 +2(apps 与 episodes 各一级),
子项目内部只需 +1 —— 这个不对称由 check_series 规则 5 当场抓出
- 新增 `pyproject.toml`:**仅** `[tool.pytest.ini_options]`。刻意不含 `[project]`
(否则 uv 会试图构建本目录)与 `[tool.ruff]`(实测 line-length=120 会重排
24/31 文件、埋掉语义 diff);刻意不放 `package.json`(`apps/*` 是 depth-1
glob,会把子项目吸进根 workspace,击穿各集 --ignore-workspace 隔离)
- 新增 README.md(apps/* 7/7 约定)
## 验证
130 测试全绿(与迁移前基线一致);check_series `2 系列/4 集 · 受检 118 · FAIL 0`
(118 = 基线 117 + 新纳管的 SKILL.md,该数字本身即 REPO 解析正确的证明);
4 集 check_script/--check-theme 与基线逐项一致(含 se/si 两处既存 WARN);
4 集 doctor 均解析到 apps/negentropy-influence/pipeline/voices/ 且零行含 /media/;
`.gitignore` 双向证明通过(零受控文件被吞、含未来分集的产物全覆盖);
pnpm 仍恰好 5 个项目、根 lockfile 零变更;全仓 media/ 引用归零。
🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
两项抽取,各自带上「让声明成为承重件」的测试——否则新增的声明只是**第四个** 事实源,严格劣于现状。 ## stages.toml:杀掉九阶段四处分裂脑 此前「有哪九个阶段」同时声明在四处:skills/01–09 的散文标题、pipeline.py 的 子命令、README §一 的 mermaid、`.agent` 路由壳的速查表。四份可各自漂移,且 **已经漂移**——文件 06 是第 ⑦ 阶段、文件 07 是第 ⑥ 阶段,此前只能靠读者自己撞见。 - 新增 `pipeline/stages.toml`:id / ordinal / name / skill 指针 / kind / commands / gate。 `kind` 是唯一真正新增的信息,它解释了「9 阶段 vs 10 子命令不是 1:1」—— authored(产出物由人/代理撰写)本就不该有子命令。注意 ⑦ 虽在生产层但为 authored:每集 3000–8000 行场景代码是创作而非生成。 - **不重命名文件**对齐序号:入链 ≥5 处且都受规则 5 死链门约束,为纯美学付这个价 不划算。改为统一 9 篇 H1 为 `# Stage <序号> <名字>(skill 规格 · <NN>)`, 于是错位从「要自己撞见的陷阱」变成「第一行就说、改错就红」。 - 新增 `tests/test_stages.py` 8 例:skill 指针存活 / commands 是真实注册的子命令 / ordinal 恰为 ①..⑨ / kind 取值与 tooled 必有命令 / 9 篇 H1 逐字相符 / 错位本身 / 路由壳覆盖全部九篇 / 路由壳自称的两条 SSOT 路径真实存在。 路由表**校验而非生成**——生成物会被手改,那是更隐蔽的第二事实源。 - 新增 `pipeline.py stages` 子命令打印全表。 **刻意不做**:不加 DAG/prerequisites 与 inputs/outputs(零消费者的维护税); 尤其 `cmd_status` 绝不消费 stages.toml——它一旦开始遍历声明里的产物清单, 就等于把 pipeline.py 文件头明令禁止的阶段状态机悄悄建起来了。 ## $R/$P 路径变量约定 + 执法 - 定义**只在** `pipeline/README.md` 一处;skills 与脚本 docstring 引用不重复定义。 - 纪律分两类且方向相反:**命令用变量**(可执行文本,变量化后位置无关); **散文链接保持真实相对路径**(AGENTS.md 强制可跳转,且规则 5 正在执法它们, 变量化会一次性造出十几条死链并让规则 5 覆盖面凭空缩小)。 - 新增 `tests/test_docs_paths.py` 4 例:命令内零硬编码路径(覆盖围栏块**与行内 代码跨**两种形态——skills/07 的命令写在行内,只查围栏会在该文件上空转)、 围栏配平(本仓有过悬空围栏把正文困进代码块的事故)、变量定义唯一。 ## 顺带的正交修正 `stages` 与 `clean-samples` 不再走 `load_config`:二者与具体工程无关,此前 「某集 toml 写坏」会连带让「清理生物特征小样」都无法执行,属荒谬耦合。 ## 验证 142 测试全绿(130 基线 + 8 stages + 4 docs_paths);两条新守卫均做过**正控** (注入硬编码后必红、还原后转绿,围栏与行内两条路径各验一次),避免出现 「判据看起来在守、其实空转」;check_series `受检 119 · FAIL 0 · WARN 0`; ruff check/format 全净(仍为默认档,未引入 [tool.ruff])。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
## 此前的问题
schema 是「pipeline.py 与 check_script.py 里 `.get()` 调用的并集」:无处可查、
无法校验、键名 typo 静默生效。两方对「缺文件」处置还相反(一个硬退、一个返回
`{}`)——而 `{}` 让 `target_minutes` 时长预算门**静默退化为 [0, 999]**。
一个「你以为开着其实关着的门」比 fatal 和 soft 都糟,这是本次改动的首要动机。
## 新增 pipeline/scripts/config.py
纯声明式 `SCHEMA`(11 键:类型 / 默认值 / 必填条件 / 说明),**不引 pydantic**:
所有脚本走 `uv run --no-project`、依赖靠调用点 `--with` 注入,而三个薄包装用
`sys.executable` 再 exec 继承调用方环境;新增一个运行期依赖要同步 pipeline.py
所有 `uv_no_project` 调用点 + 3 个薄包装契约 + 4 份 README,为 20 行 schema
付这个代价违反最小干预。
**默认值进代码、toml 只写偏离**,判据是一条正交线——删机制常数、留策略声明:
- 删 `chars_per_min` / `lang` / `draft_scale` / `draft_jpeg_quality`(四集零差异,
没有「本集为何选它」可讲)与 `episode.title`(series.json 才是标题 SSOT,
这份副本正是 AGENTS.md 禁止的「数据副本而非轻量指针」)
- 留 `engine`(有可见替代项 edge,且受 `.engine` 音色签名护栏约束——它是一条
决策记录,不是默认值)
- `server` 只给默认值 + `INDEXTTS_SERVER` 环境变量覆盖,永不写进受版本控制的
toml(沿用 skills/09 对并发度已立的「机器属性不进共享配置」原则)
每集 toml 由 11 键收缩到 6 键。**等价变换已证明**:解析并填默认后,全部 11 个
schema 已知键(= 任何代码会读的键)在 4 集上逐一相等;唯一差异是 `episode.title`
——它不在 SCHEMA 中,即无人读取,故删除不可能改变行为。
`episode.slug` 从死数据升级为**跨源身份校验**(须等于目录名)。它防的不是运行期
bug(没人读 slug),而是「`cp -r` 出来的陈旧 toml 看起来很权威」这个脚手架期
危害——而现行脚手架恰恰就是 `cp -r`。
## 边界管理(一处设计返工)
初版让 `check_script.py` 做全量校验,结果它开始因「还没挑配音样本」而 FAIL,
当场弄红三个既有内容门用例。那是把 TTS 的前置条件强加给 ④⑤ 阶段。改为
`config.load(..., scope=...)`:**每个消费者只校验自己消费的东西**——编排器全量,
内容门只管 `narration`。未知键 WARN 不受 scope 限制(typo 检测对谁都有用,
且只是 WARN)。该边界已由 `test_scope_limits_required_key_enforcement` 钉住。
## 退出语义
`status`/`doctor` 只报不退——诊断工具因为被诊断对象有病而拒绝运行是荒谬的;
其余子命令 FAIL 即退。`stages`/`clean-samples` 干脆不读 toml。
未知键 WARN + 最近邻建议(cutoff 实测定在 0.8:0.7 会把同节的另一个合法键
误判成 typo,一个乱指的建议比没有建议更容易把人带偏)。
## 发现性补偿
`doctor` 增打印带来源标注(`pipeline.toml` / `default` / `env:*`)的生效配置表
——`git config --list --show-origin` 的同类做法。默认值集中后单看 toml 不再
自证全貌,这张表是对该损失的偿付,而不是把默认值抄回每个 toml。
README 同步补齐字段表。
## 验证
156 测试全绿(+14 例 test_config,含等价变换证明、scope 边界、条件必填、
取值域、typo 提示、环境变量覆盖);「缺 toml → 门点名跳过」与「缺 toml →
编排器大声失败」两条路径各做过实测正控;4 集 check_script/--check-scenes
与迁移前基线逐项一致(含 se/si 两处既存 WARN);check_series FAIL 0;
ruff check/format 全净。顺带清掉带旧路径的 __pycache__(pytest 重写断言会把
源路径烘进字节码,陈旧缓存会让报错指向已不存在的 media/ 路径)。
🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
## 解决什么 README 原话是「以**任一**既有集工程为模板复制 video/ 骨架」。「任一」就是那个 SSOT 违规:391 行冻结基建因此有 4 个同权真理声明者,而「改任何一处须同步并验 md5 唯一」这条纸面义务**从未被执行过一次**。证据:Main.tsx 的注释/换行漂移让 两个旧集落后于两个新集,cards.tsx 裂成 3-vs-1——都在无人察觉中发生。 ## 三件套 - **pipeline/templates/video-skeleton/**:命名的复制源头。以当前多数哈希为 基线(实测 11 个 A 档文件四集全同、cards.tsx 为 3-vs-1),14 个 frozen 文件 逐字节复制,另有 4 个 `.tmpl`(package.json / theme.ts / pipeline.toml / README)与场景骨架样例(scenes-EXAMPLE.tsx.txt,刻意非 .tsx 后缀)。 - **scripts/scaffold.py**:从模板实例化新集,替代 cp -r。刻意不做的三件事: 不生成 scenes/(脚手架只拿走机械复制,保留创作性撰写——抄骨架的过程本身 有价值);不改根 .gitignore(已通配到分集级,且会修改仓库根文件的脚手架是 爆炸半径的意外扩张);不写 series.json(发布顺序是内容决策)。 - **scripts/verify_skeleton.py**:漂移门。档位 frozen / overridable / regioned / structured / seeded 全在 skeleton.toml(机器可读 SSOT,skills/06 的散文清单 同提交替换为链接——否则模板就成了第 5 份副本)。**本档只报告不阻塞**, --strict 才失败;转阻塞属后续独立决策。 ## 两个实测出来的设计修正 1. **判据必须有方向**:初版报「与某人不一致」会把符合模板的多数集反过来 报成偏离方。改为参照系制(优先模板指纹,其次系列内多数)。 2. **单集系列盲区**:初版只对 baselineOf 系列执法模板时新性,被自己的正控 (往 claude-code-explained 的 types.ts 注入漂移)当场击穿——它是单集系列, 系列内比对是空条件,模板比对又不覆盖它。改为:当前只有一份模板,故对 **全部系列**执法;将来真出现跨系列基线分叉,cp -r 模板 + 改一行 baselineOf 即可回退窄语义(机制与策略分离)。 逃逸表 [[drift]] 带强制 reason 字段(无理由的豁免下一个人无法判断能否撤销), 首批登记 3 处**门上线前既存**的漂移:self-improving 的 cards.tsx(孤立的 ChapterCard)与两个滞后 Main.tsx 的纯排版差异——刻意只登记不收敛,收敛要动 已发布集,属独立决策。另加孤儿工程检查:scaffold 让新建变便宜之后,忘了登记 series.json 的目录对两个门双向不可见,须点名。 ## 顺带 12 个薄包装统一到 ruff 默认档格式(此前模板侧被 format 过而集内没有,四集 自身仍各名单一哈希,且与模板逐字节一致);check_series 的内容门 glob 排除 templates/(机制目录非内容,扫进去只稀释信号)。 ## 验证 164 测试全绿(+8 例 test_skeleton,含**正控**:注入漂移必须让 --strict 失败、 scaffold 产物 14 个 frozen 文件与模板逐字节相等、占位符全渲染、孤儿被点名); verify_skeleton --strict 通过且受检漂移 0;check_series 受检 119 · FAIL 0; ruff 全净。模板 .tsx 无 tsc 覆盖不是漏洞而是门保证的性质(模板与真集字节相同 ⟹ 真集的 tsc 传递性验证模板),该耦合已写入 skeleton.toml 与测试文档。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
- experience-era / self-improving 两份 README 的 `pnpm run render[:draft]` 统一为 `./node_modules/.bin/remotion` 直调——skills/06 明文规定「工具一律 .bin 直调,防 pnpm run 污染根 workspace node_modules」,此前 4 集 README 存在三种互不一致的调用风格,其中两种直接违反该规则。 - knowledge-map:子项目条目更新为迁移后形态(分层布局、哨兵锚点、stages.toml、 config schema、骨架三件套、164 项测试)。 - CHANGELOG 补 Unreleased/Changed 完整条目,含兄弟 worktree TTS 产物搬迁 runbook 与「全程禁 git clean -xdf」警示。 验证:check_series 受检 119 · FAIL 0;164 项测试全绿;ruff 全净; pre-commit --all-files 全 Passed(无 Skipped)。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概要
将科普视频子项目从仓库根
media/迁入apps/negentropy-influence/,采用分层布局把「机制」(pipeline/)与「内容」(episodes/<slug>-video/)的边界显式化;并完成公共层四项抽取:stages.toml(九阶段唯一声明)、pipeline.toml schema+默认值层、骨架模板三件套(templates + scaffold + 漂移门)、$R/$P 路径变量约定。提交序列(6 个)
a79d0128git mv:191 文件全部 R100(0 增 0 删、无任何内容改动),git show --stat五秒可核821b682d19222bb895194f889c06bfcbbbe83d08迁移修掉的真实缺陷(均为实测发现)
pipeline.py/check_series.py/tts_sample.py的parents[N])——迁移后静默指向apps/,且三种失败形态各不相同、都不报错。改为.influence-root哨兵向上搜索(不用.git:本仓 worktree 的.git是文件不是目录;tmp 测试仓库没有.git;~/tools/index-tts恰好是真.git会误锚)。voices/*.wav(768 KB 生物特征)、逐句 mp3、.engine全部变为可提交,而check-added-large-files(1024 KB)拦不住;out/靠通用规则幸存反而藏住了症状。通配化(28 行→16 行)同时修掉既存漏洞:新集在补齐那 5 行之前完全没有覆盖。.agent/skills/science-video-pipeline的 13 条链接此前完全没有死链校验——正是整目录迁移会一次性打断的东西。现入check_series受检面(刻意只收该技能,不收.agent/skills/**全量以免执法别的技能的既存债)。四项抽取(每项都配了「让声明成为承重件」的执法测试)
cmd_status刻意不消费它——pipeline.py 明令无阶段状态机。episode.slug升级为跨源身份校验;doctor打印带来源标注(pipeline.toml/default/env:*)的配置表。--ignore-workspace独立可渲染。同款模式:go mod vendor+go mod verify。验证(全绿,均带判据)
check_series:2 系列/4 集 · 受检 119 · FAIL 0 · WARN 0(119 = 基线 117 + 新纳管的 SKILL.md + app README;该数字本身即 REPO 锚点正确的证明)check_script --check-scenes与迁移前基线逐项一致(含 se/si 两处迁移前就存在的 WARN)verify_skeleton --strict通过(受检漂移 0,3 处登记在案)pnpm ls -r仍恰 5 项目;根 lockfile 零变更;4 集pnpm install --ignore-workspace+tsc --noEmit全过;remotion bundle 在新路径端到端通过pre-commit run --all-files全 Passed 无 Skipped;ruff 默认档全净(刻意未加[tool.ruff]——实测 line-length=120 会重排 24/31 文件埋掉语义 diff)media/引用归零(--text --hidden --no-ignore三旗扫描;仅剩 6 处迁移叙事本身与守卫禁止清单)git mv只移动受版本控制文件——三个兄弟 worktree 的 gitignored TTS 产物留在旧路径:canberra.engine+ wav + out/ + node_modulesphiladelphia-v2.engine+ wav + out/ + node_modulescuritiba-v2合计 357 个 mp3 ≈ 4.2 h 合成(唯一不可再生资产)。在各 worktree 拿到本变更后执行:
缓存安全已证明(
digest_indextts只含字节 sha1 不含路径,搬迁零句失效)。任何时候都不跑git clean -xdf——它会删光这些缓存。另:三个分支正有 media/ 内的进行中工作(37/12/10 个提交),合并后新增文件会落回
media/,用同一扫描即可发现并搬走。明确不做(与理由,详见各文件内注)
theme.ts色板、scenes/*、motifs.tsx、各集pnpm-lock.yaml抽取(它们就是产品本身;色板反枚举原则要求每集分歧)check_script.py:38-40的正则执法w('id','id')字面形态,抽成 hook 会击穿解析器契约)