Skip to content

fix(spec): 重锚 authorable-surface.base.json 改为显式动作 —— 构建不再顺手推进删除门的锚点 - #5807

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-5358-check-authorable-surface-readonly
Aug 6, 2026
Merged

fix(spec): 重锚 authorable-surface.base.json 改为显式动作 —— 构建不再顺手推进删除门的锚点#5807
baozhoutao merged 1 commit into
mainfrom
claude/issue-5358-check-authorable-surface-readonly

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes #5358

前提核验:一半已过期,一半仍然成立

按「issue 是线索不是规格」的要求,先对 origin/main(1624f4ad)复核了本单的两条现象。

第 1 条(--check 会重写工作区)已经不成立。 build-schemas.ts 的锚点写入分支在当前 main 上已经是 if (drifted && !CHECK),--check 不写。干净树实测:

$ pnpm --filter @objectstack/spec check:authorable-surface
ℹ️  authorable-surface.base.json trails the merge base by 8 key(s) — ...
$ git diff --exit-code ; echo $?
0

第 2 条(构建/gen:schema 路径)完全成立,也正是三条 issue 评论(#4990 / #5155 / #5660)复现的那条。同一棵干净树:

$ pnpm --filter @objectstack/spec gen:schema
⚓ authorable-surface.base.json refreshed to 1624f4ad209c (7927 keys) — commit it.
$ git status --porcelain
 M packages/spec/authorable-surface.base.json
-  "baseRev": "5acb93add66435880ffed0d3aff79db29ae1e932"
+  "baseRev": "1624f4ad209c7cbdf254dc7df109c1f2df6a8751"

所以本 PR 修的是写入分支的触发条件,而不是 --check 分支 —— 与评论区三位 dev 的结论一致(「修法覆盖 build 路径而不只是 --check 路径」)。--check 的只读性作为不变量被补了自证测试,但它今天本来就绿,下面「反向核验」一节如实标注了这一点。

为什么这个锚点和它的两个邻居不同

gen:schema 写三个受版本控制的产物。其中 json-schema.manifest.jsonauthorable-surface.json本地源码的投影 —— 重新生成永远是对的,它们的 diff 就是被 review 的改动本身。

authorable-surface.base.json 不是任何本地东西的投影:它是上游某个 commit 的快照,是 #4650 删除门的基线,而它之所以有资格当基线,恰恰因为受测 commit 改不了它。把它做成「每次构建顺手刷新」,等于让这条保证依赖于「没有人跑过构建」。

代价是可量化的:一次触发 = 110 条删除(#4990 / #5155),而那 110 个正是 #4988/#5321 刚退役的 ui/ComponentAnimation 族。锚点越过退役点之后,删除门就再也看不见那次退役 —— 而且推进前后两种状态门禁都判绿,因为两者各自自洽(#5660 的观察)。三次都只靠人眼逐行读 git status 拦下。

滞后则是安全方向的:锚点越旧,离线构建需要交代的键只会更多,不会更少。

改法

给锚点一个属于它自己的模式,而不是加一条更聪明的启发式:

入口 对锚点的行为
gen:schema / 任何 pnpm build / check:docs 不写。滞后时打印一行 ℹ️,说明这不是错误,并给出显式命令
check:authorable-surface(--check) 严格只读(不变);文件缺失/畸形/不真实仍然致命
gen:authorable-surface-base(--update-base) 唯一写入路径
--check --update-base 在生成 1600 个 schema 之前拒绝 —— 一次会修复自己所检测之物的核验永远报不出问题

真实性语义一个字没动:baseRev 仍须是 origin/main 的祖先且键集与该 commit 逐行一致;仍只从 git 解析出的基线写入(绝不从被检查的构建 —— 离线时 --update-base 同样无能为力);写入仍在删除门裁决之后,所以新的显式命令也无法把基线推过一次未获证明的删除(有测试)。

顺带修正的处方:所有指向该文件的错误信息此前都写「运行 gen:schema」,而 gen:schema 已经不再碰它 —— 全部改为指向新命令。这正是本单描述的缺陷类别(声明与实际不符),留着就是新的一处。

三处不在改动范围、但被显式处理的相邻面

  1. SURFACE_BASE_DESCRIPTION 常量刻意逐字未改。 该字符串是锚点文件规范形式的一部分(readCommittedSurfaceBase 把任何差异判为手改并致命),改它就必须同时重锚该文件 —— 而本单的验收标准要求该文件与 origin/main 逐字节一致。因此描述里那句 "Written only by gen:schema" 现在是欠描述而非错误:写入者仍是同一个生成器 scripts/build-schemas.ts,只是收窄到 --update-base 一种模式。收窄方向是安全的。代码里留了注释说明,建议下一次真正重锚时把这句一并带上(那会是一个干净的、被 review 的 diff)。
  2. scripts/regen-artifacts.mjs 只改注释,gen 字段仍是 gen:schema 合并驱动打印的处方会照抄这个字段;若改成 gen:authorable-surface-base,驱动就会在 merge 未 commit 时指示用户跑那条命令 —— 那正是 os-regen 驱动指示的 gen:schema 在 merge 未 commit 时运行,会把 authorable-surface 锚点倒退回旧 merge-base —— 生成器写入、门全绿、静默撤销 main 的锚点推进 #5370 的重演(MERGE 态下 merge-base(HEAD, origin/main) 仍是分支旧分叉点,锚点会向后倒退,且倒退后依然 authentic,没有门会拦)。保留 gen:schema:对该文件的两个邻居正确,对它自己是无害空操作。注释写清了这个取舍。
  3. check:generated 的账本新增第三类 EXPLICIT_GENERATORSUNGATED_GENERATORS 会谎称「没有门核验它」(check:authorable-surface 核验其真实性),GATED 又会把它放进 --fix 的射程(那正是本次移除的副作用)。新类别要求声明 gatedBy,且该门必须是本账本已声明的门,否则 reconcile 失败。

测试

新增 build-schemas-check-mode.test.ts#5358 块(7 例),复用该文件已有的沙箱:把 scripts/ 拷进临时目录、真建一个带 refs/remotes/origin/main 的 git 仓库,生产代码路径逐字节不变。fixture 是真实形状 —— 一个滞后但真实的锚点(指向更早的上游 commit,键集与该 commit 的 baseline 逐行一致),提交到干净树后再跑,断言就是本单要求的那条:git status --porcelain -uno 为空。

pnpm --filter @objectstack/spec test:319 文件 / 8152 用例全绿;typecheck 绿;check:merge-driver 绿;check:generated --reconcile-only 绿(18 check: + 13 gen: scripts, all classified)。

反向核验(方向先说,再跑)

build-schemas.ts 换回 origin/main 的版本、只留新测试,预测「构建路径的两条红、--check 那条绿」。实际 5 红 22 绿,与预测一致:

× catches the anchor being edited to hide a deletion(处方字符串已改)
× is a committed artifact: ... only --update-base creates it
× a plain build leaves the anchor byte-identical and the working tree clean
× --update-base on an already-current anchor writes nothing
× refuses --check --update-base

核心那条的断言就是本单的机制本身:

-   "baseRev": "5a9a43914afabfeb1a81a61f01656c612341e23a",
+   "baseRev": "1c9d32fccfc462091465321f34179d2b5cac156f",
+     "data/Object:label",

如实说明:a --check run leaves the anchor byte-identical 这一条在旧代码下也是绿的。 它不是修复的证据,而是不变量的钉子 —— 本单第 1 条现象在派单前就已被别的改动修掉了。把它写成红是不诚实的,所以这里标出来。

真仓库上的验收证据

$ pnpm --filter @objectstack/spec check:authorable-surface
$ git diff --exit-code -- packages/spec/authorable-surface.base.json   → 0
$ pnpm --filter @objectstack/spec gen:schema
ℹ️  authorable-surface.base.json trails the baseline at 1624f4ad209c by 8 key(s)
   — expected, and not an error: ... `gen:authorable-surface-base` — never a side effect of this build (#5358).
$ git diff --exit-code -- packages/spec/authorable-surface.base.json   → 0
$ pnpm --filter @objectstack/spec gen:authorable-surface-base
$ git status --porcelain -- packages/spec/authorable-surface.base.json → M   (显式命令确实生效)

本 PR 中 packages/spec/authorable-surface.base.jsonorigin/main 逐字节一致(上面第三步之后已 git checkout -- 还原),不含任何一次性重锚。

check:api-surface 在本地报红,原因是这个全新 worktree 从未 build 过、packages/spec/dist 不存在(该门读 built .d.ts,即 AGENTS.md 记的 stale-dist 幻影)。本 diff 不含任何 packages/spec/src/** 文件,导出面不可能变。

对三条相邻单的影响(必答)

越界发现

无。改动严格限于锚点写入分支及其处方,外加两处为保持一致必须同步的账本/注释(见上文第 2、3 点)。


🤖 Generated with Claude Code

https://claude.ai/code/session_01559M8FVm6W6vDLABL3jvdW


Generated by Claude Code

packages/spec/authorable-surface.base.json 是 #4650 删除门在无法访问 origin/main 时
使用的基线锚点(#5235)。它不是本包源码的投影,而是某个**上游 commit** 的快照 ——
正因为受测 commit 改不了它,它才有资格当基线。

在此之前,只要它与 git 解析出的基线有差异,每一次 gen:schema 都会重写它。而
gen:schema 是 pnpm build 的第一步,于是任何一个依赖闭包里含 @objectstack/spec 的包
的构建、以及 check:docs,都会触发。三位 dev 在三个互不相关的任务里各自撞上
(#4990 净删 110 键、#5155 同样 110 键、#5660 +3 键),那 110 个正是 #4988/#5321 刚
退役的 ui/ComponentAnimation 族 —— 锚点越过退役点之后,删除门就再也看不见那次退役,
而且推进前后两种状态门禁**都判绿**。三次都只是靠提交前逐行读 git status 拦下的。

改法是给锚点一个属于它自己的模式:

- 新增 --update-base(脚本 gen:authorable-surface-base),是唯一写入该文件的路径;
- gen:schema 与任何构建都不再写它,滞后只打印一行 ℹ️ 并给出显式命令(滞后本来就不
  是错误:main 上 merge base 即 HEAD,该文件必然落后自身 surface 一个 PR);
- --check 保持严格只读,缺文件仍然致命;--check 与 --update-base 互斥并在生成前拒绝。

锚点真实性语义完全未动:baseRev 仍须是 origin/main 的祖先且键集与该 commit 一致,
仍只从 git 解析的基线写入(绝不从被检查的构建),写入仍发生在删除门裁决之后 ——
所以显式模式同样无法把基线推过一次未获证明的删除。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01559M8FVm6W6vDLABL3jvdW
@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 6, 2026 6:04am

Request Review

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

110 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/tenancy-modes.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file tests tooling labels Aug 6, 2026
@baozhoutao
baozhoutao marked this pull request as ready for review August 6, 2026 06:17
@baozhoutao
baozhoutao added this pull request to the merge queue Aug 6, 2026
Merged via the queue into main with commit a3a884d Aug 6, 2026
26 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-5358-check-authorable-surface-readonly branch August 6, 2026 06:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

2 participants