fix(app-shell): previews 只读 spec 声明的键(#3275,合并 #3281) - #3285
Merged
xuyushun441-sys merged 1 commit intoAug 3, 2026
Conversation
The previews and the console samples were wrong TOGETHER, so the gallery looked healthy. objectui#3266 corrected the samples and the gallery immediately rendered LESS: agent TOOLS/KNOWLEDGE, skill TRIGGER PHRASES, app's per-item row and `Dashboard` badge, datasource CAPABILITIES all vanished or degraded. Those blocks were only ever lit up by metadata that cannot be saved. Renderer half of that finding; same fix as PR #3258. Deleted (retiredKey tombstones, rejected by name): `agent.tools` (#3894), `agent.knowledge` (#3896), `skill.triggerPhrases` (#3896). AppPreview/AppNavCanvas: read the `type` discriminator and each branch's own target key; route via `resolveHref`, the shell's own nav -> URL mapping. `homePageId` renders as the nav item id it is, resolved to the entry it selects, never as a path. DatasourcePreview: `capabilities` rendered as the boolean-flag OBJECT it is (`Array.isArray` lit up only for the form the schema refuses); dropped `driver ?? d.type` and the `isDefault ?? default` pill. SkillPreview: trigger conditions as three columns field/operator/value, replacing `cond.expression ?? cond.value` under a `cond.type` gutter. ValidationPreview (#3281): removed the `unique`/`async`/`custom` branches (each redirects to the layer that owns the job), the `condition ?? expression` and `pattern ?? regex` aliases for keys that never existed, fixed `conditional` to read `when`, and added the missing `json_schema` branch. `validation.object` stays — anchors.ts matches standalone rules by it. Verified in the preview gallery before/after per designer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NVPjPzmmAJ2Ngtvgg5MSRa
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
xuyushun441-sys
marked this pull request as ready for review
August 3, 2026 10:57
xuyushun441-sys
deleted the
claude/issue-3275-previews-drop-retired-keys
branch
August 3, 2026 10:57
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 #3275
Fixes #3281
预览与样例此前是「一起错」才看起来正常。objectui#3266 把样例改对之后,画廊反而少画了东西 —— 因为这些预览读的键 spec 现在明确拒收。本 PR 是那件事的渲染器另一半,做法照抄 objectui#3236 / PR #3258 对
ToolPreview的同型修复。预览渲染一个保存时会被拒的键,等于告诉作者「这样写是对的」,直到发布才被打脸 —— 对 AI 生成的元数据,这正是过期键藏身并扩散的地方。所以下面每一处读取都是删掉,而不是留个兜底(AGENTS.md #0.1)。
浏览器实测 before → after
方法与 #3266 相同:
apps/console预览画廊 +?only=< type >隔离单个设计器,Playwright headless 抓取。after 一次,把改动git stash后再抓一次 before,所以下表是量出来的,不是推出来的。Landing: /Home: home → Home(id + 它选中的条目)Dashboard徽标 =itemDashboard徽标 =dashboard✅ #3266 记录的那条Docs徽标 =linkDocs徽标 =url(spec 词汇)crm_welcome/account/sales_order/sales_overview/https://docs.example.com✅ 路径行回来了TOOLS / No direct tools (skills can provide them)空态TRIGGER CONDITIONS (1)→COND | sales_orderFIELD / OPERATOR / VALUE→objectName / eq / sales_order✅CAPABILITIES: readOnly, queryAggregations✅ #3266 记录的那条CONDITION: amount > 0内容与旧输出不同是正常的 —— 它现在来自 spec 合法的键;判据是合规草稿渲染出有内容的区块,而不是空区块。
改了什么
删掉的退役键读取(都是
retiredKey()墓碑,按名字被拒):agent.tools(objectstack#3894,agent 能碰到的 tool 就是它 skills 声明的那些,ADR-0064)、agent.knowledge(objectstack#3896,从不 scope 检索)、skill.triggerPhrases(objectstack#3896,phrases 从未与用户消息匹配过)。AppPreview/AppNavCanvas——AppSchema.navigation是按type的判别联合且每支.strict()。两处都无视了判别键:kind 靠it.object/it.dashboard猜,路由靠it.path ?? it.href ?? it.route ?? it.url,landing 靠landingRoute ?? landing ?? defaultRoute ?? '/'。这些一个都不是键(landing已被 objectstack#4001 移除),所以读法是完全反的。现在:type即徽标;目标读各分支自己的键;路由交给resolveHref—— shell 自己的 nav → URL 映射(NavigationRenderer写明它是唯一真源,useNavPins/SearchResultsPage已在共用),所以预览里的链接就是运行时会走的链接。homePageId按它本来的样子渲染成 nav item 的 id,并解析出它选中的条目,绝不当路径画。DatasourcePreview——capabilities是DatasourceCapabilities布尔标志对象,而预览判的是Array.isArray,正好只对 schema 拒收的旧数组形态亮灯。改为列出置true的标志。同时删掉driver ?? d.type(schema 的提示就是type→driver)与isDefault ?? default的 default 芯片(路由在 stack 层的datasourceMapping声明,不在 datasource 上)。SkillPreview—— trigger-conditions 表原本在cond.type栏下读cond.expression ?? cond.value,于是合规条件只显示出 value 一列。改为三列field / operator / value,直接对应SkillTriggerConditionSchema;缺必填格时明说missing,而不是留个看起来「正常」的空格。ValidationPreview(#3281,PM 中途并入)—— 画了 9 个规则类型,而联合只有 6 个。unique/async/custom被validation.zod.ts同一段话裁掉(规则必须是对单条记录的确定性、同步、无副作用谓词),三者现在各自指向真正负责的那一层(唯一性用 unique 索引 —— SELECT-then-INSERT 天生有 TOCTOU 竞态;async 属表单层;custom 属生命周期钩子)。随之删掉两个别名回退:condition ?? expression、pattern ?? regex——expression和pattern从来不是任何分支的键。另有两支本来就读错了:conditional读的是condition而非它的when(合规规则显示「No expression set」,现在还会渲染嵌套的then/otherwise),json_schema压根没有分支(合规规则显示「Unknown rule type」)。一个刻意没有删的读取
validation.object保留。单子建议「确认没有别的调用方会传 object-scoped 草稿之后删掉」—— 确认结果是有:anchors.ts注册了独立的validation资源,并以anchorByField('object')匹配,所以独立校验规则确实带这个键。联合没有的键,不等于都是残留。验证
pnpm exec vitest run packages/app-shell/→ 264 files / 2272 passed, 1 skipped, 0 failedpnpm --filter @object-ui/app-shell type-check→ 干净通过(tsc --noEmit+ typetests)eslint改动的 11 个文件 → 0 errors;warning 18 条,而origin/main上同样 6 个源文件的基线是 19 条 —— 没有新增 lint 债ToolPreview.test.tsx模板补了断言:喂合规草稿断言区块渲染出来,喂带退役键的陈旧草稿断言不渲染(agent 那条更强:合规草稿与仅多带tools/knowledge的草稿 DOM 完全相同)本 PR 按当前 pin 住的
@objectstack/spec@17.0.0-rc.1实现 —— 在那个已发布版本里homePageId是合法的z.string().optional(),且 objectui 自己的AppContent.resolveLandingRoute()确实在读它。但 objectstack
main(尚未发布)已用 #4667 / ADR-0049 把app.homePageId也退役了,墓碑文案写的是「no shell ever read it」—— 这与AppContent.tsx:876的实际读取相矛盾。等 objectui 升到 spec 17.0.0 正式版时,要动的不只是这个预览,还有AppContent的落地路由解析。已在out_of_scope_findings记录,未在本 PR 处理(超出 scope fence,且需要维护者对「谁说了算」拍板)。顺带记录(未在本 PR 修)
AgentPreview侧栏读的d.permissions是合法键;d.access在 spec 里是array,预览未渲染它 —— 不是缺陷,只是没覆盖。🤖 Generated with Claude Code
https://claude.ai/code/session_01NVPjPzmmAJ2Ngtvgg5MSRa