Skip to content

feat(navigation): stabilize tab stacks - #111

Merged
GenericJam merged 3 commits into
masterfrom
fix/nc6-0736-final
Aug 30, 2026
Merged

feat(navigation): stabilize tab stacks#111
GenericJam merged 3 commits into
masterfrom
fix/nc6-0736-final

Conversation

@GenericJam

@GenericJam GenericJam commented Aug 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • reclaim component processes and native handles when their owning screen exits
  • support directional tab switches with first-mount parameters and stale-frame protection
  • add an opt-in all-stack reset for authentication/session boundaries

These changes unblock the downstream app's independent bottom-tab stacks and correct the Android tab-bar disappearance and premature Back behavior reproduced on a Moto g power 5G - 2024.

Beads: app-nc6.1, app-nc6.2, app-nc6.5

Verification

  • full Mob suite: 1327 passed, 38 excluded
  • affected suite: 247 passed, 1 excluded
  • mix format --check-formatted
  • mix credo --strict
  • warnings-as-errors compile
  • erlfmt, clang-format, SwiftLint, and diff checks
  • independent adversarial review: no P0-P3 findings

Add first-visit mount params and protect activation frames from stale renders.

Bead: clarity-nc6.2
Make logout an atomic navigation and persisted-state boundary.

Bead: clarity-nc6.5
@GenericJam

Copy link
Copy Markdown
Owner Author

Independently re-reviewed (fresh worktree, no reliance on the authoring session's review) and verified on physical hardware. Approve.

The adversarial priorities all held: (1) #103's one-shot reservation and the new activation gate compose — activate_frame nulls the reservation, the gated clause consumes the gate only on :none frames, supersession carry runs only ungated, and crash-during-nav-paint is repaired by substitute/3 copying the token (test exists); (2) component reclaim can't double-free (each server frees its own handle exactly once, before user terminate/2, raising callbacks can't skip it) and a dying predecessor can't deregister a replacement (ETS self()-check + test); (3) version-skew guards are real and individually tested, including transitive coverage of restore_persisted_state.

Physical Moto g power (Android 11): tab bar survives 60-switch churn; Back pops in-stack → switches to first stack from a secondary root → exits from the first-stack root; directional animations verified by screen recording, single burst each way; first-visit mount_params delivered and sticky, boot root back-compat with %{}; reset_to scope: :all lands on the login root with every stack fresh, persisted snapshots emptied, and a 12-cycle sign-in/churn/sign-out soak shows registry shrinking, process count flat, zero component_slots_exhausted. Gates: 1327/1327, format/credo-strict/warnings-as-errors/erlfmt/clang-format clean, swiftlint at the 2 known pre-existing warnings. Branch sits directly on the 0.7.36 tag, merge-tree clean.

Non-blocking (filing as a follow-up issue): legacy activate/2 and set_active/1 in sender.ex don't clear a pending activation_gate — unreachable today, but a hot-code downgrade mid-navigation could strand a gate and freeze that screen's untokened renders; one-line fix. Plus doc nits: Mob.Test.switch_tab/3 missing from testing.md's helper list; the MOB-115 stack-scope gap note vanished from navigation.md and should return reworded; explicit transition: :none raising on switch_tab while being the documented default is an API wart.

Merging and cutting 0.7.37.

@GenericJam
GenericJam merged commit 50589e2 into master Aug 30, 2026
4 checks passed
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