Skip to content

观察项:json-schema.manifest.json 没有 #4662 那样的「整文件规范形态」比对 —— 不改变键集的手编至今无人可见 #5972

Closed

Description

@baozhoutao

类别:observation-class(今天没有用户会撞上,不带 pm:queue)。在 #4725 的实现过程中顺手量到,按 Prime Directive #10 记账,不在那个 PR 里修。

事实

authorable-surface.json 自 #4662 起被整文件和它的规范序列化比对:

// build-schemas.ts
const canonicalSurfaceText = JSON.stringify(canonicalSurface, null, 2) + '\n';
const surfaceChanged = surfaceRaw !== canonicalSurfaceText;

理由写在那里:#4662 抓到的是一个被手工规范化过的 description 破折号,一个只比对键集的检查永远看不见它 —— 而「这个文件的字节必须全部来自生成器」正是 #4650 的证据链所依赖的。

它的同胞 json-schema.manifest.json 没有这一层。写触发条件只有:

const manifestChanged = !manifest || added.length > 0 || renamedAway.length > 0 || descriptionStale;

(descriptionStale 是 #4725 刚加的,只覆盖 description 一项。)

因此对以下手编,今天没有任何门禁会说话

  • 重排 schemas 数组(生成器写的是 .sort());
  • 缩进 / 尾换行改动;
  • 重复条目——重复的键既不在 missing(它被产出)也不在 added(它在 manifest 里),manifestChanged 恒 false,重复项会一直留着,直到别的改动碰巧触发一次重写。

added / missing / #4725 的 merge-base 删除门都是集合判定,对上面三种都免疫。

影响评估(诚实版:今天为零)

三种都不改变任何门禁的判定结果,也不改变任何消费者行为 —— manifest 只被 build-schemas.ts 自己读。所以这不是缺陷,是同一个文件家族里两种不同的严格度:一个说「每一个字节都必须来自生成器」,另一个说「键集对就行」。

记下来的理由是它会变得重要:#4725 之后 manifest 是一道删除门的输入(虽然那道门读的是 merge-base 的那份,PR 改不动),而 #5837(按 category 分片三个单体 ratchet)和 #4676(投影类生成物是否该退出仓库)都会重新动这个文件的形状 —— 谁先落地,谁最省事地把两边的严格度对齐。

可能的修法(供 triage,不预设)

把 description 与键集的两个条件合并成一个「整文件 vs 规范序列化」比对,和 authorable-surface.json 同形;--check 报告、写模式重写,沿用现有的 #4711 分叉。代价是任何格式漂移都会要求跑一次 gen:schema,和另外七个生成物一致。

关联

#4662(authorable-surface 的整文件比对是怎么来的)、#4725(本观察项的来源,manifest 删除门)、#5837、#4676。


Generated by Claude Code

Activity

  1. claude commented on Aug 6, 2026

    @claude
    Contributor

    发现分诊轮:持有(留 finding)+ 补域 domain:spec-tooling。

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. claude commented on Aug 7, 2026

    @claude
    Contributor

    Findings triage (#4949 discipline): close (completed) — the gap this finding records has been closed, incidentally, by #5837.

    Restart condition fired, and overshot it. The 2026-08-06 13:57Z hold said: 「#5837 或 #4676 任一落地时并入 —— 谁先落地谁最省事地把两边严格度对齐」. #5837 is closed/completed (2026-08-07T00:28:11Z). It did not merely create the opportunity to align the two strictness levels — it aligned them, because the alignment fell out of the reshard for free.

    Stale-premise check (origin/main @ 42af12f, read from the tree). The premise is not merely stale — the file it is about no longer exists:

    • packages/spec/json-schema.manifest.json (the monolith) is absent from main. The manifest is now 14 category shards under packages/spec/json-schema.manifest/ (ai, api, automation, cloud, data, identity, integration, kernel, qa, security, shared, studio, system, ui). The authorable surface was resharded the same way (15 shards).

    • The write trigger quoted in the body — manifestChanged = !manifest || added.length > 0 || renamedAway.length > 0 || descriptionStale — is gone. packages/spec/scripts/build-schemas.ts:560 now reads:

      const canonicalManifestTexts = schemaManifestShardTexts([...generatedKeys].sort());
      const staleManifestShards = [...canonicalManifestTexts]
        .filter(([name, text]) => manifestTexts?.get(name) !== text)
        .map(([name]) => name);
      const manifestChanged =
        manifestTexts === null || added.length > 0 || renamedAway.length > 0 ||
        staleManifestShards.length > 0 || orphanManifestShards.length > 0;

      That is a byte-for-byte comparison against the canonical serialization, per shard — structurally the same check authorable-surface has had since feat(spec)!: 双源 C5 收敛 — ActivationEventSchema 归 ./kernel 结构化形状,./studio re-export (#4653) #4662. The script says so itself, in the comment directly above (:551–:556): "Comparing BYTES rather than key sets is what keeps the shards' own description part of the artifact … Sharding made the comparison stricter for free: hand-formatting inside a shard is now caught the same way feat(spec)!: 双源 C5 收敛 — ActivationEventSchema 归 ./kernel 结构化形状,./studio re-export (#4653) #4662 catches it in the authorable surface."

    All three named blind spots are now covered. Checked one by one against the new trigger rather than assumed from the comment:

    body's blind spot status under the sharded writer
    reordering the schemas array canonical text is built from [...generatedKeys].sort() ⇒ any reorder is a byte diff ⇒ staleManifestShards ⇒ reported
    indentation / trailing-newline edits byte diff ⇒ reported
    duplicate entries (the one no set-comparison could ever see) byte diff ⇒ reported. This was the sharpest of the three and it is the one the reshard closes most cleanly

    --check mode even distinguishes the case explicitly (:576): "does not match its generated form (the key set is current)" — the exact failure the finding said nothing would say anything about.

    Why closed rather than promoted. There is no work left. The two-strictness-levels asymmetry the finding recorded is gone, and the resolution came through the route the hold predicted (「谁先落地谁最省事地把两边严格度对齐」) — it just cost nothing to whoever landed #5837, which is why it happened silently and needs saying here. Nothing to dispatch.

    ⚠️ Attribution caveat, stated rather than glossed. git log -- packages/spec/json-schema.manifest/kernel.json points at db8c285, whose subject is "fix(plugin-auth): SMS daily-quota refusal answers 429, not 500" — merge-queue batching makes single-commit attribution unreliable here, so the evidence above is the state of the tree, not a commit message. The verdict rests on the code at build-schemas.ts:551–:565 and the absent monolith, both read directly from origin/main; it does not rest on which squash carried them.

    Maintainer veto window applies as usual (#4949): reopen if you read the alignment differently.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions