TDE 与横向债务
Sentinel 关闭了十三个 Charter,里面至少有七处可辨认的横向债务,TDE 却一个都没有创建。文档类型存在,但触发它的操作准则不存在。fw-4.13.0 如何补上这个缺口 —— 以及那一串 PR 怎样顺带把关于 stacked PR 的一课写进了项目规范。
1. 十三个 Charter,零个 TDE
Issue #128 以一个令人不安的不对称开局:
"Sentinel 采用者(主要,fw-4.12.0)在 13 个已关闭的 Charter 中创建了零个 TDE,尽管有 ≥7 处横向债务通过并行机制流转。"
十三个已关闭的 Charter。至少七处可辨认的横向债务——继承自前序 Charter,跨越模块,在会话之间持续存在。零个 TDE。如果这是某个陌生操作者的数据,或许还说得过去。但操作者是我,采用者就是这个在实践中验证框架本身的项目。如果 Sentinel——整个框架被最激进使用的仓库——在十三次尝试中一次都没有产生 TDE,那一定是哪里出了问题。
出问题的不是债务本身——债务通过其他渠道被捕获了(AILOG 内部的 R<N>(新增,不在 Charter 内),以及 follow-ups-backlog.md 中的条目)。出问题的是,框架中没有任何准则说明"这一具体内容值得创建 TDE,而不是 R<N>"。文档类型存在,操作触发器不存在。
本文记录的是 2026 年 5 月 11 日至 12 日这段经历:如何诊断出缺失的触发器,如何用四条规范标准(fw-4.13.0)填补这个缺口,以及修复问题的 PR 链如何在此过程中留下了一堂关于 "stacked PR" 的操作课,并最终被写入项目的 CLAUDE.md。这是框架在同一弧线中修复了两件不同的事的第一篇博客记录,而其中第二件是无意为之的。
2. 类型存在,触发器不存在
TDE——Technical Debt Entry(技术债务条目)——自一月份的初始提交以来就存在于框架中(Post 2 记录了这一点:它是 v1.0.0 README 中八种原始类型列表中的一员)。模板在,分类法字段在,06-evolution/technical-debt/ 文件夹也在。
缺少的是在规范装置的某个地方写一句话,说*"现在创建一个 TDE"*。Issue #128 毫不留情地指出了这一点:
"阅读面向采用者的文档(
AGENT-RULES.md、DOCUMENTATION-POLICY.md、QUICK-REFERENCE.md、CLAUDE.md自主规则),没有任何明确的触发器说明'现在创建 TDE'。AILOG(随时创建)、AIDEC(考虑替代方案时)、ETH(高风险 PII)、ADR(架构决策)都有触发语言,但 TDE 只是被列为'智能体可以识别'。"
"智能体可以识别。" 如果你有心的话就识别吧。进入仓库的智能体读到这句话,耸耸肩,转向 AILOG 和 AIDEC——那两个明确告诉它何时动作。这个缺陷与 Issue #113(Post 5)中的一个如出一辙:制品技术上存在,但规范界面没有给智能体激活它所需的动词。这个案例与 #113 不同之处在于后果。Charter 的情况是看不见就不用新流程。TDE 的情况则更糟:横向债务确实在被捕获——但是碎片化的,没有整合视图,没有跨制品的优先级排序,没有供人类审阅者排序的 assigned_to 或 priority 字段。
Issue 列举后果时措辞直白,因为它详细说明了所有没有发生的事:
"在文档层面没有可查询的'所有待处理技术债务'视图。每个条目没有
影响 × 努力优先级矩阵。没有向人类审阅者暴露assigned_to/priority字段。真正跨越多个 Charter 的架构债务(例如,跨模块的范围授权缺口遗留)被碎片化到每个 Charter 的 R 编号中,而不是合并到一个 TDE 里。"
十三个 Charter 的债务被碎片化为每个 Charter 的 R<N>。从仓库操作者的角度来看:没有整合列表,没有一项被明确标注为继承而来,没有任何债务可以在项目层面进行优先级排序。一切都在仓库里。但没有一样放在仓库为那些从外部进来阅读的人类所构建的地方。
3. 债务的四条判定标准
PR #129(fw-4.13.0,在 Issue 提出整整十三小时后于 5 月 11 日 19:38 UTC 合并)用 AGENT-RULES.md §3 中的新章节——"TDE 与 R<N>(新增,不在 Charter 内)"——填补了这一缺口。四条标准,原文如下:
| 标准 | 适用情形 |
|---|---|
| 1. 继承自前序 Charter | 该债务字面上继承自上一个 Charter(严格继承),或在遵循上一个 Charter 的模式时重新出现(模式传播)。 |
| 2. 适用于多个模块或 Charter 执行边界 | 该债务跨越代码模块或跨越 Charter 之间的执行边界(治理轨迹债务)。 |
| 3. 需要在当前范围之外单独开设 Charter | 解决它需要开设自己的 Charter,超出当前 Charter 的范围。 |
| 4. 需要人类进行优先级排序/分配 | 决定优先级或分配超出智能体的职权范围。 |
操作规则:如果一项债务满足四条标准中的至少一条,它就是一个 TDE。如果一条都不满足,它就留在它出现的那个 Charter 内作为 R<N>。
四条标准各有其逻辑。继承性(1)捕获跨时间持续存在的债务,审阅者希望按来源分组,而不是按 Charter 分组。多模块或多 Charter(2)捕获存在于制品之间而非存在于某一制品内部的债务。独立 Charter(3)承认某些债务足够大,值得拥有自己的周期,因此不适合作为事前声明的风险。人类优先级排序(4)承认自主性的边界:有些决定智能体可以标记但无法解决,这些决定值得有一份文件供人类排队处理。
同一个 PR 还在 TDE 模板的元数据中增加了新字段——promoted_from_followup: FU-NNN | null——以及 FOLLOW-UPS-BACKLOG-PATTERN.md 中关于如何将后续跟进条目晋升为 TDE 的章节。晋升有两种形式,均有字面记录:现有条目的晋升(已在列表上数周的后续跟进条目成熟为 TDE),以及创建时的追溯晋升(创建 TDE 时,承认它源自先前的后续跟进条目并加以标注)。元数据字段完整了追溯链:现在任何 TDE 都可以指回产生它的后续跟进条目(如果有的话)。
4. Sentinel 的三个 TDE——实证循环闭合
Issue #128 不是靠论证关闭的,而是靠证据。同一天,Sentinel——那个在十三个 Charter 中一个 TDE 都没有产生的同一采用者——创建了三个:
- 一个关于 RequireScope 架构缺口的 TDE,继承性跨越模块。标准 1 + 2 + 3。
- 一个关于 HTTP 层缺失测试覆盖的 TDE,债务跨特性 Charter 持续存在。标准 1 + 4。
- 一个关于审查早于 Charter 格式 v3 的遗留 AILOG的 TDE,这个问题需要自己的周期。标准 1 + 3。
数小时内三份文档。速度不是关键,关键在于每一份都适用了至少一条标准,且没有任何一份落入灰色地带。标准作为明确的启发式规则发挥了作用——操作者不必自我纠结某项内容是 TDE 还是 R<N>。Issue 在上午开启的实证循环在当天下午以三份文档宣告闭合。
PR #136(fw-4.13.1,次日合并)根据同一实践经验对两条标准进行了细化。继承性(1)被明确拆分为严格继承与模式传播,因为 Sentinel 的三个 TDE 之一清晰地展示了第二种情形:债务并非字面上被继承,而是在遵循相同程序时相同模式再度出现。多模块(2)被重新表述为"多个模块或 Charter 执行边界",因为三个 TDE 中的另一个属于治理轨迹型(跨越会话边界,而非跨越代码模块)。这些标准在三个真实案例上经过演练后,只经历了一轮精化。框架再次验证了第 12 条原则:没有任何模式在第二个领域验证之前会结晶成型。
5. Stacked PR 的教训
这里文章故意转了个弯。关闭 Issue #128 的 PR 链 #129 → #131 → #133 留下了一个附带的操作教训——不关于 TDE,而是关于如何不应该叠加分支。这一教训被字面记录在公开仓库 CLAUDE.md(第 181-220 行)的 "Stacked PRs——避免,或使用合并提交" 章节中。
它是怎么出问题的
PR #131(cli-3.12.1,验证器修复——它曾拒绝 TDE 上的 status: identified)以 base = #129 打开,因为 #131 需要 #129 的代码才能编译其测试。然后 #129 以压缩合并的方式并入 main。当前的 CLAUDE.md 用值得完整引用的精确措辞描述了这一情形:
"当你把 PR B 叠加在 PR A 的分支上(B 的 base 是 A 的 head,而非
main),而 A 以压缩合并并入main时,B 的内容就会被搁置:— A 的压缩合并在
main上创建了一个新提交,其内容等同于 A,但 SHA 与 A 原始提交不同。— B 的分支仍然指向 A 的原始提交,而这些提交在
main上已没有后代。— 当 B 被合并时,GitHub 将其合并到 A 的分支(其声明的 base),而不是
main。'合并到 main'从未发生——即使 GitHub UI 显示 B 为 MERGED。"
在 #129/#131 周期中实际产生的结果:GitHub 的 UI 显示 #131 已合并,验证器测试表面上进入了 main,但内容从未到达。PR #133 是后来不得不开启的程序性同步 PR,以将内容送达目的地。诊断耗时:约三小时。理解后的恢复操作耗时:五分钟。
如何预防
CLAUDE.md 记录了两种策略,一种保守,一种务实:
"1. 顺序,而非叠加。等待 PR A 合并到
main,然后将 B 变基到main上,以base = main作为独立 PR 开启 B。较慢但万无一失。2. 如果必须叠加,对父分支使用合并提交(而非压缩)。合并提交保留了共享历史,因此后续将叠加 PR 合并到
main可以顺畅解决。用更嘈杂的git log换取 stacked-PR 的安全性。"
Sentinel 和 StrayMark 默认使用压缩合并。这个选择有助于保持 git log 整洁,每个特性一个决策,每个 PR 一个提交。但代价恰恰在这里:与 "stacked PR" 不兼容。CLAUDE.md 现在所编纂的规则是诚实的:要么不叠加,要么付出提交历史的代价才能叠加。没有第三个选项不会破坏某些东西。
如何恢复(如果已经发生)
CLAUDE.md 的恢复部分是该文档中操作性最强的内容。四个步骤:
"1.
git checkout -b chore/sync-<B-content>-to-main main2.
git cherry-pick <B 的合并提交 SHA>——应该是干净的,因为 B 触及的文件在 A 的冲突区域之外(这正是当初可以叠加的原因)。3. 推送,以
base = main, head = chore/sync-...开启 PR。cherry-pick 在main上产生新提交,因此不会有冲突。4. 如果内容已在 B(原始 PR)中经过审查,分支保护可能需要
--admin合并——同步 PR 纯属程序性操作。"
最后一步在编辑上很重要:明确说明 --admin 合并仅授权用于此类程序性 PR——即内容已在原始 PR 中经过审查的情形。这是项目"内容经人类审查"规则的唯一例外。
之所以值得将这一教训记录为 TDE 文章的一个子章节——而非独立文章——是因为两者有一个共同特征:都是框架现在明确命名的横向流程债务。一个是代码债务(TDE 作为新类型),另一个是工作流债务("stacked PR" 作为已记录的反模式)。两者同源:是真实的操作摩擦触发了文档的诞生。
6. 这段经历在仓库中留下了什么
不到二十四小时内四个 PR,三条已记录的教训:
- PR #129(
fw-4.13.0,5 月 11 日 19:38 UTC)——TDE 激活触发器。四条标准 +AGENT-RULES.md §3新章节 + FU → TDE 路径。 - PR #131(
cli-3.12.1,5 月 11 日 19:39 UTC)——验证器接受 TDE 上的status: identified。没有这个修复,在新触发器下创建的第一个 TDE 会通不过验证。 - PR #134(5 月 12 日 04:54 UTC)——"stacked PR" 教训记录在
CLAUDE.md中。它没有修改框架代码,而是修改了仓库的操作规则。 - PR #136(
fw-4.13.1,5 月 12 日 04:54 UTC)——基于 Sentinel 三个真实案例对 TDE 触发器进行细化。
关于这段时间线,我最想强调的是:CLAUDE.md(PR #134)在关闭 Issue #128 的同一弧线中被更新了。"stacked PR" 的教训没有等到被遗忘。如果框架的纪律是"每一次重大变化都留下有据可查的痕迹",这同样适用于操作摩擦,而不仅仅是设计。框架的存在,部分正是为了让昂贵的教训不会消散。
7. 结语
从这个过程中得出的四点结论:
-
没有触发器的文档类型是不可见的类型。 与 Issue #113 一样,智能体进入仓库时看不到的东西对它来说就不存在。TDE 从一月份起就在技术上存在,但直到四条标准出现在
AGENT-RULES.md §3中才开始被使用。没有激活动词的结构只是装饰。 -
横向债务值得拥有自己的类型。 将债务碎片化为每个 Charter 的
R<N>会破坏治理系统最重要的属性:整合视图。四条标准,满足任意一条即可,守住了"这是 Charter 的风险"与"这是项目的债务"之间的界线。 -
操作教训也要文档化。 PR #134 在教训浮现的同一天更新了项目的
CLAUDE.md。这不是存档偏执,而是同一规则应用于流程:如果今天这个摩擦耗费了你三小时,就在今天写下这一教训。 -
框架从特性和反模式两个方向生长。 这段经历留下了一个新类型(TDE 作为操作实体)以及一个已记录的反模式("stacked PR" 与压缩合并不兼容)。两者都是框架的素材,即使只有一个显示为版本号的变更。
下一篇文章是一段简短但具有结构性意义的经历:"西班牙语审计提示词是那个离群值"(H-10)。一个 i18n 惯例细节,揭示了哪种语言一直是规范语言——以及为什么修复它在无意间改变了框架对翻译的理解方式。
锚点:Issue #128。PR #129 · #131 · #134 · #136。版本发布:fw-4.13.0 / cli-3.12.1 / fw-4.13.1。"Stacked PR" 教训已编入仓库 CLAUDE.md 第 181-220 行。
本文档在生成式 AI 工具(Claude 4.7)的协助下撰写;内容的全部责任由人类作者承担。