Skip to content

fix(ui): reload state loss, 2nd-send freeze, folder counts + text size (#265, #267, #268)#269

Merged
iduartgomez merged 7 commits into
mainfrom
fix/beta-bug-sweep-265-267-268
May 27, 2026
Merged

fix(ui): reload state loss, 2nd-send freeze, folder counts + text size (#265, #267, #268)#269
iduartgomez merged 7 commits into
mainfrom
fix/beta-bug-sweep-265-267-268

Conversation

@iduartgomez
Copy link
Copy Markdown
Contributor

Beta-tester bug sweep from the testing feedback (5-node manual testing). Fixes three of the four reported issues; #266 is analyzed but deferred (architectural, see below).

Fixes

#265 — Sent→Draft / deleted messages return on reload

A stale GetAll echo from the mail-local-state delegate wholesale-overwrites the in-memory SNAPSHOT, wiping optimistic writes that haven't round-tripped. Drafts (#107) and kept rows (#113) were already tombstone-protected; the Sent stash, delete tombstones, and archive snapshots were not. replace_snapshot now re-merges OPTIMISTIC_SENT / OPTIMISTIC_ARCHIVED / DELETED_MESSAGES until the delegate confirms each, then drops the protection.

Scope note: closes the in-session echo race. A delegate write that fails outright (fire-and-forget spawn, no persistent retry) can still lose state across a real reload — separate follow-up.

#267 — UI freeze + WASM error on second send

DecryptedMessage::from_stored .expect()-panicked on decrypt/deserialize failure, aborting the wasm module. An undecryptable message in shared inbox state (foreign/malformed, common in a multi-node mesh) froze the whole UI on the UPDATE that followed a second send. Now returns Option; from_state filters and apply_delta skips. An undecryptable message is never fatal.

#268 — Folder counts ≠ contents; text too small

  • A: sidebar badge counted unread rows without the deleted/archived/hide_unsigned exclusions the list applies, so the badge exceeded visible rows. folder_count now shares is_inbox_row_visible with the render filter.
  • B: ~131 hardcoded sub-15px font-sizes bumped (7.5→9px … 14.5→15px); display sizes ≥16px untouched.

Not in this PR — #266 (token pop-ups despite toggles)

Root-caused (see #266 comment): allow_verified_skip_token only changes recipient contract policy; the sender path always mints + prompts. The sender-side skip was never wired into start_sending/assign_token (the #157 design note oversold it). Needs the sender to read the recipient's advertised bypass flag and skip minting — deferred to a dedicated PR.

Testing

  • Unit: 156 UI lib + 14 local_state + 3 inbox + 2 folder_count, all green. Clippy clean. use-node release build compiles.
  • Live (iso 2-node): create identity → reload persists → permission flow ✓ and alice → bob cross-node send + receive (#81) ✓. The other 4 specs failed on a pre-existing freenet-core cross-node flake (missing contract parameters wedged the gateway → ECONNREFUSED cascade), not these changes.

🤖 Generated with Claude Code

… echo (#265)

A stale GetAll echo from the mail-local-state delegate wholesale-overwrites
the SNAPSHOT, wiping optimistic writes that haven't round-tripped yet. Drafts
(#107) and kept rows (#113) were already protected by tombstones, but the
Sent stash, delete tombstones, and archive snapshots had none — so a reload
race dropped them. Symptom (beta tester): Sent messages reappear as Drafts and
deleted messages return after leaving and re-entering the app.

replace_snapshot now re-merges OPTIMISTIC_SENT, OPTIMISTIC_ARCHIVED, and
DELETED_MESSAGES on every echo until the delegate confirms the entry, mirroring
the existing draft/kept pattern. Each protection drops once the echo includes
the persisted state, so tombstones don't leak.

Tests: 3 reproduce the clobber (sent/deleted/archived), 3 pin the
confirm-then-drop lifecycle.

Note: this closes the in-session echo race only. A delegate write that fails
outright (no persistent retry) can still lose state across a real reload —
tracked separately.
DecryptedMessage::from_stored .expect()-panicked when ml_kem_decrypt or the
plaintext deserialize failed. An undecryptable message in shared inbox state
(encrypted for a different identity, or malformed/foreign in a multi-node mesh)
therefore aborted the wasm module and froze the entire UI. Symptom (beta
tester): sending a second message shortly after the first freezes the UI with a
WASM error in the console — the second send's UPDATE round-trip surfaced a
delta carrying a message this identity couldn't decrypt.

from_stored now returns Option and logs+skips on failure. from_state filters
out the undecryptable entries (filter_map) and apply_delta continues past them.
An undecryptable message in shared state must never be fatal.

Tests: from_stored returns None on garbage + on a message encrypted for another
identity; from_state keeps decryptable rows and drops the foreign one.
…268)

Two beta-tester UI complaints.

A) Folder counts don't match contents. The sidebar badge for Inbox/Quarantine
counted unread rows without excluding deleted/archived/hide_unsigned messages,
while the MessageList render filter excludes them. The badge then exceeded the
visible row count. folder_count now applies the same exclusions via a shared
is_inbox_row_visible predicate (search intentionally not applied — the badge
reflects the folder, not the search box). Tests assert the badge drops when an
unread message is deleted or archived.

B) Text too small. ~131 hardcoded sub-15px font-sizes bumped across the
component CSS (7.5px->9px ... 14.5px->15px). Display sizes >=16px left as-is.
)

End-to-end of the beta-tester flow: save draft → send (save_sent +
delete_draft) → stale GetAll echo on reload. Asserts the Sent row survives and
the deleted draft does not resurrect — the message must not 'move back to
Draft' after reloading.
@iduartgomez iduartgomez changed the title fix(ui): beta-tester bug sweep — reload state loss, 2nd-send freeze, folder counts + text size (#265, #267, #268) fix(ui): reload state loss, 2nd-send freeze, folder counts + text size (#265, #267, #268) May 27, 2026
@iduartgomez iduartgomez merged commit 6151fe3 into main May 27, 2026
5 of 6 checks passed
@iduartgomez iduartgomez deleted the fix/beta-bug-sweep-265-267-268 branch May 27, 2026 09:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant