Skip to content

fix(timestamps): send ISO-8601 and drop the offset corrections that hid it - #151

Merged
guarzo merged 1 commit into
guarzo/zoofrom
fix-timestamp-wire-format
Aug 17, 2026
Merged

fix(timestamps): send ISO-8601 and drop the offset corrections that hid it#151
guarzo merged 1 commit into
guarzo/zoofrom
fix-timestamp-wire-format

Conversation

@guarzo

@guarzo guarzo commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Follow-up to #150, which fixed the scan-age bookmark at the reader and deliberately left the ambiguous wire format alone.

What was wrong

get_system_signatures/1 and get_system_structures/1 serialised UTC as %Y/%m/%d %H:%M:%S — nothing in that string says UTC, so new Date read it as local time. Two readers compensated by adding getTimezoneOffset() to now:

  • TimeLeft.tsx:34 (the signature table's "Added"/"Updated" columns)
  • getRowBackgroundColor.ts:12 (the new-signature row highlight)

Those two cancelled the error out, which is what made the broken format look fine. Any reader that did not know the trick was silently wrong by the viewer's offset — that is exactly how the scan-age bookmark ended up pinned at 0h.

Both handlers now emit DateTime.to_iso8601/1 and both corrections are gone. These had to change together: either half alone leaves the readers double-correcting in the opposite direction, which is why #150 did not touch the serialiser.

signatureAge.ts drops the format-sniffing branch #150 added, along with its tests — nothing in lib/ emits the zone-less format any more, so there is a single parse path again.

Scope check

I surveyed every consumer before touching the shared components, and two findings shaped the change:

  • getRowBackgroundColor is a second copy of the same correction. It was not in the original plan; missing it would have left row highlighting broken while everything else was fixed.
  • No TimeAgo caller is affected. Passages, pings, comments and connection times are already ISO-8601 from raw Ash structs, and TimeAgo has no correction — so they were correct before and stay correct.
  • Structure timestamps have no frontend reader at all. mapServerStructure spreads them through untouched and the structure timers use a separate end_time field. That half is hygiene, not behaviour.

Transition note

getActualSigs compares updated_at as a string to detect changes, and getActualStructures does a JSON.stringify comparison. A tab held open across the deploy can compare a pre-deploy string against a post-deploy one and mark signatures changed once. It self-heals on the next refetch and nothing is written back — the server never reads these fields (create_timestamp/update_timestamp own them).

Tests

Both new tests fail against the old format:

  • backend: DateTime.from_iso8601/1 rejects 2026/08/16 23:09:52 outright, so the assertion is red before the change.
  • getRowBackgroundColor: a signature added five seconds ago was landing seven hours stale under the pinned test timezone, so it got no highlight at all.

1808 Elixir tests, 35 frontend tests, mix format --check-formatted, mix compile --warnings-as-errors, prettier clean, no new tsc errors.

…id it

Follow-up to #150, which fixed the scan-age bookmark at the reader while
leaving the ambiguous wire format in place.

`get_system_signatures/1` and `get_system_structures/1` serialised UTC as
`%Y/%m/%d %H:%M:%S`, which carries nothing marking it as UTC, so
`new Date` read it as local time. Two readers compensated by adding
`getTimezoneOffset()` to *now* — `TimeLeft` and `getRowBackgroundColor` —
which cancelled the error out and made the format look correct. Any
reader that did not know the trick was silently wrong by the viewer's
offset, which is how the bookmark came to sit at "0h".

Both handlers now emit `DateTime.to_iso8601/1`, and both corrections are
gone. They had to move together: either half alone leaves the readers
double-correcting in the opposite direction.

`signatureAge.ts` drops the format-sniffing branch #150 added, and its
tests go with it — nothing in lib/ emits the zone-less format any more,
so there is one parse path again.

Structure timestamps have no frontend reader at all (`mapServerStructure`
spreads them through untouched; the structure timers use a separate
`end_time` field), so that half is hygiene, not a behaviour change.

Verified: 1808 Elixir tests, 35 frontend tests, `mix format
--check-formatted`, `mix compile --warnings-as-errors`, prettier, and no
new tsc errors. The new tests fail against the old format — the backend
one because `DateTime.from_iso8601/1` rejects it outright, the row-colour
one because a signature added seconds ago was landing seven hours stale.
@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 28 minutes

Limit details: You’ve used all 3 included reviews currently available under your plan. You completed 75 included PR reviews in the past 7 days; at that activity level, included reviews refill at 3 reviews per hour.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0463c9fb-f919-47fe-beb3-374a76494526

📥 Commits

Reviewing files that changed from the base of the PR and between 11eb992 and 57586ac.

📒 Files selected for processing (8)
  • assets/js/hooks/Mapper/components/map/helpers/signatureAge.test.ts
  • assets/js/hooks/Mapper/components/map/helpers/signatureAge.ts
  • assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/helpers/getRowBackgroundColor.test.ts
  • assets/js/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/helpers/getRowBackgroundColor.ts
  • assets/js/hooks/Mapper/components/ui-kit/TimeLeft/TimeLeft.tsx
  • lib/wanderer_app_web/live/map/event_handlers/map_signatures_event_handler.ex
  • lib/wanderer_app_web/live/map/event_handlers/map_structures_event_handler.ex
  • test/wanderer_app_web/live/map/event_handlers/map_signatures_event_handler_test.exs

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

🧪 Test Results Summary

Category Result Gates merge?
🧪 Tests (4 shards) ✅ Passed ✅ yes
📝 Formatting / Compile ✅ Passed ✅ yes
⚠️ Compile warnings 0 advisory
🎯 Credo 262 issues advisory
🔍 Dialyzer 221 warnings advisory

Full output for the advisory checks is attached to this run as
build artifacts. Coverage runs on pushes to the default branch,
not on PRs.

🔧 Reproduce locally
mix format
mix test
mix credo --strict
mix dialyzer

🤖 Auto-generated by GitHub Actions

@guarzo
guarzo merged commit 062694e into guarzo/zoo Aug 17, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant