Uh oh!
There was an error while loading. Please reload this page.
Guard the first-sync deadline's time zone (test-only; #416 was fixed by #419) - #427
Conversation
The rendering defect reported in #416 was already fixed by #419 (0253fcc): formatFirstSyncDeadline appends the zone from a second Intl formatter, since ECMA-402 forbids mixing timeZoneName with dateStyle/timeStyle. What the issue also asked for is missing, and the formatter had no test coverage at all. This adds that regression guard, so the four consent surfaces that render the deadline (LLP 0100 R1 and R9, LLP 0101) cannot silently regress to a bare wall-clock time. Test-only: no production code changes. The assertions are pinned to explicit zones rather than the host's, and the cross-zone case compares against the zone token the runtime itself names, so it holds in any locale. The exact-string case is skipped off an English host. Reverted to the pre-#419 formatter body, both cases fail with 'Jul 23, 2026, 11:59 PM' where 'Jul 23, 2026, 11:59 PM PDT' is expected. Co-Authored-By: Claude <noreply@anthropic.com>
…nglish
The pinned expectation 'Jul 23, 2026, 11:59 PM PDT' is en-US-specific
formatting. Other English locales (en-GB, en-CA, en-AU) passed the old
locale.startsWith('en') guard and then failed the assertion. Tighten
the guard to the exact locale the strings encode.philcunliffe
commented
Jul 28, 2026
🤖 neutral: review round 1 — |
philcunliffe
commented
Jul 28, 2026
🤖 neutral: review round 2 (final) - |
Uh oh!
There was an error while loading. Please reload this page.
Read this first: the bug in #416 is already fixed. This PR is test-only.
The rendering defect #416 reports (the first-sync deadline printing as a bare
local wall-clock time with no zone) was already fixed by #419, commit
0253fcc, merged 2026-07-28T15:40:40Z, about 15 hours after the issue was filedagainst master @
dd3b438.formatFirstSyncDeadlineon current master alreadyappends the zone.
This PR changes no production code. It adds only the regression guard the
issue also asked for:
That ask was unmet:
formatFirstSyncDeadlinehad no test coverage at all,despite being the single formatter behind four consent surfaces (the enrolling
login message,
hyp status, thehyp initprivacy narration, andhyp sync).Why the zone is required, not cosmetic
The deadline is the moment captured history first leaves the machine. A reader
deciding whether they have an hour or a day cannot answer that from a zoneless
time, and the string outlives its context: it is pasted, screenshotted, filed in
tickets, re-rendered by
hyp statusfor the life of the hold, and read on hostswhose clock is not the reader's.
llp/0100-enrollment-privacy-review.spec.md:104(R1) requires the absolutelocal time with its time zone.
llp/0101-first-sync-review-window.decision.md:127: "an absolute time is onlymemorable if the deadline carries its time zone".
Reproduction evidence
Reverting
src/core/usage-policy/first_sync_hold.jsto its pre-#419 body(
git show 0253fcc^:src/core/usage-policy/first_sync_hold.js, i.e.toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' })), bothnew cases fail with exactly the symptom #416 describes:
On current master, unmodified, the same file passes:
So the guard has teeth: it fails on the code that had the bug and passes on the
code that fixed it. The fix commit is #419's rather than one in this PR.
What the tests assert
Both are host-independent.
withTimeZonepinsprocess.env.TZaround eachrender and restores it, and the instant is fixed (
Date.UTC(2026, 6, 24, 6, 59),11:59pm Pacific on 2026-07-23), so nothing depends on the host clock or zone.
the rendered deadline names its time zone, never a bare wall-clock timesweepsfive zones and, per zone, asserts the render is not the bare
dateStyle/timeStylestamp, that it contains the zone token the runtime itselfnames, and that it starts with that same stamp (the zone is appended, wording
unchanged). Comparing against the runtime's own token keeps it locale
independent. Verified on Node 24 (master's formatter, same instant):
Zones with no common abbreviation fall back to a GMT offset, which still answers
the question.
the rendered deadline reads as a full local date, time and zone in a pinned zonepins the exact strings for the Pacific and UTC renders, which is thecrispest statement of the property. The formatter renders in the host locale by
design, so that case skips itself off an English host; the cross-zone case above
covers every locale.
For context on the constraint both the issue and #419 hit:
{ dateStyle: 'medium', timeStyle: 'short', timeZoneName: 'short' }throwsTypeError: Invalid option : option. #419 resolved it with a secondIntl.DateTimeFormatwhosetimeZoneNamepart is appended, degrading to thebare stamp on a runtime that names no zone.
Checks
Local run (CI on this PR is the authority, not this):
npm run typecheckclean.npm test: 2770 pass, 8 fail. Those 8 are all intest/core/leave-command.test.js(leave after join removes the seed and reports the server,leave clears an applied central slot..., and six moreleave ...cases). They fail identically on cleanorigin/masterwith nochanges applied, so they are pre-existing and unrelated to this PR. Flagging
them so the reviewer is not surprised.
How to dispose of this
Merge to land the guard, or close#416 as already-fixed-by-#419 if you would
rather not carry the test. Either is a defensible call: the user-visible defect
is gone on master today.
Fixes#416