Repository navigation
spec 门禁盲区:可作者化 key 的「默认值 / 约束」变更不被任何 gate、tombstone 或 conversion 记录(#4650 / #4659 同族) #4666
Description
Activity
xuyushun441-sys commented
on Aug 3, 2026 CollaboratorMore actions分诊(2026-08-03,PM 会话
session_01Ehu85kbvMcrNTUJjwxvLJ9):入队,走 A(默认值 + 约束都纳入指纹),PM 决定 + 维护者否决窗口 —— 门禁设计属验证策略,不升级。前提复核(以
origin/main实测):build-schemas.ts仍无任何 fingerprint/default 追踪;authorable-surface.json仍只记裸 key 名 —— 盲区原样存在。关联项状态更新:#4650 已关(基线删行合法性门禁已落地),正文「与 #4650 可一起做」的联动过时,本单独立成篇;#4650 的建议 (2)(收窄收集面)未见立项,若本单实现时噪音超预期,那是它的活,不归本单扩权。A 而非 B 的两轴理由:
- 长远:约束收紧(
.min()/.max())对存量元数据是硬拒,响亮但同样零记录 —— 今天唯一的痕迹是人自觉写 semantic 条目(spec 双源清账 C8:RetryPolicy / RetryPolicySchema(./automation ≠ ./system)—— 2 条 #4661 实证)。结构性门禁优于纪律,B 把约束类留在纪律区,等于本单自己批评的「靠自觉」再活一半。 - 防 AI:默认值翻转是静默事故(B 也覆盖);但 AI 改约束和改默认值一样频繁,且 AI 恰恰最不会「自觉补 semantic 条目」。指纹 = 规范化摘要(默认值 + 约束集),describe 文案不入指纹 —— 噪音来源被结构性排除。
- 噪音出口(硬要求):变更必须有显式确认通道(ratchet 既有的 intentional-change 模式),否则每次合法调整都红,门禁会被绕行 —— 那是 authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650 刚修完的洞的新变体。
- 实现纪律:先证红再信绿(对 spec 双源清账 C8:RetryPolicy / RetryPolicySchema(./automation ≠ ./system)—— 2 条 #4661 那处
maxRetries默认值做 sabotage,新门禁必须抓到);⛔ 禁手编基线(authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650 门禁会查)。
排期:非线协议 breaking(门禁工具),不占 v17 窗口位,窗口关键批次之后排。
Generated by Claude Code
- 长远:约束收紧(
疑似域误标:本单要补的是「默认值 / 约束变更」的 gate / tombstone / conversion 记录面——落点是门禁与生成器(C 包 #5163 文件面),不是 schema 本体,建议改标
domain:spec-tooling——交分诊座位定夺。背景:维护者 2026-08-06 拍板 spec 车道缩盘方案,见 #5837。
Generated by Claude Code
标签落实(维护者 2026-08-06 指示,session_01LeEfA7CFwbJb7JJmXm2KM3):按 08-06 转席建议执行
domain:spec→domain:spec-tooling(要补的是「默认值/约束变更」的 gate / tombstone / conversion 记录面,落点门禁与生成器)。
Generated by Claude Code
维护者裁决(2026-08-07,经
domain:spec-tooling座位 PM 呈报):方向 B —— 只对默认值做指纹。即:每个可作者化 key 除名字外,再记一个**「默认值存在性 + 取值」**的规范化指纹,变更即红。约束(
.min()/.max()/.positive())不纳入。裁决理由(呈报时给出,维护者采纳)
关键是一个不对称:
- 约束收紧会硬拒。 存量
maxRetries: 20的 job 会被明确报错拒绝 —— 响亮、看得见、可诊断。本 issue 自己也写了「硬拒是响亮的、可接受的」。 - 只有默认值翻转是静默的。 客户收不到任何报错,只会发现「怎么不重试了」。这是从客户事故发现、而不是从 CI 发现的那一类。
方向 A 覆盖面最全,但代价是
authorable-surface明显变大变吵,而 #4535 §1 已经在抱怨该文件过度收集;每次微调.describe()或约束都要走一次「已确认变更」出口。B 用 A 的一小部分噪音,精确盖住危险的那一半。方向 C(AST 查 diff)噪音最低,但靠 diff 判断在 git 语境下脆(变基、压缩提交都能骗过它);方向 D 正是本 issue 要指出的「靠自觉」,不解决机制问题。
⏸ 暂不派发的原因(纯文件面串行,不是优先级)
本单落点是
packages/spec/scripts/build-schemas.ts,而 PR #6309(#5847,锚点漂移提示方向)此刻正在该文件上。同文件两单并行会互埋 diff,故本单排在 #6309 之后。#5475(把scripts/**并进 tsconfig,含build-schemas.ts的 6 条 code-tiernever真错)同样在这条串行链上。派发时会带上的额外要求(先记在这里,免得漏):
- 指纹必须有**「已确认的变更」出口**,且该出口不得是静默的(⛔ check:react-declaration-parity 是唯一没接进任何 workflow 的源码审计门禁,且无 MANIFEST 时静默 skip 退出 0 —— 它现在永远不可能红 #4690);
- 门禁必须在当前
origin/main上绿;若红,说明要么规则设计错了、要么真的抓到了一次未记录的默认值变更 —— 说明是哪一种并给证据,⛔ 不得靠放宽规则把红调绿; - 反向验证:预测先写后跑,并复现本 issue 那次 sabotage(
maxRetries默认值改一个字符)证明新门禁会红; - ⛔ 不得顺手把约束也纳入 —— 那是方向 A,已被裁掉。
Generated by Claude Code
- 约束收紧会硬拒。 存量
认领(os-dev 开发座位,session
session_014wsZeReNTqiceBfLb5Pyf5,分支claude/issue-4666-default-value-fingerprint)。按维护者 2026-08-07 裁决执行方向 B —— 只对默认值做指纹,约束不纳入。开工前先在当前
origin/main上复核前提(build-schemas.ts今天已被 #6200/#6256/#6309 移动过三次,正文行号已过期)。
Generated by Claude Code
- added a commit that references this issue
on Aug 8, 2026 - added a commit that references this issue
on Aug 17, 2026 - added a commit that references this issue
on Sep 10, 2026 - added a commit that references this issue
on Sep 17, 2026 - added a commit that references this issue
on Sep 28, 2026 - added a commit that references this issue
on Oct 7, 2026
从 #4661(#4535 C8
RetryPolicy收敛)里分出来的独立发现,已实证,不是推测。与 #4650(基线可手编)、#4659(检查 (b) 按 leaf name 匹配)是同一族:门禁看起来绿,但它没在看你以为它在看的东西。结论
packages/spec/scripts/build-schemas.ts的可作者化面门禁 只比较 key 的集合。同一个 key 的 默认值 (.default()) 和 约束 (.min()/.max()/.positive()) 变更,对它完全不可见 —— 而这类变更恰恰能静默改变已部署元数据的运行时行为。三条记录通道全部漏掉它:
authorable-surface.json比对(检查 (a) vanish)retiredKey()tombstone(检查 (b))spec-changes.json/ upgrade guide(ADR-0087 D4)也就是说:一个 PR 可以把
job.retryPolicy.maxRetries的默认值从 3 改成 0(让所有依赖默认值的存量 job 静默停止重试),而全部门禁绿、基线不动、没有任何一行 tombstone 或 conversion 记录这件事。实证(#4661 的 sabotage 验证)
在 #4661 的分支上,把
shared/retry-policy.zod.ts的maxRetries默认值从0改成3,只改这一个字符,然后跑门禁:绿。 同一处改动被 #4661 手写的运行时 pin 抓住了:
即:今天唯一能挡住这类变更的,是作者自己想起来手写一个 pin 测试。 没有任何机制强制它存在。
为什么这比听上去更糟
enabled、required、各种allow*—— 这些的默认值翻转就是安全/可靠性事件,而且是静默的。#4661把maxRetries加了max(10)、backoffMultiplier加了min(1),存量maxRetries: 20的 job 会硬拒。硬拒是响亮的、可接受的,但门禁一样没记录 —— 是人写了semantic迁移条目才留下痕迹。ConversionApplication是{from, to, path}—— 描述的是值的重写,没有「这个 key 的默认语义变了」的表达形式。可能的处置方向(未裁决,列出来供讨论)
authorable-surface.json的比对。 每个 key 除了名字再记一个形状指纹(默认值 + 约束的规范化摘要)。变更即失败,要求显式确认。.default()变更必须带semantic迁移条目,用 lint 规则(AST)检查 diff。git语境下比 ratchet 脆。倾向 A 或 B —— 与 #4650 要加的可达性窄例外是同一批门禁加固,可以一起做。但选哪个取决于维护者对「ratchet 噪音 vs 覆盖面」的偏好,所以不预设。
关联
.type就能让一个 tombstone 冒充「已登记迁移」 #4659 —— 检查 (b) 按 leaf name 匹配 conversion surfaceauthorable-surface.json过度收集