Skip to content

feat(spec): $icontains(ASCII 折叠域)+ $contains 族钉死大小写敏感 + $regex 退役指引表 (#5701) - #5752

Merged
os-zhuang merged 3 commits into
mainfrom
claude/issue-5701-regex-retire-icontains
Aug 6, 2026
Merged

feat(spec): $icontains(ASCII 折叠域)+ $contains 族钉死大小写敏感 + $regex 退役指引表 (#5701)#5752
os-zhuang merged 3 commits into
mainfrom
claude/issue-5701-regex-retire-icontains

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#5701

#4706 维护者裁决 B 案的契约半边。纯声明 + case-set + DEBT 台账,不引入任何活体拒收,不改任何驱动代码 —— 五个后端今天怎么答,落地后还怎么答。

裁定摘录(#5701 的 2026-08-06「维护者裁决转录」)

裁定本 PR 的落点
Q1A —— $icontains 折叠域 = ASCII-only(A-Z/a-z),明写进 zod .describe() 与文档,边界显著标注StringOperatorSchema.$icontains.describe() + 文档 Callout(café 不匹配 CAFÉ)
Q2A —— $contains / $startsWith / $endsWith 同批钉死为大小写敏感;filter.zod.ts:139 那句「backend level」按 PD #13 留明写取代记录StringOperatorSchema 文档块「This SUPERSEDES a recorded decision」:原句原样引用 + 五面实测分歧表
Q3B —— spec 只声明数据;新建 RETIRED_FILTER_OPERATORS,收窄 FilterConditionSchema,引入活体拒收filter.zod.ts 新增纯数据表($regex / $options),Object.freeze,处方点名 $icontains
Q4B —— 新建姊妹 case-set,expectRejection 判别式在新文件定义,五 driver 记实测 DEBT,main 不红新增 packages/spec/src/data/filter-text-conformance.ts + 门禁 5 条 DEBT
$istartsWith / $iendsWith 本批不加未加

用例面对照表(派发要求 6 条 → FILTER_TEXT_CASES)

#派发要求落地用例期望
1$icontains ASCII 双向折叠命中...matches an upper-case row from a lower-case comparand / ...from an upper-case comparand['1','2'],两向对称
2ASCII-only 域 pinASCII-only: a lower-case non-ASCII comparand does NOT match its upper-case row + 镜像['4'] / ['3'] —— 全 Unicode 折叠两向都返回 ['3','4'],两向都错
3% / _ / 正则元字符作字面量$icontains treats % / _ / . as a literal ... + $contains treats _ as a literal character too['5'] / ['7'] / ['9'] / ['7']
4空串 / 非字符串比较值拒收(ADR-0112)an empty $icontains comparand is REFUSED / a non-string ... is REFUSEDexpectRejection,code: 'INVALID_FILTER'
5Q2=A pin:$contains 大小写敏感$contains is case-SENSITIVE ×2、$startsWith$endsWith$notContains['2'] / ['1'] / ['1'] / ['2'] / 8 行
6$regex 拒收 pin,信息含 $icontains$regex is REFUSED, and the refusal names $icontains$regex with $options、悬空 $optionsexpectRejection + mustMention$icontains

九行 fixture 成对设计(ASCII 大小写 / 非 ASCII 大小写 / % / _·.),每对只差一个受测字符,所以错答返回的是看得见的错 id,而不是碰巧相同的行数。

filter-text-conformance.test.ts 用一个按声明语义写的参考求值器把整张表跑了一遍 —— 表里每个 expected 都由 ASCII 折叠语义复算出来,不是手数的;另外两条断言证明这张表非空洞:全 Unicode 折叠必须恰好在那两条 ASCII-only 用例上给出不同答案。

⚠️ 一处判断点:$icontains暂不进FILTER_OPERATORS(请重点审这段)

派发口径是「$icontains 入词表」。实施时实测发现 FILTER_OPERATORS 不是词表,是运行时白名单,有两个消费者从它派生而非重述:

  • driver-memorySUPPORTED_FIELD_OPERATORS = new Set([...FILTER_OPERATORS, '$regex', '$options']),是它形状门禁的接受集合;而 memory-matcherdefault: 分支是 break(注释写明「Unreachable through match: the shape gate refuses an operator this driver does not evaluate」)。
  • service-analyticsobjectql-echo-operator-coverage.test.ts 断言其编译器对每个成员都渲染出谓词。

实测(先写预测,再跑):把 $icontains 加进 FILTER_OPERATORS、重建 spec dist 后,在 driver-memory 内探针得到:

SUPPORTED_FIELD_OPERATORS.has('$icontains') = true
gate: NONE — ACCEPTED BY THE GATE
match({name:'zzz'}, {name:{$icontains:'acme'}}) = true // 谓词被静默丢弃

一行不该命中的记录命中了。谓词被丢不是收窄而是放大,在 RLS 读作用域上是越权读(#3948),且发生在任何后端能回答该算子之前。这与派发的三条硬约束(不动驱动代码 / 不引入活体行为 / main 不红)直接冲突。

因此本 PR 的落点:$icontains 声明在 StringOperatorSchema / FieldOperatorsSchema / Filter< T >(已核实这三处没有任何运行时白名单消费者 —— NormalizedFilterSchema 是它们唯一的消费者,而运行时无人用它 parse filter,故此处声明是惰性的),FILTER_OPERATORS 保持不变,并在其文档块写明这条过渡与解除条件。

这个差异不是无声的:filter-operator-vocabulary.test.ts 把「声明面 − 执行面」钉死为恰好 { $icontains },双向断言 ——

若维护者认为应当强行入表并同批修 driver-memory,请驳回本段,我按新口径重做(那会把本单从「零驱动改动」变成跨 #5702 领地)。

反向验证:预测 vs 实测

#事先预测实测
P1入表后 driver-memory 门禁接受$icontainshas() = true,门禁无拒收
P2接受后匹配器 default: break 使谓词被丢 → 放大不该命中的行返回 true
P3service-analytics 算子覆盖门禁变红前两轮测量作废,第三轮才成立 —— 见下✅(重测后)
P4不入表则五驱动在 FILTER_TEXT全判 DEBT(非红)矩阵 25 covered / 5 DEBT / 0 exempt,门禁 OK

全仓 $regex 清点 —— 无一处需要翻转,逐处说明

派发要求「examples / 测试 / 文档中现存 $regex 用法随本 PR 翻转」。实测结论:这三类里没有一处「使用」 —— 全是拒收 pin、历史注释,或明确划归他单的活体。逐处:

位置性质处置
examples/**skills/**零命中——
content/docs/**零处 $regex 过滤用法;唯一相关是 search 展开那句「in-memory driver matches with a case-insensitive regex」已改:改写为新契约 + 现状偏差 Callout 指向 #5702
service-analyticsread-scope-sql / 两处 *-not-null-safe 测试$regex 作「编译器必须拒收的算子」,本身就是拒收 pin保留(翻成 $icontains 会毁掉断言意图)
service-analytics 两处 objectql-*operator*.test.ts#5557 历史注释 + 一个刻意模拟 driver-memory $regex 分支的替身引擎保留,随 #5702 该分支消失而去
packages/rest/analytics-filter-refusal-envelope.test.ts:292钉死 read-scope-sql 对 $regex 的拒收报文保留(已是拒收 pin)
packages/formula/matches-filter.test.ts:95$regex 作 fail-closed 的「未知算子」样本保留(退役后它「更是」未知算子)
plugin-auth:1 生产者 + 3 测试替身全仓唯一活生产者,在认证路径上#5710
objectql/having-filter.ts(+test)、四个驱动消费者#5702
.changeset/*.md 四份待发布的历史 changeset不改写既成记录

不触清单(派发 ⛔ 项,已逐条核对)

plugin-auth/objectql-adapter.ts(#5710)、driver-sql / driver-turso / driver-memory / objectql having-filter(#5702)、component.zod / hook.zod / api-routes / kernel-contracts、content/docs/releases/

conversions/registry.ts 未触发 —— 退役的不是 authorable key(spec 从未声明 $regex),ADR-0087 D2 无对象可登记,与上轮结论一致。#4923 无冲突(其 #5731 已合入,本分支已 merge)。

一处需要更正上轮口径:StringOperatorSchema确实在 authorable-surface 轨道上,gen:schema 因此新增了恰好一个键 data/StringOperator:$icontains(纯新增,删除门禁不涉及),已随本 PR 提交。FieldOperatorsSchema 不在该轨道(全文件零命中),所以那一处声明不产生生成物变化。

顺带记录的两处实测(不在本 PR 修,已附着到 #5702)

  1. driver-memory 的 $contains 有两种大小写答案:查询路径 / 分析面走 new RegExp(escapeRegex(v), 'i')(不敏感、全 Unicode),参考匹配器 memory-matcher.match()includes(敏感)。上轮调研只读到后者,本 PR 的 DEBT 条目已按实测改写。
  2. driver-mongodb 的未知算子拒收逃出 ADR-0112 信封:default: 抛裸 new Error,而同文件的 unsupportedFilterError(另三处在用)才带 INVALID_FILTER / 400。

两条都写进了 DEBT 台账条目正文(实施者读台账即可看到),并在 #5702 留了评论。

验证输出(均在合入最新 origin/main 之后重跑)

check:generated ✓ All 10 generated artifacts are up to date.
(合并后 os-regen 驱动挂起 api-surface.json / authorable-surface.json,
--fix 只重生成这两个;authorable-surface.base.json 不动 ——
它是删除门禁的锚点,main 只在「删键」时前移,本单只加键,
check:authorable-surface 原话:trails the merge base by 5 key(s) — expected)
check:driver-conformance
OK self-test: detects driven / unused / re-declared fixtures, discovers both axes,
and holds the dead-root hard error
driver conformance matrix (5 drivers x 6 case-sets) —— FILTER_TEXT 列五格全 DEBT,其余全 ok
check-driver-conformance: OK — 25 covered cell(s), 5 in the DEBT ledger, 0 exempt.
pnpm --filter @objectstack/spec test
Test Files 319 passed (319)
Tests 8136 passed (8136)
pnpm --filter @objectstack/spec typecheck
tsc --noEmit ✓
check:test-typecheck: OK — @objectstack/spec's test layer compiles

P3 反向验证(重测,红→绿闭环)

# 反事实:$icontains 进 FILTER_OPERATORS,重建 spec dist
PATCH add: applied
--- Failed Tests 2 ---
FAIL ... > covers every operator the spec declares — no case is missing from the table
AssertionError: expected [ '$between', '$contains', ...(13) ] to deeply equal [ ...(14) ]
FAIL ... > $icontains renders a predicate in the echo
AssertionError: $icontains echoed no WHERE — the predicate was dropped
Test Files 1 failed (1) Tests 2 failed | 24 passed (26)
# 撤销 + 字节级校验 + 重建
PATCH remove: applied
RESTORED byte-identical
Test Files 1 passed (1) Tests 25 passed (25)

比预测更强:我只预测了词表等值断言变红(第 1 条)。实测多出第 2 条 —— $icontains echoed no WHERE — the predicate was dropped,即 analytics 编译器把这个谓词静默丢掉了。这是在第二个消费者身上独立复现了与 driver-memory 同一个「放大」缺陷,而不是同一处的两种说法。

过程更正(如实记录):这个测量的前两轮都作废过。第一轮两臂同红(模块收集期失败,不是断言失败),原因是新工作树没预构建 service-analytics 依赖链 —— 失败形态与「你的改动弄坏了 import」一模一样;若没有事先设好对照臂,这轮会被误读成 P3 已验证。第二轮反事实根本没被应用:perl -0pi -e "s/\Q$WITHOUT\E/.../"\Q 只关元字符、不关插值,$contains / $notContains 被 perl 当成自己的变量插成空串,两臂又都成了对照。第三轮改用 node 做替换,并把「已应用 / 已还原」从假设改成断言(出现次数必须恰为 1,还原后必须与备份字节相同),才拿到上面的红绿闭环。


Generated by Claude Code

… case-sensitive, retire $regex (#5701)
The contract half of #4706's maintainer ruling (B). Declaration only: no live
rejection, no driver code touched, every backend answers exactly what it
answered before.
- `$icontains` on StringOperatorSchema / FieldOperatorsSchema / Filter: contains,
ignoring ASCII case (A-Z against a-z) and nothing else. The boundary is stated
for authors — `café` does NOT match `CAFÉ` — because ASCII is the one fold all
five backends can deliver: SQLite without ICU (so turso and sqlite-wasm too)
folds ASCII only, and promising Unicode would repeat the defect this retires.
- `$contains` / `$notContains` / `$startsWith` / `$endsWith` are declared
CASE-SENSITIVE, superseding the recorded "Case sensitivity should be handled at
backend level" (Prime Directive #13 — the old sentence is quoted in place so
the reversal is findable from the sentence a reader remembers). What that
non-guarantee bought, measured: three different answers across five backends,
two of them inside driver-memory alone (query path folds full Unicode, the
reference matcher is case-sensitive).
- `RETIRED_FILTER_OPERATORS`: pure data, no behaviour. `$regex` and `$options`
with prescriptions naming `$icontains`. Nothing rejects them here — the five
existing refusal sites are wired to it by #5702, and #5710 must flip the one
live producer (plugin-auth's ObjectQL adapter, on the authentication path)
first or sign-in breaks.
- `FILTER_TEXT_CASES` (`data/filter-text-conformance.ts`): the shared standard
for case folding, literal comparands and the `$regex` refusal, with the
`expectRejection` discriminant `filter-logic-conformance.ts` deliberately never
grew. A sibling table rather than rows in that one, whose charter excludes both
axes and warns against red rows for work nobody is dispatched to do. Registered
in check:driver-conformance with one MEASURED DEBT row per driver pointing at
#5702 — 25 covered / 5 DEBT / 0 exempt, main stays green.
`$icontains` is deliberately NOT in `FILTER_OPERATORS` yet. That array is a
runtime allowlist, not a word list: driver-memory's shape gate derives its
ACCEPTED set from it while its matcher's `default:` arm breaks. Measured by
adding it early and rebuilding — the gate stopped refusing and
`match({name:'zzz'}, {name:{$icontains:'acme'}})` returned true, i.e. the
predicate was silently dropped and every row matched. A dropped predicate widens
rather than narrows, which on an RLS read scope is a permission bypass (#3948).
It joins the array in the PR that implements it; `filter-operator-vocabulary.test.ts`
pins the difference at exactly {$icontains} so neither adding a second staged
operator nor clearing this one can happen silently.
Claude-Session: https://claude.ai/code/session_018fxLGQdatPbBUvCgiVxg6D
Co-authored-by: Claude <noreply@anthropic.com>
…g main
The merge driver (`merge=os-regen`, AGENTS.md §11) deferred both artifacts
rather than text-merging them, and `pre-commit` collects that debt. Regenerated
from the MERGED source, so the union includes #5721's ActionSession entries
alongside this branch's $icontains / FILTER_TEXT additions.
`authorable-surface.base.json` is deliberately NOT bumped: it is the deletion
gate's anchor, main only moves it when a key is REMOVED, and this branch only
adds. `check:authorable-surface` confirms it — 'trails the merge base by 5
key(s) — expected right after a surface change lands'.
Claude-Session: https://claude.ai/code/session_018fxLGQdatPbBUvCgiVxg6D
Co-authored-by: Claude <noreply@anthropic.com>
@vercel

vercelBot commented Aug 6, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 6, 2026 3:57am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

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

  • content/docs/ai/agents.mdx(via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx(via @objectstack/spec)
  • content/docs/ai/skills.mdx(via @objectstack/spec)
  • content/docs/api/client-sdk.mdx(via @objectstack/spec)
  • content/docs/api/environment-routing.mdx(via @objectstack/spec)
  • content/docs/api/error-catalog.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx(via @objectstack/spec)
  • content/docs/api/index.mdx(via @objectstack/spec)
  • content/docs/automation/approvals.mdx(via @objectstack/spec)
  • content/docs/automation/connectors.mdx(via @objectstack/spec)
  • content/docs/automation/flows.mdx(via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx(via packages/spec)
  • content/docs/automation/hooks.mdx(via @objectstack/spec)
  • content/docs/automation/index.mdx(via @objectstack/spec)
  • content/docs/automation/webhooks.mdx(via @objectstack/spec)
  • content/docs/automation/workflows.mdx(via @objectstack/spec)
  • content/docs/concepts/architecture.mdx(via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx(via packages/spec)
  • content/docs/concepts/index.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx(via packages/spec)
  • content/docs/concepts/north-star.mdx(via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx(via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx(via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx(via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx(via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx(via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx(via @objectstack/spec)
  • content/docs/data-modeling/index.mdx(via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx(via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx(via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx(via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx(via @objectstack/spec)
  • content/docs/deployment/cli.mdx(via @objectstack/spec)
  • content/docs/deployment/tenancy-modes.mdx(via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx(via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx(via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx(via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx(via @objectstack/spec)
  • content/docs/getting-started/examples.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx(via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx(via @objectstack/spec)
  • content/docs/kernel/cluster.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx(via packages/spec)
  • content/docs/kernel/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx(via packages/spec)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/spec)
  • content/docs/kernel/services.mdx(via @objectstack/spec)
  • content/docs/permissions/authorization.mdx(via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx(via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx(via @objectstack/spec)
  • content/docs/permissions/positions.mdx(via @objectstack/spec)
  • content/docs/permissions/rls.mdx(via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx(via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx(via @objectstack/spec)
  • content/docs/plugins/development.mdx(via @objectstack/spec)
  • content/docs/plugins/index.mdx(via @objectstack/spec)
  • content/docs/plugins/packages.mdx(via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx(via @objectstack/spec)
  • content/docs/protocol/diagram.mdx(via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx(via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx(via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx(via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx(via @objectstack/spec)
  • content/docs/releases/index.mdx(via @objectstack/spec)
  • content/docs/releases/v12.mdx(via @objectstack/spec)
  • content/docs/releases/v13.mdx(via @objectstack/spec)
  • content/docs/releases/v16.mdx(via @objectstack/spec)
  • content/docs/releases/v17.mdx(via @objectstack/spec)
  • content/docs/releases/v9.mdx(via @objectstack/spec)
  • content/docs/ui/actions.mdx(via @objectstack/spec)
  • content/docs/ui/apps.mdx(via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx(via @objectstack/spec)
  • content/docs/ui/dashboards.mdx(via @objectstack/spec)
  • content/docs/ui/forms.mdx(via @objectstack/spec)
  • content/docs/ui/index.mdx(via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx(via @objectstack/spec)
  • content/docs/ui/setup-app.mdx(via @objectstack/spec)
  • content/docs/ui/translations.mdx(via @objectstack/spec)
  • content/docs/ui/views.mdx(via @objectstack/spec)

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.

@github-actionsgithub-actionsBot added size/xl documentation Improvements or additions to documentation protocol:data tests tooling labels Aug 6, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 6, 2026 04:59
@os-zhuang
os-zhuang added this pull request to the merge queueAug 6, 2026
Merged via the queue into main with commit 85d95e7Aug 6, 2026
25 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5701-regex-retire-icontains branch August 6, 2026 05:11
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:datasize/xlteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

spec: $regex 按 ADR-0049 退役 + $icontains 入算子词表与 FILTER_LOGIC_CASES(#4706 裁决 B 案 · 契约半边,先行)

2 participants

@os-zhuang@claude