Skip to content

Commit e09cbfe

Browse files
committed
docs(changeset): the IANA time-zone columns changeset declares its accept-set narrowing as BREAKING
`.changeset/platform-iana-timezone-columns.md` described an accept-set narrowing as "A NON-BREAKING ADDITION" and carried no `**BREAKING**` banner. The token's only occurrence sat inside those words, with no `**` prefix, so `check-adr-0087-registration.mjs` (which classifies from the author's own declaration, `/\*\*BREAKING/i` on the body) read the changeset as non-breaking — prose and machine agreeing for the same reason. During the launch window the bump level is not the carrier of breaking-ness (`check-changeset-no-major.mjs` pushes breaking changes to `minor`), so the banner and the ADR-0087 disposition are the only signals there are. As it stood this would have shipped a CHANGELOG telling an upgrading author the release could not break them, immediately before a write that worked yesterday is refused. The body now carries the `**BREAKING**` banner in the shape of the in-repo precedent, keeps the bump at `minor`, keeps exactly one ADR-0087 disposition (`not-required (no-migration-prescription)`, still the honest one: the domain is checked on the written value only, so no consumer has a metadata rewrite to perform), and states the consumer delta — which spellings stop being accepted, that every genuine IANA identifier including `UTC` keeps working, and that stored rows are unaffected, quoted from the published contract text in `packages/spec/src/data/field.zod.ts`. Text only: no `.ts`, no docs, no other changeset. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ARYe3yQTQCUFm5qPYNgKaJ
1 parent 0a038cc commit e09cbfe

1 file changed

Lines changed: 46 additions & 1 deletion

File tree

.changeset/platform-iana-timezone-columns.md

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,50 @@
44

55
feat(platform-objects): `sys_job.timezone` and `sys_report_schedule.timezone` are validated against the IANA domain (#15872)
66

7-
<!-- adr-0087: not-required (no-migration-prescription) A NON-BREAKING ADDITION of one field property to two existing columns. `valueDomain` is the `min`/`max`/`maxLength` transition-gate class: only a WRITTEN value is judged, a stored value outside a domain declared later is never re-read and survives unrelated edits, so `objectstack migrate meta` has nothing to rewrite. No metadata key, export, config field or stored shape is renamed, retired, re-typed or tombstoned; no column is added, dropped or re-bounded (`maxLength` is unchanged on both, deliberately), so boot schema-sync plans no DDL either. MIGRATION NOTE, stated rather than assumed: a deployment that already stored a non-IANA string in either column keeps it and reads it back unchanged; what changes is that the next WRITE of such a value is refused with the ADR-0114 field error code `value_domain`. For `sys_report_schedule` that refusal is the point — see the behaviour note below. -->
7+
**BREAKING** accept-set narrowing on two published columns, shipped as `minor`
8+
under the repo's launch-window convention for breaking changes. Both columns now
9+
declare `valueDomain: 'iana_time_zone'`, so a value the shipped build stored
10+
without complaint is refused from this release on. During the launch window the
11+
bump level is not the carrier of breaking-ness and says nothing about whether a
12+
release breaks you; this banner is the carrier, and the ADR-0087 disposition at
13+
the foot of this changeset is the other one.
14+
15+
**What stops being accepted.** A write to either column is now refused with the
16+
ADR-0114 field error code `value_domain` unless the value is a member of the
17+
IANA/tzdb set, tested with the `Intl.DateTimeFormat` probe. Three classes of
18+
string that the previous build accepted are outside that set:
19+
20+
- **UTC-offset spellings**`UTC+8`, `GMT+0800`, `+08:00`. They name an offset,
21+
not a zone, and no offset spelling is an IANA identifier. The tzdb's own
22+
fixed-offset zones are members and keep working: `Etc/GMT-8` is accepted.
23+
- **Windows / CLDR display names**`China Standard Time`,
24+
`Pacific Standard Time`. That is the Windows time-zone vocabulary, a different
25+
naming scheme from tzdb, and no member of it is a tzdb identifier.
26+
- **shape-valid identifiers for zones that do not exist**`Mars/Olympus`. A
27+
`Region/City` pattern cannot separate an unassigned identifier from a real
28+
one; membership can, which is what the domain is for.
29+
30+
**What keeps working.** Every genuine IANA identifier, including `UTC` — the
31+
membership predicate is the `Intl.DateTimeFormat` probe, deliberately not the
32+
`Intl.supportedValuesOf('timeZone')` enumeration, which omits `UTC`. That
33+
matters here rather than academically: `'UTC'` is `sys_report_schedule.timezone`'s
34+
own declared default.
35+
36+
**Stored rows are unaffected — only writes are judged.** No upgrade step, no
37+
backfill, no DDL. In the published words of the contract this declaration is
38+
governed by (`packages/spec/src/data/field.zod.ts`, the `valueDomain` description):
39+
40+
> Checked on the WRITTEN value only (the `min`/`max`/`maxLength` transition-gate
41+
> class): a stored value outside a domain declared later is never re-read and
42+
> survives unrelated edits — only a write carrying a non-member is refused, with
43+
> the field error code `value_domain`.
44+
45+
So a deployment already holding `UTC+8` in one of these columns keeps it and
46+
reads it back unchanged; what changes is the next write. The one thing to know
47+
before upgrading is therefore an authoring fact, not a data-at-rest one: a
48+
producer that writes one of the three spellings above starts getting a refusal
49+
where it previously got a success, and for `sys_report_schedule` that refusal is
50+
the point — see the behaviour note below.
851

952
The platform's two oldest IANA time-zone columns predate `valueDomain` and disagreed with each other in three dimensions at once — length (100 vs 64), default (none vs `'UTC'`) and validation (neither). This closes the third: both now declare `valueDomain: 'iana_time_zone'`, the same declaration and the same `Intl.DateTimeFormat` membership probe that `sys_business_unit.timezone` and `sys_organization.timezone` carry (#14238). Four columns, one spelling of "is this a real zone".
1053

@@ -17,3 +60,5 @@ The platform's two oldest IANA time-zone columns predate `valueDomain` and disag
1760

1861
- **the defaults still differ.** A default here is a consumer semantic, not a shape question. `sys_report_schedule` documents and implements a UTC default; `sys_job` has no reader at all, and minting one would change what an unset row means.
1962
- **the bounds still differ (100 vs 64).** `maxLength` is not only a write bound — it reaches DDL, and narrowing a physical `varchar(100)` is `driver-sql`'s `narrow_varchar` op at severity `error`, category destructive ("narrowing may truncate"). What the column physically holds in a deployment is not readable from the repo, so the convergence is a separate decision and #15872 stays open on it. Note what the domain declaration already costs the wider bound: no member is longer than 32 characters on the current Node baseline, so 100 now admits nothing 64 would not.
63+
64+
<!-- adr-0087: not-required (no-migration-prescription) A DECLARED-BREAKING accept-set narrowing on two existing columns that leaves nobody a metadata rewrite to perform. `valueDomain` is the `min`/`max`/`maxLength` transition-gate class: only a WRITTEN value is judged, a stored value outside a domain declared later is never re-read and survives unrelated edits, so `objectstack migrate meta` has nothing to rewrite and there is no tombstone to mint. No metadata key, export, config field or stored shape is renamed, retired, re-typed or tombstoned; no column is added, dropped or re-bounded (`maxLength` is unchanged on both, deliberately), so boot schema-sync plans no DDL either. What an upgrader has to know is a WRITE-PATH fact rather than a stored-shape one, and the body above states it rather than assuming it: a deployment that already stored a non-IANA string in either column keeps it and reads it back unchanged; what changes is that the next WRITE of such a value is refused with the ADR-0114 field error code `value_domain`. The channel that reaches an affected producer is that refusal, at its own write, which is more precise than a ledger line the producer never reads. -->

0 commit comments

Comments
 (0)