Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

[claude] Sync head truncates HybridDateTime to milliseconds, permanently stranding commits

オープン
#89 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 4 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
35/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
csharp

調査の方向性

QueryHelpers.cs の QueryHelpers.GetSyncState と 2 つの GetMissingCommits パスから始め、次にそれらの順序を WhereAfter と比較して SyncState を調べます。counter-sibling、stranded commits、clamp bursts、および両方の同期可能なバックエンドにまたがるエンドツーエンド同期を対象とするテストを実行します。説明されている損失ケースでコミットが孤立しなくなり、完全なテストスイートにパスすれば完了です。

索引モデルが issue の本文から書いたものです。

説明

Data bug

[Claude, autonomous]

[!TIP]
A starter branch is attached to this issue to jump-start the implementation: claude/harmony-issue-89-oga6ra  •  browse the diff

It takes the boringly-simple route instead of the full-precision one below: make the sync-head comparison inclusive on the millisecond (> → >=) in both GetMissingCommits paths, so the head's whole millisecond is re-offered rather than stranded. Per-client the HLC is monotonic, so re-offering that millisecond can never leapfrog a commit. Re-applying a commit the remote already holds is idempotent (FilterExistingCommits drops it), so the only cost is re-sending the head-millisecond commits each sync. No SyncState wire-format change and no back-compat path needed.

Tests cover every flavour of the bug and each fails before the one-line-per-path change: counter-sibling on the head millisecond, a stranded commit after the head advances (both on a whole-millisecond boundary, which the DB pre-filter drops, and with sub-millisecond ticks, which the in-memory guard drops), a full clamp burst, and an end-to-end sync across both syncable backends.

Bug. The per-client sync head is Max(DateTime).ToUnixTimeMilliseconds() (QueryHelpers.GetSyncState), and GetMissingCommits selects the push set with a strict > on that millisecond — both the DB pre-filter and the in-memory guard (QueryHelpers.cs:53,56). But commits carry microsecond DateTime and a Counter. Any commit sharing the head's millisecond fails ms > ms and is treated as already-synced: never offered, and the sync reports success. Once a later commit advances the head, the DB pre-filter excludes it too. The result is permanent, silent commit loss — usually just missing data, or a NotSupportedException in SnapshotWorker if the stranded commit was the create for an entity whose later edit did sync.

How several commits end up sharing one millisecond — HLC clamping. When the wall clock is at or behind lastDateTime, GetDateTime stamps successive commits with the same DateTime and an incrementing Counter. Two ways in: a peer's future-dated commit pulls the HLC ahead of local real time, or the local clock steps back. Either way, every commit made during the catch-up window shares one millisecond; per client, only the first that the server already holds survives, and the rest strand.

Fix. Make the head precision-complete: carry the full HybridDateTime (DateTime + Counter) per client and compare with (DateTime, Counter, Id) ordering, as WhereAfter already does. Per-client commits strictly increase in (DateTime, Counter), so a full-precision watermark is exact. SyncState is a client↔server wire type, so keep a back-compat path for clients still sending millisecond-only heads.

Related: #79 (same watermark weakness, ClientId-duplication variant; its per-client digest would also detect this loss); #7 (future-dated commits, one clamp trigger).

主要言語
C#
スター
14
フォーク
4
平均マージ
5日 4時間
マージ済み PR(30日)
13

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

sillsdev/harmony のほかの issue

sillsdev/harmony の issue をすべて見る

似ている issue

C# の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。