Carved out of the contract review of PR #7621 (card objectui#7443) by the domain:ui PM seat. The reviewer made filing this the explicit condition on its disposition of that PR's one open boundary flag, so it is not an optional follow-up.
The state PR #7621 ships
DateDisplayOptions is the one options bag that formatDate, formatRelativeDate and formatDateTime all take. PR #7621 added style?: string to it (packages/core/src/utils/date-display.ts:75) — and only formatDateTime reads it (:236).
Measured by the reviewer at head a43aa8101:
| call |
result |
formatDate(v, undefined, { style: 'short', locale: 'en-US' }) |
Jul 4, 2024 — the default face, no diagnostic |
formatRelativeDate(v, { style: 'compact' }) |
ignored |
⭐ The sharpest form of it, which the implementing dev did not name
On formatDate the inert key collides with a positional parameter of the same name:
formatDate(value: string | Date | number, style?: string, options?: DateDisplayOptions)
So that one function now has two spellings for one concept, and one of them does nothing. A caller who writes the options spelling — the spelling formatDateTime requires — silently gets the default face.
Why this was accepted for the interim, and what that costs
The reviewer ruled the shipped shape (A) correct at the contract tier for the interim, on two measured grounds:
- The precedent is real and the same shape.
dueLike is read only at formatRelativeDate:119, t only at :122; formatDateTime(v, { dueLike: true, t: () => 'X', locale }) renders Jul 4, 2024, 07:00 AM — both keys silently inert. The module already has a one-bag convention with inert keys.
- It is NOT an
AGENTS.md #0.1 instance. #0.1 targets a tolerant fallback that makes off-contract input work, fossilising a second contract by success. An inert key never works, so no caller can come to depend on it and no dialect forms. It does share #0.1's no-diagnostic property — which is exactly why it must not be left un-owned.
Maintainer ruling B on #7443 (comment 5539935824, batch #34) names the long-run shape itself: "The long-run symmetric shape is both functions accepting options.style — additive on formatDate, and ⛔ not this card's." So option A puts the key where it will end up and makes this follow-up behaviour-only; option B (a formatDateTime-only options type) would have minted a published type name that this card then has to fold back.
What this card is
Make formatDate read options.style. Additive; the ruling already names it as the target shape.
⚠️ Open questions the implementer must answer rather than assume:
Refs: objectui#7443 · PR #7621 · ruling B (5539935824) · objectui#7619 (two published formatDateTimes) · objectui#7620 · AGENTS.md #0.1.
Generated by Claude Code
Carved out of the contract review of PR #7621 (card objectui#7443) by the
domain:uiPM seat. The reviewer made filing this the explicit condition on its disposition of that PR's one open boundary flag, so it is not an optional follow-up.The state PR #7621 ships
DateDisplayOptionsis the one options bag thatformatDate,formatRelativeDateandformatDateTimeall take. PR #7621 addedstyle?: stringto it (packages/core/src/utils/date-display.ts:75) — and onlyformatDateTimereads it (:236).Measured by the reviewer at head
a43aa8101:formatDate(v, undefined, { style: 'short', locale: 'en-US' })Jul 4, 2024— the default face, no diagnosticformatRelativeDate(v, { style: 'compact' })⭐ The sharpest form of it, which the implementing dev did not name
On
formatDatethe inert key collides with a positional parameter of the same name:So that one function now has two spellings for one concept, and one of them does nothing. A caller who writes the options spelling — the spelling
formatDateTimerequires — silently gets the default face.Why this was accepted for the interim, and what that costs
The reviewer ruled the shipped shape (A) correct at the contract tier for the interim, on two measured grounds:
dueLikeis read only atformatRelativeDate:119,tonly at:122;formatDateTime(v, { dueLike: true, t: () => 'X', locale })rendersJul 4, 2024, 07:00 AM— both keys silently inert. The module already has a one-bag convention with inert keys.AGENTS.md#0.1 instance. #0.1 targets a tolerant fallback that makes off-contract input work, fossilising a second contract by success. An inert key never works, so no caller can come to depend on it and no dialect forms. It does share #0.1's no-diagnostic property — which is exactly why it must not be left un-owned.Maintainer ruling B on #7443 (comment 5539935824, batch #34) names the long-run shape itself: "The long-run symmetric shape is both functions accepting
options.style— additive onformatDate, and ⛔ not this card's." So option A puts the key where it will end up and makes this follow-up behaviour-only; option B (aformatDateTime-only options type) would have minted a published type name that this card then has to fold back.What this card is
Make
formatDatereadoptions.style. Additive; the ruling already names it as the target shape.formatDate(v, 'short', { style: 'long' })? ⛔ Do not mint a precedence rule silently; objectui#7113 is the precedence precedent and finding(types): serieschartTypeis undeclared and SILENTLY STRIPPED - the normalizer reads it first, measured not live, alias-refusal owed #7694 is the seat's recent case of an alias overwriting a canonical key.formatRelativeDateread it too, or is it genuinely style-less?styleparameter then owed a deprecation, or do both spellings stay?Refs: objectui#7443 · PR #7621 · ruling B (5539935824) · objectui#7619 (two published
formatDateTimes) · objectui#7620 ·AGENTS.md#0.1.Generated by Claude Code