fix: persist state after initial scan and meaningful progress #19
No reviewers
Labels
No labels
dep-scan
dep-scan
dep-scan
dep-scan
dep-scan
dep-scan
dep-scan
dep-scan
dep-scan
dep-scan/ignore
dep-scan/ignore
dep-scan/ignore
dep-scan/ignore
dep-scan/ignore
dep-scan/ignore
dep-scan/ignore
dep-scan/ignore
dep-scan/ignore
finding
mod-nag
mod-nag
mod-nag
mod-nag
mod-nag/ignore
mod-nag/ignore
mod-nag/ignore
mod-nag/ignore
bug
doc
duplicate
enhancement
help wanted
invalid
question
security
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
IUS/xr-invoiced!19
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/13-state-progress-save"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #13
Adds
saveStatescallback torunMailboxand calls it after updating state in the UIDValidity-changed branch, ensuring progress is persisted before entering IDLE.Review findings (ai:codex)\n\nMedium: cmd/xr-invoiced/main.go:196\nsaveStates() now persists HighestModSeq even when SearchUIDs fails in the st.LastUID > 0 fallback path. In the migration/CONDSTORE bootstrap case where HighestModSeq == 0 and LastUID > 0, a transient UID search failure advances and saves HighestModSeq to the mailbox current value without scanning those messages. On the next run, the CONDSTORE branch starts from that saved modseq and can permanently skip messages that should have been scanned.\n\nMedium: cmd/xr-invoiced/main.go:237\nsaveStates() serializes file writes, but it does not synchronize access to the state being marshaled. With multiple mailboxes, one goroutine can marshal all states while another mutates its state fields around LastUID, HighestModSeq, or LastExit updates. The new mid-run saves make that race more likely during normal operation; a race test or state-locking design is missing.\n\nLow: cmd/xr-invoiced/state_progress_regression_test.go:26\nThe regression test string-searches main.go for saveStates/Save before the IDLE log marker. It would pass if the call were before state fields are updated, inside unrelated code, or otherwise not actually persisting the intended state. A behavioral test around runMailbox/state file contents would protect this regression more directly.\n\nVerification: the focused regression test passed. Full go test ./cmd/xr-invoiced ./internal/state could not complete in the sandbox because existing doctor tests require listen tcp 127.0.0.1:0; internal/state passed.
Review: fix/13-state-progress-save
The PR is correct and solves issue #13.
Observations
Minimal and targeted: Adds
saveStates func()parameter torunMailbox, calls it once after the UIDValidity branch updates state. Ensures a crash before IDLE no longer loses initial scan progress.Other scan branches do not save: CONDSTORE and UID-search branches also update
st.LastUID/st.HighestModSeqwithout persisting. A crash during a long incremental scan loses that progress. Consider saving after those branches too.Concurrency note (pre-existing):
saveMuprotectsSave()but not the struct field mutations. One goroutine writing fields while another is insidejson.MarshalIndentis technically a data race under-race.Function signature: 8th bare
func()parameter is getting unwieldy. Consider moving to theoptionsstruct in a follow-up.Regression test: Source-scanning (grep for
saveStates). Fragile on refactoring but acceptable as a guardrail.No correctness issues found.
— reviewed by ai:claude
Pull request closed