Skip to content

release: RFC-64 public RC after bounded canary#1931

Draft
branarakic wants to merge 439 commits into
mainfrom
codex/rfc64-public-rc-testnet
Draft

release: RFC-64 public RC after bounded canary#1931
branarakic wants to merge 439 commits into
mainfrom
codex/rfc64-public-rc-testnet

Conversation

@branarakic

Copy link
Copy Markdown
Contributor

Status

Draft promotion artifact for review only. Do not make this ready or merge it until the exact head 6641868 passes PR #1930 and the bounded 2-4 hour testnet canary.

User-visible release promise

  • confirmed public-curated root publications produce one exact signed catalog head
  • warm receivers converge while publications occur
  • cold receivers started later bootstrap through a pinned policy and ordered provider list
  • receivers materialize exact finalized VM content
  • the applied head and VM graph survive an offline restart without provider-assisted repopulation

Private CG serving and generalized decentralized catalog discovery remain outside this release.

Evidence already green on this exact tree

  • agent dependency closure build
  • 116 loopback and RPC compatibility tests
  • 51 durable materialization and RFC-64 native release tests
  • clean merge composition of current testnet-canary plus integration/rfc64-devnet

Required before promotion

  1. PR release: compose RFC-64 public RC on testnet canary #1930 hosted CI and review green
  2. merge exact head to testnet-canary
  3. 2-4 hour bounded canary with warm publication, cold bootstrap, provider failover, restart, exact head and finalized VM assertions
  4. no unresolved correctness or security review findings

Branimir Rakic and others added 30 commits July 19, 2026 17:35
Wire the existing Rfc64PublicCatalogTransportV1 onto the real DKGAgent
production router with startup/shutdown lifecycle; add durable author-head
publication + best-effort announcement and a receiver scheduling/dedup path
that fetches by exact digest, re-verifies, and durably stages the head.
Terminal at durable staging: no candidate admission, no KA/SWM/VM activation
(spec Phase 1 + start of Phase 2).

- rfc64/open-catalog-policy-v1: honest open-policy authorizer. Returns the
  digest of a locally-held ContextGraphPolicyV1 (via the core primitive
  computeContextGraphPolicyObjectDigestV1), never the untrusted wire hint;
  fail-closed for unknown or non-open (accessPolicy!=0) CGs.
- rfc64/public-catalog-receiver-v1: non-blocking scheduler (the transport
  awaits onCatalogHeadAvailable before ACK, so schedule() enqueues and returns
  synchronously) with dedup (in-flight + already-staged), bounded
  concurrency/queue, retry/backoff, and drain-on-close that awaits in-flight
  durable stage writes.
- rfc64/public-catalog-service-v1 + dkg-agent-rfc64-catalog mixin: construct and
  start the service on this.router during start() (dormant without dataDir),
  drain + close it in stop() before node.stop()/persistence release; author
  publish path (produce genesis -> verify -> durable stage -> announce peers).
- Admission: no protocol exemption. On a chain-free node admission is disabled
  (no networkId) so open catalog works; with a networkId it is admission-gated
  like every other node protocol.
- Tests: receiver scheduler unit (9) + two-real-DKGAgent integration
  (announce/fetch/reverify/durably-stage the exact head; dedup; fail-closed
  without an accepted policy; no CG activation).
- devnet/rfc64-gate1-public-catalog: two-real-process demo + deterministic
  evidence artifact (git-ignored output).

Does not touch integration/rfc64-devnet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Jurij89 and others added 30 commits July 22, 2026 23:55
…pre-send outcome (#1867, #1864) (#1918)

* fix(publisher): terminal-fail definitive pre-acceptance sends; typed pre-send outcome (#1867, #1864)

#1867 — For a KA VM publish, the 'broadcast' status is recorded on the
chain:txsigned write-ahead hook, strictly before eth_sendRawTransaction
(the #1851 durability contract). A send that failed DEFINITIVELY before
mempool acceptance (e.g. insufficient funds) threw after that durable
record, so processKnowledgeAssetVmPublish's catch handed the job to chain
recovery — which chased a never-accepted tx for the full
recoveryLookupTimeoutMs (~15 min) before failing with a misleading
recovery_state_inconsistent. Such rejects are now recorded as an immediate
terminal broadcast-phase failure (insufficient_funds) via a CONSERVATIVE
classifier (isDefinitivePreAcceptanceSendFailure) that whitelists only
unambiguous pre-mempool rejects. Every ambiguous error (RPC timeouts,
replacement-underpriced, nonce races, already-known, reverts) stays on the
existing recovery early-return, preserving #1851's write-ahead durability
guarantee — no double-submit.

#1864 — Model the pre-send write-ahead boundary as an explicit typed
PreSendOutcome ('not-reached' | 'recorded-durable' | 'rolled-back-pre-send')
reported by recordDurableBroadcastBeforeSend and switched on by the catch,
replacing the prior inference from a mutable executorReturned flag + a
post-hoc getStatus re-read. Result-recording is split into its own try so
its (unchanged) broadcast-phase failure handling no longer needs the flag.

Tests: terminal insufficient_funds with no recovery chase/resend; the
locked deliberate revert-with-"insufficient funds" edge; a 6-case
safety-invariant matrix proving ambiguous/replacement/already-known/
plain-revert/timeout errors stay on recovery; and a pure classifier unit
test. Full publisher unit suite green (520 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(publisher): throw-safe pre-acceptance classifier; recorder-owned pre-send outcome (#1918 review)

Addresses the #1918 bot review:

- MUST-FIX (double-submit safety path): isDefinitivePreAcceptanceSendFailure
  no longer stringifies the error eagerly. A pathological thrown value
  (e.g. Object.create(null) → String() TypeError) previously could throw
  from the classifier, skipping the ambiguous-recovery branch and stranding
  the job off the recovery track. Message extraction is now throw-safe: an
  unstringifiable value falls back to an empty message → classified
  non-definitive → the durable 'broadcast' stays on the recovery track.

- Model the PreSendOutcome in the broadcast recorder's closure (like the
  existing recordedTxHash) instead of threading a mutable out-parameter
  through recordKnowledgeAssetVmPublishBroadcastProgress /
  recordDurableBroadcastBeforeSend; those revert to pure helpers. The
  recorder exposes a read-only `outcome`; the catch reads it directly.

- Move PreSendOutcome out of the shared persisted LiftJobState model
  (lift-job-states.ts) into a local transient type in the publisher impl.

Tests: non-stringifiable thrown value after the durable broadcast stays on
recovery (throw-safe); a whitelist<->mapper invariant test pinning that every
whitelisted error maps to terminal insufficient_funds from 'broadcast'
(kept as separate functions on purpose — the whitelist stays conservative and
must not silently widen with the mapper). Publisher unit suite green (17 in
the durability file).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(publisher): guard all thrown-value inspection in the pre-acceptance classifier (#1918 review)

Round-5 review 🔴 — the throw-safety fix was incomplete: the `.code` read
sat OUTSIDE the try, and property access can throw for a throwing accessor
or a Proxy. On the recorded-durable path that would throw out of the catch
before it returns the persisted 'broadcast' job, regressing the very
double-submit recovery decision this is meant to protect.

- isDefinitivePreAcceptanceSendFailure now wraps ALL inspection of the
  arbitrary thrown value (the `.code` read AND message extraction) in a
  single try; any failure to inspect → non-definitive → stays on recovery
  (we cannot prove a pre-acceptance reject, so treat it as ambiguous).
- Remove the now-redundant safeErrorMessageLowerCase helper (folded in).
- Un-export isDefinitivePreAcceptanceSendFailure from the package barrel
  (index.ts) — it is internal write-ahead recovery policy, not public API;
  the package-local test imports it directly from the module.

Tests: durable-broadcast + a throwing `code` accessor stays 'broadcast'
(never terminates, never resends); classifier unit test adds throwing-
accessor and throwing-Proxy cases. Durability file: 18 tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(publisher): exclude reverts from pre-acceptance whitelist; share throw-safe error extraction (#1918 review)

Round-6 review:

- 🔴 A revert is post-mempool (the tx was mined), so a `revert`/`reverted`
  message must NEVER be classified as a pre-acceptance reject — even when its
  caller-controlled revert string contains "insufficient funds".
  isDefinitivePreAcceptanceSendFailure now returns false for any revert
  message before the "insufficient funds" substring check, keeping ALL
  reverts uniformly on the recovery track (consistent with plain-revert
  handling) and confining the whitelist to node-level pre-send rejects.
  go-ethereum's balance pre-check ("insufficient funds for gas * price +
  value") contains no "revert", so no genuine pre-acceptance case is lost.
  This reverses the earlier "locked edge" — a revert is strictly narrower /
  more conservative, and no double-submit impact (recovery never resends).

- 🟡 Share the throw-safe error EXTRACTION between the mapper and the
  classifier via a new `readPublishErrorFacts(error)` (guarded code + message
  reads). The classification DECISION stays separate: the pre-acceptance
  whitelist remains a deliberately narrow predicate and must not track the
  mapper's broader signals (that widening would re-open the #1851
  double-submit hole). Their agreement stays pinned by the invariant test.

Tests: the former locked-edge test is flipped — "execution reverted:
insufficient funds" now STAYS on recovery ('broadcast'); a node-level
"insufficient funds for gas * price + value" still terminal-fails; classifier
unit test adds revert-with-insufficient-funds exclusion cases. Full publisher
unit suite green (524).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…overy

feat(rfc64): add applied-head discovery seam
…lish

# Conflicts:
#	packages/agent/scripts/test-package-root.mjs
#	packages/agent/src/dkg-agent.ts
feat(agent): cold-start RFC-64 from provider head
# Conflicts:
#	packages/agent/src/dkg-agent.ts
#	packages/agent/src/rfc64/catalog-authority-config-v1.ts
#	packages/agent/test/rfc64-dkg-agent-native-wiring.integration.test.ts
# Conflicts:
#	packages/agent/test/rfc64-dkg-agent-native-wiring.integration.test.ts
feat(agent): advance RFC-64 catalogs after public publish
feat(agent): bootstrap pinned RFC-64 public catalogs
test(agent): prove RFC-64 public release convergence
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