Skip to content

feat(search): 通用拼音搜索 — locale 开关 + 名称字段 __search 拼音伴随列(#2486, ADR-0097)#3027

Merged
os-zhuang merged 2 commits into
mainfrom
claude/vibrant-euler-of05nx
Jul 16, 2026
Merged

feat(search): 通用拼音搜索 — locale 开关 + 名称字段 __search 拼音伴随列(#2486, ADR-0097)#3027
os-zhuang merged 2 commits into
mainfrom
claude/vibrant-euler-of05nx

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

实现 #2486:在 ADR-0061 现有 $search 之上,为"输拼音"补一条名称字段伴随列,纯加性 — 其它搜索行为一律不动。方案记录为 ADR-0097

实现(按 issue 组件清单)

平台开关(locale 推导默认值)

  • @objectstack/types 新增 resolveSearchPinyinEnabled({ locales? }):显式 OS_SEARCH_PINYIN_ENABLED 永远优先;未设置时由配置 locale 推导(挂任意 zh-* 即默认开)。
  • 单一决策点:CLI serve 是唯一看得到 stack i18n 配置的地方 — 在那里解析一次并把结果回写进环境变量,之后每个消费方(各 engine 的 SchemaRegistry、插件门控)通过无参形式读到同一个答案。
  • 开关开时 serve 自动把 pinyin-search 能力加入 requires 并加载插件(与 mcp 的 default-on 模式同形态)。无字段级元数据,不存在 ADR-0049 的死标记。

编译期物化(1 列 / 对象)

  • packages/objectql/src/search-companion.ts(新):provisionSearchCompanionSchemaRegistry.registerObject 里、provisionPrimary 之后运行 — 只对 ADR-0079 解析出的 display/name 字段挂隐藏列 __search(hidden/readonly/system/searchable:false/index:true),migration 走 driver syncSchema 正常加列(ADR-0045 加性物化)。
  • 安全护栏(ADR-0061 D5 延伸,fail-closed):带 requiredPermissions(FLS)、hidden、secret/虚拟类型的源字段一律不进伴随列 — 在唯一的 eligibility gate 强制,不靠作者记得。

plugin-pinyin-search(纯 hook,对齐 plugin-sharing primary-BU 投影先例)

  • 全局 beforeInsert/beforeUpdate hook:只在源字段出现在本次写入时重算(无写放大);pinyin-pro 懒加载(开关关/非中文部署零成本);全拼+首字母同列存储("张伟""zhangwei zw");改名为非中文时清空 blob(无 stale 召回)。
  • 写路径兜底:kernel:bootstrapped 分页幂等回填 + rebuildSearchCompanion 对账/重建入口(绕过 hook 的 bulk import / 迁移直写)。

查询期接入(纯加性)

  • expandSearchToFilter:对象存在 __search 列时,每个拉丁 term 额外 OR { __search: { $contains: term } };中文 term 跳过(直打源列)。
  • resolveSearchFields 原样不动;$searchFields override 与 allowed 求交后天然够不到伴随列(已测)。$or+$contains 所有驱动已支持,零驱动改动

通用化接缝

SEARCH_COMPANION_NORMALIZERS = ['pinyin'] — 只实现 pinyin,简繁/全半角/重音折叠共用同一列与机制。

验证

showcase 真机端到端(pnpm dev --fresh,zh-CN locale 自动点亮,插件出现在加载列表):

输入 结果
$search=zhangwei(全拼) 命中 张伟 ✓
$search=zw(首字母) 命中 张伟 ✓
$search=张(中文) 命中 张伟 ✓(源列直搜,行为不变)
$search=ada(拉丁原文) 命中 Ada Lovelace ✓(不变)
$searchFields=__search 越权 求交为空 → 回退默认集,伴随列不可被 override 指定 ✓
自动生成列表/表单 __search 被 hidden 过滤,不出现 ✓

说明:__search 会随单记录默认响应返回(null 或拼音 blob)— 与现有 hidden 系统列(organization_id 等)的平台行为完全一致,且值只派生自人人可读的名称字段,无新信息面。

测试:objectql 880(新增 29:eligibility gate / provisioning / registry 集成 / 查询期 OR / override 不可达)、types 14、cli 509、plugin-pinyin-search 14(真实 pinyin-pro)全绿。开关默认关 → 全套既有测试即"纯加性"证明。

范围 / 非目标(同 issue)

相关性排序 / typo 容错 / 整词防噪属 Tier-2;不物化非名称字段、不引入 search blob、不改 searchableFields;不依赖数据库分词器,方言/引擎无关。多音字用 pinyin-pro 默认启发式(P2 字典覆盖留 issue 跟踪)。

下游:objectstack-ai/objectui#2112 分层选人器 picker 仅发 $search,拼音透明点亮,无需 UI 改动。

Closes #2486

🤖 Generated with Claude Code

https://claude.ai/code/session_01RMugRriiNv3nsnmLczfhuY


Generated by Claude Code

…on column (#2486)

Implements ADR-0097 (extends ADR-0061 Tier-1 $search, purely additive):

- OS_SEARCH_PINYIN_ENABLED platform switch (resolveSearchPinyinEnabled in
  @objectstack/types): explicit env wins; when unset the CLI boot path
  derives the default from the stack's configured locales (any zh-* -> on)
  and stamps the decision back into the env so the per-engine
  SchemaRegistry and the plugin gate read the same answer.
- Compile-time materialization: SchemaRegistry.registerObject provisions a
  hidden `__search` companion column (hidden/readonly/system/searchable:false,
  indexed) for the ADR-0079 display/name field, right after provisionPrimary.
  FLS-restricted (requiredPermissions), hidden, secret/virtual source fields
  never feed the companion (ADR-0061 D5, fail-closed).
- New @objectstack/plugin-pinyin-search: global beforeInsert/beforeUpdate
  hooks fill the blob (full pinyin + initials, "zhangwei zw") via lazy-loaded
  pinyin-pro only when the source field is in the write; paged idempotent
  boot backfill on kernel:bootstrapped plus rebuildSearchCompanion reconcile
  entry for hook-bypassing writes.
- Query-time: expandSearchToFilter ORs { __search: { $contains: term } } into
  each latin term's clause when the column exists; resolveSearchFields is
  unchanged and the companion is unreachable via $searchFields overrides.
  CJK terms skip the clause. Zero driver changes.

Verified end-to-end on the showcase app (zh-CN locale auto-enables):
$search=zhangwei / zw / 张 all recall 张伟; latin and CJK source-column
search behavior unchanged. Tests: objectql 880 passed (29 new), types 14,
cli 509, plugin-pinyin-search 14.

Closes #2486

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

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 16, 2026 6:25am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file tests tooling size/xl labels Jul 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 4 package(s): @objectstack/cli, @objectstack/objectql, @objectstack/plugin-pinyin-search, @objectstack/types.

27 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/skills-reference.mdx (via packages/cli)
  • content/docs/api/client-sdk.mdx (via @objectstack/cli)
  • content/docs/api/data-flow.mdx (via @objectstack/cli)
  • content/docs/api/environment-routing.mdx (via @objectstack/cli)
  • content/docs/api/error-catalog.mdx (via @objectstack/cli)
  • content/docs/automation/hook-bodies.mdx (via packages/cli)
  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/objectql)
  • content/docs/data-modeling/formulas.mdx (via packages/objectql)
  • content/docs/deployment/backup-restore.mdx (via @objectstack/cli)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/objectql)
  • content/docs/deployment/self-hosting.mdx (via @objectstack/cli)
  • content/docs/deployment/vercel.mdx (via @objectstack/objectql)
  • content/docs/getting-started/cli.mdx (via @objectstack/cli)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/cli)
  • content/docs/kernel/runtime-services/data-service.mdx (via packages/cli)
  • content/docs/kernel/runtime-services/index.mdx (via packages/cli)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/objectql)
  • content/docs/kernel/services.mdx (via @objectstack/objectql)
  • content/docs/permissions/authentication.mdx (via @objectstack/cli, @objectstack/objectql)
  • content/docs/plugins/index.mdx (via @objectstack/objectql)
  • content/docs/plugins/packages.mdx (via @objectstack/cli, @objectstack/objectql, @objectstack/types)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/objectql)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/cli)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/cli)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/objectql)
  • content/docs/releases/implementation-status.mdx (via @objectstack/cli, @objectstack/objectql)
  • content/docs/releases/v9.mdx (via @objectstack/objectql)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

…version group

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RMugRriiNv3nsnmLczfhuY
@os-zhuang
os-zhuang marked this pull request as ready for review July 16, 2026 07:12
@os-zhuang
os-zhuang merged commit 1c58abd into main Jul 16, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/vibrant-euler-of05nx branch July 16, 2026 07:12
os-zhuang added a commit that referenced this pull request Jul 16, 2026
…strable out of the box (#3034)

Follow-ups to the merged pinyin-search feature (ADR-0097, PR #3027):

- environment-variables.mdx: new "Search" section documenting OS_SEARCH_PINYIN_ENABLED (locale-derived default, explicit override, what it gates).
- queries.mdx: "Pinyin recall" subsection under Full-Text Search.
- showcase seed: CJK-named account (华宁科技) and contacts (张伟/王芳/李雷) so the auto-enabled pinyin search is demonstrable out of the box.

Verified on a fresh showcase boot: $search=zhangwei/zw/wf/huaning/hnkj all recall the seeded CJK records.

Refs #2486

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RMugRriiNv3nsnmLczfhuY
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

通用拼音搜索:locale 开关 + 名称字段拼音伴随列(接入 ADR-0061,纯加性)

2 participants