docs(skills): objectstack-ui 补 searchableFields 章节 —— 工具栏搜索的收窄语义与失败边界 (#6675) - #6898
Merged
os-project-manager merged 1 commit intoAug 9, 2026
Merged
Conversation
…#6675) `skills/objectstack-ui/SKILL.md` 此前对 `searchableFields` 零覆盖:该键唯一出 现的位置是生成的 `references/react-blocks.md`(由 packages/spec 生成,手改会顶掉 `check:skill-refs`)。而列表视图工具栏的搜索框正是 view 级收窄(ADR-0061)和 #4254 点号路径 400 真正打到 UI 作者的地方。PR #6670 已补上 docs 侧 (`content/docs/ui/views.mdx` 的表格行),skill 侧仍是空的 —— 而 skill 才是 AI 作者在授权时真正加载的东西。 新增 "Toolbar Search (`searchableFields`, ADR-0061)" 一节,落在 "Configuring a List View" 既有结构里(End-User Quick Filters 之后、Sorting 之前), 两个 `os:check` 例子 + 边界表 + 逐字错误文案。 不只教 happy path —— 每条边界都实测过,分两层: - **允许集由对象决定**:对象声明了 `searchableFields` 就是那份清单本身 (按存在性过滤,**不看类型**);没声明才走 auto-default(name 字段 + 文本类列)。 因此在声明了 `['subject','account_id']` 的对象上,view 收窄到 `['account_id']` 这个 lookup 是**放行**的,而收窄到对象没列进去的 `text` 列反而被**拒绝** —— 判据是集合成员,不是字段类型。 - **一条坏 entry 会让该列表的每一次搜索 400**:客户端把这份声明逐字回显为 `$searchFields`,入口门在引擎之前就拒,炸的是整个搜索框而不是变窄的结果。 - **`searchableFields: []` 不是"关掉搜索"**:三层都把空数组当作缺省 —— 客户端 整个不发这个 key,入口门把零长度覆盖当没覆盖,引擎回落到对象的允许集。写 `[]` 比写 `['subject']` 搜得**更宽**,与字面直觉相反。真要去掉搜索框是 `userActions: { search: false }`,另一个键。 - 相关记录标题只能靠**存储镜像字段**,点号路径永远被拒;完整处方(镜像字段、两条 维护 hook、为什么不能用 formula)指向 objectstack-data,不在此重述。 验证:两个 `os:check` 块除了过 `check:skill-examples` 的 tsc,还逐字抽出来跑过 真正解析它们的运行时 schema —— `defineView` → `ViewSchema` → `ObjectListViewSchema`(`packages/spec/src/ui/view.zod.ts`),确认 `searchableFields` 与 `userActions.search` 都能穿过 parse 存活。 `packages/lint/src/validate-searchable-fields.test.ts` 新增一组 skill-parity 用例, 把本节逐字引用的两条诊断和三条边界钉住(skill 经 `npx skills add` 发给第三方, 措辞漂了而没人回看 skill,发出去的就是平台已经没有的规则)。`[]` 那条的承重断言 刻意放在 `resolveSearchFields` 上而不是 lint 上 —— lint 对空数组是"什么都没产出" 式的绿,不可能因回归转红。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F8q5J1MQyocgtNspb15fSn
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckNo hand-written docs reference the 0 changed package(s). ✅ |
os-project-manager
marked this pull request as ready for review
August 9, 2026 03:31
os-project-manager
deleted the
claude/issue-6675-searchablefields-skill-coverage
branch
August 9, 2026 03:47
This was referenced Aug 9, 2026
Open
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 #6675
背景
skills/objectstack-ui/SKILL.md对searchableFields零覆盖。该键在这个 skill 里唯一出现的位置是生成的references/react-blocks.md(由packages/spec生成,手改会顶掉check:skill-refs)。而列表视图工具栏的搜索框,正是 view 级收窄(ADR-0061)和 #4254 点号路径 400 真正打到 UI 作者身上的地方。PR #6670 已经把 docs 侧补上了(
content/docs/ui/views.mdx的表格行),skill 侧仍然是空的 —— 而 skill 才是 AI 作者在授权时真正加载的东西。前提复核:在
origin/main@e5bd76859上git grep searchableFields -- skills/objectstack-ui/SKILL.md仍为零,反向对照(skills/objectstack-data/、skills/objectstack-query/)有命中,扫描器是好的。卡片前提成立。改了什么
新增 "Toolbar Search (
searchableFields, ADR-0061)" 一节,落在## Configuring a List View既有结构里(End-User Quick Filters 之后、Sorting 之前),两个os:check例子 + 边界表 + 逐字错误文案。按派单要求,不只教 happy path;每条边界都实测,不是推断。
1. 允许集由对象决定,判据是集合成员而不是字段类型
searchableFields实测:对象声明
searchableFields: ['subject', 'account_id'](account_id是 lookup)时,view 收窄到['account_id']放行,引擎拿到searchFields = ["account_id"];同一个对象上收窄到对象没列进去的account_name(一个text列)反而 400 INVALID_FIELD。一个 lookup 通过、一个 text 被拒 —— 类型判据在这里是反的。2. 一条坏 entry 会让该列表的每一次搜索 400
客户端把这份声明逐字回显为
$searchFields,入口门assertSearchFieldsAreSearchable在引擎之前就拒。炸的是整个搜索框,不是"变窄的结果"。os validatesearchableFields: []searchable-field-unknown400 INVALID_FIELDsearchable-field-unknown400 INVALID_FIELDsearchable-field-unsearchable400 INVALID_FIELD两条诊断都是 error,
os validate直接失败 —— 章节里逐字给出了作者真正会撞到的两条文案。3.
searchableFields: []不是"关掉搜索"三层都把空数组当作缺省:客户端整个不发这个 key(长度守卫),入口门把零长度覆盖当没覆盖直接 return,引擎回落到对象的允许集。所以写
[]比写['subject']搜得更宽,与字面直觉正好相反 —— 这是作者最需要、也最容易猜错的一条。真要去掉搜索框是userActions: { search: false },另一个键,附了可粘贴的例子。4. 相关记录标题
点号路径永远被拒(搜索轴不解析 traversal)。只能用存储的镜像字段;完整处方(镜像字段、维护它的两条 hook、为什么 formula 不行)指向 objectstack-data,不在此重述。注意本节只引用诊断的
message,没有引用其hint—— 后者的 "text/formula" 措辞正是 #6673 在处理的问题。验证:例子是按真正解析它的 schema 校验的
这是发布给客户的 skill,不是内部笔记,所以每个例子都要能粘贴即用。
check:skill-examples把两个os:check块抽出来对着构建产物@objectstack/spec的.d.ts跑tsc --noEmit——✅ 208 prose examples type-check,其中skills/objectstack-ui/SKILL.md:354与:437就是这两块。defineView→ViewSchema→ObjectListViewSchema(packages/spec/src/ui/view.zod.ts,即ListViewSchema去掉userFilters)。确认searchableFields与userActions.search都穿过 parse 存活(['case_number','subject']/false),不是被 strip 掉。测试
packages/lint/src/validate-searchable-fields.test.ts新增一组 skill-parity 用例。skill 经npx skills add发给第三方,措辞漂了而没人回看 skill,发出去的就是平台已经没有的规则 —— 与validate-rls-predicate-enforceability.test.ts钉住 data skill 打印的 RLS 谓词同一个理由。覆盖:逐字钉住两条诊断文案;三条边界;以及两个方向都钉 —— 对象声明集内的 lookup 放行 / 集外的 text 被拒,和它的镜像(对象没声明时,auto-default 的类型清单才说了算)。
[]那条的承重断言刻意不放在 lint 上:checkSearchableFieldList对零长度数组提前返回,就算删掉那个提前返回,entry 循环也没东西可迭代 —— "lint 干净"是因为什么都没产出,不可能因回归转红。所以承重断言放在resolveSearchFields(入口门与引擎共用的那一份 resolution)上。反向验证(方向事先预判 —— 两条都预判为红,两条实测也都红):
is outside object改成is not within object→ 逐字断言转红。resolveSearchFields的空数组回落收窄(requested.filter(...)直接返回)→[]那条承重断言转红,expected [] to deeply equal [ 'subject', 'case_number', …(1) ]。第 2 条第一次跑是绿的,因为
@objectstack/spec/data解析到dist/,改src/根本没生效(AGENTS.md §9 陈旧产物陷阱)。重新 build spec 后才转红 —— 记在这里,因为"改了源码测试还绿"在这个 workspace 里默认要先怀疑没重建。兄弟 skill 排查(派单要求,未扩大 diff)
searchableFields覆盖objectstack-dataobjectstack-querysearch.fields收窄 + 400)objectstack-uiobjectstack-api只在 API 方法表里提到 derived 的search动词,两个 skill 都没有文档化$前缀参数族,属于另一个面而非同类缺口结论:同类缺口只有
objectstack-ui一处,已补;未改动任何兄弟 skill。顺带发现(未在本 PR 修)
已另开 #6897(未认领):
content/docs/ui/views.mdx:106那行说 view 的searchableFields里 lookup "is refused",实测只在对象的允许集排除它时才拒 —— 对象声明了它就放行。文档把集合成员判据写成了类型判据,会让作者删掉一份能用的配置。本 PR 范围只在 skill,按 Prime Directive #10 不夹带。门
check:skill-examples✅ /check:skill-frame-sync✅ /check:skill-compatibility✅ /check:skill-frame-freshness✅check:doc-authoring✅ /check:nul-bytes✅ /check:role-word✅ /check:adr-anchors✅ /check:quick-reference-counts✅ /check:org-identifier✅ /check:published-files✅pnpm --filter @objectstack/lint test→ 67 files / 1753 tests 全绿;typecheck绿origin/main同口径对比),TEST_DEBT 账本零增量无 changeset
只改
skills/**与一个测试文件,不发布任何包 —— 与同类前例一致(PR #6670 本身、#6233、#6030、#5989 均无 changeset)。已打skip-changeset。Generated by Claude Code