fix(settle): arm the dismissal confirmation on the producer's presented-surface fact

TH
4h ago
+587-38

Closes #3470. Builds on #3522 (merged).

Summary

The iOS 1.5 s dismissal confirmation (#1831) now reads the producer's presented-surface fact (#3565):

  • absent rules it out: nothing was presented, so a tab switch or push keeps the plain window.
  • presented arms it, even on a rootless first capture.
  • unknown, or no fact, keeps the parent's arming, so the fact can only narrow the guard.

A stored tree outdated by a later side effect drops its fact, so an absent read taken before a sheet opened cannot disarm that sheet's dismissal. Help text updated. 10 files.

Validation

927d2ce57, iPhone 17 Pro sim, RN lab Release build (the dev client's floating button makes every screen unknown, per #3578).

Route, 4 repsBaselinewaitedMsLate diff snapshot -i
(a) selector press closepresented, 4 nodes1694–1887empty
(b) snapshot, then @ref closepresented, 6 nodes1824–1857empty
(c) back --settle, Contacts New Contact sheetpresented, 70 nodes1784–1801empty
(d) same sheet, press x y closepresented, 70 nodes2524–2865empty
(e) selector tab switchabsent627–778empty

Tab switch, same device and route: | base 40d868233 1829–1872 ms | head 627–778 ms |.

A full-screen modal reads unknown, so it keeps the confirmation. Each fact branch has a unit or daemon case that fails under mutation.

pnpm check:affected --run --base origin/main at fea0bb95a (rebased on main after #3522 merged): all runnable checks passed, 535 test files, 4,060 tests, Fallow clean on 10 files, under the host lock. The device runs above were taken at 927d2ce57. Since then the only change is help text, and the rebase onto #3522's squash is identical in content.

🤖 Generated with Claude Code