@@ -88,6 +88,84 @@ URL, so it isn't shareable. A layer that must survive reload in its own right
8888(or be linkable) keeps its open-state in the URL and derives itself from it —
8989Back then closes for free and needs no interceptor.
9090
91+ ## Scenarios
92+
93+ Compact traces of the behavior above, in the module's own vocabulary.
94+ ` arm ` registers a guard; ` release ` is a close this module didn't cause —
95+ external, imperative, or similar — reaching it as the release call;
96+ ` release(keepClaim) ` is a teardown. ` watch ` registers a spent-entry
97+ watcher. ` Back ` and ` Forward ` are user traversals; ` => ` is the observable
98+ outcome.
99+
100+ ### One layer
101+
102+ - ` arm -> Back ` => the layer closes; the page stays.
103+ - ` arm -> release ` => the entry is consumed; the next Back leaves the page.
104+ - ` arm -> Back -> Forward ` => the layer reopens, re-armed on the entry in
105+ place.
106+ - ` arm -> Back -> Forward (reopen declined) ` => stays closed, stays parked;
107+ a later Forward offers again.
108+ - ` arm -> Back (onBack declines) ` => re-armed; the next Back reaches the
109+ same layer again.
110+ - ` arm -> Back (onBack throws) ` => counts as a decline: re-armed, and the
111+ error propagates.
112+
113+ ### Release and consumption
114+
115+ - ` arm -> release -> arm (same turn) ` => the re-registration adopts the
116+ entry in place; zero traversals.
117+ - ` arm (onForward) -> Back -> release ` => the Forward watch ends; the spent
118+ entry stays in the forward stack, not the module's to spend.
119+ - ` arm -> Back -> Forward (declined) -> release ` => the declined reopen
120+ left the entry current, so it is consumed.
121+ - ` arm A -> arm B -> release both (any order) ` => both entries consumed,
122+ one traversal at a time; the next Back leaves the page.
123+ - ` arm A -> arm B -> release A ` => A's entry is buried under B: left
124+ alone. The Back that closes B surfaces it, and it is consumed alongside.
125+ - ` arm -> Back -> release ` => the Back already unwound the guard; the
126+ release is a no-op.
127+
128+ ### Forward, claims, reload
129+
130+ - ` arm (claim) -> Back -> release(keepClaim) -> watch -> Forward ` => the
131+ sole watcher reopens; the new registration adopts the entry.
132+ - ` arm (claim) -> Back -> release -> Forward ` => nothing. The close was
133+ deliberate (abandoned), and the dead entry absorbs one Forward press —
134+ an entry can't be deleted, only left to soak the traversal.
135+ - Two watchers, one claim, ` Forward ` => neither answers: they can't be
136+ told apart, and reopening the wrong layer is worse than reopening none.
137+ - ` arm (claim) -> Back -> reload -> watch -> Forward ` => reopens. The
138+ abandoned memory did not survive the reload: surrendered and lost ground
139+ now look the same.
140+ - ` arm -> reload -> Back ` => spends on nothing — the entry outlived the
141+ open-state; a Forward back onto it offers the claim.
142+ - ` Forward ` onto marked ground with no owner and no watcher => nothing —
143+ residue never unwinds anything.
144+ - ` arm A -> Back -> arm B ` => B's plant truncates the forward stack: A's
145+ spent entry and its watch are gone. A veto's re-plant does the same — a
146+ decline costs every parked watch above.
147+
148+ ### Stacked layers
149+
150+ - ` arm A -> arm B -> Back -> Back ` => closes B, then A — one per press.
151+ - ` arm A -> arm B -> release B -> Back ` => closes A; B's entry was
152+ consumed in between.
153+ - ` arm A -> arm B -> arm C -> Back -> release B -> Forward -> Forward ` =>
154+ the Back closes C; the first Forward soaks into B's abandoned entry; the
155+ second asks C, which reopens only if it still can without B.
156+ - ` history.go(-2) ` across A and B => unwinds topmost first; a decline
157+ midway re-arms and stops the unwind there.
158+ - ` history.go(+2) ` across two spent entries => offers each crossed layer
159+ its reopen, lowest first.
160+
161+ ### Timing edges
162+
163+ - A registration adopts an entry while a self-caused pop is in flight =>
164+ the swallow accounting re-plants the live guard (self-heal).
165+ - Parent and child arm in one commit (child lifecycle runs first) => the
166+ child arms beneath the parent: the first Back closes the outer layer. A
167+ layer armed after its parent unwinds inside-out as expected.
168+
91169## API
92170
93171| Export | Description |
0 commit comments