Skip to content

Fix: a hand saved before a restart and stored since is reported as a lost row at the next resync #968

Closed

Description

@svanlabs

Verdict

DEFECT-CONFIRMED on live evidence, low severity: a diagnostic that states a loss that did not happen. Three false warnings in 35 hours on build 7a1494c; no data lost. Found by the same live-log read as the redundant-join ticket.

Failing scenario

report_unsettled (crates/apps/bot/src/client/recover.rs, the function after resume_open_hand) warns "hand X was in progress at the restart and ended before the resync; ... so its row is lost" for any entry left in shared.resumable when a resync snapshot names another hand. An entry leaves the map only when its hand's result is replayed (replayed_result) or priced live by resume_open_hand, and resume_open_hand returns early when the tracker already knows the hand, without removing the entry. A hand whose row was stored is then reported as lost at the next resync:

  • SurSvan, 13:34:43 on 10-10: hand 1e8862bf, stored at 11:00:23 (net -165), reported 2 h 34 min later after a connection reset.
  • Svanism, 14:03:59: hand 7abdd813, stored at 11:00:39 (net -50), same.
  • SvanBotV10, 11:00:04, at the hot swap: hand 08305a02, stored at 10:59:57 by the process that was swapped out (net -128). The row is in hands and in the history raw table; the operator verified this on 2026-10-10.

The warning exists so that a row lost at a hot swap does not stay silent (0315). A false one at every swap hides a true one, and the next release is a swap.

Fix

Drop the entry without a warning when the store holds the hand. report_unsettled asks shared.store.hand(&bot.name, &saved) the way replayed_result does, and warns only on Ok(None): a store that cannot answer says nothing about the row. One check in the one reporter covers all three causes.

Test

Reproduce first on origin/main: resumable holds hand X, the store holds a row for X, and a resync snapshot names another hand; assert no warning and that the entry is dropped. The counterpart with no stored row still warns.

Generated-by: claude-code/claude-sonnet-5-5

Activity

  1. added
    bugSomething isn't working
    agent-friendlyFully specified so an autonomous agent can finish it end to end
    on Oct 11, 2026
  2. svanlabs commented on Oct 12, 2026

    @svanlabs
    ContributorAuthor

    Pinned for the fix (read-only prework, nothing changed):

    • Site: report_unsettled in crates/apps/bot/src/client/recover.rs removes the resumable entry and then logs. Between the removal and the log, add if matches!(shared.store.hand(&bot.name, &saved), Ok(Some(_))) { return; }. Store::hand returns Result<Option<HandRow>> (crates/libs/store/src/store/hands.rs:364), and replayed_result already treats anything but Ok(None) as "do not claim a loss".
    • Test: beside the existing report test in crates/apps/bot/src/client/handler/tests/recover.rs (the one asserting "and dropped, so the next resync does not repeat it"). Same setup, with the saved hand's row stored first; assert no "row is lost" line and the entry gone. The existing test with no stored row must still warn.
    • No simulation: log-only change.

    Generated-by: claude-code/claude-sonnet-5-5

  3. svanlabs commented on Oct 12, 2026

    @svanlabs
    ContributorAuthor

    Resolved by pull request 972, merged as 0e3d584.

    • report_unsettled now asks the store before it names a hand lost, and says nothing when the row is there. A store that cannot answer still warns. It covers all three false warnings: the hand stored by the swapped-out process, and the two stored by the live path whose saved start stayed in resumable.
    • Test a_saved_hand_the_store_already_holds_is_not_reported_lost, run red on the unmodified code first; the existing "reported lost once" test still passes. Full gate: 897 passed, 0 failed. CI: check, gate and web green.
    • Log-only change: no paired simulation, no golden change. Not released: the running build is 7a1494c.

    Generated-by: claude-code/claude-sonnet-5-5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-claimedClaimed by SvanLabs bot for active agent workagent-friendlyFully specified so an autonomous agent can finish it end to endbugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions