Skip to content

First-sync deadline prints a bare local time with no time zone #416

Description

@bgmcmullen

Problem

Team enrollment prints the first-sync deadline as a bare local time:

──────────────────────────────────────────────────────────────
  PRIVACY - review before first sync

  first sync to https://hypaware.hyperparam.app is Jul 23, 2026, 11:59 PM
  and includes your backfilled history

  to review what ships before then,
  open Claude or Codex and run the hypaware-privacy skill
──────────────────────────────────────────────────────────────

Jul 23, 2026, 11:59 PM carries no zone. This is a consent surface (LLP 0100
R1): the reader has to work out how long they have to review captured history
before it leaves the machine, and a wall-clock time with no zone does not tell
them. The ambiguity bites when:

  • the host clock is not in the reader's zone (CI runner, shared box, a VM left
    on UTC, a laptop that travelled);
  • the reader is not the person at the keyboard (pasted output, a screenshot, a
    ticket);
  • the string is read on a later day than it was computed - hyp status
    re-renders the same text for the life of the hold.

The deadline itself is computed correctly in local time (next local 11:59pm,
rolled a day when under the 4-hour floor) at
src/core/usage-policy/first_sync_hold.js:36. The gap is purely in rendering.

All four user-facing renders go through one formatter, so one fix covers them:

  • src/core/usage-policy/first_sync_hold.js:57 - formatFirstSyncDeadline,
    { dateStyle: 'medium', timeStyle: 'short' }
  • src/core/cli/remote_commands.js:198 - the enrolling-login message (R1)
  • src/core/commands/status.js:385 - the hyp status hold line (R9)
  • src/core/cli/wizard/index.js:329 - the hyp init privacy narration

Suggested fix

Render the zone in formatFirstSyncDeadline.

Note the implementation constraint: ECMA-402 forbids combining
dateStyle/timeStyle with timeZoneName, so simply adding the option to the
current call throws TypeError: Invalid option : option. Two shapes work:

  1. Explicit components in one call (recommended - no seconds noise):
new Date(deadlineMs).toLocaleString(undefined, {
  year: 'numeric', month: 'short', day: 'numeric',
  hour: 'numeric', minute: '2-digit', timeZoneName: 'short',
})
// Jul 23, 2026, 11:59 PM PDT
  1. timeStyle: 'long', which also yields the zone but adds a pointless
    seconds field: Jul 23, 2026, 11:59:00 PM PDT.

Option 1, same instant, on hosts in other zones (checked on Node 24):

America/Los_Angeles  Jul 23, 2026, 11:59 PM PDT
UTC                  Jul 24, 2026, 6:59 AM UTC
Europe/London         Jul 24, 2026, 7:59 AM GMT+1
Asia/Kolkata          Jul 24, 2026, 12:29 PM GMT+5:30
Australia/Sydney      Jul 24, 2026, 4:59 PM GMT+10

Zones with no common abbreviation fall back to a GMT offset, which still
answers the question.

The existing assertions compare against formatFirstSyncDeadline(...) rather
than literal time text (test/core/remote-login-command.test.js:888,
test/core/status-first-sync-hold.test.js:78), so a formatter change stays
green. Worth adding a case that pins the rendered deadline as carrying a zone
token at all, so the consent surface cannot silently regress to a bare time.

Secondary, while the line is open: it currently reads first sync to <url> is <time>; at <time> reads better once a zone token is attached.

Boundary

#391 is the other defect in this same printed enrollment block: the forwarding
host rendering as a clickable link that opens a generic 404. This issue is only
the deadline's missing time zone.

The 11:59pm rule and the 4-hour lead floor
(LLP 0101 #deadline) are not
in question here - only how the resulting instant is displayed.


Filed from recorded onboarding feedback. Code references against master @ dd3b438.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestneutral:fixDelegate this issue to neutral for an autonomous fix attempt (reproduce -> fix -> PR)onboardingFirst-run experience: hyp init wizard, enrollment/join, skills+agents install, first query

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions