Skip to content

fix(genesis-writer): keep sub-second precision on every emitted timestamp - #534

Merged
rickyrombo merged 2 commits into
mainfrom
mjp-release-date-nano
Aug 20, 2026
Merged

fix(genesis-writer): keep sub-second precision on every emitted timestamp#534
rickyrombo merged 2 commits into
mainfrom
mjp-release-date-nano

Conversation

@rickyrombo

@rickyrombo rickyrombo commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

time.RFC3339 has no fractional-second component, so every timestamp the writer emits was rounded down to the whole second. Measured against a full-snapshot replay compared to its source:

table sub-second in source in migrated DB
subscriptions 1,022,554 0
playlist_tracks 1,014,903 0
saves 380,604 0
reposts 361,803 0
follows 104,614 0
track_downloads 78,032 of 78,032 0
comments 7,530 0
tracks.release_date 26,129 truncated
same row:  src  2024-12-01 12:30:13.244308
           etl  2024-12-01 12:30:13

Why created_at isn't cosmetic

The indexer replays each migrated row as of its created_at (migrationBlockTime), so the timestamp drives replay semantics, not just display. Parity also keys track_downloads on created_at — which is why every sampled row of that table reported as missing rather than mismatched. The row counts match exactly (78,032 both sides); only the key failed to join.

Safety

  • parseMigrationTimestamp tries RFC3339Nano before RFC3339
  • Go's parser accepts a fractional second against a layout that lacks one, so event_create.go's stricter time.Parse(time.RFC3339, …) still succeeds
  • A value with no fractional part formats identically under both layouts, so rows without microseconds are untouched

Note on the guard

TestAllEmittedTimestampsAreUTC scans for formatting sites and fails if it finds none — it caught this rename immediately. Its pattern now matches both layouts, so reintroducing the truncating form still trips the .UTC() half.

This is a different failure from the one #519 fixed. That emitted Postgres text format, which matched no accepted layout, so the indexer fell back to block time. This parses cleanly and quietly rounds.

🤖 Generated with Claude Code

@rickyrombo
rickyrombo force-pushed the mjp-release-date-nano branch from 6169a16 to 965c5e2 Compare August 20, 2026 04:20
@rickyrombo rickyrombo changed the title fix(genesis-writer): keep sub-second precision on release_date fix(genesis-writer): keep sub-second precision on every emitted timestamp Aug 20, 2026
rickyrombo and others added 2 commits August 19, 2026 22:16
time.RFC3339 has no fractional-second component, so every release_date
carrying microseconds was rounded down to the whole second on the way out.
A full-snapshot replay compared against its source showed 26,129 current
tracks affected, e.g. 2026-02-02T15:53:12.050585Z emitted as
2026-02-02T15:53:12Z.

The indexer already accepts RFC3339Nano, and a value with no fractional
part formats identically under both layouts, so rows without microseconds
are unchanged.

This is a different failure from the one #519 fixed. That emitted
Postgres text format, which no accepted layout matched, so the indexer
fell back to block time. This parses cleanly and quietly rounds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tamp

time.RFC3339 has no fractional-second component, so every timestamp the
writer emitted was rounded down to the whole second. Verified against a
full-snapshot replay:

  track_downloads   78,032 of 78,032 source rows carry sub-second
                    created_at; the migrated table has zero
  subscriptions  1,022,554        playlist_tracks  1,014,903
  saves            380,604        reposts            361,803
  follows          104,614        comments             7,530
  tracks.release_date 26,129

created_at is not cosmetic here: the indexer replays each migrated row as
of its created_at (migrationBlockTime), and parity keys track_downloads on
it -- which is why every sampled row of that table reported as missing
rather than mismatched.

Safe for every reader. parseMigrationTimestamp tries RFC3339Nano before
RFC3339, and Go's parser accepts a fractional second against a layout that
lacks one, so event_create.go's stricter RFC3339 parse still succeeds. A
value with no fractional part formats identically under both layouts, so
rows without microseconds are untouched.

The UTC guard now matches both layouts, so reintroducing the truncating
form still trips its .UTC() half.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@rickyrombo
rickyrombo force-pushed the mjp-release-date-nano branch from 965c5e2 to 2f9a131 Compare August 20, 2026 05:17
@rickyrombo
rickyrombo merged commit bddde9e into main Aug 20, 2026
5 checks passed
@rickyrombo
rickyrombo deleted the mjp-release-date-nano branch August 20, 2026 05:38
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