Skip to content

2026.09.13 — 2026-09-07

Fixed

  • Take the clock from Studio, and let the operator pick the timezone (6a970c39)

    Every duration, expiry check and metric window in the UI was computed against the browser's clock. An operator whose workstation ran four minutes fast saw every request-reply flow age inflated by four minutes, a live API key rendered as expired, and an empty metrics chart with nothing saying why — the window it asked the server for had not happened yet.

    Studio already refuses to trust a broker's clock (ADR-0053). The browser is one more foreign clock, and it was the only one still taken on faith.

    What changes for you:

    • Ages, staleness labels and token expiry now follow Studio's clock, not the   machine the browser runs on. On a correctly-synchronised workstation nothing   moves; on a skewed one, the numbers become right.
    • The metrics window and the queue drawer's chart are quantised on the server's   clock, so a skewed workstation no longer requests a range the server has no   samples for.
    • Timestamps now render in your own timezone by default, detected from the   browser, where they were previously always UTC. Settings → Display picks a   different one, including UTC to match container and broker logs. The choice is   per-browser, needs no permission, and is never reset once made.
    • Every absolute timestamp now names the offset it is written in (Z, +03:30)   and is rendered to whole seconds, where before some carried milliseconds and   some did not.
    • The metric charts previously drew their axis in the browser's local zone while   every table beside them was UTC, with nothing disclosing the difference. Both   now follow the chosen zone.

    How it works: a new GET /api/v1/time returns Studio's clock, and the client measures its own offset NTP-style with round-trip bracketing — the same estimator and the same constants as ClockOffsetRegistry, so the two halves of the system agree about method. A reading is only allowed to teach the estimate when its round trip is at or near the best seen; an offset inside its own error bar is held at zero rather than correcting by noise. The SSE ping already carried the server's clock and the client discarded it; it is now a drift detector that asks for a real probe, never a measurement of its own, since a one-way frame cannot measure its own latency. A wall-clock step — a laptop waking, an NTP correction — is caught by comparing Date.now() against performance.now(), the client-side MonotonicClockWatch, and discards the estimate rather than slowly unlearning it.

    web/src/app/time.ts states the rule for the whole frontend: durations and expiry against a server timestamp use serverNow(); a browser-stamped instant entering such a comparison (TanStack's dataUpdatedAt is the only one) is normalised with toServerMs() at the boundary; monotonic work keeps using performance.now(). Three duplicate "ago" formatters and seven copies of the absolute-timestamp formatter are folded into it.

    Known and deliberately out of scope: the queue detail drawer's chart window is memoised on the range spec alone, so it is fixed at first render and does not advance while the drawer stays open. That predates this change.

Apache-2.0. Apache ActiveMQ and Apache ActiveMQ Artemis are trademarks of the Apache Software Foundation. Artemis Studio is an independent project, not produced by, endorsed by, or affiliated with the ASF.