Skip to content

Fix public Context Graph review follow-ups - #1853

Merged
lupuszr merged 1 commit into
testnet-canaryfrom
v10/fix-public-cg-review-followups
Jul 20, 2026
Merged

Fix public Context Graph review follow-ups#1853
lupuszr merged 1 commit into
testnet-canaryfrom
v10/fix-public-cg-review-followups

Conversation

@zsculac

@zsculac zsculac commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

This is a deliberately narrow follow-up to #1848 — Fix public Context Graph subscription catch-up, which was merged into testnet-canary as 7bbbd959727327ffb438e4e674b72251fd947445.

It implements the first three actionable review follow-ups from that PR:

  1. Clear a previously active project target when browsing a passive public catalogue graph, so the newly opened public graph tab cannot inherit the old graph's activeProjectId.
  2. Assert that public subscription actually invokes tracked catch-up with the subscribed graph ID and includeSharedMemory: true.
  3. Add snapshot/ASK parity coverage proving that an otherwise complete public definition is rejected when it is stored outside the root metadata named graph.

Review threads:

Original incident context

PR #1848 fixed a serious DKG V10 edge-node bug in which an explicitly public Context Graph entered the private join/bootstrap path and could not complete synchronization.

  • Source at reproduction: origin/testnet-canary / 87f53014858abed8558fdc5c85a83efebdaeac02
  • Node role: edge
  • Network: testnet
  • Context Graph: 0x00a9D0dcab936a418ffEbc734476C91D4027d359/balkan-places-to-visit
  • Curator peer: 12D3KooWDxBauQDeJjCmcvWiREFALfKsr5VfTzGUJbZJ6CUcc7aF
  • Reported metadata: accessPolicy=public, subscribed=true, synced=false, callerInvolved=true

The original failure sequence was:

  1. The edge discovered the public graph, but the Context Oracle catalogue hid it unless it was already subscribed or synced.
  2. The Join UI required a curator invite for that public graph.
  3. After curator approval, runImmediatePostApprovalSync() used the private metadata refresh path with a private member proof.
  4. hasAuthoritativePrivateMetaDefinition() correctly required accessPolicy=private plus an approved-member delegation.
  5. The public snapshot was rejected as missing a complete private definition/delegation.
  6. SWM synchronization was skipped as unauthorized/unconfirmed.
  7. Preferred-curator catch-up and nine-peer fallback completed with data=0 sharedMemory=0.
  8. The subscription remained synced=false.

The root cause was routing: discovery/UI forced an explicitly public graph into the private join path. The private proof code was failing closed correctly; it was being asked to validate the wrong kind of graph.

Original behavioral specification

The #1848 fix established these invariants, which this follow-up preserves:

  1. Explicitly public graphs use the public subscription and catch-up path.
  2. Public subscription/read/catch-up does not require curator approval, allowlist membership, or a private delegation proof.
  3. Public metadata is confirmed only by authoritative public evidence, such as an explicit root accessPolicy=public definition, validated ontology evidence, or identity-bound active on-chain registration.
  4. Private and curated graphs retain their existing fail-closed proof requirements.
  5. A public graph's allowlist may restrict publishing, but not reading, subscription, or catch-up.
  6. Durable and SWM catch-up run after public subscription when responders host those planes.
  7. The preferred curator/source remains first, followed by connected sync-capable fallback peers.
  8. Catch-up is tracked and visible through /api/sync/catchup-status.
  9. Empty or failed peer responses alone cannot produce synced=true; authoritative metadata, clean completion, and plane readiness are still required.
  10. Users can browse and subscribe to discovered public graphs without a curator invite.

Changes in this PR

Correct passive catalogue browsing

PanelLeft now clears activeProjectId before opening a passive public graph tab. The regression starts with an active private graph, browses a different passive public graph, and asserts that the old project target is removed while the public tab opens normally.

Pin the public catch-up contract

The public subscription readiness test now records the request passed to catchupRunner.run() and verifies the exact subscribed graph ID plus includeSharedMemory: true. Existing assertions continue to cover durable/SWM backfill, readiness fields, job completion, and /api/sync/catchup-status visibility.

Pin public-proof named-graph scoping

The public metadata proof parity matrix now moves a complete-looking definition into the data graph and verifies that both in-memory snapshot validation and the ASK query reject it. Authoritative public metadata must remain in the exact root _meta graph.

Security boundary

  • No private/curated authorization production code is changed in this PR.
  • Private metadata still requires the complete private definition and current approved-member delegation.
  • Forged/stale approval cannot activate a private subscription.
  • An allowlist does not convert explicit public read access into private membership.
  • Wrong-graph metadata and empty/failed catch-up responses remain fail-closed.

Regression evidence

The tests were exercised against intentional regressions before restoring/fixing production behavior:

  • UI test failed before the reset with activeProjectId still equal to private-active, then passed after the one-line fix.
  • Changing the route to includeSharedMemory: false made the new catch-up request assertion fail.
  • Removing either the snapshot root-graph check or the ASK fixed-graph constraint made the new named-graph parity case fail.

Verification

  • pnpm --dir packages/node-ui exec vitest run test/panel-left.test.ts --reporter=verbose — 12 passed
  • pnpm --dir packages/cli exec vitest run test/context-graph-subscribe-readiness.test.ts — 17 passed
  • pnpm --dir packages/agent exec vitest run test/context-graph-public-meta-proof.test.ts — 1 passed
  • pnpm --dir packages/agent build — passed
  • pnpm --dir packages/cli exec tsc --noEmit — passed
  • pnpm --dir packages/node-ui build — passed
  • pnpm --dir packages/cli test — 199 files passed, 2 skipped; 2,824 tests passed, 13 skipped
  • pnpm --dir packages/node-ui test — 153 files passed; 2,178 tests passed, 38 skipped (run with localhost binding permitted; the sandbox-only attempt failed with listen EPERM 127.0.0.1)
  • pnpm --dir packages/agent test — 205 files passed, 2 skipped, 25 failed late after the shared Hardhat context file disappeared; all reported failures had the same unrelated ENOENT ... dkg-hardhat-ctx-9547.json infrastructure error. The changed public-proof test and its isolated run passed.
  • git diff --check — passed

Remote query note

The separate curator response ACCESS_DENIED: Context graph is not queryable is not changed here. Remote query access has its own queryAccess policy. As documented in #1848, the testnet chain did not contain a committed registration for the exact graph hash, so denial under the default policy is expected unless the curator explicitly enables per-graph query access.

Deliberate non-goals

The later review suggestions to extract hasConfirmedMetaState() or split modal validators are maintainability opportunities, not required for these three correctness/coverage fixes. They are intentionally excluded to keep this follow-up small and low-risk.

Comment thread packages/node-ui/src/ui/components/Shell/PanelLeft.tsx
@lupuszr
lupuszr merged commit 207ec3a into testnet-canary Jul 20, 2026
3 checks passed
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.

3 participants