Skip to content

fix(hub): reset message deltas across instances - #486

Draft
SaKaNa-Y wants to merge 1 commit into
devframes:mainfrom
SaKaNa-Y:fix/message-cursor-instance
Draft

SaKaNa-Y wants to merge 1 commit into
devframes:mainfrom
SaKaNa-Y:fix/message-cursor-instance

Conversation

@SaKaNa-Y

@SaKaNa-Y SaKaNa-Y commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Summary

A message-feed consumer that reconnects to a restarted Hub can reuse a version number from the previous instance. If that number is equal to or below the new clock, listSince returns an incomplete delta. The consumer keeps stale messages and misses new ones.

Return an instance ID with each result and accept it alongside the numeric version. Update the messages panel and Hub UI to pass both values.

same instance + valid version → delta
missing or foreign instance ID → full snapshot

This fixes reads after a consumer explicitly creates a replacement connection. It does not add automatic transport reconnection.

Evidence

  • Before: four new host regression cases fail against the original implementation. After: all 13 host tests pass, including same-instance updates, removals, clear and history expiry.
  • Consumer tests cover cache replacement and instance-ID forwarding in both readers. Real RPC tests cover incremental, legacy and foreign-cursor reads.
  • Chrome with real HTTP/WS: an explicit replacement connection with a retained cache recovers at lower, equal and higher new version numbers. Old entries disappear, all new entries appear, and later removal uses a delta.
  • pnpm lint, pnpm knip, pnpm typecheck, pnpm test --run --maxWorkers=4 and pnpm build pass. Full suite: 1845 passed, 14 skipped. A default-concurrency run missed the PTY resize signal; that case passed alone and the full four-worker rerun passed.

Merge Danger

Door: two-way

Blast Radius: message-sync

Numeric versions and existing calls remain valid. Callers that omit the instance ID receive full snapshots, which increases response size until they pass it. The new result field is optional for older responses and static snapshots. Queue capacity is unchanged.

Scope message cursors to their issuing Hub instance so a retained cache can recover after an explicit replacement connection. Return full snapshots for legacy numeric-only readers and pass instance IDs through both message consumers.
@vercel

vercel Bot commented Nov 5, 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 Nov 5, 2026

Copy link
Copy Markdown

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

raw result

💭 analyzed by vercel-ai-gateway/anthropic/claude-sonnet-5
🕰️ 2026-11-05 08:55 UTC
🔗 head 04cc2af
🤖 automated by pulls.review

{
  "headSha": "04cc2af838a62cfaaf8186604d2f8006abf2ed11",
  "result": {
    "overallSummary": "Fixes a bug where a message-feed consumer reconnecting to a restarted Hub could reuse a stale version number and receive an incomplete delta instead of a full snapshot. The host now tags each result with an instance ID, and both the numeric version and the instance ID must match for a delta to be returned; otherwise a full snapshot is sent. Consumers, RPC plumbing, docs, tests and generated type snapshots are updated accordingly.",
    "groups": [
      {
        "key": "core-fix",
        "label": "Instance-aware listSince",
        "summary": "Core fix: the messages host now stamps each result with its own instance ID and only computes a delta when the caller's cursor matches that instance; otherwise it returns a full snapshot. This prevents a consumer reconnecting to a restarted Hub from applying a delta computed against a stale clock.",
        "category": "core",
        "filePaths": [
          "packages/hub/src/node/host-messages.ts",
          "packages/hub/src/types/messages.ts",
          "plugins/messages/src/node/rpc/functions/list.ts"
        ],
        "critical": true,
        "fileNotes": [
          {
            "path": "packages/hub/src/node/host-messages.ts",
            "text": "`listSince` now requires the instance ID to match before trusting the numeric cursor; a mismatch (including legacy callers that omit it) forces `full: true`.",
            "critical": true
          }
        ]
      },
      {
        "key": "consumers",
        "label": "Consumer cursor forwarding",
        "summary": "Both message-feed consumers (Hub UI panel and the plugin's client state) now store the returned `instanceId` alongside the version and pass it back on the next poll.",
        "category": "core",
        "filePaths": [
          "packages/hub-ui/src/client/state/messages.ts",
          "plugins/messages/app/client/state/messages.ts"
        ]
      },
      {
        "key": "tests",
        "label": "Tests for instance-scoped cursors",
        "summary": "Regression coverage for the fix: host-level tests for foreign/legacy cursors, RPC-level tests over a real server, and consumer tests verifying cache replacement and instance-ID forwarding in both readers.",
        "category": "tests",
        "filePaths": [
          "packages/hub-ui/src/client/state/messages.test.ts",
          "packages/hub/src/node/__tests__/host-messages.test.ts",
          "plugins/messages/test/dev-server.test.ts",
          "plugins/messages/test/message-state.test.ts"
        ]
      },
      {
        "key": "docs",
        "label": "Hub API docs",
        "summary": "Documents `listSince(version, instanceId)` usage and the full-snapshot fallback behavior.",
        "category": "docs",
        "filePaths": [
          "docs/content/8.references/6.hub-api.md"
        ]
      },
      {
        "key": "snapshots",
        "label": "Generated type snapshots",
        "summary": "Auto-generated public API snapshots updated to reflect the new `instanceId` parameter and field.",
        "category": "other",
        "filePaths": [
          "tests/__snapshots__/tsnapi/@devframes/hub/index.snapshot.d.ts",
          "tests/__snapshots__/tsnapi/@devframes/hub/node.snapshot.d.ts",
          "tests/__snapshots__/tsnapi/@devframes/hub/node.snapshot.js",
          "tests/__snapshots__/tsnapi/@devframes/hub/types.snapshot.d.ts",
          "tests/__snapshots__/tsnapi/@devframes/plugin-messages/rpc.snapshot.d.ts"
        ]
      }
    ],
    "schemaVersion": 1,
    "source": "llm",
    "generatedAt": "2026-11-05T08:55:38.206Z",
    "model": "vercel-ai-gateway/anthropic/claude-sonnet-5",
    "locale": "en"
  }
}

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