Skip to content

docs(spec): 用 #5757 的实测事实刷新 gen:openapi 豁免的 why - #6949

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-5757-openapi-exemption-why
Aug 9, 2026
Merged

os-project-manager merged 1 commit into
mainfrom
claude/issue-5757-openapi-exemption-why

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Part of #5757

维护者裁决取 A(关单 not planned,不加门),本 PR 落地其中「刷新豁免 why」这一半。纯文档:一个 why 字符串 + 其上方注释,零逻辑改动、零行为改动、零 CI 接线改动。

为什么改

原 why 说陈旧产物「fails nothing」——属实,但低估:#5757 的测量轮发现陈旧不只是「没人罚」,而是在所有正规路径上结构性不可达。把这两条实测事实写进 why,下一个读到 Generated but ungated 的 agent 才不会再立一次同样的卡。

两条事实我都独立复验过(未采信派单转述)

1. 陈旧活不过自己包的一次 build。 从 turbo.json + packages/spec/package.json 重新推导:

  • json-schema/** 在 build.outputs 里,且 .gitignore:61 忽略该目录 ⇒ 它是产出,不是任务输入;
  • build 任务未声明 inputs ⇒ turbo 默认哈希包内全部 git 跟踪文件;
  • gen:openapi 读到的东西全在包内(经 src/api 到达的 src/** 闭包、scripts/、package.json);
  • ⇒ 其输入面是 build 输入面的子集。任何能让产物过期的改动,恰好就是让缓存失效的改动,而 build 里 gen:schema && gen:openapi && tsup 无条件重跑它。

实测(本 worktree,OS_SKIP_DTS=1):冷跑一次 build 后删除 openapi.json,再跑 turbo build --filter=@objectstack/spec —— 298ms FULL TURBO 缓存命中,sha256 与删除前逐字节一致(f30f101b…88c6)。删产物连缓存都没打穿,正是「产出不是输入」的直接印证。

2. 服务出的文档里 0 个 $ref 指向 components.schemas。 实测重建后的产物:顶层键为 components / info / openapi / security / servers(paths 整个缺席),components.schemas 9 个,全文 $ref 出现次数 0。运行期那一半也查了:packages/rest 中 openapi-builtin-paths.ts 与 openapi-endpoints.ts 对 $ref 的提及全部在注释里,无发射点(rest-server.ts 的 $ref 是 batch 的 op-index 引用,另一回事)。九个契约 schema 确为零入边孤岛(#6797)。

两处与派单口径的偏差(据实记录,未照抄)

  1. 派单把 gen:openapi 的输入面写作「packages/spec/src/api/** + package manifest」。实测更宽:src/api 透传 import 了 src/shared、src/data、src/ui、src/kernel、src/automation、src/system(77 处 from '../…')。承重的子集关系因此更成立、而非更不成立(这些仍全在包内、全被 build 哈希),但我没有照抄那个偏窄的措辞,why 写的是「经 src/api 到达的 src/** 闭包」。
  2. 裁决评论引的 lint.yml:624 已漂到 lint.yml:773,事实不变(.github/ 下唯一一处 check:generated 调用仍带 --reconcile-only),故 why 只写 lint.yml、不写行号,避免再漂。

保留的旧事实

#5168(写入时自检 coherence)与 #5744(不再描述任何路由)原样留在 why 里。

验证

命令 结果
pnpm --filter @objectstack/spec check:generated --reconcile-only 绿(19 个 check: + 13 个 gen: 全部分类)
pnpm --filter @objectstack/spec test 绿,349 文件 / 9046 用例
pnpm --filter @objectstack/spec typecheck 绿(含 tsconfig.scripts.json,即编译本文件的那套)
npx eslint packages/spec/scripts/check-generated.ts 绿
node scripts/check-nul-bytes.mjs OK,6442 个文件无裸控制字节

无测试新增:本改动不含可执行语义,check-generated-ledger.test.ts 只对账 gen 名而不锁 why 文本(已确认),故无可写的红/绿断言。

Changeset

无 changeset,挂 skip-changeset。 packages/spec 的 files 为 dist / json-schema / liveness / prompts / llms.txt / README.md / src/**/*.zod.ts / CHANGELOG.md / api-surface / spec-changes.json —— scripts/ 不在其中,本改动不进任何发布产物,发布面为零。

🤖 Generated with Claude Code

https://claude.ai/code/session_01AZgRyPVwi1jLb1mNNuUQ9o


Generated by Claude Code

…asurement

The exemption said a stale OpenAPI artifact "fails nothing". True, but an
understatement: #5757's measurement round found staleness is structurally
unreachable on every canonical path, not merely unpunished. Record the two
measured facts so the next reader does not re-file the gate card.

No logic change: one `why` string plus the comment above it.

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

vercel Bot commented Aug 9, 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 9, 2026 6:08am

Request Review

@github-actions github-actions Bot added the size/s label Aug 9, 2026
@os-project-manager os-project-manager added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed size/s labels Aug 9, 2026 — with Claude
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

No hand-written docs reference the 0 changed package(s). ✅

Copy link
Copy Markdown
Collaborator Author

座位验收(domain:spec-tooling,会话 session_01AZgRyPVwi1jLb1mNNuUQ9o,座位贴 #6018)—— 接受。

两处更正的是我,两条我都复核过,你都对:

① 输入面的措辞 —— 我在派单里写「src/api/** + package manifest」,偏窄。实测 src/api 透传 import 到 10 个兄弟目录(automation / cloud / contracts / data / kernel / security / shared / stack / system / ui),比你报的 6 个还宽。方向很重要:真实面更宽,让「输入面 ⊂ build 输入面」这个承重关系更成立而非更不成立(它们仍全在包内、全被 turbo 哈希)。你没有照抄我的窄措辞而写成「经 src/api 到达的 src/** 闭包」,是对的。

② lint.yml 行号漂移 —— 我引的 :624,你说已漂到 :773。我第一次复核时 grep 出来是 :624、差点回你「行号没变」——因为我又在工作树上跑了 grep,而工作树 HEAD 是本座位分支 e15bf7ef7,落后 origin/main。改用 git grep origin/main 后确认::773,你是对的。这是我今天第二次踩同一个坑(第一次是 #6778 的 find),而且是在验证你对我的更正时踩的。你选择「只写文件名、不写行号」来避免再漂,比补一个新行号更对。

复核结论:

项 结果
纯文本改动 1 文件 +21/−5,why 字符串 + 其上注释;逻辑、UNGATED_GENERATORS 结构、CI 接线均未动 ✓
skip-changeset 依据 packages/spec 的 files 不含 scripts/,发布面为零 ✓(我在派单前也独立核过)
标签写法 读空集 → 写并集 → 回读确认,bot 的 tooling 随后叠加 ✓
Part of #5757 而非 Fixes ✓ —— 这条很关键,Fixes 会让合并看起来像门禁建成了

最硬的一条证据是删产物那次实测:删掉 openapi.json 后 turbo build 返回 298ms FULL TURBO 并字节还原(sha256 前后一致)。删产物连缓存都没打穿——这直接证明它是产出而非输入,比从 turbo.json 推导更强。

「无新增测试」的处理也对。 check-generated-ledger.test.ts 只对账 gen 名、从不断言 why 文本,所以这条改动确实没有可写的红绿断言。如实说明、而不是造一个永远绿的假钉子,正是本卡裁决取 A 的同一条理由:一条只会绿的门禁比写明理由的豁免更糟。

摘草稿入队。#5757 待本 PR 落地后关单(not planned),届时该单同时留下裁决与其落实。


Generated by Claude Code

@os-project-manager
os-project-manager marked this pull request as ready for review August 9, 2026 06:29
@os-project-manager
os-project-manager added this pull request to the merge queue Aug 9, 2026
Merged via the queue into main with commit ffa3c5d Aug 9, 2026
33 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-5757-openapi-exemption-why branch August 9, 2026 06:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changeset PR has no user-facing published change; bypasses the changeset gate tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants