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
driver-memory analytics silently accepts an unparseable dateRange and matches EVERY row — and the platform's own documented spelling 'Last 7 days' is one of them #16041
Found while working on #15825 (the calendar repair in the same function). ⛔ Deliberately NOT fixed there — triage on that card ruled 「先做拼写修复(UTC 化两个缺陷),⛔ 不要顺手换掉整个 parser」 and asked that anyone proposing to replace the parser first measure which range forms actually reach it. This card is that measurement. Refs #15825.
The shape
packages/drivers/driver-memory/src/memory-analytics.tsparseDateRangeString() recognises exactly two forms — the literal 'today', and range.startsWith('last ') — and its final line is:
return [range, range]; // Fallback
That fallback is not a refusal. The caller (the analytics query path, same file) does not distinguish it from a real window: it sees range.length === 2 and pushes the pair straight into the $match as bounds.
Two things measured, 2026-09-05
1. The fallback matches every row rather than none. With range unparseable, the emitted predicate is {$gte: '<garbage>', $lte: '<garbage>'} (plus the Date-typed twin, which is Invalid Date). Driven through mingo directly over four rows:
rows: 2020-01-01 (Date), 2026-09-05 (Date), 2099-01-01 (Date), 2026-09-05 (ISO string)
matched: [ 'a', 'b', 'c' ] <- every Date-typed row, including 2099
Under BSON cross-type ordering a Date compares above a String, so both bounds are satisfied by every Date. ⇒ The time filter is silently dropped, not refused. A dashboard asking for one week gets all of history, with no error anywhere.
2. The spelling the repo's own sources use is one of the unrecognised ones.range.startsWith('last ') is case-SENSITIVE. Every authored dateRange string literal in the tree, counted:
count
literal
reaches a window?
3
'Last 7 days'
⛔ no — capital L
1
'2026-01-20'
⛔ no
12
field names ('signed_at', 'closed_date', …)
⛔ no — a different, probably separate authoring error
'Last 7 days' is not an incidental fixture typo: it is the spelling written into the schema's own documentation of the field, packages/spec/src/data/analytics.zod.ts:
and packages/spec/src/contracts/analytics-service.ts discusses a dateRange: last_30_days (snake_case), which is also unrecognised. So the documented vocabulary and the implemented vocabulary do not intersect on the one example the schema gives.
Recognised vs not, evaluated against the implementation:
#15825's fence was the calendar (local-vs-UTC), and its acceptance is two precise pins. This is a different defect class — vocabulary and refusal, not arithmetic — and repairing it means deciding a contract, which is exactly what that card's triage declined to fold in.
The decision this needs (not obvious, hence no patch attached)
What is the vocabulary? Case-insensitive last N <unit>? Also yesterday / this week / last_30_days? @objectstack/core's filter-token macros ({today}, {7_days_ago}, period tokens) already define a rich, tested vocabulary for exactly this job — reusing it would make the driver agree with the rest of the platform instead of carrying a second dialect. Note the Prime Directive Add comprehensive test suite for Zod schema validation #12 direction: one strict contract, not N dialects.
What happens to an unrecognised string? Under ADR-0112 the honest answer is a refusal envelope with a code and status, not a window that quietly matches everything. Silently widening is the worst of the three options (refuse / widen / narrow) because nothing downstream can tell.
Where does it get enforced?AnalyticsQuerySchema types dateRange as a bare z.string(), so a bad value is accepted at the door. If the vocabulary is closed, the schema is the place to reject it (contract-first), with the driver then unable to receive one.
Unlabelled on purpose: routing, domain:*, type and priority belong to triage.
Found while working on #15825 (the calendar repair in the same function). ⛔ Deliberately NOT fixed there — triage on that card ruled 「先做拼写修复(UTC 化两个缺陷),⛔ 不要顺手换掉整个 parser」 and asked that anyone proposing to replace the parser first measure which
rangeforms actually reach it. This card is that measurement. Refs #15825.The shape
packages/drivers/driver-memory/src/memory-analytics.tsparseDateRangeString()recognises exactly two forms — the literal'today', andrange.startsWith('last ')— and its final line is:That fallback is not a refusal. The caller (the analytics query path, same file) does not distinguish it from a real window: it sees
range.length === 2and pushes the pair straight into the$matchas bounds.Two things measured, 2026-09-05
1. The fallback matches every row rather than none. With
rangeunparseable, the emitted predicate is{$gte: '<garbage>', $lte: '<garbage>'}(plus theDate-typed twin, which isInvalid Date). Driven through mingo directly over four rows:Under BSON cross-type ordering a
Datecompares above aString, so both bounds are satisfied by everyDate. ⇒ The time filter is silently dropped, not refused. A dashboard asking for one week gets all of history, with no error anywhere.2. The spelling the repo's own sources use is one of the unrecognised ones.
range.startsWith('last ')is case-SENSITIVE. Every authoreddateRangestring literal in the tree, counted:'Last 7 days'L'2026-01-20''signed_at','closed_date', …)'Last 7 days'is not an incidental fixture typo: it is the spelling written into the schema's own documentation of the field,packages/spec/src/data/analytics.zod.ts:and
packages/spec/src/contracts/analytics-service.tsdiscusses adateRange: last_30_days(snake_case), which is also unrecognised. So the documented vocabulary and the implemented vocabulary do not intersect on the one example the schema gives.Recognised vs not, evaluated against the implementation:
Why this is filed rather than repaired in #15825
#15825's fence was the calendar (local-vs-UTC), and its acceptance is two precise pins. This is a different defect class — vocabulary and refusal, not arithmetic — and repairing it means deciding a contract, which is exactly what that card's triage declined to fold in.
The decision this needs (not obvious, hence no patch attached)
last N <unit>? Alsoyesterday/this week/last_30_days?@objectstack/core's filter-token macros ({today},{7_days_ago}, period tokens) already define a rich, tested vocabulary for exactly this job — reusing it would make the driver agree with the rest of the platform instead of carrying a second dialect. Note the Prime Directive Add comprehensive test suite for Zod schema validation #12 direction: one strict contract, not N dialects.codeandstatus, not a window that quietly matches everything. Silently widening is the worst of the three options (refuse / widen / narrow) because nothing downstream can tell.AnalyticsQuerySchematypesdateRangeas a barez.string(), so a bad value is accepted at the door. If the vocabulary is closed, the schema is the place to reject it (contract-first), with the driver then unable to receive one.Unlabelled on purpose: routing,
domain:*, type and priority belong to triage.