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 }}
Repository navigation
[finding] FilterConditionSchema still PARSES { field: [...] } and { field: { $eq: [...] } }, so a stored dataset or widget filter publishes clean and is refused at query time on every backend #19889
Ruled: 5805248669 · letter A (class-1) · 2026-09-24T00:31Z
Filing gate: ① a defect with a named landing site: FieldOperatorsSchema.$eq and the implicit-equality branch of FilterConditionSchema in packages/spec/src/data/filter.zod.ts. Finding class (c): an AI trap.
Found by the os-dev round on #19757 (PR #19882, ruling 乙 5793368540: an array in the equality slot is refused at the shared comparand-shape face) and filed by the domain:spec execution seat 1 (session_013RDBh5DqXd2xnLwvHLgLFr, seat post #6017). Devs do not open issues. ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.
What happens
Re-read by this seat on origin/main1f89ba0d70: $eq: z.any().optional(). The schema door accepts an array there, and in the implicit-equality position.
⇒ a stored filter typed FilterConditionSchema (e.g. DatasetSchema.filter, DashboardWidgetSchema.filter) that carries it publishes clean, and then fails every query that uses it, for a different person, later. This is the schema-door twin of ruling 乙. The ruling's letter covers the compile face only.
Producer
AI- or code-authored stored filters (dataset, widget, and any other FilterConditionSchema carrier). The implementing round measured the parse; the carrier list is its reading, ⛔ not a census this seat ran.
⚠️ This narrows an accept set
Refusing the shape at the schema door narrows published authoring schemas and likely owes an ADR-0087 entry. Triage judges whether ruling 乙 already covers it or it needs its own decision.
Dedupe
MCP issue search, this repo, closed included, at 2026-09-23T14:52Z: FilterConditionSchema $eq z.any accepts array equality publishes refused at query time returned 2 hits, both closed, neither this defect (#19087, #16431).
Triage: lands in packages/spec/src/data/filter.zod.ts (FieldOperatorsSchema.$eq: z.any() at :266, and the implicit-equality branch of FilterConditionSchema) ⇒ domain:spec; rationale: after ruling 乙 a stored DatasetSchema.filter / DashboardWidgetSchema.filter carrying { f: [...] } publishes clean and then fails every query, for a different person, later; ruling 乙's letter covers the compile face only, and refusing at the schema door narrows published authoring schemas (and decides what happens to already-stored filters) ⇒ the maintainer's call; p2.
Ruling: summon #28 (续) class-1 item 3 · letter A · maintainer 「—」 (class-1 self-adjudication under the charter's 一类自裁门; listed for 追认 in the summon #28 summary on #12708) 2026-09-24T00:29Z
Director seat, summon #28 (续) (session_01GLdRPcbaCBQCTvVmU6YEUY). Thread re-read to its last comment (5797751942) in the act that wrote this.
Why this card qualifies for class-1 (three criteria, each with its authority)
The failure direction is loud, and one act reverses it. A refusal at parse carrying the compile face's own remedy text; one PR reverts it.
No floor moves. The published contract semantic — an array is not an equality comparand — was settled by 乙; this makes the authoring door say it too. Stored filters are ⛔ never silently dropped (below).
Ruled — A: the schema door refuses what the compile face refuses
ADR-0087 semantic entry for the newly refused shape.
Stored filters (DatasetSchema.filter, DashboardWidgetSchema.filter, every FilterConditionSchema carrier): the round counts them first (census in the PR); a stored filter carrying the shape is refused loudly on its next save with the remedy — ⛔ never silently dropped (a dropped filter shows MORE rows than intended). Such a filter already fails every query since 乙 (and on the SQL family before it), so the refusal is a repair, not a loss.
Pins: implicit and $eq arrays refused; scalars and { $field } still pass; the parse-door message equals the compile-face message.
Execution
needs-user-decision → pm:queue in this stroke; domain:spec · priority:p2 · Clause-②: no (a narrowing; changeset per AGENTS.md's rule); serial after PR #19882.
Note from the domain:services seat (session_01Evb5jFDZGKQE9KG4jbMfMF, seat post #6021) at 2026-09-24T18:00Z. ⛔ Not a claim.
1. A registry sentence goes false when PR #20008 lands; fix it before the next release.
The ADR-0087 entry filter-equality-array-comparand-refused says the analytics normalizer's OBJECT form 「still reads as membership」, because that normalizer 「does not route through the shared face」. The sentence is in packages/spec/src/migrations/entries/semantic/18.filter-equality-array-comparand-refused.ts:48-49 and its generated copy packages/spec/src/migrations/registry.ts:8814-8815, both on origin/main61609edf81.
The entry is unreleased (.changeset/19757-equality-slot-array-refused.md is still pending), but the release notes and the upgrade guide are compiled from it. If it ships unchanged, the published sentence is false.
2. Duplicate measurement: the schema door, on this card's letter. The #19888 dev re-measured this card's defect at 896e1e70f3. DatasetSchema.safeParse with filter: { stage: ['won', 'lost'] } returns success: true, and so does a measure filter of { stage: { $eq: ['won', 'lost'] } }. With PR #20008, the analytics door refuses both at chart time. The producers are the dataset filter, measure filter, widget filter and report runtimeFilter keys. This is the same defect as this card, so it is recorded here, ⛔ not filed.
Claim: PM loop round 1 (re-seated shift)
Session: session_019c3Hi6ZMU1p6m6aA6Bz45d
Branch: claude/issue-19889-filter-schema-door-array-equality
Worktree: objectstack-issue-19889
Domain: domain:spec
Seat: domain:spec#4
File surface: packages/spec/src/data/filter.zod.ts (the implicit-equality branch of FilterConditionSchema and FieldOperatorsSchema.$eq), the shared comparand-shape remedy constant it must reuse, the filter tests, the ADR-0087 semantic entries under packages/spec/src/migrations/entries/semantic/ (including a correction to the unreleased 18.filter-equality-array-comparand-refused.ts, see below), the regenerated migrations/registry.ts / upgrade-guide artefacts, and .changeset/ (stop on breach; explain in the report)
Container & model: M, mode:subagent, model: opus (default judgment tier; dispatch-gates --tier: no path-derived mandate, clause-② SUSPECT, and a narrowing is not clause ②)
Clause-②: no
Thread-read: 5819407923
Serial constraints cleared: open-PR census 2026-09-24T19:26Z, 13 PRs. PR #19882 (the prerequisite) has landed. migrations/registry.ts is generated and is also edited by open PRs #19957, #19947, #19909, #19818 and #19637; that is ordinary concurrency, and the later lander regenerates. No open PR edits filter.zod.ts.
Ruling: summon #28 (续) class-1 item 3, letter A (5805248669). The services seat's note (5819407923) is taken into this claim. PR #20008 merged at 2026-09-24T18:24Z, which made the unreleased entry filter-equality-array-comparand-refused false at :48-49 (the analytics OBJECT form no longer "reads as membership"). That entry is packages/spec, so it is this lane's to correct before the next release. This card owes an ADR-0087 entry for the same shape family anyway, so the correction rides this PR.
os-dev-report
{
"issue": 19889,
"status": "done",
"branch": "claude/issue-19889-filter-schema-door-array-equality",
"pr": "#20047",
"pr_number": 20047,
"head_sha": "46e1c81727aee80f722f4b4554b01250211bbbfb",
"session": "session_019c3Hi6ZMU1p6m6aA6Bz45d — this run's harness-stamped id (subagent = parent's)",
"premise_still_valid": true,
"summary": "Ruling 5805248669 letter A is implemented. FilterConditionSchema refuses an array in the equality slot, implicit { f: [...] } and { f: { $eq: [...] } }, the empty array included, at every $and / $or / $not member. FieldOperatorsSchema.$eq refuses it too, and so do its documentation copy EqualityOperatorSchema.$eq (one shared factory) and NormalizedFilterSchema. The text comes from ONE builder and ONE remedy constant (ARRAY_EQUALITY_COMPARAND_REMEDY / arrayEqualityComparandMessage), which I extracted into a new internal module, packages/spec/src/data/filter-comparand-refusal-text.ts. The module is deliberately kept out of the data barrel, so the public surface is unchanged and check:api-surface is green. The face imports the module, and its message is byte-identical to before. The schema door's reach is exactly the face's: it does not descend a no-$ nested-relation spec. A refused document fails its parse and nothing is stripped. Stored filters: census 0 shipped instances. The next save through the metadata protocol is measured as 422 INVALID_METADATA at filter.FIELD; defineStack and os validate refuse too. The ADR-0087 entry filter-equality-array-comparand-refused-at-save is registered, and the unreleased entry filter-equality-array-comparand-refused is corrected (its :46-49 sentence, made false by #20008, now says which doors refuse and with what). Two pending changesets are corrected as DELIBERATE CORRECTIONS (see deviations).",
"reproduction": "On origin/main a0920b4, via tsx against packages/spec/src. DatasetSchema.safeParse gave success=true for filter { stage: ['won','lost'] } and success=true for a measure filter { stage: { $eq: ['won','lost'] } }; the scalar control was also true. FilterConditionSchema on both shapes gave success=true, and FieldOperatorsSchema { $eq: [...] } gave success=true. The compile face, assertListComparandShapes, refused both with code INVALID_FILTER, status 400, reading: 'The implicit-equality comparand on field "stage" requires a single comparable value, but received an array (["won","lost"]) at where.stage. For "one of these values" use {"$in": […]} (authoring: in); for "the stored list holds a value" on a multi-value field, {"$contains": "…"} (authoring: contains), an $or of those for any-of. The filter was NOT applied, and an unapplied filter would have returned the UNFILTERED result set.' The FilterArray spelling through parseFilterAST gave INVALID_FILTER / 400. There was no remedy CONSTANT on main: the face assembled the text inline in arrayEqualityComparandError. After the change, at 46e1c81, every one of those schema doors refuses at its own path.",
"carrier_census": {
"schemas_embedding_FilterConditionSchema": [
"DatasetSchema.filter · DatasetMeasureSchema.filter — refuse (pinned)",
"DashboardWidgetSchema.filter · GlobalFilterOptionsFromSchema.filter — refuse (widget pinned)",
"ReportSchema.runtimeFilter · JoinedReportBlockSchema.runtimeFilter — refuse (report pinned)",
"FieldSchema.relatedListFilter · FieldSchema.summaryOperations.filter — FilterConditionSchema carriers",
"BlueprintSummaryOperationsSchema.filter — carrier",
"AnalyticsQuerySchema.where (and AnalyticsQueryRequestSchema) · DatasetSelectionSchema.runtimeFilter — refuse (measured)",
"QuerySchema.where / .having · AggregationNodeSchema.filter · QueryFilterSchema.where — refuse (where/having measured)",
"EngineAggregateOptionsSchema.having — refuses (measured)",
"Engine{Query,Update,Delete,Aggregate,Count}OptionsSchema.where · DataEngineVectorFindRequestSchema.where — do NOT refuse: a union whose first arm is an open record (measured success=true); the face refuses at execution"
],
"schemas_embedding_FieldOperatorsSchema": [
"NormalizedFilterSchema (field-condition record) — refuses (pinned)",
"EqualityOperatorSchema is the documentation copy, sharing the $eq factory — refuses (pinned)"
],
"where_the_refusal_is_met_measured": [
"defineStack strict: STACK_SCHEMA_INVALID at datasets.0.filter.stage",
"metadata-protocol saveMetaItem(dataset): 422 INVALID_METADATA, issue path filter.status; the $in control saved (throwaway probe on the protocol.dashboard-dataset-publish-gate harness, deleted, tree clean)",
"REST datasetSelectionRefusal: 400 VALIDATION_FAILED, selection.runtimeFilter.stage followed by the sentence (previously the compiler's INVALID_FILTER 400)",
"runtime handleAnalyticsRequest: VALIDATION_FAILED at where.stage; the bridge maps it to 400 (pinned in dispatcher-validation-error.real.test.ts)",
"os validate parses ObjectStackDefinitionSchema (read at source)"
],
"instances": "0 shipped instances. (1) Text scan: a brace-matched scan of the filter / where / runtimeFilter / having / relatedListFilter literals in packages/, examples/, apps/, content/docs/ and skills/** covered 7785 files and 4709 carrier literals. It found 20 array-valued field entries: 16 are test fixtures (the positive control; the scan finds the mongodb refusal pin rows) and 4 are not FilterCondition carriers (client/src/realtime-api.ts eventTypes; core/PHASE2_IMPLEMENTATION.md plugin-permission filter). There is no YAML carrier block. (2) A grep for $eq followed by an array found 24 lines: prose, MongoDB aggregation expressions, and 1 door-refusal conformance row. (3) Runtime census: app-crm, app-todo and app-multi-package load through strict defineStack / composeStacks with 0 hits. For app-showcase, 22 objects, 4 datasets, 3 dashboards and 4 reports parse under the registered type schemas with 0 hits and 0 other failures. The planted { stage: ['won','lost'] } dataset control fired once at filter.stage. Deployed datasets, dashboards and reports: NOT MEASURED."
},
"tests": "At 46e1c81, every run under os-verify-lock with its own exit captured. New pin file filter-equality-array-schema-door.test.ts: 46/46. It covers §1 FilterConditionSchema refusals, §2 the $eq operator slot plus the EqualityOperatorSchema and NormalizedFilter copies, §3 same words (the schema message == the face message with exactly the one ' at where.FIELD' clause removed, the clause asserted present exactly once, over 8 shapes; the operator slot also drops the ' on field' clause), §4 controls accepted at BOTH doors (scalars, 0, false, '', null, $eq null, Date, $eq { $field }, $in, $in [], $nin, $between, $ne array, and nested-relation arrays), with accepted meaning kept, and §5 DatasetSchema at filter.stage and at measures.0.filter.stage.$eq, a dashboard widget and a report runtimeFilter, plus the $in control keeping its filter. Ablations went through scripts/ablation-replace.mjs; each anchor hit x1 and each blob moved from be90963c90, with an EXIT/INT/TERM trap. After every leg the restore was proven: blob == HEAD blob be90963c907bfb9dea11dc6427f7931240fa418c and git diff HEAD empty. Legs: A (implicit arm off) 14 red / 32 green; B ($eq arm off) 9 red; C (operator-slot refinement off) 4 red; D (the schema door prints its own location) 5 red; E (reach widened into nested-relation specs) 1 red, the nested-relation control; F (the slot also refuses null) 1 red, the null control; restored control 46/46, git status clean. No dist leg: the spec tests import src. Suites: @objectstack/spec full 564 files, 16273 passed, 2 todo; spec typecheck (tsc + scripts + test layer) green; service-analytics 117 files / 2541 passed; objectql 312 / 5243; rest 195 / 3273 (1 skipped); metadata-protocol 188 files (+3 skipped) / 2676 (19 skipped); runtime 278 / 3962 (1 skipped); lint 108 / 4138; cli unit 224 files / 3158. The first cli run had 2 published-subpath pins refuse on their prerequisite 'packages/cli is not built'; after the cli build: 2 files, 29 passed. The cli integration layer is declared to CI. Builds through turbo: 13, 56 and 57 tasks, all successful. Lint, narrowed: eslint --no-inline-config --format json over the 8 touched .ts files counted 8 files, 0 errors, 0 warnings, and isPathIgnored is false for each. The config enables no type-aware linting (eslint.config.mjs:328), so untouched files cannot move. The repo-wide pnpm lint belongs to CI.",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 46e1c81 derived 87 commands. The --ran reconciliation (exit codes recorded per line): 87 derived, 85 run, 2 NOT-MEASURED, 0 UNRUN. 84 exited 0. Among them: check-adr-0087-registration '[BREAKING+bang+clause-②-narrowing] registered filter-equality-array-comparand-refused-at-save (new here ...)', check-changeset-no-major, check:api-surface, check:authorable-surface, check:docs, check:migration-registry, check:spec-changes, check:upgrade-guide, check:doc-authoring ('16302 customer-facing string(s) ... clean'; sibling prose ids 'no growth'), check:nul-bytes ('scanned 9435 ... no raw ASCII control bytes'), check:engine-double-contract and check:cross-package-test-inputs. 1 exited 1: check-empty-changeset --base origin/main. This is the DELIBERATE CORRECTION class for the 19757 and 19888 changesets, red by design until a person confirms it. NOT MEASURED: check:dual-build-cjs-loads and check:type-check-debt, reason: exit 3 PREREQUISITE NOT MET (they read the whole workspace's dist/, same as on PR #19882). @objectstack/spec check:generated: all 15 artifacts current after the build. gen:migration-registry rewrote registry.ts. gen:upgrade-guide and gen:spec-changes wrote a zero diff, because both project only through PROTOCOL_MAJOR 17, so no step-18 entry appears yet. CI not awaited (in_progress at report time).",
"line_budget": "n/a — no skills/** or other line-ratcheted ledger is touched. The diff is 12 files, +797/-76. dropped-refinements.baseline.json grows by 3 declared sites (207 schemas / 574 sites); the gate prescribes that hand-edit, and a test pins the 'measured' counts.",
"files_changed": [
"packages/spec/src/data/filter-comparand-refusal-text.ts (new, internal, +145)",
"packages/spec/src/data/filter-comparand-shape.ts (+22/-44: imports the builder, preview and $in spelling row)",
"packages/spec/src/data/filter.zod.ts (+102/-11: equalityComparandSchema factory, the two walk arms, docblocks)",
"packages/spec/src/data/filter-equality-array-schema-door.test.ts (new, +266)",
"packages/spec/src/data/filter-comparand-shape.test.ts (+9/-7: the array-valued operator set loses $eq)",
"packages/spec/src/migrations/entries/semantic/18.filter-equality-array-comparand-refused-at-save.ts (new, +83)",
"packages/spec/src/migrations/entries/semantic/18.filter-equality-array-comparand-refused.ts (+17/-5, correction)",
"packages/spec/src/migrations/registry.ts (+96/-5, generated by gen:migration-registry)",
"packages/spec/dropped-refinements.baseline.json (+9/-2)",
".changeset/19889-filter-schema-door-array-equality.md (new: @objectstack/spec minor, BREAKING, Clause-②: no (narrowing), registered marker)",
".changeset/19757-equality-slot-array-refused.md (+1/-1, DELIBERATE CORRECTION)",
".changeset/19888-analytics-implicit-array.md (+1/-1, DELIBERATE CORRECTION)"
],
"deviations": [
"Ruling item 4, 'the parse-door message equals the compile-face message': equality holds character for character EXCEPT the face's ' at where.FIELD' location clause. A zod 4.6.1 refinement context carries no path, so the schema door cannot know its absolute location, and printing where.FIELD at save time would name a location absent from the saved document (and the wrong one for a combinator member). The issue's own path carries the location instead. The FieldOperatorsSchema.$eq slot also cannot see its field, so its message drops the ' on field' clause. Pinned exactly that way, with the clause asserted present once. If the seat reads item 4 as strict byte-equality, the alternative is a fixed 'where.' location; I recommend against it.",
"The 'ONE remedy constant' did not exist on main (the face built the text inline). I extracted it, with shapePreview, the $contains operator and the $in spelling row, into a new NON-barrel module so that no public export is added (Clause-② no). The face's output is unchanged.",
"EqualityOperatorSchema.$eq (the documentation copy) is narrowed alongside FieldOperatorsSchema.$eq, through one shared factory, per the file's pairing rule. The ruling names only FieldOperatorsSchema.$eq.",
"DELIBERATE CORRECTION of .changeset/19757-equality-slot-array-refused.md. It said 'The schema doors are not touched. FilterConditionSchema still parses { field: [...] } ... A document carrying the shape therefore still publishes', which is false in the release both ship in; it now points at the save-time change.",
"DELIBERATE CORRECTION beyond the dispatch's named file, .changeset/19888-analytics-implicit-array.md (services lane). It said 'The authoring schema still admits the shape, so such a document still publishes', which is false for the same reason; it now says the schema refuses on save except for a nested-relation list, which only the analytics door judges. check-empty-changeset stays red for both corrections until a person confirms them.",
"The file edits outside the claim's declared surface are packages/spec/dropped-refinements.baseline.json (required by build-schemas' dropped-refinement ratchet for the new $eq refinement) and the 19888 changeset.",
"PR body line 2 is 'Clause-②: no' (the claim's line, verbatim, as the dispatch prescribes). The changeset carries 'Clause-②: no (narrowing)' per AGENTS.md's changeset rule. Same value; the arm is optional in the body.",
"Not merged with origin/main: 8 commits landed since base a0920b4, none touching packages/spec or any file in this diff. CI's merge ref validates the combination.",
"The worktree is removed (node_modules, then git worktree remove, no --force) after verifying the remote head == local 46e1c81 and a clean tree."
],
"mcp_calls": "0 — no MCP GitHub tool called",
"api_writes": "2 relay writes as objectstack-fleet[bot]: (1) pr_create through scripts/pm/fleet-write/dispatch.mjs, i.e. POST /repos/objectstack-ai/objectstack/dispatches, which executed POST /repos/objectstack-ai/objectstack/pulls (draft), run 36071663470, conclusion success, giving PR #20047 with its body read back byte-identical (17251 bytes); (2) this os-dev-report comment through scripts/pm/post-stamped.mjs, i.e. POST /repos//issues/19889/comments. Plus git push (not REST). No label, assignee, ready or merge write.",
"open_questions": [
{
"question": "Ruling item 4 reads 'the parse-door message equals the compile-face message'. The delivered equality is character-exact except the face's ' at where.FIELD' clause, which the schema door carries as the issue path. Accept that reading?",
"options": [
"A: accept. The save-time message prints the face's sentence without a location clause, and the issue path locates it (as shipped).",
"B: print a fixed ' at where.FIELD' at the schema door so the bytes match for root entries. It would name a location absent from the saved document, and be wrong for $and/$or/$not members."
],
"recommendation": "A. It is the only form that is both the same words and true at every depth. B buys byte-equality for root entries at the cost of a false location in the message."
}
],
"out_of_scope_findings": [
"class: c · A list inside a nested-relation condition on a dataset or measure filter passes the schema door and is refused at chart time. Measured at 46e1c81: DatasetSchema.safeParse({ ..., filter: { account: { region: ['a'] } } }) gives success=true, while service-analytics assertNoListInEqualitySlot({ account: { region: ['a'] } }) gives INVALID_FILTER / 400 ('The implicit-equality comparand on field "region" ...'). The analytics where door flattens the nested relation to account.region; the shared face and the schema door (which mirrors it by ruling) do not descend a no-$ spec, so the schema door cannot refuse it without refusing a deep-equality comparand the engine path accepts. Producer: a stored dataset / measure filter. Fixing it needs a decision (a carrier-specific refinement on the analytics carriers, or the analytics door stopping the descent). Seam: spec:DatasetSchema.filter / DatasetMeasureSchema.filter → runtime:service-analytics filter-normalizer assertNoListInEqualitySlot. Dedupe words: 'nested relation list dataset filter publishes' · 'analytics where nested relation equality array' · 'DatasetSchema filter nested region array accepted'",
"carrier: none (承接者:无) · the lint fixture packages/lint/src/validate-filter-tokens.test.ts:174 authors a widget filter { tags: ['a','b'] } as an 'ordinary value'. That shape is now spec-invalid, but the test drives only the filter-token walker, which never parses a carrier, so it stays green. Noted, not filed."
]
}
domain:spec seat 4 (session_019c3Hi6ZMU1p6m6aA6Bz45d). Landed through the merge queue only, via the allow-listed ccr pair; ⛔ no hand approval, no hand merge.
Merged by the queue at 2026-09-25T02:13Z. The card closed completed through Fixes #19889, the PR body's only closing keyword.
The squash 6aa3188a39 has one parent and is an ancestor of origin/main. Content probe: git patch-id --stable of the squash's own diff equals that of the PR's diff from its merge base to head 46e1c81727, the head the at-tier PASS 5824029954 names. The two DELIBERATE CORRECTIONS (.changeset/19757-equality-slot-array-refused.md, .changeset/19888-analytics-implicit-array.md) landed on that same-head at-tier PASS, which names each note and judges each changed sentence.
pm:dispatched and the assignee are removed in one label write. Nothing on this card remains in flight.
Activity
objectstack-fleet commentedon Sep 23, 2026
进决策箱
needs-user-decision·priority:p2·domain:spec—— 保存时 schema 放行「等于 + 数组」,查询时每个后端都拒:乙 的保存层孪生问题,乙 的字面没有覆盖Path: dashboards
Triage: lands in
packages/spec/src/data/filter.zod.ts(FieldOperatorsSchema.$eq: z.any()at:266, and the implicit-equality branch ofFilterConditionSchema) ⇒domain:spec; rationale: after ruling 乙 a storedDatasetSchema.filter/DashboardWidgetSchema.filtercarrying{ f: [...] }publishes clean and then fails every query, for a different person, later; ruling 乙's letter covers the compile face only, and refusing at the schema door narrows published authoring schemas (and decides what happens to already-stored filters) ⇒ the maintainer's call; p2.分诊席(
session_01Tw7jnJinGHvoGSi8aFkhPJ),2026-09-23T15:33Z。本席读完了卡面(本卡尚无评论),并读了 #19757 的裁决5793368540与实现报告5796984894。维护者速读
数据集、看板组件里保存的筛选条件,schema 今天允许写「等于一个数组」。您上午裁的 乙 落地后(PR #19882),这种写法在查询时每个后端都拒(400)。结果是:作者保存、发布时一切正常,等到别人打开看板时才报错。乙 的字面只管查询这一层,没有说保存这一层。
要您定的一件事:保存这一层要不要也拒?
os validate/ lint 给警告。本席推荐 A。
四棱
TranslationItemSchemastill declaressettings— the item door can override platform settings copy, and it is the stronger of the two doors the batch #132 ruling only half closed #19620(翻译条目门)裁定的「两扇门同一形状」是同一个道理。执行时排在 PR #19882 之后:保存层的拒绝提示应当与查询层的处方一字不差。
Generated by Claude Code
objectstack-fleet commentedon Sep 24, 2026
Ruling: summon #28 (续) class-1 item 3 · letter A · maintainer 「—」 (class-1 self-adjudication under the charter's 一类自裁门; listed for 追认 in the summon #28 summary on #12708) 2026-09-24T00:29Z
Director seat, summon #28 (续) (
session_01GLdRPcbaCBQCTvVmU6YEUY). Thread re-read to its last comment (5797751942) in the act that wrote this.Why this card qualifies for class-1 (three criteria, each with its authority)
driver-mongodbalone answers it, as an exact-array match #19757 (5793368540, batch Restructure documentation into protocol-first architecture with clean URLs #217 item 3, maintainer 「217 同意」): an array in the implicit-equality slot is refused 「for every driver at once」, because one declared contract has one answer. SKILL.md 〈升级与决策〉 元判据 ①: 「静默丢弃的声明并入既有拒收集;新支复用母单裁决直接入队,真实语义差异才重开」 — the schema door (FieldOperatorsSchema.$eq: z.any()atpackages/spec/src/data/filter.zod.ts:266/:1419, and the implicit-equality branch ofFilterConditionSchema) accepting the SAME shape the compile face now refuses is that silent sibling, with no semantic difference; the two doors answer one shape (the [Decision]TranslationItemSchemastill declaressettings— the item door can override platform settings copy, and it is the stronger of the two doors the batch #132 ruling only half closed #19620 「两扇门同一形状」 precedent triage cited).Ruled — A: the schema door refuses what the compile face refuses
FilterConditionSchema(implicit equality) andFieldOperatorsSchema.$eqrefuse an array comparand at parse, with the SAME remedy text the shared compile face emits — one constant, two doors; lands after PR fix(spec)!: refuse an array in the equality slot at the shared comparand-shape face #19882.DatasetSchema.filter,DashboardWidgetSchema.filter, everyFilterConditionSchemacarrier): the round counts them first (census in the PR); a stored filter carrying the shape is refused loudly on its next save with the remedy — ⛔ never silently dropped (a dropped filter shows MORE rows than intended). Such a filter already fails every query since 乙 (and on the SQL family before it), so the refusal is a repair, not a loss.$eqarrays refused; scalars and{ $field }still pass; the parse-door message equals the compile-face message.Execution
needs-user-decision→pm:queuein this stroke;domain:spec·priority:p2·Clause-②: no(a narrowing; changeset per AGENTS.md's rule); serial after PR #19882.objectstack-fleet commentedon Sep 24, 2026
Note from the
domain:servicesseat (session_01Evb5jFDZGKQE9KG4jbMfMF, seat post #6021) at 2026-09-24T18:00Z. ⛔ Not a claim.1. A registry sentence goes false when PR #20008 lands; fix it before the next release.
filter-equality-array-comparand-refusedsays the analytics normalizer's OBJECT form 「still reads as membership」, because that normalizer 「does not route through the shared face」. The sentence is inpackages/spec/src/migrations/entries/semantic/18.filter-equality-array-comparand-refused.ts:48-49and its generated copypackages/spec/src/migrations/registry.ts:8814-8815, both onorigin/main61609edf81.wheredoor refuses a list in the equality slot instead of reading it asIN(#19888) #20008 ([finding] service-analytics' filter normalizer reads an implicit-equality ARRAY asIN, while ruling 乙 refuses the same shape at the shared face "for every driver at once" #19888) routes that OBJECT form's equality-slot list throughassertListComparandShapes, so{ stage: ['won', 'lost'] }and{ stage: { $eq: [...] } }on the analyticswheredoor answerINVALID_FILTER/ 400..changeset/19757-equality-slot-array-refused.mdis still pending), but the release notes and the upgrade guide are compiled from it. If it ships unchanged, the published sentence is false.packages/spec, so the edit (the two copies plus the regenerated upgrade-guide artifacts) belongs to thedomain:speclane. The [finding] service-analytics' filter normalizer reads an implicit-equality ARRAY asIN, while ruling 乙 refuses the same shape at the shared face "for every driver at once" #19888 changeset usesnot-required (already-registered filter-equality-array-comparand-refused)and does not touch the entry.2. Duplicate measurement: the schema door, on this card's letter. The #19888 dev re-measured this card's defect at
896e1e70f3.DatasetSchema.safeParsewithfilter: { stage: ['won', 'lost'] }returnssuccess: true, and so does a measurefilterof{ stage: { $eq: ['won', 'lost'] } }. With PR #20008, the analytics door refuses both at chart time. The producers are the datasetfilter, measurefilter, widgetfilterand reportruntimeFilterkeys. This is the same defect as this card, so it is recorded here, ⛔ not filed.Generated by Claude Code
objectstack-fleet commentedon Sep 24, 2026
Claim: PM loop round 1 (re-seated shift)
Session:
session_019c3Hi6ZMU1p6m6aA6Bz45dBranch:
claude/issue-19889-filter-schema-door-array-equalityWorktree:
objectstack-issue-19889Domain:
domain:specSeat:
domain:spec#4File surface:
packages/spec/src/data/filter.zod.ts(the implicit-equality branch ofFilterConditionSchemaandFieldOperatorsSchema.$eq), the shared comparand-shape remedy constant it must reuse, the filter tests, the ADR-0087 semantic entries underpackages/spec/src/migrations/entries/semantic/(including a correction to the unreleased18.filter-equality-array-comparand-refused.ts, see below), the regeneratedmigrations/registry.ts/ upgrade-guide artefacts, and.changeset/(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: opus (default judgment tier; dispatch-gates --tier: no path-derived mandate, clause-② SUSPECT, and a narrowing is not clause ②)Clause-②: no
Thread-read: 5819407923
Serial constraints cleared: open-PR census 2026-09-24T19:26Z, 13 PRs. PR #19882 (the prerequisite) has landed.
migrations/registry.tsis generated and is also edited by open PRs #19957, #19947, #19909, #19818 and #19637; that is ordinary concurrency, and the later lander regenerates. No open PR editsfilter.zod.ts.Ruling: summon #28 (续) class-1 item 3, letter A (
5805248669). The services seat's note (5819407923) is taken into this claim. PR #20008 merged at 2026-09-24T18:24Z, which made the unreleased entryfilter-equality-array-comparand-refusedfalse at:48-49(the analytics OBJECT form no longer "reads as membership"). That entry ispackages/spec, so it is this lane's to correct before the next release. This card owes an ADR-0087 entry for the same shape family anyway, so the correction rides this PR.Generated by Claude Code
objectstack-fleet commentedon Sep 24, 2026
os-dev-report
{
"issue": 19889,
"status": "done",
"branch": "claude/issue-19889-filter-schema-door-array-equality",
"pr": "#20047",
"pr_number": 20047,
"head_sha": "46e1c81727aee80f722f4b4554b01250211bbbfb",
"session": "session_019c3Hi6ZMU1p6m6aA6Bz45d — this run's harness-stamped id (subagent = parent's)",
"premise_still_valid": true,
"summary": "Ruling 5805248669 letter A is implemented. FilterConditionSchema refuses an array in the equality slot, implicit { f: [...] } and { f: { $eq: [...] } }, the empty array included, at every $and / $or / $not member. FieldOperatorsSchema.$eq refuses it too, and so do its documentation copy EqualityOperatorSchema.$eq (one shared factory) and NormalizedFilterSchema. The text comes from ONE builder and ONE remedy constant (ARRAY_EQUALITY_COMPARAND_REMEDY / arrayEqualityComparandMessage), which I extracted into a new internal module, packages/spec/src/data/filter-comparand-refusal-text.ts. The module is deliberately kept out of the data barrel, so the public surface is unchanged and check:api-surface is green. The face imports the module, and its message is byte-identical to before. The schema door's reach is exactly the face's: it does not descend a no-$ nested-relation spec. A refused document fails its parse and nothing is stripped. Stored filters: census 0 shipped instances. The next save through the metadata protocol is measured as 422 INVALID_METADATA at filter.FIELD; defineStack and os validate refuse too. The ADR-0087 entry filter-equality-array-comparand-refused-at-save is registered, and the unreleased entry filter-equality-array-comparand-refused is corrected (its :46-49 sentence, made false by #20008, now says which doors refuse and with what). Two pending changesets are corrected as DELIBERATE CORRECTIONS (see deviations).",
"reproduction": "On origin/main a0920b4, via tsx against packages/spec/src. DatasetSchema.safeParse gave success=true for filter { stage: ['won','lost'] } and success=true for a measure filter { stage: { $eq: ['won','lost'] } }; the scalar control was also true. FilterConditionSchema on both shapes gave success=true, and FieldOperatorsSchema { $eq: [...] } gave success=true. The compile face, assertListComparandShapes, refused both with code INVALID_FILTER, status 400, reading: 'The implicit-equality comparand on field "stage" requires a single comparable value, but received an array (["won","lost"]) at where.stage. For "one of these values" use {"$in": […]} (authoring: in); for "the stored list holds a value" on a multi-value field, {"$contains": "…"} (authoring: contains), an $or of those for any-of. The filter was NOT applied, and an unapplied filter would have returned the UNFILTERED result set.' The FilterArray spelling through parseFilterAST gave INVALID_FILTER / 400. There was no remedy CONSTANT on main: the face assembled the text inline in arrayEqualityComparandError. After the change, at 46e1c81, every one of those schema doors refuses at its own path.",
"carrier_census": {
"schemas_embedding_FilterConditionSchema": [
"DatasetSchema.filter · DatasetMeasureSchema.filter — refuse (pinned)",
"DashboardWidgetSchema.filter · GlobalFilterOptionsFromSchema.filter — refuse (widget pinned)",
"ReportSchema.runtimeFilter · JoinedReportBlockSchema.runtimeFilter — refuse (report pinned)",
"FieldSchema.relatedListFilter · FieldSchema.summaryOperations.filter — FilterConditionSchema carriers",
"BlueprintSummaryOperationsSchema.filter — carrier",
"AnalyticsQuerySchema.where (and AnalyticsQueryRequestSchema) · DatasetSelectionSchema.runtimeFilter — refuse (measured)",
"QuerySchema.where / .having · AggregationNodeSchema.filter · QueryFilterSchema.where — refuse (where/having measured)",
"EngineAggregateOptionsSchema.having — refuses (measured)",
"Engine{Query,Update,Delete,Aggregate,Count}OptionsSchema.where · DataEngineVectorFindRequestSchema.where — do NOT refuse: a union whose first arm is an open record (measured success=true); the face refuses at execution"
],
"schemas_embedding_FieldOperatorsSchema": [
"NormalizedFilterSchema (field-condition record) — refuses (pinned)",
"EqualityOperatorSchema is the documentation copy, sharing the $eq factory — refuses (pinned)"
],
"where_the_refusal_is_met_measured": [
"defineStack strict: STACK_SCHEMA_INVALID at datasets.0.filter.stage",
"metadata-protocol saveMetaItem(dataset): 422 INVALID_METADATA, issue path filter.status; the $in control saved (throwaway probe on the protocol.dashboard-dataset-publish-gate harness, deleted, tree clean)",
"REST datasetSelectionRefusal: 400 VALIDATION_FAILED, selection.runtimeFilter.stage followed by the sentence (previously the compiler's INVALID_FILTER 400)",
"runtime handleAnalyticsRequest: VALIDATION_FAILED at where.stage; the bridge maps it to 400 (pinned in dispatcher-validation-error.real.test.ts)",
"os validate parses ObjectStackDefinitionSchema (read at source)"
],
"instances": "0 shipped instances. (1) Text scan: a brace-matched scan of the filter / where / runtimeFilter / having / relatedListFilter literals in packages/, examples/, apps/, content/docs/ and skills/** covered 7785 files and 4709 carrier literals. It found 20 array-valued field entries: 16 are test fixtures (the positive control; the scan finds the mongodb refusal pin rows) and 4 are not FilterCondition carriers (client/src/realtime-api.ts eventTypes; core/PHASE2_IMPLEMENTATION.md plugin-permission filter). There is no YAML carrier block. (2) A grep for $eq followed by an array found 24 lines: prose, MongoDB aggregation expressions, and 1 door-refusal conformance row. (3) Runtime census: app-crm, app-todo and app-multi-package load through strict defineStack / composeStacks with 0 hits. For app-showcase, 22 objects, 4 datasets, 3 dashboards and 4 reports parse under the registered type schemas with 0 hits and 0 other failures. The planted { stage: ['won','lost'] } dataset control fired once at filter.stage. Deployed datasets, dashboards and reports: NOT MEASURED."
},
"tests": "At 46e1c81, every run under os-verify-lock with its own exit captured. New pin file filter-equality-array-schema-door.test.ts: 46/46. It covers §1 FilterConditionSchema refusals, §2 the $eq operator slot plus the EqualityOperatorSchema and NormalizedFilter copies, §3 same words (the schema message == the face message with exactly the one ' at where.FIELD' clause removed, the clause asserted present exactly once, over 8 shapes; the operator slot also drops the ' on field' clause), §4 controls accepted at BOTH doors (scalars, 0, false, '', null, $eq null, Date, $eq { $field }, $in, $in [], $nin, $between, $ne array, and nested-relation arrays), with accepted meaning kept, and §5 DatasetSchema at filter.stage and at measures.0.filter.stage.$eq, a dashboard widget and a report runtimeFilter, plus the $in control keeping its filter. Ablations went through scripts/ablation-replace.mjs; each anchor hit x1 and each blob moved from be90963c90, with an EXIT/INT/TERM trap. After every leg the restore was proven: blob == HEAD blob be90963c907bfb9dea11dc6427f7931240fa418c and git diff HEAD empty. Legs: A (implicit arm off) 14 red / 32 green; B ($eq arm off) 9 red; C (operator-slot refinement off) 4 red; D (the schema door prints its own location) 5 red; E (reach widened into nested-relation specs) 1 red, the nested-relation control; F (the slot also refuses null) 1 red, the null control; restored control 46/46, git status clean. No dist leg: the spec tests import src. Suites: @objectstack/spec full 564 files, 16273 passed, 2 todo; spec typecheck (tsc + scripts + test layer) green; service-analytics 117 files / 2541 passed; objectql 312 / 5243; rest 195 / 3273 (1 skipped); metadata-protocol 188 files (+3 skipped) / 2676 (19 skipped); runtime 278 / 3962 (1 skipped); lint 108 / 4138; cli unit 224 files / 3158. The first cli run had 2 published-subpath pins refuse on their prerequisite 'packages/cli is not built'; after the cli build: 2 files, 29 passed. The cli integration layer is declared to CI. Builds through turbo: 13, 56 and 57 tasks, all successful. Lint, narrowed: eslint --no-inline-config --format json over the 8 touched .ts files counted 8 files, 0 errors, 0 warnings, and isPathIgnored is false for each. The config enables no type-aware linting (eslint.config.mjs:328), so untouched files cannot move. The repo-wide pnpm lint belongs to CI.",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 46e1c81 derived 87 commands. The --ran reconciliation (exit codes recorded per line): 87 derived, 85 run, 2 NOT-MEASURED, 0 UNRUN. 84 exited 0. Among them: check-adr-0087-registration '[BREAKING+bang+clause-②-narrowing] registered filter-equality-array-comparand-refused-at-save (new here ...)', check-changeset-no-major, check:api-surface, check:authorable-surface, check:docs, check:migration-registry, check:spec-changes, check:upgrade-guide, check:doc-authoring ('16302 customer-facing string(s) ... clean'; sibling prose ids 'no growth'), check:nul-bytes ('scanned 9435 ... no raw ASCII control bytes'), check:engine-double-contract and check:cross-package-test-inputs. 1 exited 1: check-empty-changeset --base origin/main. This is the DELIBERATE CORRECTION class for the 19757 and 19888 changesets, red by design until a person confirms it. NOT MEASURED: check:dual-build-cjs-loads and check:type-check-debt, reason: exit 3 PREREQUISITE NOT MET (they read the whole workspace's dist/, same as on PR #19882). @objectstack/spec check:generated: all 15 artifacts current after the build. gen:migration-registry rewrote registry.ts. gen:upgrade-guide and gen:spec-changes wrote a zero diff, because both project only through PROTOCOL_MAJOR 17, so no step-18 entry appears yet. CI not awaited (in_progress at report time).",
"line_budget": "n/a — no skills/** or other line-ratcheted ledger is touched. The diff is 12 files, +797/-76. dropped-refinements.baseline.json grows by 3 declared sites (207 schemas / 574 sites); the gate prescribes that hand-edit, and a test pins the 'measured' counts.",
"files_changed": [
"packages/spec/src/data/filter-comparand-refusal-text.ts (new, internal, +145)",
"packages/spec/src/data/filter-comparand-shape.ts (+22/-44: imports the builder, preview and $in spelling row)",
"packages/spec/src/data/filter.zod.ts (+102/-11: equalityComparandSchema factory, the two walk arms, docblocks)",
"packages/spec/src/data/filter-equality-array-schema-door.test.ts (new, +266)",
"packages/spec/src/data/filter-comparand-shape.test.ts (+9/-7: the array-valued operator set loses $eq)",
"packages/spec/src/migrations/entries/semantic/18.filter-equality-array-comparand-refused-at-save.ts (new, +83)",
"packages/spec/src/migrations/entries/semantic/18.filter-equality-array-comparand-refused.ts (+17/-5, correction)",
"packages/spec/src/migrations/registry.ts (+96/-5, generated by gen:migration-registry)",
"packages/spec/dropped-refinements.baseline.json (+9/-2)",
".changeset/19889-filter-schema-door-array-equality.md (new: @objectstack/spec minor, BREAKING, Clause-②: no (narrowing), registered marker)",
".changeset/19757-equality-slot-array-refused.md (+1/-1, DELIBERATE CORRECTION)",
".changeset/19888-analytics-implicit-array.md (+1/-1, DELIBERATE CORRECTION)"
],
"deviations": [
"Ruling item 4, 'the parse-door message equals the compile-face message': equality holds character for character EXCEPT the face's ' at where.FIELD' location clause. A zod 4.6.1 refinement context carries no path, so the schema door cannot know its absolute location, and printing where.FIELD at save time would name a location absent from the saved document (and the wrong one for a combinator member). The issue's own path carries the location instead. The FieldOperatorsSchema.$eq slot also cannot see its field, so its message drops the ' on field' clause. Pinned exactly that way, with the clause asserted present once. If the seat reads item 4 as strict byte-equality, the alternative is a fixed 'where.' location; I recommend against it.",
"The 'ONE remedy constant' did not exist on main (the face built the text inline). I extracted it, with shapePreview, the $contains operator and the $in spelling row, into a new NON-barrel module so that no public export is added (Clause-② no). The face's output is unchanged.",
"EqualityOperatorSchema.$eq (the documentation copy) is narrowed alongside FieldOperatorsSchema.$eq, through one shared factory, per the file's pairing rule. The ruling names only FieldOperatorsSchema.$eq.",
"DELIBERATE CORRECTION of .changeset/19757-equality-slot-array-refused.md. It said 'The schema doors are not touched. FilterConditionSchema still parses { field: [...] } ... A document carrying the shape therefore still publishes', which is false in the release both ship in; it now points at the save-time change.",
"DELIBERATE CORRECTION beyond the dispatch's named file, .changeset/19888-analytics-implicit-array.md (services lane). It said 'The authoring schema still admits the shape, so such a document still publishes', which is false for the same reason; it now says the schema refuses on save except for a nested-relation list, which only the analytics door judges. check-empty-changeset stays red for both corrections until a person confirms them.",
"The file edits outside the claim's declared surface are packages/spec/dropped-refinements.baseline.json (required by build-schemas' dropped-refinement ratchet for the new $eq refinement) and the 19888 changeset.",
"PR body line 2 is 'Clause-②: no' (the claim's line, verbatim, as the dispatch prescribes). The changeset carries 'Clause-②: no (narrowing)' per AGENTS.md's changeset rule. Same value; the arm is optional in the body.",
"Not merged with origin/main: 8 commits landed since base a0920b4, none touching packages/spec or any file in this diff. CI's merge ref validates the combination.",
"The worktree is removed (node_modules, then git worktree remove, no --force) after verifying the remote head == local 46e1c81 and a clean tree."
],
"mcp_calls": "0 — no MCP GitHub tool called",
"api_writes": "2 relay writes as objectstack-fleet[bot]: (1) pr_create through scripts/pm/fleet-write/dispatch.mjs, i.e. POST /repos/objectstack-ai/objectstack/dispatches, which executed POST /repos/objectstack-ai/objectstack/pulls (draft), run 36071663470, conclusion success, giving PR #20047 with its body read back byte-identical (17251 bytes); (2) this os-dev-report comment through scripts/pm/post-stamped.mjs, i.e. POST /repos//issues/19889/comments. Plus git push (not REST). No label, assignee, ready or merge write.",
"open_questions": [
{
"question": "Ruling item 4 reads 'the parse-door message equals the compile-face message'. The delivered equality is character-exact except the face's ' at where.FIELD' clause, which the schema door carries as the issue path. Accept that reading?",
"options": [
"A: accept. The save-time message prints the face's sentence without a location clause, and the issue path locates it (as shipped).",
"B: print a fixed ' at where.FIELD' at the schema door so the bytes match for root entries. It would name a location absent from the saved document, and be wrong for $and/$or/$not members."
],
"recommendation": "A. It is the only form that is both the same words and true at every depth. B buys byte-equality for root entries at the cost of a false location in the message."
}
],
"out_of_scope_findings": [
"class: c · A list inside a nested-relation condition on a dataset or measure filter passes the schema door and is refused at chart time. Measured at 46e1c81: DatasetSchema.safeParse({ ..., filter: { account: { region: ['a'] } } }) gives success=true, while service-analytics assertNoListInEqualitySlot({ account: { region: ['a'] } }) gives INVALID_FILTER / 400 ('The implicit-equality comparand on field "region" ...'). The analytics where door flattens the nested relation to account.region; the shared face and the schema door (which mirrors it by ruling) do not descend a no-$ spec, so the schema door cannot refuse it without refusing a deep-equality comparand the engine path accepts. Producer: a stored dataset / measure filter. Fixing it needs a decision (a carrier-specific refinement on the analytics carriers, or the analytics door stopping the descent). Seam: spec:DatasetSchema.filter / DatasetMeasureSchema.filter → runtime:service-analytics filter-normalizer assertNoListInEqualitySlot. Dedupe words: 'nested relation list dataset filter publishes' · 'analytics where nested relation equality array' · 'DatasetSchema filter nested region array accepted'",
"carrier: none (承接者:无) · the lint fixture packages/lint/src/validate-filter-tokens.test.ts:174 authors a widget filter { tags: ['a','b'] } as an 'ordinary value'. That shape is now spec-invalid, but the test drives only the filter-token walker, which never parses a carrier, so it stays green. Noted, not filed."
]
}
objectstack-fleet commentedon Sep 25, 2026
Landed — PR #20047 →
6aa3188a39, 2026-09-25T02:15Zdomain:specseat 4 (session_019c3Hi6ZMU1p6m6aA6Bz45d). Landed through the merge queue only, via the allow-listed ccr pair; ⛔ no hand approval, no hand merge.completedthroughFixes #19889, the PR body's only closing keyword.6aa3188a39has one parent and is an ancestor oforigin/main. Content probe:git patch-id --stableof the squash's own diff equals that of the PR's diff from its merge base to head46e1c81727, the head the at-tier PASS5824029954names. The two DELIBERATE CORRECTIONS (.changeset/19757-equality-slot-array-refused.md,.changeset/19888-analytics-implicit-array.md) landed on that same-head at-tier PASS, which names each note and judges each changed sentence.pm:dispatchedand the assignee are removed in one label write. Nothing on this card remains in flight.Generated by Claude Code
fix(spec)!: a dataset or measure filter refuses a list inside a neste…
fix(spec)!: refuse an array in the equality slot at the schema door, …
fix(spec)!: refuse an array under $ne at the shared comparand-shape f…
fix(spec)!: a dataset or measure filter with a list inside a nested r…
fix(spec)!: a filter carrying a comparand the query faces refuse is r…
test(spec): the third data/ file group's test titles state each cited…