- Remove `canAutoSync` dep from scheduler; auto-sync now runs during playback/stats
- Sync window always passes `--force`; WAL snapshots and transactional merges handle concurrent writers
- Update docs to clarify live vs cold-start sync modes
- Remote merge step now passes --json to get NDJSON output
- Parses merge-summary from remote stdout; emits as merge-summary/remote event
- Falls back to remote-output for non-JSON runs
- Updates docs and changelog to reflect per-machine merge summaries
- Use StringDecoder to avoid corrupting multibyte chars (e.g. Japanese titles) split across stdout/stderr chunks
- Settle a run within EXIT_DRAIN_MS (2s) after child exit when no terminal NDJSON arrives, instead of waiting on `close` that retained pipes can withhold indefinitely
- Re-issue post-cleanup quit via setImmediate so Electron doesn't drop it while unwinding the prevented quit
- Use requestAppQuit (not app.quit) on sync window close for forced-exit fallback coverage
- Settle cancelled/timed-out runs immediately when child already exited to avoid hanging on close held open by descendants
- `runSyncLauncher`: defer exit settlement until result event parsed; handle exit-before-stdout race
- AppImage sync commands now run in Node-only mode (`ELECTRON_RUN_AS_NODE=1 -e ...`) so remote sync needs no display server
- Update docs and changelog to reflect both changes
- Use runAppCommandInteractive so sync-window inherits the terminal directly
- Quit app on window-all-closed when launched with --sync-window on macOS
- Catch synchronous onWillQuitCleanup errors to prevent quit getting stuck
The remote tracker increments imm_words/imm_kanji.frequency live, so a
snapshot holding a stale ACTIVE session (skipped by the merge) has that
session's partial occurrences baked into frequency. A word new to the
local DB adopted that full total, then received the same occurrences
again when the session finalized and merged on a later sync.
Subtract active-session occurrence counts when adopting a new row; they
are re-added exactly once when the session completes. Existing rows were
already safe (isNew guard in addWordOccurrences/addKanjiOccurrences).
Verified red/green: the new two-sync regression test fails without the
subtraction (frequency 9 instead of 5).
rollup_day is a local epoch day, but the copy-vs-recompute guard read its
month back via day * 86400 (UTC midnight), which resolves to the previous
civil month for the 1st of a month anywhere west of UTC. Anchor at local
noon (+43200) instead. Pre-existing on main, surfaced by CodeRabbit review.
- Merge related fix entries into single files (name-match-span-merge into character-name-split-and-scan-recovery, kanji-non-independent-noun-annotations + lexicalized-expression-frequency into content-adverb-annotation-stop-list, greedy-name-parsing-priority into character-name-split-and-scan-recovery, kiku-field-grouping-cancel-double-toast into kiku-field-grouping-modal-recovery, history-rofi-cover-art into launcher-history-command)
- Rewrite remaining entries for brevity and reclassify stats-trend-title-limits as "changed"
- Add allowReadingOnlyMatch:false to kanji token known-word lookups so 渓谷/けいこく no longer matches a mined 警告/けいこく card via reading-only index
- Greedy name pre-pass yields when a strictly longer generic word starts at the same position (空 no longer splits 空気; ties still go to the name)
- 確かに and やはり no longer excluded from frequency/JLPT highlighting and vocab stats
- Stop-word list now covers only interjections, pronouns, and grammar fragments
- Drop changes/kiku-field-grouping-modal-wiring.md (landed in #138)
- Drop changes/known-word-partial-reading-highlight.md (landed in #142)
- Remove assets/minecard.mkv demo video