fix(ui): decode UpdateNotification(Delta) as UpdateInbox#104
Merged
iduartgomez merged 3 commits intomainfrom May 4, 2026
Merged
fix(ui): decode UpdateNotification(Delta) as UpdateInbox#104iduartgomez merged 3 commits intomainfrom
iduartgomez merged 3 commits intomainfrom
Conversation
api.rs:1085 was unwrapping `serde_json::from_slice::<StoredInbox>(delta)` on the wire payload of an inbox `UpdateNotification`. The sender writes `UpdateInbox::AddMessages` (an enum), not the full `Inbox` struct, so the decode panicked with `missing field "messages"` and the executor died. The only path that surfaced an incoming cross-node message was a hard refresh that re-issued a `Get` and got a fresh `StoredInbox` via `UpdateData::State`. Reverse-direction sends never surfaced at all because the panic killed the WS task before the second arm could run. Add `InboxModel::apply_delta` that handles `AddMessages` (decrypt + push, de-dupe by `assignment_hash`) and `RemoveMessages` (filter by hash). Drop the now-dead `merge` helper. Also flip the cross-node send test's `FREENET_LIVE_E2E_SEND` gate off (panic was the root cause of the harness flake we were debugging), and hide the disabled "Unarchive" button (#60 still pending; the dead affordance was confusing per user feedback). Add a multi-round live-node test exercising send → click-to-read → reply → archive with a console-panic assertion that fails fast on WASM unwrap regressions.
This was referenced May 4, 2026
Focused Playwright spec that drives the iso 2-node harness with a verified contact import, captures both browser consoles, and probes alice's Drafts immediately post-Send (#107) plus bob's inbox-after- click flow (#106). Not part of CI; runs manually against an iso harness with the contract URL in FREENET_EMAIL_BASE_URL. Current findings: - #107 (drafts/sent leak) does NOT reproduce on a clean post-#104 iso run. \`delete_draft_now\` runs to completion on the verified- send success path; alice's Drafts is empty. - #106 (disappear-on-click) is blocked: bob's inbox never gets the message in the harness even with verified contact + AFT auto-allow (#105). Bob can't click a row that doesn't exist. Spec is structured so #106/#107 will fall out automatically once #105 is unblocked enough to deliver across the iso harness.
iduartgomez
added a commit
that referenced
this pull request
May 4, 2026
…108) * fix(ui): make local_state GENERATION reactive + tombstone draft deletes Two related local_state correctness bugs surfaced during cross-node manual testing post-#102/#104: #106 — clicking an inbox row removed it from the list. `mark_as_read` moves the row from the live `messages` Vec into the per-alias `kept` HashMap and bumps `GENERATION`, but `GENERATION` was an `AtomicUsize` and components called `.load(Relaxed)` on it. Atomic loads do NOT register a Dioxus reactive dep, so the kept-merge loop in `MessageList` did not re-run after the bump and the row stayed gone until something else dirtied the component. Switched `GENERATION` to a `GlobalSignal<usize>`; readers use `GENERATION()` to subscribe properly. #107 — sent messages re-appeared in Drafts. `delete_draft_now` removes the draft locally and asynchronously asks the delegate to delete. If a debounced `save_draft` was already past the autosave-token guard and in-flight when Send fires, its delegate-echoed snapshot (with the draft still present) lands AFTER the local delete and `replace_snapshot` overwrites the optimistic delete. Added a `DELETED_DRAFTS` tombstone set keyed by `(alias, draft_id)`; `replace_snapshot` strips matching ids from incoming snapshots and clears the tombstone once the delegate echo no longer contains the id. * fmt
1 task
iduartgomez
added a commit
that referenced
this pull request
May 4, 2026
Cross-node send fails on iso harness because both contact imports left `verified: false`, and `verify_on_send` defaults to true. The send_msg path silently rejects (toast: "Recipient is not verified") so bob never receives — root cause of the harness-only failure tracked in #105. The repro spec added in #104 already had this fix; live-node.spec.ts just hadn't been updated. Tick `fm-verify-check` after filling the local label so the import lands verified.
iduartgomez
added a commit
that referenced
this pull request
May 4, 2026
Cross-node send fails on iso harness because both contact imports left `verified: false`, and `verify_on_send` defaults to true. The send_msg path silently rejects (toast: "Recipient is not verified") so bob never receives — root cause of the harness-only failure tracked in #105. The repro spec added in #104 already had this fix; live-node.spec.ts just hadn't been updated. Tick `fm-verify-check` after filling the local label so the import lands verified.
iduartgomez
added a commit
that referenced
this pull request
May 4, 2026
* test(e2e): tick verify checkbox on contact import (#105) Cross-node send fails on iso harness because both contact imports left `verified: false`, and `verify_on_send` defaults to true. The send_msg path silently rejects (toast: "Recipient is not verified") so bob never receives — root cause of the harness-only failure tracked in #105. The repro spec added in #104 already had this fix; live-node.spec.ts just hadn't been updated. Tick `fm-verify-check` after filling the local label so the import lands verified. * docs(qa): add manual-test inventory + freenet-mail-qa skill `docs/qa/manual-test-inventory.md` catalogs every behavior across 9 feature areas (Identity, Contacts, Inbox, Compose, Drafts, Sent, Archive, Settings, Layout, Network) with a status of `auto` / `manual` / `automatable` / `blocked` and either a link to the covering test or a manual repro recipe. `.claude/skills/freenet-mail-qa/SKILL.md` instructs agents on when to consult the matrix (pre-merge, post-bug-fix, pre-release) and how to update it when tests are added. AGENTS.md gains a pointer at the top of the End-to-end testing section so this is discoverable without explicit invocation. Surfaced gaps for future automation: - multi-recipient send - verify_on_send toast on unverified contact - search filter - auto-sign idempotent on Resend - settings round-trip across reload - backup → restore round-trip - 3+ identity switching - reply from Archive folder - Sent Pending → Failed on send error (needs failure-injection harness)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
api.rs:1085was unwrappingserde_json::from_slice::<StoredInbox>(delta)on the wire payload of an inboxUpdateNotification. The sender writesUpdateInbox::AddMessages(an enum), not the fullInboxstruct, so the decode panicked with `missing field "messages"` and the executor task died. The visible symptom: cross-node sends required a hard refresh on the receiver to surface, and reverse-direction sends never surfaced because the panic killed the WS task before the second arm could run.Add `InboxModel::apply_delta` that handles `AddMessages` (decrypt + push, de-dupe by `assignment_hash`) and `RemoveMessages` (filter by hash). Drop the now-dead `merge` helper and the disabled "Unarchive" affordance (#60 is still pending; the dead button was confusing per user feedback).
Browser console error this fixes:
```
WASM PANIC: panicked at ui/src/api.rs:1085:76:
called `Result::unwrap()` on an `Err` value: Error("missing field `messages`", line: 1, column: 31)
```
Caveat — cross-node E2E still flaky
The new `multi-round + read + archive` test (and the pre-existing `alice → bob` test from #94) reproduce a deeper cross-node delivery flake on the iso harness even with this decode fix in place. Both are gated behind `FREENET_LIVE_E2E_SEND=1`. Manual repro on a real browser does work post-fix; iso harness coverage is being chased separately.
Test plan