You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
[finding] QueryParams carries [key: string]: any (packages/types/src/data.ts:133), so a misspelled query key (filter for $filter) type-checks and is silently dropped by convertQueryParams — the index signature that let the published testing guide teach a test that could never pass #7497
Filed by the skills lane seat (session session_01LraLgQVGq8egUwfYZpbYt1) from the #7494 flight (PR #7496, report comment 5524854506, out-of-scope finding 3). Unassigned, bare, for triage; landing surface packages/types (a published contract) plus every caller that leans on the extra keys.
Measured by the flight at 20cb8db and re-read by the seat at 11:17Z
packages/types/src/data.ts:43 opens export interface QueryParams {; :133 closes it with [key: string]: any;.
packages/data-objectstack/src/index.ts:3817convertQueryParams(params?: QueryParams) reads only the dollar-prefixed keys, so any other key is accepted by the type and dropped at runtime.
The published guide skills/objectui/guides/testing.md Pattern 7 taught adapter.find('contacts', { filter: { active: true } }) and asserted the client saw that filter: it compiled, the key was dropped, and the assertion could never match — for as long as the fence existed. PR fix(skills): teach the honest test-double idiom in testing.md, retiring its three bare-any rows #7496 corrects the guide; the type that made the mistake invisible is unchanged.
Prior art, both closed and both on the guide or the $filter value type, not on the index signature: #6006 (data-integration guide taught unprefixed keys the adapters drop) and #3909 ($filter declared as a record while the sink takes an AST).
Scope
Measure first: every consumer that passes or reads a non-dollar key through QueryParams (grep the adapters, the console and the apps; the index signature may be carrying real extras for one adapter). Report the census before choosing.
Tighten the contract so a typo is a compile error: drop the index signature, or replace it with a narrow, named extension point (for example a single extra bag, or a template-literal key type for dollar-prefixed extensions) that the readers actually consume. Contract-first: declared = enforced.
Any caller that breaks is either a real extra (route it through the named extension point) or a latent typo (fix it and say so — those are the wins).
Published contract: a narrowing is breaking for callers that relied on extras; the changeset states the semver judgement with the census behind it. needs:contract-review on the PR by clause ② (acceptance set changes).
Size M. Fixes this card. ⛔ Not in scope: the guides (PR #7496 covers the testing guide); $filter's own value type (#3909).
The published guide skills/objectui/guides/testing.md Pattern 7 taught adapter.find('contacts', { filter: { active: true } }) and asserted the client saw that filter: it compiled, the key was dropped, and the assertion could never match — for as long as the fence existed.
Measure first: every consumer that passes or reads a non-dollar key through QueryParams (grep the adapters, the console and the apps; the index signature may be carrying real extras for one adapter). Report the census before choosing.
⚠️ 这次普查决定第 2 步是"直接删"还是"换成具名扩展点"——两者的迁移成本差一个数量级。
三条候选形状(卡片给的,都可接受):删掉 index signature / 换成一个具名的 extra bag / 用模板字面量键类型只放行 $-前缀扩展。⭐ 第三条最贴合实际语义(convertQueryParams 读的就是 dollar-prefixed 键),值得优先评估。
调用方崩了怎么办,卡片给了二分法,照用:"either a real extra (route it through the named extension point) or a latent typo (fix it and say so — those are the wins)"。⭐ 后一类是这次改动的收益,请在 PR 里逐条列出来 —— 那是证明这次收紧值得的最好材料。
Activity
os-zhuang commentedon Sep 5, 2026
分诊 —
domain:spec/priority:p2/pm:queue/finding/needs:contract-review锚定 (anchoring):
packages/types/src/data.ts的已发布契约 ⇒domain:spec。在
origin/maina472b07上复核 —— 站点成立,行号未漂同一文件
:1265还有一个[key: string]: any,但它不是同一个缺陷:AggregateResult是聚合结果(每个条目一个分组 + 聚合值),开放形状在那里是合理的。⛔ 收紧QueryParams时不要顺手动它。另记:
convertQueryParams是类方法(this.convertQueryParams(params),data-objectstack/src/index.ts:2452处调用),不是自由函数 —— 用git grep "function convertQueryParams"找不到它。⛔ 接手者按方法形式找。⭐ 这张卡最有力的证据:它已经造成过一次真实的、发布出去的错误
⭐ 这不是"理论上可能出错",而是一个已发布的指南教了一个永远不可能通过的测试,而类型系统全程沉默。PR #7496 修了指南;让这个错误隐形的那个类型没动——这正是本卡。
定级理由 ——
priority:p2filter而非$filter)类型检查通过,运行时被丢掉,无警告。作者拿到的是"查询没生效"而不是"你写错了"。QueryParams调用方。ObjectKanbanSchemarequiresgroupField(zero read sites) and declares neithergroupBynorlimit— no workingobject-kanbannode is assignable to any declared type #7322 同族("照着声明写就一定错,且两侧都不报"),同样定 p2。不上 p1:无数据损坏、无权限面;且失败方向是"查询更宽"而非"越权"——服务端仍按权限返回。
⛔ 定型:收紧已发布契约 ⇒ 踩人工底线
卡片自己标了
needs:contract-review(Clause ②,accept-set 变更),本席采纳并加上该标。⛔ 分诊席不裁决。⛔ 给执行席的边界 —— 卡片的第 1 步是硬前置
⭐ 先普查再选形状,⛔ 不要先删 index signature:
三条候选形状(卡片给的,都可接受):删掉 index signature / 换成一个具名的
extrabag / 用模板字面量键类型只放行$-前缀扩展。⭐ 第三条最贴合实际语义(convertQueryParams读的就是 dollar-prefixed 键),值得优先评估。调用方崩了怎么办,卡片给了二分法,照用:"either a real extra (route it through the named extension point) or a latent typo (fix it and say so — those are the wins)"。⭐ 后一类是这次改动的收益,请在 PR 里逐条列出来 —— 那是证明这次收紧值得的最好材料。
⛔ 不在范围内(卡片明列):指南本身(PR fix(skills): teach the honest test-double idiom in testing.md, retiring its three bare-any rows #7496 已覆盖测试指南);
$filter自己的值类型(观察:QueryParams.$filter声明为Record< string, any >,但仓内下沉口早已往里送 ObjectQL AST 数组 #3909,已关闭但是另一个轴)。⛔ 不要用
as any或@ts-expect-error让调用方通过 —— 那会把一处宽契约换成 N 处逃逸,且门禁看不见。⛔ 分诊席不认领、不派单、不写码、不裁决 accept-set 变更。
Generated by Claude Code