Skip to content

Commit 9e3c485

Browse files
os-billclaude
andauthored
docs(spec): state the ADR-0053 D-D upper-bound rule in the date-macros header (#17651)
* wip(spec): correct the date-macros header to ADR-0053 D-D Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH * docs(spec): state the ADR-0053 D-D upper-bound rule in the date-macros header The "Out of scope" block still carried the pre-ADR-0053 reading — that on a `datetime` column `<= {current_year_end}` stops at midnight on the 31st, with the half-open `< {next_year_start}` prescribed as the correction. Since #3777 a bare `YYYY-MM-DD` used as an upper bound denotes the WHOLE day, compiled half-open to the next calendar day; the rule is stated once in `packages/spec/src/data/calendar-day.ts` (ADR-0053 D-D) and pinned cross-driver by `packages/spec/src/data/temporal-conformance.ts`. The header now keeps its load-bearing first clause — a `*_end` token is the period's last calendar DAY — and cites `calendar-day.ts` for what that bare day denotes on each side of an operator, rather than restating it, so the two cannot drift apart again. Comment lines only; no schema behaviour changes. The generated reference page `content/docs/references/data/date-macros.mdx` is regenerated from the header with the repo's own generator. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 9c9e6d0 commit 9e3c485

3 files changed

Lines changed: 77 additions & 6 deletions

File tree

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
`date-macros.zod.ts`'s module header states the ADR-0053 D-D upper-bound rule the platform implements, instead of the rule it replaced
6+
7+
The header's "Out of scope" block told an author that on a `datetime` column
8+
`<= {current_year_end}` **stops at midnight on the 31st**, and prescribed the
9+
half-open `< {next_year_start}` as the fix. That is the pre-ADR-0053 reading.
10+
The platform rule has been the opposite since #3777: a bare `YYYY-MM-DD` used
11+
as an upper bound denotes the WHOLE day, compiled half-open to the next
12+
calendar day. It is stated once, in
13+
`packages/spec/src/data/calendar-day.ts` (ADR-0053 D-D), whose own operator
14+
table reads:
15+
16+
| Operator | A bare `YYYY-MM-DD` on a `datetime` column means |
17+
|---|---|
18+
| `$gte` / `$gt` / `$lt` | that day's `00:00:00.000` — already correct as written |
19+
| `$lte`, a `$between` max, a `dateRange` end | the WHOLE day → compile `< nextUtcCalendarDay(day)` |
20+
21+
and which `packages/spec/src/data/temporal-conformance.ts` pins cross-driver:
22+
the case *"datetime: bare-day `$lte` keeps the whole final day"* expects
23+
`d_mid` (09:15 on the boundary day) and `e_late` (21:40 on it) as members.
24+
25+
**Why this header and not a note.** It is the doc comment on the vocabulary an
26+
AI author reaches for, and it is the one place in the tree that says what a
27+
`*_end` token does on the right-hand side of an operator. Both the old
28+
prescription and the correct spelling parse, run and return rows, so nothing
29+
downstream reports the mismatch — the author simply carries the wrong model
30+
into every later filter.
31+
32+
**What the correction does.** The load-bearing first clause is kept verbatim: a
33+
`*_end` token IS the period's last calendar DAY. What follows now **cites**
34+
`calendar-day.ts` rather than restating the rule, so the two statements cannot
35+
drift apart again, and the half-open detour is refused by name for the reason
36+
it is now wrong — the widening is already applied.
37+
38+
⛔ No behaviour changes. The diff is comment lines only; no schema, accept set,
39+
authorable key or published payload moves.
40+
41+
**This is shipped, which is why it carries a changeset rather than
42+
`skip-changeset`.** `@objectstack/spec`'s published `files[]` lists
43+
`src/**/*.zod.ts`, so this file ships verbatim as source, and the header is the
44+
first thing in it.
45+
46+
The generated reference page `content/docs/references/data/date-macros.mdx`
47+
carried the same sentence — it is rendered from this header and is marked
48+
AUTO-GENERATED — and is regenerated here with
49+
`pnpm --filter @objectstack/spec gen:schema && … gen:docs`.

content/docs/references/data/date-macros.mdx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,20 @@ inside any single UI implementation.
7272
calendars) are defined by the resolver implementation; spec only
7373
freezes the **vocabulary**. One property is worth stating here
7474
because it is authored against: a `*_end` token is the period's
75-
last calendar DAY (`{current_year_end}``2026-12-31`), so on a
76-
`datetime` column `<= {current_year_end}` stops at midnight on the
77-
31st. Filter a timestamp with the half-open `< {next_year_start}`.
75+
last calendar DAY (`{current_year_end}``2026-12-31`). What a
76+
bare day DENOTES once it lands on one side of an operator is a
77+
separate contract, stated once in
78+
`packages/spec/src/data/calendar-day.ts` (ADR-0053 D-D) and
79+
deliberately not restated here: as an upper bound (`$lte`, a
80+
`$between` max, a `dateRange` end) a bare day means the WHOLE
81+
day, compiled half-open to the next calendar day, so
82+
`<= {current_year_end}` reaches the final instant of Dec 31; as
83+
`$gte` / `$gt` / `$lt` it means that day's `00:00:00.000`.
84+
⛔ Do NOT hand-write a half-open detour (`< {next_year_start}`)
85+
to cover a period's last day on a `datetime` column: every
86+
backend already applies the widening, and
87+
`packages/spec/src/data/temporal-conformance.ts` pins it
88+
cross-driver.
7889

7990
<Callout type="info">
8091
**Source:** `packages/spec/src/data/date-macros.zod.ts`

packages/spec/src/data/date-macros.zod.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,20 @@ import { z } from 'zod';
6868
* calendars) are defined by the resolver implementation; spec only
6969
* freezes the **vocabulary**. One property is worth stating here
7070
* because it is authored against: a `*_end` token is the period's
71-
* last calendar DAY (`{current_year_end}` → `2026-12-31`), so on a
72-
* `datetime` column `<= {current_year_end}` stops at midnight on the
73-
* 31st. Filter a timestamp with the half-open `< {next_year_start}`.
71+
* last calendar DAY (`{current_year_end}` → `2026-12-31`). What a
72+
* bare day DENOTES once it lands on one side of an operator is a
73+
* separate contract, stated once in
74+
* `packages/spec/src/data/calendar-day.ts` (ADR-0053 D-D) and
75+
* deliberately not restated here: as an upper bound (`$lte`, a
76+
* `$between` max, a `dateRange` end) a bare day means the WHOLE
77+
* day, compiled half-open to the next calendar day, so
78+
* `<= {current_year_end}` reaches the final instant of Dec 31; as
79+
* `$gte` / `$gt` / `$lt` it means that day's `00:00:00.000`.
80+
* ⛔ Do NOT hand-write a half-open detour (`< {next_year_start}`)
81+
* to cover a period's last day on a `datetime` column: every
82+
* backend already applies the widening, and
83+
* `packages/spec/src/data/temporal-conformance.ts` pins it
84+
* cross-driver.
7485
*/
7586

7687
/** Single-point tokens — moments in time. */

0 commit comments

Comments
 (0)