Filed by the domain:spec seat 4 (session_01AmH9bKvGoLjiY86Q4Z3og2, seat post #18917) from the at-tier contract review chain on card #19377 / PR #19501. ⛔ Filed unassigned, ⛔ no priority:*, ⛔ no domain:*, ⛔ no type — routing and grading are triage's. ⛔ Not a claim. ⛔ Not a ruling.
The defect
A shipped ADR-0087 ledger entry prescribes a sweep that finds nothing on four of the six carriers it names.
packages/spec/src/migrations/entries/semantic/18.filter-between-blank-endpoint-refused.ts — already on main, already rendered into the published protocol upgrade guide — tells an upgrader, in its own words:
surface: 「either endpoint of a $between range, authored BLANK … on any carrier of FieldOperatorsSchema / RangeOperatorSchema: a view or dashboard widget filter, a dataset filter, a report runtimeFilter, a page or component filter, a rollup filter, and the NormalizedFilter AST」
acceptanceCriteria: 「… so FieldOperatorsSchema.safeParse and re-saving the document both make the sweep mechanical」
⇒ an upgrader re-saves every dashboard, every dataset and every report, finds nothing refused, and concludes the sweep is done. It is not.
⏱️ Measured — origin/main, taken by this seat at filing, ⛔ not adopted from any report
Leg 1 — the four slots the entry names are not carriers of the schemas it names. They are FilterConditionSchema, which is z.record(z.string(), z.unknown()) intersected with the $and/$or/$not shape (packages/spec/src/data/filter.zod.ts:1704) — a loose record that never judges an operator map:
| slot the entry names |
line |
type |
| dashboard widget filter |
packages/spec/src/ui/dashboard.zod.ts:872 |
FilterConditionSchema |
| dashboard source filter |
packages/spec/src/ui/dashboard.zod.ts:1285 |
FilterConditionSchema |
Report.runtimeFilter |
packages/spec/src/ui/report.zod.ts:239 |
FilterConditionSchema |
| dataset filter |
packages/spec/src/ui/dataset.zod.ts:191 and :337 |
FilterConditionSchema |
| rollup / related-list filter |
packages/spec/src/data/field.zod.ts:1525 and :1630 |
FilterConditionSchema |
Leg 2 — the control, and it is why this is a partial falsehood rather than a whole one. The view carrier the same sentence names does refuse: ListView.filter is z.array(ViewFilterRuleSchema) (packages/spec/src/ui/view.zod.ts:590), and NormalizedFilterSchema refuses outright. ⇒ the entry is right about view / page / component / the AST and wrong about the other four, which is exactly what makes the prescription dangerous: it half-works, so the upgrader has no signal that it did not finish.
Leg 3 — reproduction. Parse a document carrying { close_date: { $between: ['2026-01-01', ''] } } (a blank endpoint, this entry's own subject) through DashboardSchema, DatasetSchema, ReportSchema and the rollup FieldSchema: zero issues at the filter path. The same filter through FieldOperatorsSchema or NormalizedFilterSchema: refused.
Why this is filed rather than fixed where it was found
It was found by the at-tier review of PR #19501, whose own new entry carried the identical wording and was FAILed for it (record 5755750784). That PR repaired its own entry. ⛔ It deliberately did not touch this one: it is a different card's shipped text, and the dev's reasoning is right — 「a third copy of the wording is exactly what should not be made」.
⭐ Note the shape: this is the second entry found carrying this sentence. Whoever takes this card should check whether the wording is a template the other semantic entries inherited, rather than fixing two copies and leaving a third.
What a fix looks like
The repaired sibling is the worked example, on PR #19501's head: split surface into (a) carriers refused at save and (b) FilterConditionSchema slots where nothing judges the endpoint until the filter is executed, and rewrite acceptanceCriteria so re-save is named mechanical only for (a), with grep plus executing the surface as the detector for (b). The entry file and the generated registry.ts mirror move together; check:migration-registry and check-adr-0087-registration decide the regen.
⛔ No behavioural change is implied: nothing about what the platform refuses is wrong. What is wrong is what the document tells a human to do about it.
查重词
blank endpoint entry re-save · FilterConditionSchema loose record · ledger acceptance criteria false · dashboard widget filter not judged · 18 filter-between-blank-endpoint-refused · ADR-0087 surface names wrong carrier
Generated by Claude Code
Filed by the
domain:specseat 4 (session_01AmH9bKvGoLjiY86Q4Z3og2, seat post #18917) from the at-tier contract review chain on card #19377 / PR #19501. ⛔ Filed unassigned, ⛔ nopriority:*, ⛔ nodomain:*, ⛔ no type — routing and grading are triage's. ⛔ Not a claim. ⛔ Not a ruling.The defect
A shipped ADR-0087 ledger entry prescribes a sweep that finds nothing on four of the six carriers it names.
packages/spec/src/migrations/entries/semantic/18.filter-between-blank-endpoint-refused.ts— already onmain, already rendered into the published protocol upgrade guide — tells an upgrader, in its own words:⇒ an upgrader re-saves every dashboard, every dataset and every report, finds nothing refused, and concludes the sweep is done. It is not.
⏱️ Measured —
origin/main, taken by this seat at filing, ⛔ not adopted from any reportLeg 1 — the four slots the entry names are not carriers of the schemas it names. They are
FilterConditionSchema, which isz.record(z.string(), z.unknown())intersected with the$and/$or/$notshape (packages/spec/src/data/filter.zod.ts:1704) — a loose record that never judges an operator map:packages/spec/src/ui/dashboard.zod.ts:872FilterConditionSchemapackages/spec/src/ui/dashboard.zod.ts:1285FilterConditionSchemaReport.runtimeFilterpackages/spec/src/ui/report.zod.ts:239FilterConditionSchemapackages/spec/src/ui/dataset.zod.ts:191and:337FilterConditionSchemapackages/spec/src/data/field.zod.ts:1525and:1630FilterConditionSchemaLeg 2 — the control, and it is why this is a partial falsehood rather than a whole one. The
viewcarrier the same sentence names does refuse:ListView.filterisz.array(ViewFilterRuleSchema)(packages/spec/src/ui/view.zod.ts:590), andNormalizedFilterSchemarefuses outright. ⇒ the entry is right about view / page / component / the AST and wrong about the other four, which is exactly what makes the prescription dangerous: it half-works, so the upgrader has no signal that it did not finish.Leg 3 — reproduction. Parse a document carrying
{ close_date: { $between: ['2026-01-01', ''] } }(a blank endpoint, this entry's own subject) throughDashboardSchema,DatasetSchema,ReportSchemaand the rollupFieldSchema: zero issues at the filter path. The same filter throughFieldOperatorsSchemaorNormalizedFilterSchema: refused.Why this is filed rather than fixed where it was found
It was found by the at-tier review of PR #19501, whose own new entry carried the identical wording and was FAILed for it (record
5755750784). That PR repaired its own entry. ⛔ It deliberately did not touch this one: it is a different card's shipped text, and the dev's reasoning is right — 「a third copy of the wording is exactly what should not be made」.⭐ Note the shape: this is the second entry found carrying this sentence. Whoever takes this card should check whether the wording is a template the other semantic entries inherited, rather than fixing two copies and leaving a third.
What a fix looks like
The repaired sibling is the worked example, on PR #19501's head: split
surfaceinto (a) carriers refused at save and (b)FilterConditionSchemaslots where nothing judges the endpoint until the filter is executed, and rewriteacceptanceCriteriaso re-save is named mechanical only for (a), with grep plus executing the surface as the detector for (b). The entry file and the generatedregistry.tsmirror move together;check:migration-registryandcheck-adr-0087-registrationdecide the regen.⛔ No behavioural change is implied: nothing about what the platform refuses is wrong. What is wrong is what the document tells a human to do about it.
查重词
blank endpoint entry re-save·FilterConditionSchema loose record·ledger acceptance criteria false·dashboard widget filter not judged·18 filter-between-blank-endpoint-refused·ADR-0087 surface names wrong carrierGenerated by Claude Code