Read commit timestamps in UTC via linq2db and remove NormalizeTimestamp#2391
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughThis PR fixes DateTimeOffset/timezone parity issues between EF Core and linq2db. It corrects linq2db mapping schema registration, removes a manual timestamp normalization workaround in HistoryService, refactors commit deletion to an ID-based approach, adds parity tests, forces a non-UTC CI timezone, and documents linq2db timestamp comparison caveats. ChangesTimestamp/timezone parity fix
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
hahn-kev
left a comment
There was a problem hiding this comment.
nice catch. I have some suggestions.
Locks in that every persisted DateTimeOffset round-trips to the same UTC instant through both EF Core and linq2db (#2092). linq2db skips the converter for the Harmony commit timestamp so HistoryService normalizes it by hand; comment dates use the global EF converter, which linq2db also applies. These errors equal the local UTC offset, so they vanish on UTC — hence the FwLite test job now runs under Eastern time (non-UTC, DST, negative offset). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
lexbox's second UseLinqToDB created a fresh MappingSchema that shadowed Harmony's, dropping Harmony's Commit.HybridDateTime.DateTime UTC converter. linq2db then read commit timestamps in local time, so HistoryService normalized them by hand (#2092). Extend Harmony's existing schema instead of replacing it: the converter now applies, the redundant Commit column re-declaration is gone, and HistoryService.NormalizeTimestamp is deleted. The parity test now also covers UnreadComment.MarkedUnreadAt and fails loudly instead of a silent no-op when run on UTC. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Collapse the repetitive per-column tuples into a generic AssertColumnsAreUtc<T> helper, and add a DeletedAt test that reads it from the deleted snapshot (EntityIsDeleted column) since it is never non-null in a projected column. Tightened comments. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
All plain DateTimeOffset columns share one global converter, so testing many proves nothing extra. Drop the generic helper and MarkedUnreadAt; keep one comment timestamp, the commit timestamp, and DeletedAt — the three distinct mechanisms. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Explain the conditional AddMappingSchema (UseLinqToDbCrdt already registered the schema); drop the duplicated DeletedAt note from the test header and state it once at the call site, including why that test isn't gated on a non-UTC zone. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Move RequireNonUtc() into InitializeAsync so it guards every test in the class (per hahn-kev); DeletedAt is now gated too, fine since it still round-trips correctly under a non-UTC zone. - Add an explicit linq2db read of the commit timestamp so the linq2db path stays covered even if HistoryService ever moves to EF. - Set the comment thread CreatedAt to a known non-UTC-offset instant and assert it exactly, testing that the write is recorded (not just the round-tripped return). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Falling back to a fresh MappingSchema silently dropped Harmony's Commit UTC conversion, reintroducing local-time timestamps (#2092). Fail loudly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2cb4964 to
1d8ffe9
Compare
|
Rebased and resolved merge conflicts |
|
The latest updates on your projects. Learn more about Argos notifications ↗︎
|
linq2db renders timestamp parameters truncated to milliseconds while SQLite's strftime (which linq2db wraps around every timestamp comparison) rounds to the nearest millisecond, so WhereAfter via ToLinqToDB() classified targetCommit as after itself and deleted it — the PreserveAllFieldWorksCommits CI failure (~25% of runs, timezone-independent; reproducible on this branch, not on develop, because reusing Harmony's mapping schema changed how the parameter renders). sillsdev/harmony#78 fixes the parameter rendering, but linq2db comparisons stay millisecond-grained, so exact commit ordering belongs in EF regardless. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CreateCommentThread requires a known user identity since Comments (#2382). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Makes every
DateTimeOffsetwe persist round-trip to the same UTC instant through both EF Core and linq2db, and removes the hand-rolledHistoryService.NormalizeTimestampworkaround for #2092.Root cause: lexbox's second
UseLinqToDBcreated a freshMappingSchemathat shadowed Harmony's, dropping Harmony'sCommit.HybridDateTime.DateTimeUTC converter — so linq2db read commit timestamps in local time andHistoryServicereinterpreted the ticks by hand. The fix is to extend Harmony's existing schema (its own get-or-create pattern) instead of replacing it; the converter then applies, the redundant Commit column re-declaration is deleted, andNormalizeTimestampis gone.DateTimeOffsetOrmParityTestslocks this in: the commit timestamp (EF + bothHistoryServicelinq2db paths) and the plain columns (commentCreatedAt/UpdatedAt,UnreadComment.MarkedUnreadAt) must all report the same UTC instant at offset zero.Set-TimeZonestep; the test fails loudly rather than passing vacuously if ever run on UTC.SnapshotAtCommitService.DeleteCommitsAftercompared timestamps through linq2db — which is millisecond-grained (linq2db wraps SQLite timestamp comparisons instrftime('...%f')) and could delete the target commit itself (thePreserveAllFieldWorksCommitsCI failure, ~25% of runs, timezone-independent).WhereAfternow runs through EF like Harmony's ownCrdtRepository; linq2db keeps only theJson.Valueauthor filter. The rule is documented inbackend/FwLite/AGENTS.md. Bind SQLite timestamp parameters as the exact stored text harmony#78 hardens the parameter rendering upstream — this PR does not depend on it.🤖 Generated with Claude Code