fix: filter the restored view stack against RESTORABLE_VIEWS (closes #224)
All checks were successful
check / check (push) Successful in 34s

restoreView() refuses to reopen the popup ONTO a non-restorable view, but
the stack behind it was restored verbatim, so a screen the popup will not
render -- export-privkey, show-phrase -- could sit in it. Back then landed
on a view whose content is deliberately never re-rendered, and show-phrase
has no Back control to leave by. No secret is exposed: those screens are
empty precisely because nothing is restored into them. This is navigation,
not disclosure.

loadState() now truncates the stored stack at the first entry outside
RESTORABLE_VIEWS rather than splicing that entry out, so the result stays a
prefix of what was stored and every surviving entry keeps exactly the Back
target it had; splicing would silently re-point the entry above the hole at
a different screen. A stack truncated to nothing under a restorable
non-root view gets main beneath it, so Back always has somewhere to go.
Stacks with no unrenderable entry are restored unchanged.

The filter is on load, not on save: the live in-session stack is
legitimate, since the screen really is rendered while the popup is open,
and only a load-side filter also repairs the stacks already in storage,
including ones written before a view left the set.
This commit is contained in:
2026-08-12 09:32:11 +00:00
parent c6a1f97247
commit e36d83627a
3 changed files with 129 additions and 1 deletions

View File

@@ -44,6 +44,12 @@ undefined identifiers, which is how
# Completed Steps
- 2026-08-12: The restored navigation stack is filtered against
`RESTORABLE_VIEWS` on load, truncated at the first entry the popup would not
render so that every surviving entry keeps the Back target it had. Reopening
the popup can no longer put Back onto a screen whose content is never
re-rendered, such as `export-privkey` or `show-phrase`
([#224](https://git.eeqj.de/sneak/AutistMask/issues/224)).
- 2026-08-12: The dust threshold field now explains a rejection instead of
snapping back in silence, with the parse in a pure, unit-tested module that
accepts plain decimal digits only — hex and exponent notation are refused