Skip to content

spec/lint: a date-range PRESET name is refused only under ordering operators — the same preset on the same date field passes as a bare / $eq / $in comparand #16106

Description

@os-steve

Found while surveying which platform rules fire on objectstack-ai/hotcrm (its #1621, step 3 of epic #1579). Read-only survey, report-first, unassigned.

Measured against the pinned @objectstack/spec@17.3.0 and @objectstack/lint@17.3.0, hotcrm at 1670557. Injections proven on disk before reading a verdict; restored by blob hash verified by observation.

What is already shipped, and works

#8793 (closed, the ruled C half of #8690) refuses a declared preset name as a bare temporal comparand at publish time. Confirmed working, verbatim:

  • Injection: a dashboard widget filter, close_date: { $gte: '{12_months_ago}' } to close_date: { $gte: 'last_30_days' }.
  • Result: defineStack refuses, exit 1, with a precise message — "last_30_days" is a dashboard date-range PRESET name, not a filter value … As a bare "$gte" comparand nothing resolves it: a declared datetime/date field refuses the query at the engine (INVALID_FILTER / 400) …

The same refusal fires from a report runtimeFilter, so it is not dashboard-specific.

The residue

filter-preset-comparand judges only ORDERING_DOLLAR_OPS = {$gt, $gte, $lt, $lte}, ORDERING_INFIX_OPS and ORDERING_RULE_OPS, and the publish-time refusal covers the same set. Every non-ordering position on the same declared date field passes both gates. Three injections into the same widget filter, on close_date (a declared date column of crm_opportunity, the dataset's object):

authored comparand defineStack objectstack lint exit
close_date: { $gte: 'last_30_days' } refuses not reached 1
close_date: 'last_30_days' accepts passed: true, no finding 0
close_date: { $eq: 'last_30_days' } accepts passed: true, no finding 0
close_date: { $in: ['last_30_days'] } accepts passed: true, no finding 0

Baseline for all four rows is identical (errors: 0, warnings: 17, suggestions: 12), and the ordering row is the working control that the harness does detect this value.

Why the residue matters

The consequence #8690 named is not specific to ordering operators: an unlowered preset string reaches the driver as a literal, compares false against every row, and the surface answers 200 with zero rows and no diagnostic. close_date == 'last_30_days' is exactly that shape — arguably the more likely authoring slip, since equality is what an author writes when they mean "in this window".

Two readings, and I do not have standing to choose between them:

  1. The ruling's scope was "bare temporal comparand", and equality/$in positions are simply the rest of that scope — extend the publish-time refusal (and filter-preset-comparand) to any comparand position on a temporal field.
  2. Ordering positions were chosen deliberately because they are the only ones the console lowers, and the rest is out of scope by design — in which case this card is a note on Refuse the declared relative-date preset vocabulary as a bare temporal comparand at publish time — the ruled C half of #8690, carved out for the spec seat #8793, not a defect.

Recorded rather than assumed. filter-preset-comparand's own reachability is a consequence either way: on a defineStack-authored app the schema refuses the ordering positions first, so the lint rule id never appears in output at all.

Dedupe

#8690 and #8793 read in full; #8793 is closed/completed and covers the ordering half only. No open card names the equality/$in/bare positions.

Activity

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions