{"assessments":[],"deployments":[],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"60960f29-4054-4c00-ac58-4788e78800c9","kind":"skill:build-contract-project","nodes":[{"acceptedSubmissionHash":"86a212cc68ade9217646b8862e8a0dc7d4d8d17a0381df6b8e99ab3601993c77","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"6b8d2c2ebd3301cff2be8edb1e1cc6ba65c858c02fe7247be81722b969842265","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"6b8d2c2ebd3301cff2be8edb1e1cc6ba65c858c02fe7247be81722b969842265","skillId":"build-contract-project","state":"accepted"}],"objective":"CONTRACTS: Sorphera Passport deployment integration and release rehearsal\n\nContinue https://github.com/identity-md-launches/launch-961-build-sorphera-smart-contracts\nStart from latest main after PR #9; preserve newer work.\n\nONE Contracts task: finish deployment wiring, integration verification and release artifacts for the existing Passport. No new features, website work, live signing/funding/broadcast, mainnet deployment or production sales. Local test transactions are allowed. Do not retarget parked launch 961.\n\nThe previous pass reports 103 offline tests but no fresh integration run. Entry processing, ABI layouts, refund divisors and entitlements changed, so \"buy is unchanged\" cannot justify skipping integration. Deployers/manifests still omit Passport.\n\nRead PASSPORT-HANDOFF, TESTING, DEPLOYMENT, CANARY, KEEPER and current source. Preserve reward rules, 10% paid-sale fees, custody protections, strict cutoffs, separate NFT tie VRF and immutable accepted requests.\n\n1. DEPLOYMENT WIRING\n\nUpdate actual deployers/decoders: Rehearse.s.sol, SepoliaCanary preparation, canary/release CLIs and manifest consumers, not just wrappers.\n\nDeploy Router -> VaultFactory -> Sorphera -> SorpheraPassport(lottery, qualifyingPriceWei). Complete both owner bindings: factory.setLottery(lottery) and lottery.setPassport(passport).\n\nQualifying price is an explicit input; 5000000000000000 wei (0.005 ETH) is only a local fixture. Production price/owner remain unapproved inputs. Validate the price under lottery rules and against both intended qualifying games. Other-priced rounds remain ineligible; never reprice earned rewards.\n\nAdd fail-closed preflight/rehearsal checks for:\n- Correct chain, owner and dependency/configuration bindings.\n- Expected Passport code, passport.lottery() == lottery, lottery.passport() == passport and expected qualifyingPrice.\n- Missing/wrong addresses, incompatible code, wrong price and repeated binding.\n- Missing/misbound Passport blocks release readiness even though ordinary buy can work without it.\n- Sales remain disabled during release setup and at rehearsal completion. Lifecycle tests may enable only isolated local fixtures.\n\nPrefer script/preflight fixes; change lottery code only for a reproduced need. Preserve launch guards and the absence of privileged reward grants.\n\n2. MANIFESTS AND RELEASE ARTIFACTS\n\nUse the permitted release workflow to include Passport, constructor inputs and post-deployment actions in manifests/configuration.\n\nPreserve protected launch.json and historical records unless the platform permits edits. If blocked, provide a concrete candidate patch/template and exact release commands for IMD. Do not bypass protection, remove hashes or claim unapplied changes are complete. Keep mainnet drafts separate from Sepolia rehearsals.\n\nRegenerate canonical ABIs, size reports and permitted release metadata from final source. Include Passport in address discovery, exports and required configuration. Check keeper/canary decoding of appended Round fields, Ticket.reward, Cancelled's paid count and reward issuance.\n\nValidate runtime hashes against locally deployed code, including constructor immutables/addresses. Label fixture values local; leave unknown production values unset. Never fake hashes. List website ABI/config updates for the later Website task.\n\nEnforce production size limits with pinned compiler/settings. Sorphera was 24,366 bytes against 24,576, leaving 210 bytes. Report final sizes and fail on oversize. Do not raise limits or weaken safeguards; put extra logic outside the lottery where practical.\n\n3. COMPLETE LIFECYCLE VERIFICATION\n\nRun fresh offline, tooling and relevant fork/integration suites against this candidate and deployment path. Historical passes are not current evidence.\n\nExtend integration tests to deploy/bind Passport and cover:\n- Direct buy and paid entry through Passport; correct player ownership and exact ETH forwarding.\n- 12 qualifying paid entries -> own round Won/Rolled -> finalization -> reward, with remainders across games/rounds.\n- Free-only/mixed entries; total/paid/reward counts, fees and FWA acquisition budget.\n- Paid/reward ETH winners, a reward winner in the separate NFT tie-break and vault claims.\n- Cancellation: paid-only refunds/FWA tokens/exceptional NFT recovery rights; reward restoration once.\n- Zero-paid cancelled cohorts, same-game carry-forward and late recoveries. Prove which vaults/groups can receive late ETH/tokens/NFTs, including prior-group assets; an empty new-vault test alone is insufficient.\n- Reverts, cutoff/pause, retries, duplicate processing/restoration, wallet isolation and keeper continuation.\n\nExercise real FWA pool/rewards/helper paths on a pinned fork without replacing deployed dependency code. Verify chain, block hash and bindings. Label test funding, impersonation and simulated callbacks; a fork pass is not live VRF proof. Check custody, token delivery, liabilities and claim balances, not only successful transactions.\n\nKeep tests bounded. Add focused regressions for reproduced defects; preserve existing assertions/guards. Record gas/batch limits and deployed sizes.\n\n4. NETWORK AND LIVE-CANARY BOUNDARY\n\nCheck permitted RPC/network access early, using documented endpoints or configured inputs. Never bypass controls or expose API keys.\n\nIf fork access is blocked, finish local implementation, deployment rehearsal and offline/tooling checks. Supply runnable fork commands, required environment-variable names, the actual connection failure and the runner/RPC capability needed. Mark those checks BLOCKED/NOT RUN, not passed or unnecessary. Missing RPC access does not require wallet funding.\n\nUpdate the resumable Sepolia canary for Passport deployment/binding and rewards; rehearse locally only. Do not run it live. Keep actual coordinator fulfillment/proof/billing receipts separate from simulations. A company signer, subscription, test funds and separate live authorization remain later inputs.\n\nDo not address permanent accepted-VRF nonfulfillment with a reroll, replacement seed, discretionary cancellation or winner change. Record that existing issue separately. Never bypass or claim a private IMD gate rerun without its runner.\n\n5. DELIVERABLES AND COMPLETION\n\nDeliver code/tooling fixes, interfaces, permitted manifest edits or concrete protected-change patches, plus concise integration/release instructions in existing docs. Keep these within the Contracts task.\n\nProvide a validation table: command, source revision, toolchain, network/block, result, evidence and blocker. Separate historical results, current offline/fork passes and unperformed live steps. Automated checks are not a professional audit.\n\nCompletion checklist:\nA. Fresh local deployment includes Passport, verifies both bindings/price and ends with sales disabled.\nB. Rewards, both games' claims and cancellation/restoration pass the updated integration path. Any external RPC blocker is explicitly recorded as outstanding, not successful comple","parentJobId":"b99b441b-44dd-4aa7-b7da-cc88c49b8f49","planHash":"901f07a4f30e43e7bc8f6487915dad0d8a2503cb0db3d4382edd1094494a641a","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"a3707b79-51b8-4d04-9e32-3e786d91c1d9","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-961-build-sorphera-smart-contracts"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"50995","feedbackHash":"6fc4ee9b27f7352b371ebac29ec8c79f66e2df2590f1dcb49e114a7f20a4f5b0","nodeKey":"build_contract_project","submissionHash":"86a212cc68ade9217646b8862e8a0dc7d4d8d17a0381df6b8e99ab3601993c77","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"98715df6e230779d6707e29c5cd1d63b625aab988a7d7deea1d08e66c88efc4e","state":"completed","submissions":[{"artifacts":[],"attempt":2,"bundleHash":"5f7558cb801e0028efe7f3ac1caedf1285c7da899ad79fb25ffd15cdf2066c49","device":"b5e3297a04468fd3","findings":[],"hash":"86a212cc68ade9217646b8862e8a0dc7d4d8d17a0381df6b8e99ab3601993c77","nodeId":"c8efc923-148b-4ee7-bc57-9a8991de8c0c","outcome":"completed","summary":"Work is complete and verified. Final state:\n\n**Deployment wiring**\n- `script/Rehearse.s.sol` now takes an explicit `qualifyingPriceWei`, deploys Router → VaultFactory → Sorphera → SorpheraPassport, performs both owner bindings, runs fail-closed checks, compares the Passport runtime code hash against a same-immutables reference deployment, and ends with sales disabled.\n- New `script/ReleaseChecks.sol` holds the readiness checks outside the lottery (Sorphera stays at 24,366 bytes, 210 bytes headroom). It reverts with named reasons on wrong chain, owner, dependency bindings, missing/misbound Passport, wrong price, a game frozen at another price, or enabled sales. Missing Passport blocks readiness while ordinary `buy` still works.\n- `script/SepoliaCanary.s.sol` and `tools/canary.py` deploy and bind the Passport and verify bindings before subscription work. The canary CLI's hard-coded 22-field `getRound` decoder was a reproduced defect (Round now has 24 fields); fixed and pinned to the exported ABI by a new tooling test, along with `tickets(...).reward` and `Cancelled.tickets`.\n\n**Manifests and artifacts**\n- `deployments/mainnet.launch.json` draft adds SorpheraPassport with the price explicitly null (unapproved input) plus post-deployment owner actions. `deployments/sepolia.launch.candidate.json` is the concrete candidate patch for protected `launch.json`, not applied. Config templates, schema, `tools/preflight.py`, and frontend deployment/configuration files include the Passport, its constructor inputs, bindings and Website follow-ups. ABIs and sizes regenerated from the final build.\n\n**Verification (fresh, this run)**\n\n| Check | Result |\n| --- | --- |\n| `forge build`, `forge fmt --check` (both profiles) | PASS |\n| `forge test` with the verifier seed | 108 passed, 0 failed (new `SorpheraReleaseTest` 5/5) |\n| Python tooling tests | 49 passed |\n| Mainnet fork suite, block 26,145,236 (hash matches pin) | 12/12 incl. new Passport test through the real FWA pool |\n| Sepolia fork constructor rehearsal, block 11,866,914 (hash matches pin) | 3/3 |\n\nFull table, commands, RPC notes and blockers are in `docs/RELEASE-REHEARSAL.md` and `docs/release-validation.json`.\n\n**Not run, recorded as outstanding:** live Sepolia canary (company signer, subscription, funds, authorization), the private IMD gate, the Rehearse script with production owner/price (unapproved inputs), and an independent audit. Publicnode's Sepolia endpoint prunes the pinned block; an archive endpoint is required. The permanent accepted-VRF nonfulfillment issue is left untouched and recorded separately.","treeHash":"35fdfea2b415a906054cf40d8655c959d0d7855a","usage":{"cachedInputTokens":4562528,"inputTokens":1058,"model":"claude-fable-5-1","outputTokens":66237,"runtime":"claude","turns":60,"wallClockMs":1533263}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fd5402086dce252e","findings":[],"hash":"cba9b4fe6eb9bd9a8012aedb9e88cea35e592bba3416b46375e43f05cd1b4144","nodeId":"c8efc923-148b-4ee7-bc57-9a8991de8c0c","outcome":"failed","summary":"the local build failed, so this was not submitted:\nforge build exited with 1:\nCompiling 46 files with Solc 0.8.26\nError: solc exited with signal: 9 (SIGKILL)\n<empty output>","treeHash":null,"usage":{"cachedInputTokens":5285628,"inputTokens":962,"model":"claude-fable-5-1","outputTokens":97273,"runtime":"claude","turns":87,"wallClockMs":2700275}}],"verification":[{"checks":[{"durationMs":207382,"exitCode":0,"name":"build","output":"Compiling 47 files with Solc 0.8.26\nSolc 0.8.26 finished in 207.15s\nCompiler run successful with warnings:\nWarning (8760): This declaration has the same name as another declaration.\n   --> src/SorpheraPassport.sol:155:13:\n    |\n155 |             uint256 stamps,\n    |             ^^^^^^^^^^^^^^\nNote: The other declaration is here:\n   --> src/SorpheraPassport.sol:177:5:\n    |\n177 |     function stamps(address wallet) external view returns (uint256) {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2519): This declaration shadows an existing declaration.\n   --> test/helpers/SorpheraFixture.sol:104:9:\n    |\n104 |         uint256 rewards,\n    |         ^^^^^^^^^^^^^^^\nNote: The shadowed declaration is here:\n  --> test/helpers/SorpheraFixture.sol:29:5:\n   |\n29 |     MockRewards internal rewards;\n   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nWarning (2519): This declaration shadows an existing declaration.\n  --> test/SorpheraPassport.t.sol:66:33:\n   |\n66 |     function _earn(address who, uint256 n) internal returns (uint256 id) {\n   |                                 ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/SorpheraPassport.t.sol:484:5:\n    |\n484 |     uint256 internal n; // the cancelled NFT round\n    |     ^^^^^^^^^^^^^^^^^^\n\nWarning (2519): This declaration shadows an existing declaration.\n   --> test/SorpheraPassport.t.sol:150:10:\n    |\n150 |         (uint256 n, SorpheraVault v) = _openNFT();\n    |          ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/SorpheraPassport.t.sol:484:5:\n    |\n484 |     uint256 internal n; // the cancelled NFT round\n    |     ^^^^^^^^^^^^^^^^^^\n\nWarning (2519): This declaration shadows an existing declaration.\n   --> test/SorpheraPassport.t.sol:169:10:\n    |\n169 |         (uint256 n, SorpheraVault v) = _openNFT();\n    |          ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/SorpheraPassport.t.sol:484:5:\n    |\n484 |     uint256 internal n; // the cancelled NFT round\n    |     ^^^^^^^^^^^^^^^^^^\n\nWarning (2519): This declaration shadows an existing declaration.\n   --> test/SorpheraPassport.t.sol:189:46:\n    |\n189 |     function _repeat(Sorphera.Pick memory p, uint256 n) internal pure returns (Sorphera.Pick[] memory picks) {\n    |                                              ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/SorpheraPassport.t.sol:484:5:\n    |\n484 |     uint256 internal n; // the cancelled NFT round\n    |     ^^^^^^^^^^^^^^^^^^\n\nWarning (2519): This declaration shadows an existing declaration.\n   --> test/SorpheraPassport.t.sol:460:10:\n    |\n460 |         (uint256 n, SorpheraVault v) = _openNFT();\n    |          ^^^^^^^^^\nNote: The shadowed declaration is here:\n   --> test/SorpheraPassport.t.sol:484:5:\n    |\n484 |     uint256 internal n; // the cancelled NFT round\n    |     ^^^^^^^^^^^^^^^^^^\n\n","passed":true},{"durationMs":20299,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 5 tests for test/SorpheraRelease.t.sol:SorpheraReleaseTest\n[PASS] testChecksFailClosedOnWrongInputsMisbindingAndRepeatedBinding() (gas: 1925734)\n[PASS] testLifecycleDirectBuyPassportEntryRewardRedemptionAndCancellationRestore() (gas: 12019601)\n[PASS] testMissingPassportBlocksReadinessWhileOrdinaryBuyWorks() (gas: 5022305)\n[PASS] testRehearsalDeploysBindsPassportAndEndsWithSalesDisabled() (gas: 2291208)\n[PASS] testRehearsalRejectsWrongChainOwnerPriceAndCoordinator() (gas: 4109533)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 209.53ms (35.43ms CPU time)\n\nRan 8 tests for test/SorpheraReviewRegression.t.sol:SorpheraReviewRegressionTest\n[PASS] testFrozenReserveRejectsRequestBeforeAcceptanceThenTopupAllowsSameRound() (gas: 5262030)\n[PASS] testHostileOwnerOfCannotExhaustCancellationSweepGas() (gas: 5186683)\n[PASS] testInsufficientCallbackGasIsBilledAndCannotReplaceAcceptedDraw() (gas: 4374598)\n[PASS] testLargePendingCancellationReviewCommitsBoundedProgress() (gas: 21198769)\n[PASS] testPermanentTieNonfulfillmentLocksUntilOriginalDelayedCallback() (gas: 6627071)\n[PASS] testPredeadlineCustodyInLastCancellationBatchPreservesDraw() (gas: 24103543)\n[PASS] testReservePermissionsCurrencyAndConsumerRecheckedBeforeRequest() (gas: 4446862)\n[PASS] testUnreconciledPredeadlineCustodyCannotBeFrontRunByCancellation() (gas: 5540005)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 324.93ms (28.76ms CPU time)\n\nRan 6 tests for test/SorpheraHardening.t.sol:SorpheraHardeningTest\n[PASS] testChangedChainStopsSalesAndRequests() (gas: 3961458)\n[PASS] testChangedHelperPermissionsStopNewRiskButPreserveCashClaims() (gas: 5104556)\n[PASS] testConstructorDiagnosticsEmptyChainAndUnresolvedDependencies() (gas: 6162)\n[PASS] testIndependentTieBreakLocksPrizesFeesAndNextRound() (gas: 6981909)\n[PASS] testProductionRejectsSimulationAndIncorrectGasLane() (gas: 150346)\n[PASS] testUnavailableInventoryDoesNotConsumeBudget() (gas: 5189775)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 461.48ms (9.86ms CPU time)\n\nRan 27 tests for test/SorpheraPassport.t.sol:SorpheraPassportTest\n[PASS] testCancellationDividesRecoveryAmongPaidEntriesOnly() (gas: 14298204)\n[PASS] testCancelledRewardIsRestoredExactlyOnceWithoutStamps() (gas: 21566922)\n[PASS] testCancelledRoundEarnsNothing() (gas: 4729069)\n[PASS] testContractWalletCannotOverspendThroughNestedRedemption() (gas: 10190838)\n[PASS] testFinalizationAlongsideRedemptionInOneTransaction() (gas: 9017906)\n[PASS] testFreeOnlyRedemptionCreatesOwnedZeroPriceTickets() (gas: 9901310)\n[PASS] testFuzzBatchAndOrderEquivalence(uint8,uint8,uint8,uint8) (runs: 256, μ: 14954280, ~: 15023680)\nLogs:\n  Bound result 0\n  Bound result 2\n  Bound result 1\n\n[PASS] testLosingAndWinningRewardEntriesAreNotRestored() (gas: 14284784)\n[PASS] testMixedBatchChargesOnlyPaidEntries() (gas: 9421161)\n[PASS] testMixedGamesShareOneCounter() (gas: 14415998)\n[PASS] testOnlyThePassportCanIssueRewardEntries() (gas: 3523147)\n[PASS] testOtherPriceRoundsEarnNothingAndRefuseRewards() (gas: 15323747)\n[PASS] testPendingUntilOwnRoundIsWonOrRolled() (gas: 5673249)\n[PASS] testProcessingCreditsOnlyTheNamedWalletFromItsOwnEntries() (gas: 5455297)\n[PASS] testProcessingGasDoesNotGrowWithHistory() (gas: 32352221)\n[PASS] testRedemptionFailuresPreserveCredit() (gas: 11063134)\n[PASS] testRewardAndPaidWinnersShareETHEqually() (gas: 11308139)\n[PASS] testRewardOnlyCancelledRoundHasNoDivisionByZeroAndCarriesRecoveries() (gas: 16530047)\n[PASS] testRewardOnlyRoundStillDrawsAndRolls() (gas: 9923067)\n[PASS] testRewardTicketCanWinNFTTieBreakAndClaim() (gas: 15703090)\n[PASS] testRewardTicketHasNoTokenOrNFTRecoveryRights() (gas: 14926836)\n[PASS] testRewardsCannotBeInflatedByRepeatedProcessingOrSelfCalls() (gas: 9374627)\n[PASS] testThresholdsAndRemainders() (gas: 19604006)\n[PASS] testUnboundLotteryRefusesRewardEntriesUntilConfigured() (gas: 5600770)\n[PASS] testUnknownGameOrRoundIsIgnored() (gas: 173745)\n[PASS] testWalletSplittingCannotIncreaseRewards() (gas: 5670194)\n[PASS] testWonRoundCreditsStampsOnce() (gas: 5370891)\nSuite result: ok. 27 passed; 0 failed; 0 skipped; finished in 461.64ms (532.81ms CPU time)\n\nRan 40 tests for test/Sorphera.t.sol:SorpheraTest\n[PASS] testApplicationSizeAndNoEscapeOpcodes() (gas: 18758562)\n[PASS] testBlackoutSlippageBudgetDeadlineAndFailedAcquireRollback() (gas: 4313410)\n[PASS] testBuilderAttributionOverpaymentAndPurchaserRewardsSeparated() (gas: 6209830)\n[PASS] testCallbackAuthenticationBindingDuplicateNoRerollOrCancellation() (gas: 4664381)\n[PASS] testCallbacksOutOfOrderAreBoundToSeparateGamesAndZeroWordValid() (gas: 10411891)\nLogs:\n  tie-break finalize gas: 224262\n\n[PASS] testCustodyBeforeDeadlineCountsEvenWhenReconciledAfter() (gas: 6361078)\nLogs:\n  tie-break finalize gas: 224262\n\n[PASS] testDelayedCashoutNFTGameRemainsIncidentalETHAndCancels() (gas: 4995724)\n[PASS] testETHForcedNFTCustodyIsReservedForWinners() (gas: 6026534)\n[PASS] testETHOneMatchFullPrizeAndOperatorReserve() (gas: 6055569)\n[PASS] testETHRolloverOldTicketsExpireCarryNeverSpent() (gas: 9525131)\n[PASS] testExpiredAcquisitionBlocksDrawUntilReconciled() (gas: 5457545)\n[PASS] testFactoryOnlyRegisteredLotteryCreatesVaults() (gas: 3564731)\n[PASS] testFixedETHSettlementEvenAfterExclusiveWindow() (gas: 4604870)\n[PASS] testForcedDeliveryAfterDeadlineStillCancels() (gas: 5305526)\n[PASS] testFuzzConservationAfterFWAChargesCashoutAndLateFunds(uint8,uint64) (runs: 256, μ: 6929259, ~: 6566335)\nLogs:\n  Bound result 6\n\n[PASS] testFuzzConservationUnusedBudget(uint8,uint64) (runs: 256, μ: 6886776, ~: 5926895)\nLogs:\n  Bound result 1\n\n[PASS] testFuzzSamplingRangeDistinctAndReplay(uint256) (runs: 256, μ: 33452, ~: 33403)\n[PASS] testLargeSalesConstantFinalizationAndPartialLargeInventory() (gas: 188655233)\nLogs:\n  draw finalize gas, 2000 tickets / 104 NFTs: 138860\n  tie-break finalize gas: 224262\n\n[PASS] testLateAllocationAfterCancellationSettlesToDivisibleETHRefund() (gas: 5490498)\n[PASS] testLateETHRecoveryGoesToOriginalWinnerNotNextRound() (gas: 8387603)\n[PASS] testLateNFTDoesNotRescueCancelledRoundAndSharedRecovery() (gas: 5741901)\n[PASS] testMultipleETHMatchesDuplicatesAndRounding() (gas: 5117369)\n[PASS] testNFTCancellationFeesPartialRefundAndLateRecovery() (gas: 5495758)\n[PASS] testNFTFeeReserveCannotBeWithdrawnUntilSuccess() (gas: 6208600)\nLogs:\n  tie-break finalize gas: 224262\n\n[PASS] testNFTOneWinnerAllAssetsAndFunds() (gas: 8087674)\n[PASS] testNFTRolloverInventoryAndResidualCannotRespin() (gas: 10378000)\n[PASS] testNFTTieBreakIncludesEveryDuplicateAndIsDomainSeparated() (gas: 7222931)\n[PASS] testNFTTransferFailuresAreIsolatedAndRetryable() (gas: 7590118)\n[PASS] testNoLateEntryAndBoundedTickets() (gas: 3642884)\n[PASS] testPermanentlyStuckNFTNeverFreezesETHGameAndLateRecoveryFollowsWinner() (gas: 9823764)\n[PASS] testRejectedETHAndReentrancyRetainLiabilities() (gas: 5045598)\n[PASS] testRewardHelperFailureRollsBackAllowanceAndClaims() (gas: 5125955)\n[PASS] testStartsDisabledUnconfiguredAndOwnerSettings() (gas: 6172885)\n[PASS] testStuckNFTCustodyRequiredAndRecoveryAfterWindow() (gas: 6902807)\n[PASS] testStuckOnlyNFTCancelsRoundAndLateRecoveryIsSharedByRefundCohort() (gas: 9069255)\n[PASS] testUnclaimedWinningsStayReservedAcrossNewRoundAndWithdrawals() (gas: 9583455)\n[PASS] testUnorderedNumbersIndexedNoTicketTransfer() (gas: 4176416)\n[PASS] testUnwithdrawnFWARefundPreventsDraw() (gas: 4840414)\n[PASS] testWeeklyGamesIndependentFreezeAndPauseClaims() (gas: 8752238)\n[PASS] testZeroTicketsSkipRandomnessAndSeparateGameDoesNotBlock() (gas: 10156301)\nSuite result: ok. 40 passed; 0 failed; 0 skipped; finished in 461.73ms (1.08s CPU time)\n\nRan 17 tests for test/SorpheraAdversarial.t.sol:SorpheraAdversarialTest\n[PASS] testBadCallbackShapeUnknownRequestAndFutureRulesCannotMutateActiveRound() (gas: 8055888)\n[PASS] testCancellationAccumulatesSubTicketLateRecoveriesWithoutFees() (gas: 4837724)\n[PASS] testDuplicateClaimIdsNeverMultiplyPayoutAndMixedOwnerBatchRollsBack() (gas: 5075052)\n[PASS] testEmptyAndOversizedMaintenanceAndClaimBatchesReject() (gas: 3869975)\n[PASS] testEmptyAndUnderpaidAndOverpaidSalesAreAtomic() (gas: 3605994)\n[PASS] testEveryCombinationHasUniqueKeyAndAllSixOrdersMatch() (gas: 356135009)\n[PASS] testForgedReceiptStampCannotRescueLateDeliveryAndDeadlineBoundaryIsStrict() (gas: 5737200)\n[PASS] testFuzzPriceEdgesKeepExactSplitAndFullBatchRefund(uint256,uint8) (runs: 1000, μ: 6314871, ~: 5339639)\nLogs:\n  Bound result 16599\n  Bound result 92\n\n[PASS] testFuzzReceiptTimeNotReconcileTimeDecidesCancellation(uint256,bool) (runs: 512, μ: 5450313, ~: 5487086)\nLogs:\n  Bound result 1719234\n\n[PASS] testInvalidTicketAtEndRollsBackEntireBatchAndBothAccounts() (gas: 8811512)\n[PASS] testMaximumTicketPriceFullBatchRefundsAllUnspentFunds() (gas: 12089766)\nLogs:\n  Bound result 10000000000000000000\n  Bound result 100\n\n[PASS] testMinimumTicketPriceSingleEntryRefundsAllUnspentFunds() (gas: 4233456)\nLogs:\n  Bound result 1\n  Bound result 1\n\n[PASS] testNFTReceiverCannotReenterClaimAnotherAsset() (gas: 7281265)\n[PASS] testPauseBlocksSaleButPreservesPermissionlessSettlement() (gas: 6530984)\n[PASS] testSecondLotteryCannotValidateAgainstBoundFactoryOrCreateVaults() (gas: 9250774)\n[PASS] testStuckAssetRecoveredIntoRolledRoundJoinsCarryoverForNextWinnerOnly() (gas: 11863070)\n[PASS] testVaultPrivilegeAndCrossRoundRequestBoundaries() (gas: 7823251)\nSuite result: ok. 17 passed; 0 failed; 0 skipped; finished in 562.35ms (1.19s CPU time)\n\nRan 2 tests for test/SepoliaCanary.t.sol:SepoliaCanaryTest\n[PASS] testControlledDependenciesAndNoPublicSalesWindow() (gas: 4146881)\n[PASS] testFullCoverageTwoGamesDelayedDrawAndIndependentTieClaims() (gas: 10760653)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.17s (1.15s CPU time)\n\nRan 1 test for test/SorpheraPassportInvariant.t.sol:SorpheraPassportInvariantTest\n[PASS]\nSorpheraPassportInvariantTest invariants:\n[PASS] invariant_passportCreditIsBoundedByFinalizedPaidTickets\n[PASS] invariant_rewardEntriesCreateNoLiabilityAndFundsConserve\n SorpheraPassportInvariantTest invariants (runs: 64, calls: 2560, reverts: 63)\n\n╭-----------------+----------+-------+---------+----------╮\n| Contract        | Selector | Calls | Reverts | Discards |\n+=========================================================+\n| PassportHandler | buy      | 651   | 63      | 0        |\n|-----------------+----------+-------+---------+----------|\n| PassportHandler | finish   | 665   | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| PassportHandler | process  | 620   | 0       | 0        |\n|-----------------+----------+-------+---------+----------|\n| PassportHandler | redeem   | 624   | 0       | 0        |\n╰-----------------+----------+-------+---------+----------╯\n\nLogs:\n  Bound result 1\n  Bound result 1\n  Bound result 5\n  Bound result 1\n  Bound result 9\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 8\n  Bound result 0\n  Bound result 0\n  Bound result 11\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 2\n  Bound result 3\n  Bound result 0\n  Bound result 0\n  Bound result 6\n  Bound result 1\n  Bound result 1\n  Bound result 3\n  Bound result 3\n  Bound result 1\n  Bound result 1\n  Bound result 11\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 13\n  Bound result 1\n  Bound result 2\n  Bound result 1\n  Bound result 3\n  Bound result 1\n  Bound result 7\n  Bound result 0\n  Bound result 1\n  Bound result 14\n  Bound result 7\n  Bound result 10\n  Bound result 9\n  Bound result 1\n  Bound result 1\n  Bound result 3\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.14s (2.11s CPU time)\n\nRan 2 tests for test/SorpheraInvariant.t.sol:SorpheraInvariantTest\n[PASS]\nSorpheraInvariantTest invariants:\n[PASS] invariant_externalFlowsConserveETH\n[PASS] invariant_gameAssetsNeverCrossSubsidize\n[PASS] invariant_liabilitiesEqualReservedFeesCashAndUnpaidTickets\n[PASS] invariant_purchaserAndBuilderTokensStayConserved\n[PASS] invariant_roundOutcomesFollowFixedRules\n[PASS] invariant_vaultRequestsAndCustodyRemainBacked\n SorpheraInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭-----------------+-----------------+-------+---------+----------╮\n| Contract        | Selector        | Calls | Reverts | Discards |\n+================================================================+\n| SorpheraHandler | acquire         | 976   | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | advance         | 1049  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | builderReward   | 1031  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | buy             | 2053  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | claim           | 1044  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | claimNFT        | 997   | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | forceSettlement | 1047  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | pause           | 1020  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | queueTokens     | 1029  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | receiveTokens   | 999   | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | recoverStuck    | 986   | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | resolve         | 1051  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | rewardEpoch     | 1013  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | syncOrDonate    | 1066  | 0       | 0        |\n|-----------------+-----------------+-------+---------+----------|\n| SorpheraHandler | withdraw        | 1023  | 0       | 0        |\n╰-----------------+-----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 8\n  Bound result 0\n  Bound result 1\n  Bound result 4\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 20000000000000000\n  Bound result 2\n  Bound result 20000000000000000\n  Bound result 3\n  Bound result 2\n  Bound result 0\n  Bound result 1\n  Bound result 103\n  Bound result 1\n  Bound result 1\n  Bound result 101\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 3\n  Bound result 3\n  Bound result 1\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 9\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1459\n  Bound result 2\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 5700\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 0\n  Bound result 1\n  Bound result 20000000000000000\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 2\n  Bound result 3\n  Bound result 3\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 12392619650145354316\n  Bound result 0\n  Bound result 1\n\n[PASS] testHandlerPinnedLifecycleExercisesClaimsAndLateRecoveries() (gas: 15801613)\nLogs:\n  Bound result 0\n  Bound result 8\n  Bound result 0\n  Bound result 1\n  Bound result 4\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 20000000000000000\n  Bound result 2\n  Bound result 20000000000000000\n  Bound result 3\n  Bound result 2\n  Bound result 0\n  Bound result 1\n  Bound result 103\n  Bound result 1\n  Bound result 1\n  Bound result 101\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 17\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 4000000000000000\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 0\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 8\n  Bound result 2\n  Bound result 1\n  Bound result 1\n  Bound result 4\n  Bound result 0\n  Bound result 1\n  Bound result 1\n  Bound result 1\n  Bound result 5\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 1\n  Bound result 1\n  Bound result 2\n  Bound result 1\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 20.07s (20.02s CPU time)\n\nRan 9 test suites in 20.08s (25.86s CPU time): 108 tests passed, 0 failed, 0 skipped (108 total tests)\n","passed":true},{"durationMs":329,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Sorphera.acceptOwner()\",\"Sorphera.buy(uint8,uint256,(uint8[3],uint8)[])\",\"Sorphera.claimETH(uint8,uint256,uint256[],address)\",\"Sorphera.close(uint8,uint256)\",\"Sorphera.configureRandomness((uint256,bytes32,uint16,uint32,bool))\",\"Sorphera.configureRules(uint8,(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256))\",\"Sorphera.configureVRFReserve(uint96,uint96)\",\"Sorphera.credit(uint8,uint256)\",\"Sorphera.enter(address,uint8,uint256,(uint8[3],uint8)[],uint256)\",\"Sorphera.finalize(uint8,uint256)\",\"Sorphera.finalizeTieBreak(uint8,uint256)\",\"Sorphera.openRound(uint8)\",\"Sorphera.proposeOwner(address)\",\"Sorphera.rawFulfillRandomWords(uint256,uint256[])\",\"Sorphera.recordNFT(uint8,uint256,uint256)\",\"Sorphera.requestDraw(uint8,uint256)\",\"Sorphera.requestTieBreak(uint8,uint256)\",\"Sorphera.setPassport(address)\",\"Sorphera.setSalesEnabled(bool)\",\"Sorphera.validateLaunch()\",\"Sorphera.withdrawOperator(address,uint256)\",\"SorpheraPassport.enter(uint8,uint256,(uint8[3],uint8)[],uint256,(uint8,uint256)[])\",\"SorpheraPassport.process(address,(uint8,uint256)[])\",\"SorpheraRouter.acceptOwner()\",\"SorpheraRouter.acquire(address,uint256,uint256,uint256,uint256,uint256)\",\"SorpheraRouter.claimBuilderRewards(address,address,uint256,uint256)\",\"SorpheraRouter.configure(address,address)\",\"SorpheraRouter.proposeOwner(address)\",\"SorpheraRouter.receive()\",\"SorpheraRouter.recoverBuilderAllowance(address,address)\",\"SorpheraVault.acquire(uint256,uint256)\",\"SorpheraVault.claimEpochRewards(uint256[])\",\"SorpheraVault.claimNFTs(uint256,uint256[],address)\",\"SorpheraVault.claimTokens(uint256,address,uint256)\",\"SorpheraVault.deliver(uint256,address)\",\"SorpheraVault.fund()\",\"SorpheraVault.onERC721Received(address,address,uint256,bytes)\",\"SorpheraVault.process(uint256)\",\"SorpheraVault.receive()\",\"SorpheraVault.reconcile(uint256[])\",\"SorpheraVault.recoverNFT(uint256)\",\"SorpheraVault.recoverRefund()\",\"SorpheraVault.reviewCancellation(uint256)\",\"SorpheraVault.settle(uint256)\",\"SorpheraVault.syncETH()\",\"SorpheraVaultFactory.acceptOwner()\",\"SorpheraVaultFactory.create(uint8,uint256,(uint256,uint256,uint256,uint256,uint256))\",\"SorpheraVaultFactory.proposeOwner(address)\",\"SorpheraVaultFactory.setLottery(address)\"],\"files\":{\".gitignore\":3,\"DESIGN.md\":83,\"README.md\":117,\"deployments/canary.example.json\":26,\"deployments/canary.schema.json\":32,\"deployments/config.schema.json\":185,\"deployments/fork.json\":15,\"deployments/mainnet.json\":30,\"deployments/mainnet.launch.json\":47,\"deployments/sepolia.json\":30,\"deployments/sepolia.launch.candidate.json\":46,\"dist/assets/Chamber-m37PT9hZ.js\":1,\"dist/assets/DrawRoom-CGPqvfiq.js\":2,\"dist/assets/LiveWorkspace-DrRPS7p5.js\":46,\"dist/assets/ccip-C3htbo9-.js\":1,\"dist/assets/index-Bn_J9Yml.js\":73,\"dist/assets/index-DyvbRqjF.css\":1,\"dist/brand/eth-ball.webp\":31,\"dist/brand/hero-world.webp\":399,\"dist/brand/nft-ball.webp\":34,\"dist/brand/plush/albedo.webp\":734,\"dist/brand/plush/surface.webp\":472,\"dist/brand/sorphera-banner-ice-blue.webp\":379,\"dist/brand/sorphera-brand-board-ice-blue.webp\":380,\"dist/brand/sorphera-globe-icon-ice-blue.webp\":18,\"dist/brand/sorphera-wordmark-ice-blue.webp\":226,\"dist/index.html\":31,\"docs/CANARY.md\":123,\"docs/CONTINUATION.md\":47,\"docs/DEPENDENCIES.md\":46,\"docs/DEPLOYMENT.md\":38,\"docs/IMD-SUPPORT-DRAFT.md\":7,\"docs/KEEPER.md\":72,\"docs/MAINNET.md\":46,\"docs/OPERATIONS.md\":60,\"docs/PASSPORT-HANDOFF.md\":96,\"docs/REHEARSAL.md\":43,\"docs/RELEASE-REHEARSAL.md\":165,\"docs/REVIEW-CONTINUATION.md\":79,\"docs/TESTING.md\":70,\"docs/TOOLING-REVIEW.md\":36,\"docs/continuation-validation.json\":174,\"docs/evidence/baseline.txt\":125,\"docs/evidence/build.txt\":834,\"docs/evidence/commands.json\":49,\"docs/evidence/compiler-settings.json\":8,\"docs/evidence/constructor-empty.txt\":31,\"docs/evidence/continuation/build.log\":858,\"docs/evidence/continuation/canary-dry-run.json\":30,\"docs/evidence/continuation/empty-constructor.log\":9,\"docs/evidence/continuation/forge-tests.log\":154,\"docs/evidence/continuation/keeper-fork-simulation.json\":2408,\"docs/evidence/continuation/keeper-fork-simulation.log\":83,\"docs/evidence/continuation/mainnet-fork.log\":22,\"docs/evidence/continuation/runtime-simulation.json\":17,\"docs/evidence/continuation/sepolia-fork.log\":14,\"docs/evidence/continuation/source-content.json\":97,\"docs/evidence/continuation/tooling-tests.log\":52,\"docs/evidence/fmt-check.txt\":0,\"docs/evidence/gas-scaling.txt\":252,\"docs/evidence/imd-launch-961.json\":168,\"docs/evidence/imd-launch-capabilities.json\":144,\"docs/evidence/integration-fmt-check.txt\":0,\"docs/evidence/mainnet-builder-trace.txt\":853,\"docs/evidence/mainnet-fork.txt\":22,\"docs/evidence/offline-tests.txt\":134,\"docs/evidence/sepolia-fork-and-constructor.txt\":121,\"docs/reference/FWAV2.sepolia.abi.json\":1,\"docs/reference/FWAV2Rewards.sepolia.abi.json\":1,\"docs/reference/mainnet/buyback.runtime.hex\":1,\"docs/reference/mainnet/coordinator.abi.json\":1750,\"docs/reference/mainnet/coordinator.runtime.hex\":1,\"docs/reference/mainnet/floorOracle.abi.json\":1439,\"docs/reference/mainnet/floorOracle.runtime.hex\":1,\"docs/reference/mainnet/helper.abi.json\":591,\"docs/reference/mainnet/helper.runtime.hex\":1,\"docs/reference/mainnet/hook.abi.json\":1352,\"docs/reference/mainnet/hook.runtime.hex\":1,\"docs/reference/mainnet/notifier.runtime.hex\":1,\"docs/reference/mainnet/permit2.abi.json\":901,\"docs/reference/mainnet/permit2.runtime.hex\":1,\"docs/reference/mainnet/pool.abi.json\":2979,\"docs/reference/mainnet/pool.runtime.hex\":1,\"docs/reference/mainnet/poolManager.abi.json\":1366,\"docs/reference/mainnet/poolManager.runtime.hex\":1,\"docs/reference/mainnet/rewards.abi.json\":1623,\"docs/reference/mainnet/rewards.runtime.hex\":1,\"docs/reference/mainnet/service.runtime.hex\":1,\"docs/reference/mainnet/snapshot.json\":956,\"docs/reference/mainnet/source-bindings.json\":29,\"docs/reference/mainnet/token.abi.json\":1214,\"docs/reference/mainnet/token.runtime.hex\":1,\"docs/reference/sepolia-readback.json\":46,\"docs/reference/verification.json\":21,\"docs/release-validation.json\":83,\"docs/validation.json\":91,\"foundry.toml\":20,\"frontend/README.md\":13,\"frontend/abi/Sorphera.json\":2330,\"frontend/abi/SorpheraPassport.json\":460,\"frontend/abi/SorpheraRouter.json\":468,\"frontend/abi/SorpheraVault.json\":1071,\"frontend/abi/SorpheraVaultFactory.json\":245,\"frontend/bytecode-sizes.json\":22,\"frontend/configuration.json\":88,\"frontend/deployment.json\":47,\"integration/Sepolia.t.sol\":42,\"integration/mainnet/Mainnet.t.sol\":504,\"integration/rehearsal/Constructor.t.sol\":61,\"launch.json\":9,\"ops/keeper.example.json\":27,\"ops/keeper.schema.json\":33,\"ops/sorphera-keeper.service\":33,\"script/CanaryDependencies.sol\":266,\"script/Operations.s.sol\":149,\"script/Rehearse.s.sol\":85,\"script/ReleaseChecks.sol\":99,\"script/SepoliaCanary.s.sol\":56,\"src/Sorphera.sol\":719,\"src/SorpheraPassport.sol\":198,\"src/SorpheraRouter.sol\":136,\"src/SorpheraVault.sol\":325,\"src/SorpheraVaultFactory.sol\":39,\"src/interfaces/External.sol\":126,\"src/lib/Balls.sol\":46,\"src/lib/Networks.sol\":23,\"src/lib/RewardTransfer.sol\":54,\"src/lib/Security.sol\":47,\"test/README.md\":7,\"test/SepoliaCanary.t.sol\":186,\"test/Sorphera.t.sol\":988,\"test/SorpheraAdversarial.t.sol\":458,\"test/SorpheraHardening.t.sol\":150,\"test/SorpheraInvariant.t.sol\":666,\"test/SorpheraPassport.t.sol\":729,\"test/SorpheraPassportInvariant.t.sol\":238,\"test/SorpheraRelease.t.sol\":378,\"test/SorpheraReviewRegression.t.sol\":259,\"test/helpers/SimulatedSorphera.sol\":14,\"test/helpers/SorpheraFixture.sol\":159,\"test/mocks/ExternalMocks.sol\":416,\"tools/canary.py\":443,\"tools/contracts.py\":50,\"tools/export.py\":19,\"tools/keeper.py\":302,\"tools/keeper_smoke.py\":230,\"tools/preflight.py\":70,\"tools/read-only-rpc.py\":36,\"tools/runtime.py\":366,\"tools/snapshot-mainnet.py\":65,\"tools/source_manifest.py\":32,\"tools/test_canary.py\":280,\"tools/test_keeper.py\":302,\"tools/test_runtime.py\":394,\"web/README.md\":82,\"web/THIRD_PARTY_NOTICES.md\":20,\"web/artwork/README.md\":56,\"web/artwork/plush-source.webp\":1783,\"web/evidence/asset-manifest.json\":62,\"web/evidence/build.txt\":18,\"web/evidence/bundle-report.json\":14,\"web/evidence/claim-mobile.jpg\":97,\"web/evidence/continuity/build.txt\":17,\"web/evidence/continuity/checkout-cutoff.jpg\":86,\"web/evidence/continuity/design-probe-dejavu.json\":116,\"web/evidence/continuity/design-probe.json\":5522,\"web/evidence/continuity/draw-390.jpg\":703,\"web/evidence/continuity/draw-mobile-reduced-after.jpg\":78,\"web/evidence/continuity/globe-away.jpg\":135,\"web/evidence/continuity/globe-bonus-stop.jpg\":136,\"web/evidence/continuity/globe-landed.jpg\":135,\"web/evidence/continuity/globe-mid-turn.jpg\":140,\"web/evidence/continuity/globe-stopped.jpg\":116,\"web/evidence/continuity/home-390-arial.jpg\":297,\"web/evidence/continuity/home-390.jpg\":306,\"web/evidence/continuity/index.html\":48,\"web/evidence/continuity/material-hashes.json\":8,\"web/evidence/continuity/motion-summary.json\":164,\"web/evidence/continuity/offline-export-results.json\":15,\"web/evidence/continuity/packaging.json\":36,\"web/evidence/continuity/paused-checkout-results.json\":8,\"web/evidence/continuity/play-320-eth.jpg\":226,\"web/evidence/continuity/play-320-nft.jpg\":211,\"web/evidence/continuity/play-schedule-390.jpg\":132,\"web/evidence/continuity/plush-comparison.jpg\":438,\"web/evidence/continuity/plush-fallback-comparison.jpg\":414,\"web/evidence/continuity/plush-fallback-full-turn.jpg\":744,\"web/evidence/continuity/plush-fallback-poles.jpg\":355,\"web/evidence/continuity/plush-full-turn.jpg\":824,\"web/evidence/continuity/plush-poles-before.jpg\":347,\"web/evidence/continuity/plush-poles.jpg\":349,\"web/evidence/continuity/plush-results.json\":252,\"web/evidence/continuity/reveal-canvas-results.json\":11,\"web/evidence/continuity/reveal-canvas.mp4\":1173,\"web/evidence/continuity/reveal-webgl-results.json\":11,\"web/evidence/continuity/reveal-webgl.mp4\":1175,\"web/evidence/continuity/revision-reproduction.json\":152,\"web/evidence/continuity/revision-validation.md\":63,\"web/evidence/continuity/schedule-chromium-results.json\":15,\"web/evidence/continuity/schedule-unit-tests.txt\":82,\"web/evidence/continuity/sorphera-nft-42-draw-window.ics\":13,\"web/evidence/continuity/sorphera-nft-42-sales-closing.ics\":13,\"web/evidence/continuity/tickets-390.jpg\":360,\"web/evidence/continuity/typecheck.txt\":3,\"web/evidence/continuity/unit-tests.txt\":290,\"web/evidence/continuity/upcoming-desktop.jpg\":218,\"web/evidence/continuity/validation.md\":84,\"web/evidence/continuity/video-canvas-metadata.txt\":18,\"web/evidence/continuity/video-webgl-metadata.txt\":18,\"web/evidence/draw-finale-desktop.jpg\":596,\"web/evidence/draw-mobile-reduced.jpg\":764,\"web/evidence/iteration/browser-results.json\":14,\"web/evidence/iteration/budget-after.jpg\":134,\"web/evidence/iteration/budget-before.jpg\":134,\"web/evidence/iteration/build.txt\":17,\"web/evidence/iteration/bundle-report.json\":14,\"web/evidence/iteration/claim-after.jpg\":165,\"web/evidence/iteration/contrast.json\":20,\"web/evidence/iteration/draw-mobile-reduced-after.jpg\":81,\"web/evidence/iteration/globe-away.jpg\":133,\"web/evidence/iteration/globe-bonus-stop.jpg\":144,\"web/evidence/iteration/globe-landed.jpg\":148,\"web/evidence/iteration/globe-mid-turn.jpg\":134,\"web/evidence/iteration/globe-stopped.jpg\":129,\"web/evidence/iteration/home-after.jpg\":557,\"web/evidence/iteration/home-before.jpg\":699,\"web/evidence/iteration/index.html\":51,\"web/evidence/iteration/keyboard-focus.jpg\":247,\"web/evidence/iteration/motion-summary.json\":76,\"web/evidence/iteration/play-mobile-after.jpg\":452,\"web/evidence/iteration/publication.json\":12,\"web/evidence/iteration/reveal-normal.mp4\":1967,\"web/evidence/iteration/reveal-results.json\":11,\"web/evidence/iteration/review-after.jpg\":133,\"web/evidence/iteration/review-before.jpg\":139,\"web/evidence/iteration/tests.txt\":260,\"web/evidence/iteration/typecheck.txt\":4,\"web/evidence/iteration/validation.md\":70,\"web/evidence/iteration/video-probe.json\":19,\"web/evidence/iteration2/atlas-390.png\":356,\"web/evidence/iteration2/home-390.png\":994,\"web/evidence/iteration2/receipt-free-1440.png\":559,\"web/evidence/iteration2/validation.md\":46,\"web/evidence/play-desktop.jpg\":146,\"web/evidence/play-mobile.jpg\":1220,\"web/evidence/receipt-desktop.jpg\":280,\"web/evidence/reveal-1-back-facing.jpg\":255,\"web/evidence/reveal-2-stopped-badge.jpg\":223,\"web/evidence/reveal-3-third-ball-hold.png\":753,\"web/evidence/revision/bonus-stop.jpg\":137,\"web/evidence/revision/browser-results.json\":14,\"web/evidence/revision/draw-stop.jpg\":151,\"web/evidence/revision/home-390.jpg\":278,\"web/evidence/revision/plush-comparison.jpg\":254,\"web/evidence/revision/plush-results.json\":37,\"web/evidence/revision/reveal-results.json\":11,\"web/evidence/revision/taste-summary.json\":116,\"web/evidence/revision/validation.md\":99,\"web/evidence/tests.txt\":52,\"web/evidence/typecheck.txt\":5,\"web/evidence/validation.md\":55,\"web/index.html\":30,\"web/licenses/better-interface.txt\":220,\"web/licenses/react-dom.txt\":21,\"web/licenses/react.txt\":21,\"web/licenses/viem.txt\":21,\"web/package-lock.json\":2150,\"web/package.json\":27,\"web/public/brand/eth-ball.webp\":31,\"web/public/brand/hero-world.webp\":399,\"web/public/brand/nft-ball.webp\":34,\"web/public/brand/plush/albedo.webp\":734,\"web/public/brand/plush/surface.webp\":472,\"web/public/brand/sorphera-banner-ice-blue.webp\":379,\"web/public/brand/sorphera-brand-board-ice-blue.webp\":380,\"web/public/brand/sorphera-globe-icon-ice-blue.webp\":18,\"web/public/brand/sorphera-wordmark-ice-blue.webp\":226,\"web/scripts/plush-materials.py\":145,\"web/src/App.tsx\":304,\"web/src/Chamber.tsx\":90,\"web/src/DrawRoom.tsx\":590,\"web/src/LiveWorkspace.tsx\":863,\"web/src/Passport.tsx\":131,\"web/src/Play.tsx\":1164,\"web/src/PlushGlobe.tsx\":66,\"web/src/RoundSchedule.tsx\":145,\"web/src/Sorphera.abi.ts\":1234,\"web/src/SorpheraRouter.abi.ts\":279,\"web/src/SorpheraVault.abi.ts\":647,\"web/src/SorpheraVaultFactory.abi.ts\":158,\"web/src/Tickets.tsx\":512,\"web/src/UpcomingDraw.tsx\":154,\"web/src/budget.ts\":263,\"web/src/components.tsx\":155,\"web/src/contract.ts\":612,\"web/src/core.test.ts\":873,\"web/src/core.ts\":308,\"web/src/demoStorage.ts\":64,\"web/src/deployment.json\":13,\"web/src/earth-land.json\":1,\"web/src/fixtures.ts\":332,\"web/src/helper.abi.ts\":45,\"web/src/indexer.ts\":119,\"web/src/main.tsx\":34,\"web/src/pages.tsx\":457,\"web/src/passport.ts\":280,\"web/src/plushModel.ts\":591,\"web/src/reveal.ts\":99,\"web/src/schedule.test.ts\":197,\"web/src/schedule.ts\":69,\"web/src/styles.css\":3213,\"web/tests/browser.mjs\":527,\"web/tests/paused-checkout.mjs\":217,\"web/tests/plush.mjs\":328,\"web/tests/reveal.mjs\":250,\"web/tests/schedule.mjs\":421,\"web/tsconfig.json\":17,\"web/vite.config.ts\":7},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"86a212cc68ade9217646b8862e8a0dc7d4d8d17a0381df6b8e99ab3601993c77","verifiedTreeHash":"35fdfea2b415a906054cf40d8655c959d0d7855a","verifierVersion":"0.1.0+67c588fa"}]}