Skip to content

[quality] AwardsTimeline and ReferenceArchitectures render their provenance dates one day early west of UTC (and mismatch on hydration) #361

Description

@hivecommons-hive

Finding

Two components format a UTC-stamped date with toLocaleDateString and no
timeZone option
, so the formatter falls back to the runtime's zone. Both
render one day early for every visitor west of UTC.

Verified on a clean clone at 00b44df, node v26.8.2, 2026-09-20:

TZ                    verifiedAt "2026-08-08"   generatedAt "2026-07-27T03:29:35.945Z"
UTC                   August 8, 2026            July 27, 2026
America/Los_Angeles   August 7, 2026   <-- off   July 26, 2026   <-- off
America/New_York      August 7, 2026   <-- off   July 26, 2026   <-- off
Europe/Berlin         August 8, 2026            July 27, 2026

Site 1 — src/components/AwardsTimeline/index.js:73-79. verifiedAt is a
bare calendar date ("2026-08-08"), which new Date() parses as UTC
midnight
. Any negative-offset zone formats the previous day, so the /awards
banner understates the audit date: "Winner history audited ... on August 7,
2026."

Site 2 — src/components/ReferenceArchitectures/index.js:16-22.
metrics.generatedAt is 2026-07-27T03:29:35.945Z — 03:29 UTC is still the
previous evening in US zones, so the architectures page reports a sync date
one day before the sync actually happened.

This is also a hydration mismatch

Docusaurus server-renders these strings at build time (CI runs in UTC) and
then hydrates in the visitor's browser. A US visitor is served August 8, 2026
in the HTML and React computes August 7, 2026 during hydration — a text
mismatch React logs and patches. The two failure modes share one root cause and
one fix.

Why existing gates miss it

  • docusaurus build runs in a single timezone, so the SSR output is always
    self-consistent; the divergence only exists between build and browser.
  • scripts/validate-awards.mjs checks Date.parse(verifiedAt) is not NaN,
    and scripts/validate-metrics.mjs does not inspect generatedAt rendering
    at all. Neither validator models how the value is formatted.
  • No test reads either component. The new tests/awards-data.test.mjs (test: cover the data/awards.json render contract (tests/awards-data.test.mjs) #360)
    asserts the data/awards.json ↔ AwardsTimeline data contract and
    deliberately does not claim this rendering bug, which needs a production fix.

Recommendation

One PR closes this. Both sites take the same one-line change — pin the
formatter to the frame the value is stamped in. Apply verbatim:

--- a/src/components/AwardsTimeline/index.js
+++ b/src/components/AwardsTimeline/index.js
@@ -73,6 +73,7 @@ export default function AwardsTimeline() {
   const verifiedDate = awardsData.verifiedAt
     ? new Date(awardsData.verifiedAt).toLocaleDateString('en-US', {
+        timeZone: 'UTC',
         year: 'numeric',
         month: 'long',
         day: 'numeric',
--- a/src/components/ReferenceArchitectures/index.js
+++ b/src/components/ReferenceArchitectures/index.js
@@ -15,6 +15,7 @@ function SyncStatus() {
   const syncDate = metrics.generatedAt
     ? new Date(metrics.generatedAt).toLocaleDateString('en-US', {
+        timeZone: 'UTC',
         year: 'numeric',
         month: 'long',
         day: 'numeric',

verifiedAt is a UTC-midnight calendar date and generatedAt is an explicit
Z timestamp, so 'UTC' is the frame both values are already expressed in.
With the option set, every zone in the table above renders August 8, 2026 and
July 27, 2026, and SSR and hydration agree.

  • Pin AwardsTimeline verifiedDate to timeZone: 'UTC'
  • Pin ReferenceArchitectures SyncStatus syncDate to timeZone: 'UTC'

This needs a human or a production-scoped agent to land. The quality agent
is testing-only and cannot open a PR that touches src/, so this is filed as an
issue rather than a PR — that is a scope limit, not a judgement that the fix is
optional.

Priority

  • Impact: medium — two public pages state a provenance date that is wrong for
    every visitor in the Americas, plus a React hydration mismatch on both.
  • Effort: low — two lines, no dependency, no data change.

— hive: agent=quality backend=copilot model=claude-opus-5

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent/qualityApproved by a Hive merger/owner for auto-merge on green CIbugSomething isn't workinghive/hosted-available-lke648397-260827-5n31Approved by a Hive merger/owner for auto-merge on green CIqualityApproved by a Hive merger/owner for auto-merge on green CI

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions