ci(spec): check:skill-examples 拒绝 os:check 块内的裸 any (#5943) - #6049
Conversation
os:check 标记是作者的声明「这段应当能编译」。块内一旦出现裸 any,该声明即为空转: 该值上的每一次属性访问都不再被检查,tsc 全绿却什么也没证明。#5720 是实测标本 —— 两段被标记的 hook 示例写着 beforeUpdate(ctx: any),读的 ctx.services 在 hook 上下文 里根本不存在(引擎逐键构造九键、沙箱十键均不产),照抄的 hook 会无条件抛 PERMISSION_DENIED;同一个 any 此前还掩盖了 #5605 的 ctx.session?.positions。 现在提取阶段(extractFromFile 之后、写 build dir 之前)对每个被标记块做 AST 扫描, 对「本身就是 any」的标注失败:参数、变量、属性、返回类型、类型别名,以及 as any / satisfies any / 尖括号断言,报到 页面:行:列 并给出两条处方。断言与局部变量 一并纳入,不是为了对称:只管入参的规则会被「参数标红时作者顺手做的那一步编辑」 绕过 —— 把 any 下移一行(const c: any = ctx)或塞进访问((ctx as any).services)。 嵌套 any(Record<string, any> / any[] / Promise<any>)刻意不报,与 check-exported-any.ts 划的是同一条零误报线。 基线为一处三条:content/docs/protocol/kernel/lifecycle.mdx 的生成式迁移示例逐字复现 os generate migration 的 Knex 输出(packages/cli/src/commands/generate.ts 产出 up(db: any) / (table: any)),且不 import 任何 @objectstack/spec —— 给它标注类型会让 文档对 CLI 的实际产物说谎,故按处方二去掉其 os:check 标记;余下 207 块全部编译通过。 --self-test 红/绿双向覆盖,并把 页面行号换算(bodyStartLine + line - 1)钉成字面量; 包脚本改为「先自测再审计」,与 check:exported-any / check:dual-source-exports 一致。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014wsZeReNTqiceBfLb5Pyf5
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
本 PR 不发布任何东西:`packages/spec` 的 `files` 不含 `scripts/`,改动只有一个开发 脚本、`package.json` 的 `scripts` 字段接线,以及一行渲染为空的文档注释。 pr-automation.yml 的 changeset-check 在 #5292 之后把三条路排了优先级,并把空 frontmatter changeset 明确降为 LAST RESORT:它与标签不等价 —— 标签是门级豁免、不 向 changesets/action 提供任何输入;空 changeset 是真实输入,当待处理集合全为空时 action 走 "hasChangesets && !hasNonEmptyChangesets" 分支,打印 "All changesets are empty; not creating PR" 后 0 秒返回,Release 仍然全绿(#4898 即以此静默卡住 17.0.0-rc.2)。且空 changeset 不指名任何包,正文到不了任何 CHANGELOG。 故按该工作流自己的处方走路线 2。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014wsZeReNTqiceBfLb5Pyf5
|
CI 红签名判读(PM 座位,会话 15:42–15:47Z 窗口内 4 个 check 红(No other open PR may claim the same issue / Flag docs affected / Validate Package Dependencies / Check Changeset),抽验 3 个 job 日志签名逐字一致:runner 引导阶段 处置:4 个 run 的失败 job 已原样重投(201 已入队)。若重投再次同签名失败 = 平台故障未过,继续等窗口再投,⛔ 不改代码;出现任何其它签名才是真问题,按新问题诊断。@dev:无需对这批红做任何改动。 Generated by Claude Code |
📓 Docs Drift CheckThis PR changes 1 package(s): 112 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
|
队列踢出判读与重投(PM 座位,会话 本 PR ~22:0xZ 入队后被移出(未合并;同窗口队头 pr-6034、pr-6012 亦被踢且 main 未动)——归因今日 GitHub Actions 平台事故对 merge_group 构建的持续 churn,非本 PR 签名(PR 级检查此刻 Generated by Claude Code |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 31132803246 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
|
队列踢出分诊(PM 座位,会话 Generated by Claude Code |
Fixes #5943
前提复核(先于实现)
对
origin/main(739f496)实测,issue 前提成立:packages/spec/scripts/check-skill-examples.ts已有两道反空转断言 —— orphan marker、零块fail()—— 但没有任何any相关检查;any入参 3 条,全在同一块内。这道门补的是什么
os:check标记是作者的声明:「这段应当能编译」。块内一旦出现裸any,声明即空转 —— 该值上的每一次属性访问都不再被检查,tsc全绿却什么也没证明。#5720 是实测标本:两段被标记的 hook 示例写着beforeUpdate(ctx: any),读的ctx.services在 hook 上下文里根本不存在(引擎逐键构造九键、沙箱十键均不产),照抄的 hook 会因可选链短路无条件抛PERMISSION_DENIED;同一个any此前还掩盖了 #5605 的ctx.session?.positions。实现落在 issue 建议的位置:
extractFromFile之后、写 build dir 之前,对每个被标记块做 AST 扫描(ts.createSourceFile),报到页面:行:列并给出两条处方。三个「待承接方实测后定」的细节,按实测定下
1. 范围 —— 入参 + 断言 + 局部变量,但只管「本身就是
any」的位置。判定条件是
parent.type === node:参数、变量、属性、返回类型、类型别名,以及as any/satisfies any/ 尖括号断言。嵌套any(Record< string, any >、any[]、Promise< any >)刻意不报 —— 与check-exported-any.ts划的是同一条零误报线(该脚本原文:「a type withanysomewhere inside it is NOT flagged … drawing the line here keeps the gate at zero false positives so red keeps meaning broken」)。把断言与局部变量一并纳入,不是为了对称,而是因为只管入参的规则会被「参数标红时作者顺手做的那一步编辑」绕过:把
any下移一行(const c: any = ctx)或塞进访问((ctx as any).services),缺陷分毫未动而门重新变绿。实测代价为零:全库 208 块里as any0 条、const/let: any0 条。2. 既有基线 —— 3 条,一次改净,不建棘轮。
3 条全在
content/docs/protocol/kernel/lifecycle.mdx:515/516/524,同一个生成式迁移示例。该块逐字复现os generate migration的 Knex 输出(packages/cli/src/commands/generate.ts确实产出up(db: any)与(table: any)),且不 import 任何@objectstack/spec—— 给它标注类型会让文档对 CLI 的实际产物说谎,typecheck 它也证明不了任何 spec 契约。故按门自己给的处方二处理:去掉该块的os:check标记(标记是渲染为空的注释,页面正文一字未改)。余下 207 块全部编译通过,无棘轮文件、无豁免名单 —— 基线是零并保持为零。3.
--self-test—— 红/绿双向,外加误报边。跑真实的
extractFromFile,三个 fixture:.mdx):[docs] runtime-services 的 hook 示例在教ctx.services—— hook 上下文从来没有这个键,照抄的 hook 会拒掉每一次写入 #5720 的原形beforeUpdate(ctx: any),断言恰好 1 条命中、where === 'parameter \ctx`'`、页面行号字面量 9;.md):四个非入参位置(as any/const loose: any/type Loose = any/ 返回any)各一条,行号逐条钉死;HookContext后 0 条,并同块塞入Record< string, any >、any[]、'any'字面量联合、注释里的英文 "any" —— 四种形状真实存在于语料,报任何一个都会逼出一次无缺陷的全库改写;同文件另有一个未标记块写着ctx: any,断言只提取到 1 块(门只审作者标记过的东西)。页面行号换算(
bodyStartLine + line - 1)被钉成字面量而非重算 —— 那是会静默漂移的一环,指错行的诊断比没有诊断更糟。用 AST 而非正则,是因为语料是散文:
'any'出现在字符串字面量联合里、JSDoc 里、以及注释中的普通英文。实测正则按行扫会报出 3 条这类行,无一是类型标注。包脚本改为
--self-test && audit,与check:exported-any/check:dual-source-exports一致(CI 该段的注释原文就是「Self-tests first, like exported-any」)。反向验证(方向先判、后跑)
预判:红。在改文档之前、门刚写完时对真实语料跑,应当报出探针量到的那 3 行。实跑逐字命中:
去掉标记后转绿:
✅ 207 prose examples type-check against @objectstack/spec。验收对照
any⇒ 门红,报页面 + 行号 + 处方--self-test覆盖红/绿两个方向Changeset:走
skip-changeset标签,不是空 changeset派单给的先例是
.changeset/per-package-typecheck-coverage.md式的空 frontmatter changeset。实测后没有照搬,因为该先例早于 #5292 对这条处方的修正:pr-automation.yml的changeset-check现在把三条路排了优先级,并把空 frontmatter changeset 明确降为 LAST RESORT,理由是它与标签不等价 ——changesets/action提供任何输入,不可能影响发布;hasChangesets && !hasNonEmptyChangesets分支,打印 "All changesets are empty; not creating PR" 后 0 秒返回 —— 无 version PR、无 publish,而 Release 那一跑仍然全绿。这就是 空 changeset 会静默卡死已 version 的发布:Release run 全绿,但 npm 和 Docker 什么都没发(17.0.0-rc.2 现在就卡着) #4898,它静默卡住了 17.0.0-rc.2。本 PR 确实不发布任何东西:
packages/spec的files字段(dist/json-schema/liveness/prompts/src/**/*.zod.ts/ …)不含scripts/,改动只有一个开发脚本、package.json的scripts字段接线,以及一行渲染为空的文档注释。故按工作流自己的处方走路线 2:已在 PR 建好后立即打上skip-changeset(与既有size/m做并集写入,不覆盖 bot 刚打的标签),并撤下先写的那份空 changeset。本地验证
check:skill-examples(自测 + 审计):✅ 207 prose examples type-check against @objectstack/specpnpm --filter @objectstack/spec typecheck:通过(tsc --noEmit+check:test-typecheck)scripts/**不在两个 tsconfig project 内,故另跑tsc --ignoreConfig --strict单文件校验,0 errorpnpm --filter @objectstack/spec exec vitest run --maxWorkers=2:325 files / 8308 tests 全通过pnpm exec eslint packages/spec/scripts/check-skill-examples.ts:0pnpm check:doc-authoring:362 files cleannode scripts/check-nul-bytes.mjs:OK(5779 tracked text files,无裸控制字节)不在本单范围
#5837(spec artifact 分片)正在改读三个生成产物的packages/spec/scripts/**;本文件不读authorable-surface.json/json-schema.manifest.json/api-surface.json中的任何一个,build-schemas.ts/build-docs.ts/.gitattributes一律未碰,确认无交叠。🤖 Generated with Claude Code
https://claude.ai/code/session_014wsZeReNTqiceBfLb5Pyf5