Skip to content

Commit be930d1

Browse files
committed
gate startup on required sync stages and final refresh
1 parent 7c44f34 commit be930d1

18 files changed

Lines changed: 540 additions & 36 deletions

‎PLAN.md‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,20 @@
77
- [x] Import contact app-state events and resolve saved names regardless of chat/contact event order, including known identity aliases and concurrent imports.
88
- [x] Import initial/recent chat names and up to 50 newest messages per conversation per batch; retain existing history, keep full-archive message bodies out of the automatic import, and emit ordered batch completion.
99
- [x] Use saved app-state versions for incremental sync, enable full-sync events before connection without runtime flag races, and reconcile metadata after app-state sync.
10-
- [ ] Restore explicit loading/readiness stages with honest partial/error states and a final snapshot barrier.
11-
- [ ] Validate Linux tests, vet, race checks, and document the startup behavior.
10+
- [x] Restore blocking loading/readiness stages across contact/app-state, metadata, announced history chunks and catch-up, followed by an atomic final snapshot barrier; errors remain explicit and configurable cached browsing never enables sending.
11+
- [x] Validate Linux tests, vet, race checks, and document the startup behavior.
12+
13+
Verified on Linux on 2026-09-24: `make test`, `make lint`, full
14+
`make test-race`, ten repeated startup/order/error test runs, and
15+
`git diff --check`. Tests use synthetic accounts; real pairing/reconnect
16+
validation is still required. No private sessions were read or modified.
17+
The 50-message policy is per automatic conversation batch and affects local
18+
import, not the protocol library's history download size.
19+
20+
Separate correction commits so far: `2083726` (contact ordering/aliases),
21+
`2e56273` (initial/recent history), `5e744ba` (incremental app-state),
22+
and `7c44f34` (cached names/settings reconciliation). The staged-readiness
23+
change is committed separately as `gate startup on required sync stages and final refresh`.
1224

1325
### Reliability remediation (September 2026)
1426

@@ -26,7 +38,7 @@ validation. No live account traffic is required for automated validation.
2638
- [x] Persist explicit invalidation of missing media cache paths, with compare-and-clear protection for concurrent downloads.
2739
- [x] Default Linux image/video/file openers to auto capability probing; preserve strict explicit command overrides and document the distinction in generated/example config.
2840
- [x] Bound retained history to eight chats and 400 messages per window, page in both directions, reload around historical focus, and complete pending quote jumps using direct bounded target lookup.
29-
- [x] Retry initial connection failures with cancellable exponential backoff capped at 30 seconds; keep chats/history/drafts usable during background sync while gating protocol actions until readiness.
41+
- [x] Retry initial connection failures with cancellable exponential backoff capped at 30 seconds; explicit cached browsing during staged sync keeps local chats/drafts usable without enabling protocol actions.
3042
- [x] Extract composer persistence/actions, history windows/loading, sync progress/state, live event orchestration, outgoing sends/recovery, and message actions into focused files with regression tests preserved.
3143
- [x] Remove Windows support code/tests/obligations and configure Linux amd64/arm64 CI artifacts plus version-tagged releases.
3244

@@ -72,7 +84,7 @@ The starting revision was `706dd85`. Each change can be inspected with `git show
7284
- Real paired WhatsApp sessions, QR login/logout, live ingestion, canonical PN/LID identity repair, on-demand remote history, metadata sync, remote media/sticker/avatar downloads, and native Linux notifications.
7385
- Text and single-attachment/sticker sends with durable status, interrupted-send recovery, and explicit same-ID text/media retries. Uncertain delivery is never silently retried.
7486
- Replay-safe edits/receipts/payloads, transactional forwarded-message queueing, targeted read acknowledgements, and persisted missing-cache invalidation.
75-
- Bounded history windows and chat retention with direct target lookup; initial reconnect backoff and nonblocking local UI during sync.
87+
- Bounded history windows and chat retention with direct target lookup; reconnect backoff, blocking staged sync, explicit cached browsing, and persistent readiness/failure indicators.
7688
- Linux media previews (`ueberzug++` → `chafa` → external), automatic image/video/file opener defaults, argv-safe configurable integrations, clipboard and audio playback.
7789
- Linux amd64/arm64 CI artifacts; tests, vet, race checks, and version-tag-only release publication with checksums.
7890

@@ -279,7 +291,7 @@ The large-chat and title-correctness hardening milestone is implemented:
279291
- Canonicalize direct chats onto the mapped WhatsApp LID identity when PN/LID aliases are known, and merge split alias threads so one person cannot appear as multiple chats after history sync or mixed-device traffic.
280292
- Refresh joined group/contact metadata after the live WhatsApp connection comes online, without blocking TUI startup.
281293
- Display neutral group placeholders when old rows contain phone-like/JID-derived group titles.
282-
- Debounce live DB snapshot refreshes, consolidate reconnect catch-up as nonblocking background progress and a final snapshot barrier, require WhatsApp's ordered offline-complete marker before readiness, treat pre-marker inactivity only as a stall warning, wait for known post-marker message recoveries with a bounded fallback, summarize catch-up notifications once, and bound message render windows for chats with hundreds of loaded messages.
294+
- Debounce live DB snapshot refreshes; gate readiness on app-state/contact reconciliation, metadata, announced initial/recent history batches, reconnect catch-up and the final snapshot. Offer cached browsing explicitly, keep progress persistent, report missing markers/recoveries/import failures honestly, summarize catch-up notifications once, and bound message render windows.
283295

284296
The TUI stability and modal polish milestone is implemented:
285297

‎README.md‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,13 @@ Draft text, attachments, reply context, and mentions are saved per chat with ord
3838

3939
Interrupted sends are marked `uncertain` (`?`) on startup; no message is silently resent. `R` or `:retry-message` retries failed/uncertain text or media using the original delivery ID. A timeout is not proof of non-delivery—check the conversation before retrying. The legacy configurable binding name `key_normal_retry_failed_media` now covers text too.
4040

41-
Local chats and drafts stay usable during reconnect/sync. Sending remains disabled until catch-up is ready. History retention is bounded to eight chats and 400 messages per window; quote jumps load around their target. Scroll down at a historical window's end to load newer messages, or use the configured go-bottom binding (`G` by default) to return to the newest window.
41+
Startup and reconnect show a loading screen for contacts/settings, name resolution, recent history, catch-up, and the final chat refresh. `login complete` means paired, not fully synchronized. `WA:READY` appears only after required imports and the final refresh succeed. Missing history, metadata failures, and stalled startup are shown explicitly; they do not silently become ready.
42+
43+
Press `b` on the loading screen (`key_sync_browse`) to browse cached chats and edit drafts while syncing. This does not enable sending. Progress remains in the status bar; `WA:SYNC FAILED` means restart the app to retry. `Ctrl+C` quits normally and flushes drafts. Optional avatars and sticker/media downloads do not hold up core readiness.
44+
45+
Automatic initial/recent history imports chat names and up to 50 newest messages per conversation per received batch. Full-archive batches contribute chat metadata, not their message bodies. This is a local import policy: the protocol library may still download larger history payloads. Existing local messages are never pruned by this policy; older remote history is fetched on demand.
46+
47+
The UI keeps at most eight chats and 400 messages per window in memory; quote jumps load around their target. Scroll down at a historical window's end to load newer messages, or use the configured go-bottom binding (`G` by default) to return to the newest window.
4248

4349
Image/video/file opener defaults are `auto`: installed candidates are tried in order. Existing explicit command settings remain strict; change old `nsxiv`/`mpv` defaults to `auto` to opt into fallback. Without the optional `yazi` picker, use `:attach <path>`.
4450

‎config.example.toml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ key_help_close_alt = "?"
4545

4646
# Normal mode
4747
key_normal_cancel = "esc"
48+
# Sync screen only: browse cached chats while loading; sending stays disabled.
49+
key_sync_browse = "b"
4850
key_normal_quit = "q"
4951
key_normal_help = "?"
5052
key_normal_insert = "i"

‎internal/app/app.go‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ func runTUI(env Environment, stderr io.Writer) int {
196196
ConnectionState: initialConnection,
197197
LiveUpdates: liveUpdateSource,
198198
RequireOnlineForSend: liveEnabled,
199-
BackgroundSync: true,
199+
BlockLiveStartup: liveEnabled,
200200
PersistMessage: func(outgoing ui.OutgoingMessage) (store.Message, error) {
201201
for i, attachment := range outgoing.Attachments {
202202
if env.Paths.IsManagedCachePath(attachment.LocalPath) {
@@ -608,6 +608,7 @@ var (
608608
databaseImportInactivity = 750 * time.Millisecond
609609
databaseImportMaxDuration = 60 * time.Second
610610
liveStartupSyncSettle = 1 * time.Second
611+
startupSyncTimeout = 2 * time.Minute
611612
)
612613

613614
type textSendRequest struct {

0 commit comments

Comments
 (0)