Skip to content

Commit 5a8c6ed

Browse files
committed
prerelease 10-07 a3: merge verify_hydration (A3-11 confirmed and widened, A3-12 confirmed); plan final
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SjCrbdguMkfe4bhbaREiwo
1 parent 6d2d911 commit 5a8c6ed

3 files changed

Lines changed: 28 additions & 12 deletions

File tree

‎prerelease_testing/2026-10-07-a3/FINDINGS.md‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,23 +175,39 @@ Numbered A3-xx. "Pending verification" until a `verify_*` item reports.
175175
- Filed: [reflex-enterprise#274](https://github.com/reflex-dev/reflex-enterprise/issues/274) (2026-10-07). N-033's a3 re-check added to
176176
[reflex-enterprise#262](https://github.com/reflex-dev/reflex-enterprise/issues/262#issuecomment-6047554210).
177177

178-
### A3-11: `sync=True` LocalStorage: the #7493 boot echo writes back the stale value a tab read at connect time, so a change made in another tab while tabs are booting starts an endless cross-tab storage ping-pong (MEDIUM, regression vs a2, not vs 0.9.12; pending verification)
178+
### A3-11: `sync=True` LocalStorage: the #7493 boot echo writes back the stale value a tab read at connect time, so a change made in another tab while tabs are booting starts an endless cross-tab storage ping-pong (MEDIUM, regression vs a2, not vs 0.9.12; CONFIRMED and widened by independent verifier; fix PR reflex#7505)
179179
- Item `a3_hydration` (inbox 1). `src/bootecho`, `scripts/run_storm.sh a3 dev 8 3142 8142 S 6`: tab 0 sets the synced `be_theme` 5× 250 ms
180180
apart while 6 more tabs load in the same browser context. a3: endless ping-pong dev 6/9 (+3/3 long runs), prod 2/5; a2 0/15; 0.9.12
181181
9/10. Long runs: 8k–39k websocket frames per 5 s for 60 s, tabs stuck on mixed s2–s4 (the user's last value s5 is lost), backend
182182
~50–70 % CPU. Two-tab form with inbound messages held: transient revert 1/2 (a2 0/2). Cause: `reflex/state.py:2401` + `2420-2422`
183183
re-mark the applied browser values dirty after the snapshot → the boot delta carries the value read at CONNECT → `state.js:896/1076`
184184
`localStorage.setItem` of the stale value → `storage` event in the other tabs (`state.js:1267`) → `update_vars_internal` → deltas write
185185
back again. #7493 restored 0.9.12's boot echo, and with it 0.9.12's storm; a2 was immune because it echoed nothing.
186+
- **Verification (`verify_hydration`, own app + drivers incl. stock headful Chromium over raw CDP with real background tabs, 100 ms RTT
187+
proxy): CONFIRMED, wider than reported.** One user change and 3 tabs suffice: returning user, browser restart restoring 3 tabs 300 ms
188+
apart, one click in the foreground tab → endless ping-pong a3 3/3 (+60 s run: 22–27k frames per 5 s, no decay), a2 0/3, 0.9.12 3/3;
189+
Playwright 7 restored tabs: a3 stormed every time a tab booted across the click, a2 0/7, 0.9.12 6/6; prod + Redis 9 workers 2/2. With 2
190+
tabs the user's own tab flips back to the old value 3–53 times (1/5 runs looped > 10 s). Effects: the clicked tab shows the old value
191+
again, tabs end on mixed values, localStorage ends on the OLD value in 3/10 storms, a later click is swallowed, one client with 3 tabs
192+
keeps the backend at ~72 % CPU; nothing logged. Not a Playwright artefact (no timers in the storm path). The explorer's localhost Part S
193+
rate depends on machine load (verifier: a3 0/7 on localhost; the CONNECT→echo window is ~10 ms there, ~1 RTT on a real network).
194+
Same mechanism as 0.9.12 (whose window is wider). Realistic trigger: `sync=True` LocalStorage, real network, ≥3 tabs, a change within
195+
~1 RTT of another tab booting (session restore, reload, new tab). Fix location: the boot echo — keep #7493's re-marking for `get_delta`
196+
overrides, but never write back an unchanged echo (the verifier's scratch patch of the compiled state.js: 0 storms).
186197
- **Fix prototyped (10-07, at the maintainer's request)** on branch `claude/a3-11-storage-echo` (frontend only, `state.js`): do not write
187198
an echoed local/session storage value back (cookies still renew `max_age`); on a storage event send the value stored now, not
188199
`e.newValue`; resync a synced var whose echo crossed a newer stored value. Storm driver vs published a3: dev 0 storms in 11 runs
189200
(a3 3/4), prod 0/7; `on_load` stamps (A3-12) 0 storms in 16 runs, all converge (a3 4/4 storms). 3 Playwright regression tests fail on main. PR [reflex-dev/reflex#7505](https://github.com/reflex-dev/reflex/pull/7505).
190201

191-
### A3-12: `sync=True` LocalStorage written concurrently by several tabs (an on_load that stamps a synced var, a browser session restore) loops forever between the tabs (MEDIUM, pre-existing on 0.9.12, a2 and a3; pending verification)
202+
### A3-12: `sync=True` LocalStorage written concurrently by several tabs (an on_load that stamps a synced var, a browser session restore) loops forever between the tabs (MEDIUM, pre-existing on 0.9.12, a2 and a3; CONFIRMED by independent verifier; fixed by the same PR reflex#7505)
192203
- Item `a3_hydration` (inbox 2). `src/syncstamp` (`Stamp.last = rx.LocalStorage("", name="ss_last", sync=True)` set to a per-tab value in
193204
`/stamp`'s on_load), `scripts/run_stamp.sh a3 dev 4 3142 8142 /stamp 6`: 3–6 tabs → a3 41k–234k, a2 118k–137k, 0.9.12 40k–64k frames
194205
per 5 s; the control `/same` (same value from every tab) stays quiet. The volume crashed the Playwright driver in 4/12 runs.
206+
- **Verification (`verify_hydration`): CONFIRMED, pre-existing.** Also triggers with no user action: 4 quiet tabs on `/doc/<slug>` pages
207+
whose `on_load` stamps a synced var, then one dev backend reload (a save, deploy or restart): every tab reconnects, re-runs on_load and
208+
the loop never ends (a3, a2, 0.9.12 2/2 each); 6 restored background tabs 2/2 each; explorer `/stamp 6` 2/2 each; 20–65k frames per
209+
5 s, tabs end on 2–3 values. Fixing the storage-sync path alone ends the loop but leaves a tab on a stale value unless it re-reads
210+
localStorage when a sync answer disagrees — which #7505 does (0 storms, all converge in 16 runs).
195211

196212
### A3-13: #7493 re-sends client-storage vars and their dependent computed vars in a second boot delta, so storage-dependent computed vars run twice per page load (LOW, performance; same as 0.9.12, a2 ran them once)
197213
- Item `a3_events_tp` (inbox 2). `events/src/bootdup` (core only): on each reload with a stored value a3 sends 4 deltas and evaluates every

‎prerelease_testing/2026-10-07-a3/RELEASE_PLAN.md‎

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# Release plan after the 0.10.0a3 re-verification (reflex / reflex-base 0.10.0a3 + reflex-enterprise 0.9.7a5)
22

3-
**Status: DRAFT** — written at 2026-10-07 ~22:25 UTC after every exploration item finished; the independent verifications of
4-
A3-06..A3-10 are in; A3-11/A3-12's is still running and may change the triage below. Rubric (testing skill): fix before release =
3+
**Status: FINAL (pending #7505 CI/review)** — every exploration item and all four independent verifications (A3-01..A3-12) are in. Rubric (testing skill): fix before release =
54
confirmed regression vs the previous stable (0.9.12), security-relevant, significant user impact, or trivially small. Evidence:
65
[FINDINGS.md](./FINDINGS.md). Supersedes [../2026-10-07/RELEASE_PLAN.md](../2026-10-07/RELEASE_PLAN.md) for everything it re-checked.
76

@@ -23,13 +22,12 @@ No upgrade regression 0.9.12 → a3 or a2 → a3; F-002/F-003/F-004 stay fixed;
2322

2423
## Fix before release
2524

26-
- **A3-11** (MEDIUM, regression vs a2, NOT vs 0.9.12; verification running) — `sync=True` LocalStorage: #7493's boot echo writes back the
27-
value a tab read at connect time, so changing the value in one tab while other tabs boot starts an endless cross-tab ping-pong (tens of
28-
thousands of frames per 5 s, backend 50–70 % CPU, the user's last value lost). It does not meet the strict "regression vs the previous
29-
stable" arm (0.9.12 storms 9/10), but #7493 reintroduced it in a release that had removed it, it burns server CPU indefinitely, and the
30-
fix is local to the boot echo (do not re-send a client-storage value the browser itself just sent, or have the frontend skip an echo of
31-
the value it sent at boot). **Maintainer decision:** fix in 0.10.0, or ship with 0.9.12 parity and file it with A3-12.
32-
**Decided 10-07:** fix it — prototype on `claude/a3-11-storage-echo` (frontend only, also ends the A3-12 ping-pong): [reflex-dev/reflex#7505](https://github.com/reflex-dev/reflex/pull/7505).
25+
- **A3-11 + A3-12** (MEDIUM; A3-11 regression vs a2, not vs 0.9.12; A3-12 pre-existing; both CONFIRMED by an independent verifier, A3-11
26+
wider than first reported: one change with 3 tabs over a real network, e.g. a session restore, loops forever at ~72 % backend CPU and
27+
can leave localStorage on the old value; A3-12 is set off by any dev save/deploy/restart with ≥4 tabs whose on_load stamps a synced
28+
var). **Decided 10-07: fix in 0.10.0** — [reflex-dev/reflex#7505](https://github.com/reflex-dev/reflex/pull/7505) (frontend only: no
29+
write-back of unchanged echoes, storage events send the stored value, synced vars resync when an echo crossed a newer value; 0 storms
30+
and full convergence in 26 runs dev/prod; 3 Playwright regression tests). The verifier independently arrived at the same design.
3331
- **A3-01** (LOW, regression vs a2; CONFIRMED) — trivially small arm: in `BaseStateMeta.__setattr__`, push the "kept default" undo entry
3432
before `_keep_client_storage` / `_accepts_default` can raise (so a rejected `mock.patch.object` / pytest-mock patch round-trips), and
3533
make `__delattr__` and the identity restore pop only an entry that the same patch pushed. The docs already promise the round trip.
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
item: verify_hydration
22
claimed_by: session_01SjCrbdguMkfe4bhbaREiwo
33
claimed_at: 2026-10-07T21:59:38Z
4-
status: in-progress
4+
status: done
55
note: orchestrator subagent
6+
released_at: 2026-10-07T23:18:12Z
7+
release_note: A3-11 confirmed+widened, A3-12 confirmed

0 commit comments

Comments
 (0)