Skip to content

[finding] the shipped ADR-0087 blank-endpoint ledger entry prescribes a re-save sweep that finds nothing on four of the six carriers it names — dashboard, dataset, report and rollup filters are FilterConditionSchema and never judge the endpoint #19523

Description

@os-steve

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions