Skip to content

fix(shared-state): keep initial snapshots local - #454

Draft
SaKaNa-Y wants to merge 2 commits into
devframes:mainfrom
SaKaNa-Y:fix/shared-state-initial-snapshot
Draft

SaKaNa-Y wants to merge 2 commits into
devframes:mainfrom
SaKaNa-Y:fix/shared-state-initial-snapshot

Conversation

@SaKaNa-Y

@SaKaNa-Y SaKaNa-Y commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Summary

When a wire service is installed while the RPC client reads its initial shared-state snapshot, the client can send the old snapshot back to the node side. This removes the service advertisement even though direct RPC calls still work. New connections then also fail to discover the installed service.

Give the initial snapshot its own sync ID and exclude that ID from outgoing writes. Track updates while the read is pending and ignore its result if the state changed or was deleted. This also preserves a local undo that restores the original object. Remove the temporary update listener when the read finishes. Local writes, including writes triggered by a snapshot listener, still reach the node side.

 initial snapshot arrives
- apply snapshot and send it back to the node side
+ apply locally only if no update occurred and the state still exists

This PR and #422 are independent fixes with no dependency on each other. This PR is based on main and does not include changes from #422. It fixes initial snapshot reads; #422 fixes echoes from received broadcasts and patches.

Evidence

  • The undo regression failed before the update: an old snapshot replaced the restored value. It passes with update tracking. A second test confirms that an unchanged mutation still allows the initial snapshot to apply.
  • All nine client shared-state tests and 16 shared-state utility tests pass. Coverage includes snapshot echo suppression, newer updates, local writes, undo, nested writes, and deletion.
  • Public WebSocket and SSE workflows pass against the updated build: early service installation preserves both registries, a new connection discovers the service, and direct RPC calls succeed.
  • pnpm lint, pnpm knip, pnpm typecheck, and pnpm build pass.
  • pnpm test --run: 157 test files pass; 1762 tests pass and 13 are skipped.

Merge Danger

Door: two-way. No wire-format or public API changes.

Blast Radius: shared-state. The change affects initial reads with an initialValue; later local writes retain their existing behavior.

@vercel

vercel Bot commented Oct 21, 2026

Copy link
Copy Markdown

@SaKaNa-Y is attempting to deploy a commit to the NuxtLabs Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

👁️‍🗨️ Review this pull request with grouped, summarized diffs at:
👉 https://pulls.review/gh/devframes/devframe/454?from=github-actions[bot]

raw result

💭 analyzed by vercel-ai-gateway/anthropic/claude-sonnet-5
🕰️ 2026-10-25 05:34 UTC
🔗 head e495123
🤖 automated by pulls.review

{
  "headSha": "e4951237fa468d87a74f108924ec58edf1ac8e57",
  "result": {
    "overallSummary": "Fixes a race where a wire service's initial shared-state snapshot read could be echoed back to the node side, wiping out a service that was registered concurrently. The fix tags the initial read with its own sync ID so it's excluded from outgoing writes, and skips applying it if the state was updated or deleted in the meantime; regular local writes still propagate.",
    "groups": [
      {
        "key": "shared-state-fix",
        "label": "Keep initial snapshots local",
        "summary": "Gives each initial shared-state snapshot read its own sync ID, excluding that ID from outgoing writes so the stale initial value isn't echoed back to the node side. Also guards against applying a pending snapshot if the state was updated or deleted while the read was in flight, while still forwarding local writes (including those triggered from an 'updated' listener).",
        "category": "core",
        "filePaths": [
          "packages/devframe/src/client/rpc-shared-state.ts"
        ],
        "critical": true,
        "lineNotes": [
          {
            "path": "packages/devframe/src/client/rpc-shared-state.ts",
            "side": "additions",
            "line": 112,
            "text": "Skips applying the fetched snapshot if the shared state was replaced/removed or updated locally while the RPC call was pending, preventing clobbering of newer local state."
          }
        ]
      },
      {
        "key": "shared-state-tests",
        "label": "Initial snapshot regression tests",
        "summary": "Adds regression tests covering the initial snapshot race: ensures snapshots aren't echoed back, concurrent updates/writes/deletes during the pending read are respected, and writes triggered from snapshot listeners still reach the node side.",
        "category": "tests",
        "filePaths": [
          "packages/devframe/src/client/rpc-shared-state.test.ts"
        ]
      }
    ],
    "schemaVersion": 1,
    "source": "llm",
    "generatedAt": "2026-10-25T05:34:39.737Z",
    "model": "vercel-ai-gateway/anthropic/claude-sonnet-5",
    "locale": "en"
  }
}

@SaKaNa-Y
SaKaNa-Y marked this pull request as draft October 21, 2026 13:36
Track updates while the initial snapshot is pending. Restoring the original object after a local edit must not make a stale snapshot current again.

Add an undo regression and retain initial synchronization after unchanged mutations. All required checks and the WebSocket/SSE service-discovery workflows pass.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant