PRIVATE lifecycle offline expected-execution model — 2026-08-28

Evidence class: offline source-contract analysis. This document is neither SBF build evidence nor validator, simulation, devnet, or mainnet evidence. The executable producer is tools/release/private-validator-lifecycle/preflight.py; it reads no key, uses no RPC, starts no validator, and runs no build.

Result

The current PRIVATE completion is eight stages, not one opaque end-to-end command:

founding -> participant -> ALT -> seal -> Direct Hot
         -> resolution -> payout -> retirement

Three prerequisite rails precede those completion stages:

checked mutable prepare -> exact local bankroll -> administration/activation

Pyth's eight prerequisite mutations sit between Direct and Resolution. They are not a ninth public lifecycle stage: their terminal four-field facts are an input to the Resolution semantic owner. Likewise market-input production and the Direct payout-schedule projection are read-only handoff producers, not separate completion stages.

The current source derives DCLTGMF2 as a 132-coordinate instruction whose v0 transaction locks 60 complete keys, below the devnet limit of 64. Direct Hot is also source-pinned: four static plus 57 loaded addresses, 61 unique message accounts, 1,159 wire bytes, and ten exact poststates. These facts refute a present lock/packet contradiction in those two routes. They do not predict SBF frame or compute consumption.

The model is intentionally version-derived. It reads the sole current GENERIC_MARKET_FOUNDING_MAGIC_Vn and the matching fixed, physical-funding, and complete-key constants. A successor DCLTGMF3 cut must update its Market, durable founding journal, and runner vocabulary coherently, but the preflight does not hard-code V3 or silently accept an incomplete rename.

Full source-derived graph

StepCaller and terminal handoffSigner/key sourceRequired prestateAccepted poststate and next consumer
preparelocal-mutable-prepare-v1, then local-mutable-plan-authenticate-v1; dclutch-local-mutable-prepare-report-v1seed-derived disposable roles; Python opens no keyclean source; exact checked gate; 13 links; 18 genesis accountsseven mutable protocol Loader pairs plus two immutable Pyth pairs; bankroll consumes report
fundingSolana CLI one-shot transfer; dclutch-private-validator-local-test-bankroll-v1, /status=finalizedcore-upgrade-authority is source and fee payercampaign payer absent; source has more than 100 SOL plus fee; five protocol-created roles vacantcampaign payer exactly 100,000,000,000 lamports; administration/founding consume the state
administrationcampaign --through activation; campaign report /execution/completed=trueexact campaign_administration_keypairs projection, solely core-upgrade-authoritychecked mutable slots and funded payerinfrastructure initialized and release activated; market input/founding consume it
foundinglocal-private-validator-market-v1, then founding-only campaign; six finalized submission journalsexact campaign_founding_keypairs; founder public identity is separately boundfive rent prefundings, exact fixture supply partition, vacant Market/Custody/Claims targetsOpen Market, aggregate, founder Position, admission, accepted Resolution funding; participant and Direct consume report
participantlocal-private-validator-user-position-admission-v1; dclutch-owned-loopback-user-position-admission-execution-v1, /phase=finalizedparticipant signs owner/collateral; core-upgrade-authority paysvacant Position; exact 100,000,000-atom fixture sourceadmitted Position plus finalized token/Custody delegation; Direct producer consumes the report
ALTrepeated local-private-validator-direct-trade-v1; Direct journals /phase=finalizedauthenticated private-session payertable vacant or exact durable prefixone exact frozen, activated 57-address table; seal consumes it
sealsame Direct executor and journal completionauthenticated private-session payerfrozen ALT and checked public manifestexact capability seal; Hot consumes it
Directlocal-private-validator-direct-trade-produce-v1, repeated executor, then local-private-validator-direct-payout-schedule-v1; finalized evidence /status=finalizedfounding founder sells; participant buys; session owns payerexact Market/root/Positions/tokens; replay roots vacant or authenticatedten poststates and exhaustive K seller plus one buyer claim schedule; Pyth/Resolution run, then payout consumes schedule
Pyth prerequisiteeight ordered local-private-validator-pyth-vaa-provision-v1 journals and one terminal reauthenticationpayer and EncodedVaa keys; update signer remains unopened/vacantEncodedVaa and update vacant; immutable slot-zero Receiver/Routerverified VAA journal prefix and four-field facts; Resolution alone performs Receiver PostUpdate
resolutionrepeated local-private-validator-flagship-resolution-v1; checkpoint V3 /verifiedTerminal=truetable authority, submitter, resolver, update signer from prepared key directory by authenticated addressPyth facts; active funding; Core Opensubmit, provider-execute, Core-accept, reclaim in strictly advancing finalized slots; payouts consume terminal Market
payoutread-only payout-input plus repeated local-private-validator-wallet-terminal-payout-v1; evidence /phase=finalizedeach claim owner; core-upgrade-authority paysselected Position balance and aggregate supply positivewinner credits collateral; losers are real zero-collateral burns with byte-identical Custody/token state; retirement consumes exact supply-zero state
retirementterminal sequence to 15-retirement-replay-handoff.json, then local-private-validator-aggregate-retirement-v1; completion /status=finalizedcore-upgrade-authority pays; program child authorities are PDAsevery claim supply zero, Core terminal, source receipt and frozen ALT exactprepare, close-vault, close-replay, finish; exact rent/refund conservation; activity/session/receipt consumers follow

Caller exposure and final evidence

The one-seed full probe needs fourteen exposed successor commands: five founding/participant commands and nine Direct-through-retirement commands. The twenty-seed terminal mode additionally needs six final evidence callers:

For every selected mode, the offline preflight proves both sides of reachability from source: a dispatch arm in main.rs and the exact command string inside the help function that main::usage exposes. It separately joins sixteen runner schema constants back to their Rust semantic-owner modules. A string merely existing elsewhere in a module is insufficient. This is the distinction that caught the Direct command being dispatched but hidden from accepted help.

The three other usage surfaces carrying literal patch markers were repaired in the same cut: Pyth prerequisites, wallet payout, and aggregate retirement. The preflight now refuses \\n+ inside any required help function.

Cross-stage quantities

The fixture supply has one exact partition:

Token-2022 total supply = founding collateral atoms + 100,000,000 fixture atoms

Mint authority must be removed. Direct's owned-loopback producer fixes its fill at 100,000,000 atoms and independently proves that the participant has enough gross collateral plus fee; the runner never turns lamports or fee arithmetic into token quantity.

The Direct payout schedule is deliberately exhaustive, not winner-only. It contains every positive seller claim coordinate plus the filled buyer coordinate. After terminal resolution the payout route burns losing claims with zero collateral and no Custody effect. Retirement is correctly unreachable until every aggregate supply coordinate is zero. Treating a zero payout as a no-op would be a supply leak; treating it as an error would make retirement unreachable.

Predicted and observed frontier

The source read established these outcomes before another validator campaign:

Running the offline gate

python3 tools/release/private-validator-lifecycle/preflight.py \
  --repo /absolute/clean/dclutch \
  --through full-probe \
  --output /absolute/new/preflight.json

The output path is create-new and mode 0600. The report binds every source file it relied on by SHA-256 and binds its own canonical model as model_sha256.

Focused adversarial gate at this cut:

python3 -m unittest -v tools/release/private-validator-lifecycle/test_preflight.py
19/19 passed

The hostile cases delete dispatch, hide help, reintroduce patch markers, drift schemas, zero or substitute fixture supply, add an airdrop role, raise founding above 64 keys, split the founding magic join, reorder private stages and Pyth actions, alter Direct geometry/vocabulary, remove zero-payout semantics, reorder Resolution receipts, move the retirement handoff, and try to clobber output.