Skip to content

fix(sync): batched exact VM reconciliation (#1871) + lazy on-chain probe (#1852) - #1876

Merged
branarakic merged 12 commits into
testnet-canaryfrom
fix/testnet-canary-fifa-sync-v2
Jul 21, 2026
Merged

fix(sync): batched exact VM reconciliation (#1871) + lazy on-chain probe (#1852)#1876
branarakic merged 12 commits into
testnet-canaryfrom
fix/testnet-canary-fifa-sync-v2

Conversation

@branarakic

Copy link
Copy Markdown
Contributor

What ships (step 1 of 2)

Two changes that pair to deliver full VM sync on public Context Graphs:

  1. feat(agent): batch exact missing VM asset reconciliation #1871 — batched exact missing-VM reconciliation (carried in full): scan up to 10 on-chain registration ordinals, build one recovery batch of only the KAs not locally complete, fetch those exact UALs through the authenticated sync protocol, revalidate each against its on-chain root.
  2. fix(swm): evaluate on-chain public probe lazily — restores receive-path latency #1852 — lazy on-chain public probe: removes an unconditional chain RPC from the hot path of every SWM gossip receive (~3ms → ~33ms regression). Proven effect: LIVE-receiver VM delivery restored from 150s timeouts to ~3s.

Base: current origin/testnet-canary. Merging this supersedes #1852 and carries #1871. The big-CG pair (#1868 64k _meta ceiling + #1842 catch-up materialization — canonical on main) follows as step 2.

Gate evidence (6-node devnet, full public-CG sync suite, run from this exact head)

verify-fixes.mjs — 8/10, both failures pre-sanctioned known issues:

[FAIL] #1779: PEER sees markdown CONTENT triples (not just metadata) — EMPTY on peer after 90243ms
[FAIL] #1780: CURATOR VM-published the MEMBER-shared root — http=409 VM_PUBLISH_PRECONDITION

proof.mjs run 1 — 33/35, failures limited to the two known watermark checks:

FAILED: public-open: LIVE receiver VM SYNC MECHANISM advanced (watermark reached chain head)
FAILED: public-curated: LIVE receiver VM SYNC MECHANISM advanced (watermark reached chain head)

proof.mjs run 2 (stability) — 32/34, identical failure set: watermarks only.

Known issues, stated plainly

🤖 Generated with Claude Code

Branimir Rakic and others added 11 commits July 20, 2026 14:55
…ated CGs

The must-vs-may refactor turned the probe unconditional: every SWM gossip
receive awaited isContextGraphProvenPublicOnChain (a live chain read through
resolveOnChainAccessPolicyState with its timeout machinery) even when the CG
has no agent gate — the case where resolveWorkspaceEncryptionRequirement never
reads the answer, because both requires and supports collapse to
hasPrivateAccessPolicy.

Measured on a 6-node devnet, that took SWM receive-apply from ~3ms to ~33ms
and turned the public-CG sync gate red in BOTH public cells: the author's next
convergence poll slipped one 3s cycle, the VM publish therefore landed AFTER
the live receiver's subscribe-triggered catch-up had already run, and — since
chain-promote defers without transaction provenance and the snapshot
materializer lane is separately parser-blocked ("ambiguous publishedAt") — the
live receiver starved until the ~5-minute periodic sweep. Symptom in the gate:
"LIVE receiver has VM content — TIMEOUT ... reconcile pending watermark=0/1"
at 150s, while the LATE receiver (fresh catch-up, runs post-publish by
construction) converged in ~3s.

Restore the pre-refactor evaluation order — probe only when
agentGateAddresses !== null — while keeping the must-vs-may split intact.
For a gated CG behaviour is unchanged.

Tests drive the REAL handler with a counting oracle, in the unit include list:
 - ungated CG: write applies AND the probe is never invoked. Mutation-tested:
   re-introducing the unconditional await fails exactly this test.
 - gated CG: the probe IS invoked and a public proof admits plaintext, so
   laziness cannot regress into "never".

Note: the underlying exposure is pre-existing and NOT closed here — a LIVE
subscriber whose catch-up ran before the publish has no event-driven VM
delivery lane (finalization broadcast schedules no durable sync; chain-promote
requires provenance it never gets; the SWM materializer heal lane dies on
"ambiguous publishedAt" fleet-wide). The baseline passes the gate only because
its receive path is fast enough that the publish beats the queued catch-up.
Deserves its own issue.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…the agent-to-handler oracle wiring

Two review follow-ups on #1843:

- resolveWorkspaceEncryptionRequirement (and its must-vs-may rationale) moves
  from the 2.3k-line workspace-handler.ts into workspace-encryption-policy.ts;
  the handler keeps only the local lazy-probe sequencing note, and the policy
  tests import the focused module instead of the orchestration file.
- New agent-level regression builds SharedMemoryHandler through the REAL
  getOrCreateSharedMemoryHandler and delivers a signed plaintext write on an
  agent-gated CG with a counting isContextGraphPublicOnChain: the write must
  apply and the probe must be consulted. Removing the
  publicAccessPolicyOnChainOracle wiring from dkg-agent-swm-substrate.ts fails
  this test with the exact production drop it prevents (mutation-verified).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ive recovery

Two review fixes for the batched exact VM reconciliation path:

- recoverVmReconcileBatch now requests at most MAX_EXACT_SYNC_ASSETS UALs
  per peer. A scan batch configured above the protocol cap
  (DKG_VM_RECONCILE_BATCH_SIZE > 10) previously produced a filter that
  requireExactAssetUals rejects, so every exact fetch threw and recovery
  was silently dead. Over-cap targets stay in `remaining` for a later
  peer or pass; fetch telemetry and revalidation (which costs chain
  reads per ordinal) are restricted to the requested slice.

- The batch fetch is now gated on the per-CG active-fetch cooldown. The
  batched path deliberately skips the per-UAL negative cache (consulting
  it primes connections to every discovered agent), which left no damper
  at all: a CG with permanently unavailable KAs ran a 3-peer,
  priority-1000 exact sync on every reconcile pass. An unproductive
  batch now costs one bounded fetch per sweep interval. Mirroring the
  inline path, progress or an unreachable network clears the cooldown,
  so a draining backlog still proceeds slice after slice.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t-sync test coverage

Review blockers (lupuszr):

- Re-check the captured local-CG -> on-chain-CG binding immediately after
  recoverPendingOrdinals resolves. Recovery is the longest await in a
  reconcile pass; a rebind landing during it could let outcomes recovered
  under the old binding advance or persist cursor state for the rebound
  CG. Staleness detected there is now treated exactly like staleness
  during ordinal work: outcomes discarded, no watermark move, scan
  cursor reset.

- Gate every exact-recovery peer through ensurePeerAdmittedForRecovery
  before sending. Curator hints and getConnections() both predate the
  network-identity probe, so a merely-connected peer is not necessarily
  admitted; the batch path could previously send authenticated exact
  requests to unverified or rejected-network peers.

- Contain ordinal-worker failures. The pool used fail-fast Promise.all,
  so one rejecting ordinal left sibling workers running past the pass's
  lifetime, overlapping their network/store side effects with the
  caller's retry. The first error now stops dispatch across all
  workers, in-flight ordinals drain, and only then does the pass reject.

Coverage (review-bot asks):

- runDurableSync integration: exactAssetUalsFor reaches both fetch
  phases and an old-responder full-CG payload is filtered before the
  verification worker sees it.
- Page-fetch coalescing + durable single-flight identity now covered
  for assetUals (different batches never share a run; identical
  batches do).
- parseSyncRequest wire tests for both formats: valid filters survive,
  present-but-invalid fail closed to [], absent stays undefined.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@branarakic

Copy link
Copy Markdown
Contributor Author

Updated: absorbed #1871's latest head 6c4343f (three reconcile race/boundary fixes + widened exact-sync coverage) — zero merge conflicts. Full re-gate on the new head: build clean, verify-fixes 8/10 (excepted knowns only), proof 32/34 (watermark-only). This PR now carries #1871 complete and current. Clear to merge — use a MERGE COMMIT so #1871/#1852 auto-close.

@branarakic
branarakic merged commit f11bb12 into testnet-canary Jul 21, 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.

1 participant