Symptom
From the project chat (@Rocket_bunny2, 2026-09-26): 102 trades show up in Analytics as having no close date, while in MoonBot everything is closed. The user did not notice any disconnect.
Mechanism (verified in code)
- When the core closes a trade, it updates the existing report row (the close date is written into the same
newRecID; the id does not change). The terminal receives this as a live RowUpsert.
- If that update is lost (e.g. a short automatic reconnect to the core that the user never sees), catch-up does not bring it back: it resumes above the cursor, and the row's
newRecID is below it. The alive map only carries visibility, not content.
- The only repair is
check_open_rows. Its set is built once, when the replica is opened at terminal start (rep::init → open_row_ids, crates/moon-core/src/db/rep.rs): at most 100 open rows per core, newest first. feed/live/mod.rs sends the same startup snapshot on every (re)connect of the core, and nothing refreshes ReportSink::open_rows during the session.
Net effect:
- A trade that opened AND closed while the terminal was running, with the close lost in a reconnect, stays "open / undated" in the replica until the next terminal restart. ↻ «Переподключить» does not help, because it resends the stale snapshot.
- With more than 100 such rows on one core, only the newest 100 are checked per start, so the rest need extra restarts. This user had 102.
Expected
On every (re)connect, recheck the rows that are open in the replica NOW (recompute open_row_ids instead of reusing the startup snapshot), and page through them if there are more than 100, so that a missed close heals on reconnect without a terminal restart.
Symptom
From the project chat (@Rocket_bunny2, 2026-09-26): 102 trades show up in Analytics as having no close date, while in MoonBot everything is closed. The user did not notice any disconnect.
Mechanism (verified in code)
newRecID; the id does not change). The terminal receives this as a liveRowUpsert.newRecIDis below it. The alive map only carries visibility, not content.check_open_rows. Its set is built once, when the replica is opened at terminal start (rep::init→open_row_ids,crates/moon-core/src/db/rep.rs): at most 100 open rows per core, newest first.feed/live/mod.rssends the same startup snapshot on every (re)connect of the core, and nothing refreshesReportSink::open_rowsduring the session.Net effect:
Expected
On every (re)connect, recheck the rows that are open in the replica NOW (recompute
open_row_idsinstead of reusing the startup snapshot), and page through them if there are more than 100, so that a missed close heals on reconnect without a terminal restart.