Skip to content

fix(store): resend the NgRx action log after the server forgets the page - #251

Merged
erkamyaman merged 2 commits into
mainfrom
fix/ngrx-resync-after-forget
Oct 11, 2026
Merged

erkamyaman merged 2 commits into
mainfrom
fix/ngrx-resync-after-forget

Conversation

@erkamyaman

@erkamyaman erkamyaman commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

What and why

The NgRx overlay keeps up to maxLog action log entries, but each push sends only the entries newer than sentSeq, the seq the server last answered. When the server no longer has the page, mergeNgrxReport treats those few entries as the whole log. It stores them, sets dropped to every earlier seq, and answers the newest seq. The page then thinks everything was delivered and never resends the older entries it still holds.

The server forgets a page in a few everyday ways:

  • forget-ngrx-page on pagehide, including a bfcache restore
  • the 15 second expiry while the socket is down, for example after a laptop sleep
  • a hub or dev server restart

If the next push carries any new action, which is nearly always the case with polling effects or socket-driven actions, the earlier history is gone for good. The Store page and the NgRx agent tools show a log starting at the latest action, with "N older actions were dropped".

The fix:

  • NgrxPageReport gets an optional since: the seq the page's report continues from.
  • mergeNgrxReport checks for that: when it has no record of this page session but since > 0, it knows it lost the page. It stores no partial log and answers 0.
  • The overlay sees the answer go backwards, resets what it thinks was sent (including the unrestorable marks), and schedules a push that sends the full held log.

How it was verified

Added a test to ngrx-collector.test.ts with the real Store DevTools setup and the real mergeNgrxReport behind the RPC. It pushes two actions, calls leave() (the server forgets the page), dispatches a third action, and pushes. On main the server ends up with [3] (expected [ 3 ] to deeply equal [ 1, 2, 3 ]) and dropped: 2. With the fix it has [1, 2, 3] and dropped: 0.

  • pnpm commit:check (commit messages follow the guidelines)
  • pnpm format:check
  • pnpm typecheck (includes the ngc template checks)
  • pnpm test:devtools (all passing)
  • pnpm skills:check (when .claude/ changed): not changed
  • No docs change needed: a bug fix with no change to options, labels or agent tools (no-docs)
  • pnpm extension:build and extension/ui committed (when app/ changed): not changed
  • Checked in the browser with axe (when the UI changed): no UI change

Notes for reviewers

since is optional. An older overlay that doesn't send it gets the old behavior.

Summary by CodeRabbit

  • Bug Fixes
    • Improved Store DevTools log recovery when a page is removed and later rediscovered. Previously retained entries are resent, helping preserve the log across the interruption.
    • Rediscovered pages now recover entries even when the server has lost its record of the page’s progress, preventing those entries from being incorrectly treated as already received.

The page sends only log entries newer than the seq the server last
confirmed. When the server forgot the page (pagehide or a bfcache restore,
the 15 second expiry while the socket was down, a hub restart), the next
push carried only the newest entries. The server stored them as the whole
log, marked every earlier seq as dropped, and answered the newest seq, so
the page never resent the history it still held.

Reports now carry the seq they continue from. When the server has no
record of that page session, it answers 0, and the page pushes its full
held log again.
@erkamyaman erkamyaman added the no-docs This pull request needs no docs change (the reason is in the description) label Oct 10, 2026
@erkamyaman erkamyaman added the no-docs This pull request needs no docs change (the reason is in the description) label Oct 10, 2026
@github-actions github-actions Bot added area: package The ng-devtools package (packages/ng-devtools) area: agents MCP server, agent tools and resources labels Oct 10, 2026
@coderabbitai

coderabbitai Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: e6160c37-dde0-4cfb-98bb-c96bf4ff0755

📥 Commits

Reviewing files that changed from the base of the PR and between 5cc857e and 7858122.


You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 4d62ba6d-ed5f-4dfd-baf2-7a6e78aa81f7


📥 Commits

Reviewing files that changed from the base of the PR and between f245551 and 5cc857e.



📒 Files selected for processing (4)
  • packages/devtools/src/__tests__/ngrx-collector.test.ts
  • packages/devtools/src/ngrx-overlay.ts
  • packages/devtools/src/ngrx-shared.ts
  • packages/devtools/src/rpc/ngrx-tools.ts


Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.




📝 Walkthrough
📝 Walkthrough

Walkthrough

The Ngrx page report now includes the last confirmed sequence. Server merge logic and the overlay use sequence regressions to trigger a resend of retained log entries. A regression test checks that the page’s entries return after the server forgets the page.

Changes

Ngrx log resynchronization

Layer / File(s) Summary
Report contract and server resynchronization
packages/devtools/src/ngrx-shared.ts, packages/devtools/src/rpc/ngrx-tools.ts
NgrxPageReport adds optional since. For an unknown page or changed session, mergeNgrxReport discards the partial log when since is greater than zero.
Overlay resend and regression test
packages/devtools/src/ngrx-overlay.ts, packages/devtools/src/__tests__/ngrx-collector.test.ts
The overlay resets sentLost and schedules another push when the returned sequence decreases. The test checks that sequences 1–3 are present after the page is recreated and that its dropped count is zero.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix



Merge Risk: ⚪ Minimal · up to 5cc85

The retained action log can be resent after the server forgets the page. No merge-blocking issue was identified.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 5cc85

Recovery improves retained action history without adding a new endpoint or action permission. A lost recovery response can still prevent full replay, and transport-level isolation was not verified.

Retained concerns

  • Low · reliability · inferred: The replay handshake is not idempotent if the reset response is lost after server-side processing. For example, an unknown page reporting since=2 with entry 3 creates an empty record and returns 0. If the client does not receive that response, its cursor remains 2. The next retry sees a matching session, accepts entry 3, and acknowledges 3, leaving held entries 1–2 missing. Periodic retries do not repair the history after that acknowledgement. The base already lost earlier history after page removal; this is a residual failure-containment gap in the new recovery design, not a demonstrated security regression.
Security review details

Security Blast Radius

  • inferred — The changed data flow retransmits history already retained by the reporting page to the same server map and shared-state recipients. Repository evidence does not show a new recipient or privilege. Effective cross-project exposure cannot be bounded without the external transport's identity and isolation controls.

Trust Boundaries and Controls

  • observed — The report validator checks pageId/session strings and stores/log arrays. Page identity and session are supplied by the reporter; session matching controls log continuity, not authentication. Caller authentication and origin isolation are not established by these local checks.

Resilience and Maintainability Implications

  • observed — Pushes are serialized, and rejected calls do not advance the client cursor. Active-overlay refresh provides later push opportunities. Leave remains an independent forget call rather than a terminal replay barrier; pagehide suspends refresh and pageshow resumes it. These controls predate the new handshake and do not resolve its lost-reset-response window.

Hardening Proposals

  • proposed — Preserve a replay-required state until a full replay is received, so repeated positive-since reports continue receiving a reset response after interruption. This would make recovery retry-safe without changing reporting authority or recipients.

Pre-merge checks | Passed 4 | Failed 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: resending the NgRx action log after the server forgets the page.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.



✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR



🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR



  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Failed ❌

View logs ↗
7858122 2026-10-11T02:05:53.227Z View logs ↗
  • Build: Failed ❌

View logs ↗
5cc857e 2026-10-10T21:51:54.799Z View logs ↗

@erkamyaman
erkamyaman merged commit 120dcc0 into main Oct 11, 2026
6 of 7 checks passed
@erkamyaman
erkamyaman deleted the fix/ngrx-resync-after-forget branch October 11, 2026 02:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: agents MCP server, agent tools and resources area: package The ng-devtools package (packages/ng-devtools) no-docs This pull request needs no docs change (the reason is in the description)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant