fix(vscode): 片段展开出来的 metadata 现在过得了 spec,并加了一条常驻 gate 让它别再过期 (#4917) - #5031
Merged
Conversation
… that keeps them there (#4917) `snippets/objectstack.json` is a metadata PRODUCER — whatever `os-view-grid` expands to is the first `.view.ts` an author (human or AI) ever writes — and nothing in this repo had ever parsed that output. So the snippets drifted out of the spec in silence. An audit of all eight found five broken: - os-view-grid: `list.defaultSort` / `list.pageSize` (never declared on ListViewSchema), plus `type` / `objectName` on the CONTAINER, which is the flat-view-where-a-container-goes mistake ViewSchema's own guidance names. Now `defineView({ object, list: { sort: [{field, order}], pagination: { pageSize } } })`. - os-flow: node `name` / `next` and a top-level `trigger` block. Now `defineFlow` with the binding on the START node's config and explicit edges. - os-agent: `tools`, removed in protocol 17 (#3894). Now `skills`. - os-stack: manifest missing the required `id` / `type`. - os-field-lookup: `reference: { object, labelField }`; `reference` is a plain object name, the label field is `displayField`. Separately all five module snippets imported `{ Data }` / `{ UI }` / `{ Automation }` / `{ AI }` from the package root. Those namespace re-exports were removed as untree-shakeable (packages/spec/src/index.ts), so the first line of every scaffold did not resolve. They now import from the subpath and author through the domain's validating factory (ObjectSchema.create, defineView, defineFlow, defineAgent, defineStack) — which parses at authoring time and, as a value import, fails loudly instead of degrading to `any` (issue #2035's rationale, applied to the scaffolds themselves). The recurrence is the actual fix. os-view-grid broke because #4001 closed ListViewSchema and no gate anywhere could see a snippet body; the next strictness batch would have broken another one identically. The package now has a `test` script that expands every snippet, evaluates it against the real @objectstack/spec, and safeParses the authored literal with the schema the runtime uses. Three independent failure modes — the expansion does not evaluate, the literal does not parse, an import names a binding the spec no longer exports — plus a negative control asserting the pre-fix shape is still rejected, a plan table that fails when a snippet arrives ungated, and a lockstep assertion on the engines.protocol major so that stamp cannot rot. Tests live in their own tsconfig project (the extension is CommonJS for the VS Code host; the gate is ESM) and are wired into `typecheck`, so they are not hidden from `tsc --noEmit`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4917
先核实:议题点的两个键确实被拒,但坏掉的不止一个片段
对着本分支基线
bf1edef的ViewSchema实测,议题描述属实:但议题只实测了
os-view-grid。按派发要求把全部 8 个片段都展开过了一遍 safeParse,结果是 5 个坏的,不是 1 个:os-view-gridlist.defaultSort、list.pageSize;外加 container 上的type/objectName—— 后者正是ViewSchema自己的 guidance 点名的「把扁平 view 写在 container 位置」defineView({ object, list: { …, sort: [{ field, order }], pagination: { pageSize } } })os-flowname/next(键是label+ 一个edges数组),以及顶层trigger块defineFlow,对象绑定放在 START 节点的config: { objectName, triggerType },edges显式声明os-agenttools—— 协议 17 已退役(#3894)skills: []os-stackmanifest缺必填的id和type{ id, namespace, version, type, name, engines }os-field-lookupreference: { object, labelField }——reference是个裸对象名reference: 'target_object'+displayField排序 / 分页现在声明在哪是读 schema 定的,没猜:
ListViewSchema.sort是{ field, order }[](注意是order,不是片段原来写的direction),pageSize在PaginationConfigSchema里,挂list.pagination。list.defaultSort在ListViewSchema上从来没声明过 —— 议题的判断是对的,不是改拼写能解决的,是键的位置本来就错。一个议题没提、但更早就断的东西:import 那一行
5 个整文件片段全部写着
import { Data } from '@objectstack/spec'(以及{ UI }/{ Automation }/{ AI })。这些根命名空间 re-export 早就被删了(Node ESM 下不可 tree-shake,packages/spec/src/index.ts里有整段说明,还配了no-restricted-imports规则)。也就是说:片段的第一行就解析不了,根本轮不到 metadata 形状出问题。改成从 subpath 导入,并且一律走该 domain 的校验工厂(
ObjectSchema.create/defineView/defineFlow/defineAgent/defineStack)—— 这是 examples 里的既有写法,也是 eslint 里 issue #2035 那条规则写明的理由:工厂在.parse()时就校验,而且是 value import,断了会硬报错,不会静默降级成any。结构性问题的回答:之前没有任何东西在 CI 里 parse 过片段产物
全仓搜
snippets/objectstack.json只有三处命中:片段文件自己、package.json的 contributes 声明、README 的表格。没有测试、没有脚本、没有 CI job 读过它。所以 #4001 关掉两个键的时候,不可能有任何东西变红 —— 下一批严格化会以完全相同的方式再打坏一个片段。本 PR 加的常驻校验(
packages/vscode-objectstack/test/snippets.test.ts+test/snippet-harness.ts),接进该包自己的pnpm test,跑一次 2.5 秒:${n:default}→default,${n|a,b|}→ 第一个选项(VS Code 预选的那个),${n}→pn,$0→ 空。这四种形式都是全定义的,所以「作者拿到的是什么」是一个确定的字符串;遇到表以外的形式($TM_FILENAME、transform、嵌套占位)直接抛,而不是悄悄展开成没人会看到的文本 —— 这就是派发单里问的「占位符导致展开不平凡」的处理方式:不放弃,但把模型不了的形式变成红。ts.transpileModule转译 +require走真正的@objectstack/spec(不 stub —— stub 正是让 gate 停止跟踪它所守护的契约的办法)。工厂调用被录下来,拿到作者写的那个字面量(pre-parse、pre-defaults)。safeParse那个字面量。.d.ts,因为Data是个类型命名空间,任何运行时检查都看不见它消失。这就是抓住上面那半个 bug 的那条。双向证明
把片段文件换回本 PR 之前的版本再跑,11 条判红:
报错文案例:
修好之后 21/21 绿。
另外三条负控制常驻在测试文件里,所以「红」这件事本身也不依赖手动复现:重新引入 #4001 关掉的那两个键必须被拒、引入一个 spec 不再导出的绑定必须被查出、模型不了的占位符形式必须抛。
两条结构性防护
PLANS里有条目,否则那条断言直接红 —— 新片段没法绕过 gate 落地。engines.protocol锁步:os-stack里那个^17是硬编码的字面量,正是本议题这一类会烂掉的东西。scripts/sync-template-versions.mjs只管create-objectstack的模板,不知道这个文件,所以锁步断言写在这条 gate 里,读 spec 自己的package.json大版本。大版本一升,这里就红。改动范围
只动 VS Code 扩展包 + 一个 changeset。没有碰
lint.yml、没有碰根package.json、没有碰任何共享脚本或配置 —— 根pnpm test/pnpm typecheck就是turbo run test|typecheck,该包新加的test脚本自动被 turbo 收进去(test任务本来就dependsOn: ["^build"],spec 会先构建),CI 不需要任何改动。pnpm-lock.yaml的变动仅来自该包新增的 devDependencies。测试放在自己的 tsconfig project(
tsconfig.test.json):扩展本体必须是 CommonJS(VS Code host 要求),gate 是 ESM(要import.meta.url定位 shipped 的片段文件),两者没法共用一份compilerOptions。typecheck脚本串了两次tsc,所以测试没有被排除在tsc --noEmit之外(AGENTS.md 那条)。check:type-check-coverage已验证仍然 OK。验证
顺手记的一个旁支(未修,已另开)
#5028 —— 扩展的
contributes.jsonValidation指向./schemas/objectstack.schema.json,这个文件在仓库里不存在,也没有任何脚本生成它;README 却写着 "Validatesobjectstack.jsonfiles against the bundled schema"。同一类 declared ≠ enforced,但落点和修法都不同(要决定扩展到底要不要 bundle 一份 JSON Schema),不塞进本 PR。已按 Prime Directive #10 未认领立单。Generated by Claude Code