fix(ui): tombstone optimistic kept entries (#113 partial)#115
Merged
iduartgomez merged 3 commits intomainfrom May 5, 2026
Merged
fix(ui): tombstone optimistic kept entries (#113 partial)#115iduartgomez merged 3 commits intomainfrom
iduartgomez merged 3 commits intomainfrom
Conversation
Adds 5 unit tests in local_state and 1 #[ignore]'d failing test that reproduces the click-to-read regression (#113). Stale GetAll echoes hit replace_snapshot before the optimistic local_mark_read write round-trips through the delegate, so kept_for returns empty and the just-evicted row vanishes from the inbox list. Also makes bump() a runtime-aware no-op when called outside Dioxus so the SNAPSHOT mutators can be exercised in plain unit tests. Adds Playwright tracing + per-context console mirroring to the multi-round live-node spec so the next iso-harness CI run captures artifacts useful for the fix follow-up. Refs #113, #81
Mirrors the DELETED_DRAFTS pattern from #107: every local_mark_read write also lands in PENDING_KEPT, keyed by (alias, msg_id). On every replace_snapshot, the tombstone walks the incoming snapshot: - if the delegate's echo already contains the kept entry, the MarkRead round-trip is durable — drop the tombstone. - if not, this is a stale echo from before the write — re-merge the optimistic kept entry (and re-apply read=true) into the new snapshot so kept_for keeps surfacing the row. Without this, a click-to-read on a cross-node delivery left the row gone from the inbox list: the inbox contract had already evicted it (by design — read messages move out of the live mailbox), and a stale GetAll reply landing after the click cleared SNAPSHOT.kept before the MarkRead delegate write had echoed back. kept_for then returned empty and the user-visible row vanished (#113). archive and delete supersede kept, so both drop the pending tombstone to avoid resurrecting the kept row under an archived/deleted id on a late echo. Adds 4 tests pinning the new behavior: - replace_snapshot_does_not_clobber_optimistic_kept (the #113 race; previously #[ignore]'d as failing) - pending_kept_drops_after_delegate_echo_includes_entry - local_archive_drops_pending_kept_tombstone - local_delete_drops_pending_kept_tombstone Closes #113
This was referenced May 6, 2026
Open
iduartgomez
added a commit
that referenced
this pull request
May 6, 2026
…on (#81) (#123) #114 + #115 + #120 fixes plus a spec correction (use page.reload() instead of page.goBack(), since the SPA doesn't push history entries on click — goBack landed on about:blank rather than the inbox) make tests 2 + 3 deterministically green on the iso harness. Drop the FREENET_LIVE_E2E_SEND gate so they run by default. Two assertions stay gated as separate concerns: - Test 3 round 3 (alice → bob retry) gated on FREENET_LIVE_E2E_AFT_CAP_RAISED — AFT day-1 cap is 1 slot, alice burned hers in round 1; needs #85 to make tier configurable. - Test 3 round 2 (bob → alice reply) gated on FREENET_LIVE_E2E_REPLY — flaky ~33%, separate flake tracked in #122. Click-to-read + reload assertion (the original #113 target) still runs and passes deterministically. Verified locally via 3 consecutive `cargo make test-e2e-real-node` runs, all passing in ~12s each.
iduartgomez
added a commit
that referenced
this pull request
May 6, 2026
* test(e2e): flip FREENET_LIVE_E2E_SEND off + fix click-to-read assertion (#81) #114 + #115 + #120 fixes plus a spec correction (use page.reload() instead of page.goBack(), since the SPA doesn't push history entries on click — goBack landed on about:blank rather than the inbox) make tests 2 + 3 deterministically green on the iso harness. Drop the FREENET_LIVE_E2E_SEND gate so they run by default. Two assertions stay gated as separate concerns: - Test 3 round 3 (alice → bob retry) gated on FREENET_LIVE_E2E_AFT_CAP_RAISED — AFT day-1 cap is 1 slot, alice burned hers in round 1; needs #85 to make tier configurable. - Test 3 round 2 (bob → alice reply) gated on FREENET_LIVE_E2E_REPLY — flaky ~33%, separate flake tracked in #122. Click-to-read + reload assertion (the original #113 target) still runs and passes deterministically. Verified locally via 3 consecutive `cargo make test-e2e-real-node` runs, all passing in ~12s each. * feat(ui): refuse-with-error on alias collision in Create/Restore (#117) Before submitting a NodeAction::CreateIdentity for a new alias name, check Identity::get_alias(name). If it returns Some, refuse with an inline error banner instead of advancing through keygen → reveal → delegate write. Two paths are guarded: - CreateAliasForm::submit — Create new identity. Rejects before keygen (no burned keys for a refused name). - ImportForm::onclick (Restore) — refuses to overwrite an existing identity record from a backup file, since the backup's keys would silently replace the on-device delegate entry and orphan the previous inbox. Mirrors the existing rename collision guard at \`Identity::rename_in_place\`. The two flows are now consistent: explicit two-step (delete then create/restore) is required to swap an alias, and there is no UI path that silently destroys access to a prior inbox. Adds an offline-mode Playwright test that submits "address1" — already seeded — and asserts the banner appears and the fingerprint reveal does not.
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
Refs #113. Partial fix — the kept_for race documented in #113 is real and now has both unit-test coverage and a working repair. However, end-to-end verification on the iso harness still trips on a separate duplicate-inbox bug filed as #114, so the multi-round Playwright test still fails. Landing this anyway because the race fix is independently correct.
What changed
Why this is partial
After landing the fix, the iso harness multi-round test still fails the same way. Bob's UI is subscribed to two distinct inbox contracts both registered against `alias=bob` — see #114 for the gateway-log evidence. `mark_as_read` then targets the wrong inbox via `inbox_data[active_id]`, and the row disappears regardless of `kept_for`. The race fix is necessary but not sufficient for the full click-to-read end-to-end story.
Test plan