Synthetic-local Pyth release V1

Status: partially superseded, 2026-08-27. Everything below this banner is the original 2026-08-22 text, retained verbatim. Two of its claims have since been measured against the live clusters and one of them is wrong. Read §Supersession before using the quorum paragraph or deriving any release from this file. The measurements live in fixtures/pyth/upgraded-2026-08-26/PROVENANCE.md.

This manifest derives the feature-gated dClutch lab release from fixtures/pyth/local-upgraded-2026-08-22/. It is local execution evidence, not a production catalog row, provider-availability claim, or authenticated Solana cluster release.

Measured identifiers

The adapter authenticates the exact Program and ProgramData keys and their deployment slots. It does not hash the combined 1,072,824 ELF bytes during each resolution; the ProgramData generation is the onchain executable bind, while the ELF digests make the fixture and ABI evidence reproducible.

Domain-separated identifiers

The synthetic local release label/cluster identifier is SHA-256 of these exact bytes:

dclutch/synthetic-local-release/v1 || 00 || local-upgraded-2026-08-22

Its digest is 4081d55d4031313fcf4b7c41313d547a9441c8f9c048741a7a951b3e035e22d9. This is deliberately not a devnet or mainnet genesis hash.

The dClutch adapter semantic identifier is SHA-256 of these exact byte strings, separated by one 00 byte:

dclutch/pyth-adapter/v1
resolve-categorical-pyth-v1
internal-post-update
inline-terminal-receipt

Its digest is 3fdfc94589c69b133864468320976f8e790e7fe0f145897b6eabc22bd7c8711b.

Quorum distinction

The captured receiver Config has minimum_signatures = 5. That local receiver policy is not the router's guardian-set cardinality or strict-majority fact. The adapter binds the complete Config digest, while the authenticated router generation and verified EncodedVaa path own full-VAA verification. The lab release therefore must not compare the Config value five with the 19-guardian strict-majority threshold ten.

The fixture feed ID [0x2a; 32] has no real asset meaning. A lab Market must pair it with explicitly synthetic base and quote semantic IDs in its inline feed profile, and that profile cannot seed a production Market.

---

Supersession (2026-08-27)

Added by the PY lane after a bounded public-RPC observation of both clusters. The section above is unchanged; this section says what is now known.

1. This is the upgraded generation, not a superseded one — CORRECTED

The Pyth Core cutover landed 2026-08-26T16:00:49Z and it was reasonable to assume that a fixture captured on 2026-08-22 sat on the wrong side of it. It does not. Measured 2026-08-27:

So the receiver ABI identifier pinned above, c5079559864fc34dbd5fe87b4aa9fba3a1ed22690363ec490449e8660e73af64, is the upgraded generation's receiver. The 2026-08-22 capture named the upgraded program IDs and took the upgraded binaries; the cutover made that generation canonical without changing those bytes.

Nothing in the ABI moved, and the adapter needed no change. The pyth_price_route campaign passes unmodified against the new generation, executing rec2HHDDnjLfj4kE7VyEtFA1HPGQLK33259532cRyHp's real ELF.

This corrects the reading in docs/design/MAINNET_STATE_RELAY.md §2.2 consequence 1, which called this identity "the legacy generation". It is not. The operative caution in that consequence still stands for a different reason — see §3 below.

2. The quorum-distinction paragraph is superseded

The paragraph above says:

The lab release therefore must not compare the Config value five with the 19-guardian strict-majority threshold ten.

That instruction described a real hazard against the guardian set of the time. It no longer describes the deployment. Measured on both clusters:

lab fixturelive upgraded generation
guardian set index00
guardian set cardinality19 (synthetic, upstream dummy_guardians_addresses())5
Config.minimum_signatures53
Config fee10
admitted data sources1, chain 1, emitter [0x01; 32]1, chain 26 (Pythnet), emitter PythnetPythnetPythnetPythnetPyth
strict majority of the set103

Two things follow.

The comparison the paragraph forbids no longer exists. On the live generation minimum_signatures = 3 and the strict majority of five is also 3, so the receiver's own policy value and PythReleaseV1's strict-majority rule (count / 2 + 1) coincide. They did not under the nineteen-key set. The InvalidStrictMajority refusal in dclutch-pyth-svm needs no change; a release for the live generation is guardian_set_count = 5, required_guardian_count = 3, which is exactly what its tests already use.

The lab's quorum shape is now unlike production, and that must be said out loud. The fixture's 5-of-19 is a lab shape. It is not a scaled-down model of the live 3-of-5 and must never be described as one. What the lab proves is that the real router ELF performs real signature verification and that dClutch rolls back atomically around it — not that dClutch has exercised the production quorum.

The trust root is a 3-of-5 Pyth-controlled multisig, guardian set index 0, expiration_time = 0, five keys byte-identical across clusters. "Zero new trust" for a Pyth-sourced market remains exact, but what that trust is has become materially smaller, and that belongs in the Product's disclosure rather than a footnote.

3. A release is per cluster, and the reason is not the binary

PythReleaseV1 already carries a cluster_id. This is the measured justification for requiring it to be nonzero and cluster-specific, and for naming the cluster by its genesis hash rather than letting an adapter infer it:

clustergenesis hash
mainnet-beta5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d
devnetEtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG

The upgraded generation's three ELFs are identical across clusters. What is not identical, and what a release actually binds:

bound factshared?
receiver / router / push-oracle ELF digestshared
program ids and ProgramData keysshared
ProgramData allocation sizesshared
deployment slotper cluster
upgrade authorityper cluster (6oXTdojy… vs upg8KLAL…)
complete ProgramData body digestper cluster
Config.governance_authorityper cluster (6oXTdojy… vs 7g4Los4W…)
complete Config digestper cluster
GuardianSet[0] account digestper cluster (creation_time differs by 104 s)
guardian key material, Config trust fieldsshared

So config_digest, receiver_deployment_slot and router_deployment_slot in PythReleaseV1Input are cluster-specific by construction, and two release rows are required to cover both clusters even though one ABI serves both. This is the operative caution the "legacy generation" reading was reaching for: no production release row may be derived from this file for either cluster, because this file pins a lab Config (05038cf7…) that exists on neither.

crates/dclutch-svm-harness/tests/pyth_upgraded_generation.rs makes this executable: it rebuilds all six observed ProgramData bodies from one shared copy of each ELF plus six committed per-cluster headers, and requires each observed digest exactly.

4. Staleness is a measurement with a date, not a constant

measured-profile, 2026-08-27, getSignaturesForAddress on the SOL/USD account 7AviUf9nL62mcxNbQGKm4nKDQnPjswo6c5MX4D57HmyE, successful transactions only, distinct block times:

devnetmainnet-beta
window170.42 h (7.10 d)12.21 h
gaps1,9977,017
p50 / p90 / p99313 / 321 / 325 s7 / 9 / 13 s
max observed gap4,784 s21 s

The single largest devnet gap ran 2026-08-25T08:42:02Z → 10:01:46Z; the next largest was 354 s, so it was one discrete outage rather than drift.

This supersedes the earlier n = 12 single-window figure of 310–318 s. That sample had the median right (p50 = 313 s here) and missed the tail entirely. The 400 s devnet staleness budget it suggested would have refused every read for 79 consecutive minutes two days ago. A WindowSpecV1 max_age_seconds is a maximum, not a median.

Both figures remain measured-profile and provisional. A finite observation window is not a bound; the lifting plan is continuous observation with a running maximum, not a longer one-off measurement. Until that exists, a devnet majors Product must treat provider silence as an expected state with a funded permissionless failure path, not as an anomaly.

Push identity, most recent 12 postings per cluster: devnet is a single payer (4p16wya1Vw2u9w22oah4yXQgySb6eWKRRLMsEXCreish, 12/12); mainnet-beta is not a single payer (9F6ApEtzkHVdZXzsury6BYmyEh4pahDBxuhNLaGC6saC 9/12, 9uFDvq24JQ8SzbFuQ5opBDfNy2NoCxUJCHdSapBxLufF 3/12). This corrects an earlier "sole fee payer" reading for mainnet. It is a sample of 12, not an enumeration of the pusher set.

5. Which surface targets which generation

surfacegenerationevidence level
fixtures/pyth/local-upgraded-2026-08-22/upgraded (ELFs), lab (Config, guardians, VAA, price)synthetic-local execution of the real upgraded ABI
fixtures/pyth/upgraded-2026-08-26/upgraded, as deployeddated cluster observation; not executable on its own
crates/dclutch-pyth-svm decodersgeneration-independent byte viewsunit; now exercised against both lab and live shapes
crates/dclutch-pyth-svm::release::PRODUCTION_RELEASESnonedeliberately empty; no row exists for either cluster
crates/dclutch-svm-harness/tests/pyth_price_route.rsupgraded ELFs, lab Config/VAA/pricesynthetic-local execution, passes on the new generation
crates/dclutch-svm-harness/tests/pyth_upgraded_generation.rsupgraded, as deployedoffline byte evidence against the observation
tools/local-validator/bootstrap/upgraded ELFs, lab everything elselocal-validator execution

None of these is devnet-price, provider-availability, production-release, or mainnet evidence.