{"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":"46232ab7-1448-4034-985f-5b89ed67d77b","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"f15cc523e8f8ec683b203f75e37a557954472fa7d91591f82ee18d86e7f4cef8","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"4fd350358737ef287cefdde4da5ad68e2d81a6eb127242da6b54642466439f0b","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"11e02841bafe7a7cb4222b75f1725ed8a62be64452cfae4e1b77a1343d5698b2","dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"b89279670f5a00f5d26286edee00c97dd158b997031350a01cafe6e0329ad227","skillId":"audit-judge","subagents":4,"tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"b89279670f5a00f5d26286edee00c97dd158b997031350a01cafe6e0329ad227","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"fc9afe74e3d70a7989e34feb7ab07c98adfdaa539311c3fec2aa8084652136f8","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"88a93d51471788608fbf11992e62c4b87c2676e24df726feb4469e759254bb7a","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"99105bf11d03b710153e313470e07239c1f063fbcc2eadfd03032723e4b1f094","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"15b04fc8f60521936b9e2b37c09a804685ec689fc98cd5b04510d986d3106a15","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"15b04fc8f60521936b9e2b37c09a804685ec689fc98cd5b04510d986d3106a15","skillId":"build-contract-project","state":"accepted"},{"acceptedSubmissionHash":"f94d1da2e3bd963854dd53f2182e9b95031fc4b1a9ed8567461c4302c932df7a","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"5b1292f5cd1612d0eb2d244c4ee2c4ddfb188377d4ee46ea41c2e46b64bf4303","dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"606842ccca0e7c5d3017a54684625438eab9b351eb51dcf0cf88c43d1ea41464","skillId":"write-foundry-tests","subagents":4,"tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"606842ccca0e7c5d3017a54684625438eab9b351eb51dcf0cf88c43d1ea41464","skillId":"write-foundry-tests","state":"accepted"}],"objective":"IMD revision job: HamsterRun — train from SqueekCore certified wheel work\nParent deploy: https://explorer.imd.fun/jobs/bc21659e-db7c-49fc-ad15-b3a0f75645ba\nRepo: https://github.com/identity-md-launches/launch-2865-hmr\nLive Sepolia (may redeploy or patch — prefer new suite if Care is fused into NFT):\n\nHamsterRunNFT 0x140128b9208ee5de9690cd96b3bb7bc601d5b4ec\nMatchQueue 0x98d449abfaeaa0d0ebd0cf073f19faae24d32308\nProduct correction: timed 6h self-clock training is wrong. Training gain must come from Squeekchain’s real hamster wheel work as certified on SqueekCore, not block.timestamp alone.\n\nKeep from v2 (unchanged intent)\nMax supply 9999; free mint 1/wallet; start stamina 10; uncapped stamina\nWeight Fit / Normal / Obese + body score; Hungry lockout (no burn)\nFeed every 72h; three ETH tiers 0.0001 / 0.0002 / 0.0003 with distinct train bps\nOn-chain random MatchQueue (bands, 10-block wait, etc.)\nNo SQK yield / insurance / airdrop claims\nChange: Care / training\nRemove\nFixed TRAIN_SECONDS (6h) clock as the source of stamina gain\nAny formula that settles train without reading Core\nAdd — SqueekCore-backed train window\nSepolia upstream (read-only): SqueekCore 0x74665dAecA35A2303e767E76a2FF1FB6F93e119f\n(Rounds = 600s from genesis; use CoreReader-style helper or bind Core immutably.)\n\nstartTraining(tokenId) (fed, Idle, owner):\n\nSnapshot startRound = currentRound() derived from Core genesis + 600s (do not invent a Core currentRound() if absent).\nBook a window of N consecutive rounds (default N = 6, same as v1 “one hour of wheel time”).\nStore trainStartRound, trainEndRound = startRound + N - 1 (or exclusive end — pin in DESIGN), lastFeed bps, tokenId lock.\nRevert if Hungry.\nsettleTraining(tokenId) (permissionless when ready):\n\nRequire Core settledThroughRound >= trainEndRound (certified frontier). If lagging, revert with clear error — never invent work for uncertified rounds.\nRead certified physical work (or block units — prefer sum of certified round work / delta cumulativeWork over the booked rounds; pin exact getter: roundPage / per-round records). Zero-work certified rounds count as 0, not “unknown”.\nStamina gain = f(certifiedWorkInWindow) × lastFeedBps / 10000, with diminishing-in-current-stamina optional but secondary; food tiers must stay strictly ordered.\nUpdate body score as today (food + train), then clear train lock.\nUI / README smoke: show Core frontier vs booked end round; banner when settle waits on certification lag.\n\nOptional CoreReader\nThin immutable adapter (like v1) is OK if it simplifies paging; do not reintroduce MatchBook challenge flow.\n\nOut of scope\nSQK minting, SqueekMining claims, burning HAM on hunger, mainnet, website (contracts + DESIGN/tests only unless asked).\n\nSuccess\nNew Sepolia deploy (or clearly versioned upgrade path) where: mint → feed → startTraining books Core rounds → after those rounds are certified on SqueekCore, settle yields stamina proportional to real certified wheel work × food tier; Hungry / zero-work / lag paths tested; MatchQueue still works. Addresses JSON + ABIs + DESIGN formulas pinned.\n\nToken name: hamsterrun\nToken symbol: HMR","parentJobId":null,"planHash":"6d4fac836b9b479bc907c301e7f32a4eb037f685c872bd4b402f2a83938001fb","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"46232ab7-1448-4034-985f-5b89ed67d77b","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-2874-hamsterrun"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52121","feedbackHash":"e92aadb67ac808ea0c68109ff3e7f49f041c8433c7a89b77312873dd94b08cfd","nodeKey":"audit_economics","submissionHash":"f15cc523e8f8ec683b203f75e37a557954472fa7d91591f82ee18d86e7f4cef8","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51027","feedbackHash":"119bfba87866fea22cf3f212e81233c222ebfa296f0261b7859aae1907a348e8","nodeKey":"audit_flow","submissionHash":"4fd350358737ef287cefdde4da5ad68e2d81a6eb127242da6b54642466439f0b","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"54155","feedbackHash":"663bf859bed483fee547817538eb05b0117698c1dfe3200ce2ad9dfedbfef5b5","nodeKey":"audit_judge","submissionHash":"11e02841bafe7a7cb4222b75f1725ed8a62be64452cfae4e1b77a1343d5698b2","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"55405","feedbackHash":"87586b801334a3b6fc9c3833d538db43abdb909f2575e196d0f443606154489d","nodeKey":"audit_judge","submissionHash":"8fe4b21821c3ec104e083f5f55f831638efcb1885d42b5c1a3075f025424d961","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52679","feedbackHash":"3e3a7bfc949f9fee10c117d1948a030b576c00c42543579ce4dbdd2f0acc5438","nodeKey":"audit_math","submissionHash":"fc9afe74e3d70a7989e34feb7ab07c98adfdaa539311c3fec2aa8084652136f8","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52192","feedbackHash":"a96ccc5de337d52ff5ac6e5e308a44b8b1bc2fe6ccd9bb208e2df87e4facbc80","nodeKey":"audit_permissions","submissionHash":"88a93d51471788608fbf11992e62c4b87c2676e24df726feb4469e759254bb7a","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"54236","feedbackHash":"af79ab6937b3faadfcacbc87758c7066039bb987baa657c43f98120b125982fb","nodeKey":"build_contract_project","submissionHash":"99105bf11d03b710153e313470e07239c1f063fbcc2eadfd03032723e4b1f094","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"53903","feedbackHash":"a66df3590659f7601e3c802934032de42320c864ff696f1da3ac46cb619cd924","nodeKey":"build_contract_project","submissionHash":"8d1ecded1456d1dd46945f9c58725f427e5075d689c2ef4f578029e23a347930","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52552","feedbackHash":"7b3bec812513bd485d71739205ab25b2ba5f3945bc769e59465a704d74b32508","nodeKey":"manifest","submissionHash":"f94d1da2e3bd963854dd53f2182e9b95031fc4b1a9ed8567461c4302c932df7a","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51380","feedbackHash":"404732652304f9a77a0fbe1ea80220781a2a94cf8ac3a320e6ca7de6d93f3ca4","nodeKey":"manifest","submissionHash":"e7547d20dce3c657233c4bd825cb256ea700f9e62215595bb4460793d0fdbcb5","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52669","feedbackHash":"6dfd48bebbd8df9af8b38f4c366b634caa254343da5b970b6b83a587c6c9497f","nodeKey":"write_foundry_tests","submissionHash":"0b26a086706c85456adb2436e2b85ee2814f41bb57828b28f243cfa8d49c2c8b","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"54233","feedbackHash":"a83ed703e50d7e1919d8431e480ccbd305f27fd782debbd43c376720b1e8ed09","nodeKey":"write_foundry_tests","submissionHash":"5b1292f5cd1612d0eb2d244c4ee2c4ddfb188377d4ee46ea41c2e46b64bf4303","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"cd6e19ef54916d2da7ca31bf3ddee8f0208bea50bb3f0a3adb5e5580209d7ad4","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"75afe6de725fac08429fba540982fa03b90052f54fe0f49426f5ecb2d2098057","device":"7cb215928f3c9473","findings":[{"description":"feed() requires Activity.Idle (_requireOwnerIdle, line 151), and startTraining locks the pet in Training until settleTraining, which can only succeed once SqueekCore.settledThroughRound >= trainEndRound. Certification lag has no upper bound. While it lasts, (a) the 72h food expires and _projectBody charges 5 per begun hungry day, which the owner cannot stop because feeding reverts Locked, and (b) lastTrainAt is only refreshed at a positive-work settle, so every day spent booked counts as an inactivity day at 5 per day. The only way out is cancelTraining, which gives up the booked certified work. Training is supposed to be the healthy action, but under lag it is strictly worse for body score than doing nothing. This is current, not hypothetical: on 2026-11-02 a read of Sepolia SqueekCore 0x74665dAecA35A2303e767E76a2FF1FB6F93e119f returned settledThroughRound = 1973 while the current round derived from genesis 1791847800 was 2951, about 6.8 days behind. The repository's snapshot at block 12047523 shows the same frontier, so a booking made today would wait at least that long. DESIGN.md says only that settlement after food expiry is allowed; it does not cover a lock that makes the owner unable to feed.","line":151,"path":"src/HamsterRunNFT.sol","reproduction":"Using test/helpers/GameTest setup (MockSqueekCore, genesis 1_799_994_000, now 1_800_000_000): alice mints, feeds tier 2 (body 62), startTraining (rounds 11..16). Warp +7 days with no certification. Expected: either the owner can keep the pet fed while it waits, or the waiting time does not count as hunger/inactivity damage, so a booked pet is not penalised for Core's lag. Actual: nft.feed{value:0.0003 ether}(id,2) reverts Locked(); hamster(id).bodyScore = 7 (Obese, -35 idle, -20 hunger) and isHungry = true. After core.certify(16, 5) and settleTraining, stamina = 30 and body = 23, still Obese and far below the 62 at booking. Scratch test: mint/feed(2) -> startTraining -> vm.warp(+7 days) -> expectRevert(Locked) on feed -> certify(end,5) -> settleTraining -> body 23.","severity":"medium","title":"A pet waiting on Core certification is locked in Training, cannot be fed, and takes unavoidable hunger and inactivity damage"}],"hash":"0b26a086706c85456adb2436e2b85ee2814f41bb57828b28f243cfa8d49c2c8b","nodeId":"ec1da5f7-5d18-4455-8b79-03a8b70e1c0a","outcome":"completed","summary":"I added one test file, `test/CertifiedWorkOracle.t.sol`, and reported one medium defect in `.imd-findings.json`. With the verifier's fuzz seed, `forge build` and the full `forge test` both pass: 14 suites, 209 tests, 0 failures. The existing suite was already thorough, so the new file targets what it lacked.\n\n**What the new tests add**\n- **An independent work ledger.** The existing invariant handler worked out expected gain by calling Core's `roundPage`, the same call the contract makes, so it partly repeated the code it tested. My tests keep their own record of work per round, fill in rounds at random (some with zero work), and add up the six booked rounds themselves. A fuzz test then checks that the gain equals that total × 2 × food bps / 10000. It covers any round and any moment within a round, all three food tiers, earlier rounds already certified, and certification continuing past the window.\n- **Invariant campaign** (64 runs × 64 calls, any unexpected revert fails it) over feed, start, certify, settle, cancel, time passing and withdraw across six pets:\n  - each pet's stamina is exactly what its certified work earned;\n  - no window is credited twice, and settling before certification never succeeds;\n  - fees paid equal the contract's balance plus withdrawals;\n  - a pet's training record, its Training lock and `trainingStatus` (ready vs. waiting) always agree.\n  \n  A fixed-sequence test confirms the campaign really reaches settles with work, settles blocked by certification lag, and cancels.\n- **Failure paths:**\n  - settling with the Core frontier one round short reverts with `CoreCertificationLag`; exactly at the end round it works;\n  - settling twice, or settling a cancelled booking, fails, even when work was certified;\n  - other users, including approved operators, can't start or cancel training;\n  - nonexistent token IDs revert;\n  - hunger blocks booking: a never-fed pet, and one second after food expires (at exactly the expiry it's still fed);\n  - training and queueing block each other, and feeding is blocked while training;\n  - stamina doesn't depend on who settles or how late.\n- **End to end:** mint → feed → train → certify → settle → race in MatchQueue, using the stamina that training earned.\n\n**Finding (medium): a pet waiting on certification can't be fed and gets damaged for it.**\nWhile a pet is in Training, `feed` reverts with `Locked` (`src/HamsterRunNFT.sol:151`), and the pet stays locked until Core certifies its booked rounds. That wait has no limit. Meanwhile:\n- its food runs out and it takes hunger damage;\n- every day counts as an inactive day, because the inactivity clock only resets when training settles with work.\n\nThe only way out is cancelling, which throws away the booked work.\n\nIn a reproduction with a 7-day wait, body score fell from 62 to 7 (Obese). After settling it was only back to 23.\n\nThis is happening now. I read the live Sepolia SqueekCore today: it has certified through round 1973, but the current round is 2951, so it is about 6.8 days behind. The repo's earlier snapshot shows the same 1973, so a pet booked today would wait at least that long. The finding includes the full scenario with inputs and expected-versus-actual results. I didn't write a test asserting this behaviour, because it's the defect, not intended behaviour.\n\nI made no commit, and changed nothing outside `test/` apart from the findings file.","treeHash":"4199aa39fb9ce438d4011b0a487d041d145fea1c","usage":{"cachedInputTokens":1113118,"inputTokens":30,"model":"claude-opus-5-5","outputTokens":25535,"runtime":"claude","turns":21,"wallClockMs":394454}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"4aa8623bfb8d8e5e","findings":[],"hash":"0c32de380a8b166cfd85ad2ff100b1094ce4735bee2237e7056a10c0a838c67e","nodeId":"dfde1a56-6c56-44a4-ace6-d7a45bebe09c","outcome":"failed","summary":"Claude Code can't use your Claude subscription, usually because a payment is past due · Pay or renew at https://claude.ai/… (if you just paid, try again shortly), or use an Anthropic API key instead","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":null,"outputTokens":0,"runtime":"claude","turns":1,"wallClockMs":1312}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"989e104186cad5ec","findings":[{"citation":"resolved","description":"Consequence of the fix for the band-scale finding (0b5b9f3e...), reported for the author's awareness only. bandForStamina returns 0 for every stamina below BAND_WIDTH = 500, and DESIGN.md line 153 states the factor-of-two guarantee 'above band 0' and that band 0 'holds untrained and match-only pets'. A pet whose booked window certified little work stays in band 0 with trained stamina: tier 0 with 244 work gains 488 (10 + 488 = 498, band 0); tier 2 with 122 work gains 488 likewise. GameMath.raceScore for a Fit 10-stamina pet with maximum noise is mulDiv(10, 12500, 20000) = 6, while an Obese 498-stamina pet with minimum noise scores mulDiv(498, 7500, 20000) = 186, so the newborn loses every race against it. v2's 25-wide grid separated 10 from 498; the new table does not. No funds, no revert, no lock: the loser still receives +1 stamina and 2 points, and the lightly trained pet leaves band 0 after any live-sized window (typical ~450 work gives at least 900 stamina). The author has pinned band 0 as the untrained bucket, so this is a design note, not a defect that reopens the work; a narrower band 0 (e.g. BAND_WIDTH applied as a linear grid below 500) would restore v2 fairness for untrained pets if wanted.","line":247,"path":"src/MatchQueue.sol","reproduction":"Pure: MatchQueue.bandForStamina(10) == 0 and bandForStamina(499) == 0. Stateful (MockSqueekCore, genesis 1_799_994_000, now 1_800_000_000): alice mint -> id 1 (stamina 10). bob mint -> id 2; bob feed{0.0001 ether}(2, 0); bob startTraining(2) books 11..16; core certifies through 16 with 244 work; settleTraining(2) -> stamina 10 + 244*2*10000/10000 = 498. Both feed and enqueue: both land in _queues[0]; after 10 blocks requestRound(0) locks both; fulfillRound pairs them; matchInfo shows scoreA <= 6 for token 1 and scoreB >= 186 for token 2 for any seed, so token 1 can never win. Expected per DESIGN line 153 ('a pet cannot meet one many times its size'): a 50x stamina gap is not matched. Actual: band 0 has no ratio bound.","severity":"info","snippet":"        return scaled == 0 ? 0 : Math.log2(scaled) + 1;","title":"Band 0 of the new geometric band table spans stamina 0..499 with no ratio bound, so a newborn (10) can be paired with a lightly trained pet (up to 499) it cannot beat; documented, not blocking"}],"hash":"11e02841bafe7a7cb4222b75f1725ed8a62be64452cfae4e1b77a1343d5698b2","nodeId":"6d26c51d-b379-40ae-84c3-187cd3ecc3dc","outcome":"completed","summary":"All three prior findings are fixed, and the revision introduced no new defect. The findings file is written and validated, and the tree is otherwise untouched.\n\n**Settled findings**\n\n- **Idle decay during the Training lock (medium, a399f1ae).** Fixed. `_projectBody` now stops the inactivity clock at the booking time while a pet is Training, positive-work settlement resets the clock as in v2, and zero-work settlement and cancel resume it by excising the locked span. I traced the booking, feed, settle and cancel paths for underflow and double charging and found none. My proof passes unmodified.\n- **Feed refused during Training (medium, 0f38d5c5).** Fixed. `feed()` now accepts Idle or Training and still rejects Queued and Matched, whose stamina and weight snapshot must stay stable. A feed during the wait writes nothing that settlement reads, so the booked tier and bps are paid as booked. My proof passes unmodified. The two specialist proofs that fail do so only at an `expectRevert(Locked)` on a feed during Training, which is the old defect they were asserting.\n- **Band scale (medium, 0b5b9f3e).** Fixed on the band side. Bands are now geometric from a width of 500 using OpenZeppelin log2, so any two pets above band 0 are within a factor of two. Two live-sized windows land in the same band and race in the new tests. The ABI export and DESIGN table are updated. My proof passes unmodified.\n- **Reporter lag advisory (info).** Documented in DESIGN.md and README as requested. No code change was needed.\n\n**One new note, info only.** Band 0 now spans stamina 0 to 499 with no ratio bound, so a newborn at 10 stamina can be paired with a lightly trained pet at up to 499 and can never win that race. DESIGN.md already pins band 0 as the untrained bucket and limits the factor-of-two claim to bands above it, so this is a design observation with a concrete reproduction, not a blocking defect.\n\n**Verification run**\n\n| Check | Result |\n| --- | --- |\n| Full suite | 224 passed, 0 failed |\n| My three proofs | all pass on the revised code |\n| Runtime sizes | NFT 18,861 B, Queue 10,828 B, both under limit |\n| launch.json | schema keys only, args in declaration order, no extra fields |\n\nThe coverage record answers all 30 entry points, with the single info finding attached to `MatchQueue.enqueue`, plus rows recording each settled finding and the deployability check.","treeHash":null,"usage":{"cachedInputTokens":620043,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":15178,"runtime":"claude","turns":16,"wallClockMs":294679}},{"artifacts":[],"attempt":2,"bundleHash":null,"device":"61b4050710026370","findings":[{"citation":"resolved","description":"feed() requires Activity.Idle, so a pet in Training cannot be fed until settleTraining or cancelTraining. In v2 that lock lasted six hours. In v3 the Training state lasts until SqueekCore certifies trainEndRound, which is unbounded and in practice days: the live Sepolia Core (0x74665dAecA35A2303e767E76a2FF1FB6F93e119f) reported settledThroughRound = 1973 at block 12040000, 12045000 and 12047804 (ts 1793618352), while the derived current round at that timestamp is 2951, i.e. ~978 rounds (~6.8 days) behind, and it did not move in the last ~26 hours. The brief keeps 'Feed every 72h' and 'Hungry lockout', yet the only inputs that feed() needs for a training pet (the booking already snapshots lastFeedBps and tier at startTraining, lines 200) are unaffected by a later feed, so the lock protects nothing. The owner's only ways out are (a) let the pet go Hungry for days, taking 5 body damage per begun hungry day, which also makes it Hungry for enqueue immediately after settlement, or (b) cancelTraining and forfeit the window. Fix: let feed() run while Activity.Training (keep the lock only for Queued/Matched, whose snapshots are taken by the queue), or alternatively stop the hunger clock while a booking is awaiting certification. Either keeps the booked bps/tier untouched.","line":176,"path":"src/HamsterRunNFT.sol","reproduction":"Mock Core with genesis 1_799_994_000, now = 1_800_000_000. alice: mint() -> id; feed{value: 0.0003 ether}(id, 2) (body 50 -> 62, fedUntil = now + 72h); startTraining(id) (end round = start + 5). Core does not certify. warp now + 3 days + 1 s: isHungry(id) == true; alice feed{value: 0.0003 ether}(id, 2) reverts Locked(). warp now + 7 days, Core certifies through end with 1000 work; anyone settleTraining(id): stamina 10 -> 4010 but bodyScore 62 -> 23 (idle 7 days = -35, hunger days 4 = -20, credit +16) and weight Obese. Expected: the owner can feed during the wait (or the wait does not count as hunger) so a high-tier trained pet does not end Obese. Verified with test/scratch/LagCare.t.sol::test_trainingLockBlocksFeedingAndLagDrainsBody (asserts the defective values).","severity":"medium","snippet":"    function feed(uint256 tokenId, uint8 tier) external payable nonReentrant {\n        _requireOwnerIdle(tokenId);","title":"feed() is refused for the whole certification wait, so a training pet is forced Hungry and takes hunger damage it cannot prevent"},{"citation":"resolved","description":"The inactivity clock only resets in settleTraining when work != 0 (lines 221-223: clock.lastTrainAt = block.timestamp). It is not reset or paused by startTraining. Each completed day between two settlements costs 5 body points (line 422), while the maximum training credit is 2 + 2*tier + min(gain,10) <= 16 (line 220). In v2 a cycle took six hours, so a daily trainer accrued no idle damage. In v3 a cycle cannot be shorter than the Core's certification delay, which on live Sepolia is currently days (frontier 1973 vs current round 2951, unchanged since at least block 12040000). With a lag of >= 2 days, idle damage (>= 10) plus tier-2 credit (16) nets at most +6 per cycle only if the pet is also fed within the cycle, which finding 1 forbids; with the observed ~7-day lag a cycle nets -35 idle before credit. DESIGN.md states 'Only mid/high training can build Fit weight', but under the real upstream cadence training drives the pet to Obese and the only way to stay Fit is to never train and spam feeds (no cooldown, +12 each). Fix: measure inactivity from the booking (set lastTrainAt / idleDaysApplied at startTraining, or exclude [startTraining, settle] from idleDays), so the player is charged for not booking, not for the Reporter being late.","line":418,"path":"src/HamsterRunNFT.sol","reproduction":"Same setup as finding 1. alice: mint(), feed tier 2 (body 62), startTraining(id). Keep the pet fed is impossible (finding 1), so use a 2-day lag so hunger does not contribute: warp now + 2 days, Core certifies through trainEndRound with 1000 work, settleTraining(id). Actual: bodyScore = 62 - 10 (2 idle days) + 16 = 68, still Normal; repeating with the live ~7-day lag gives 62 - 35 - 20 + 16 = 23 Obese (finding 1 test). Expected: a fully fed, successfully trained pet does not lose body score for the time the window spent waiting on certification. Verified with test/scratch/LagCare.t.sol::test_idleDamageAccruesDuringCertificationLagAlone.","severity":"medium","snippet":"        idleDays = (block.timestamp - clock.lastTrainAt) / 1 days;","title":"Idle-day body damage is measured from the previous settlement, so Core certification lag the player cannot influence makes every training cycle a net body loss"},{"citation":"resolved","description":"Band is stamina / 25 and gain is 2 * work * bps / 10000 with no scaling. The pinned real window in docs/core-sepolia-snapshot.json (rounds 1868-1873) certified 1012 work, i.e. +2024 / +3036 / +4048 stamina for one booking depending on tier. A fresh pet (stamina 10) is band 0; after that single window the same pet is band 81, 121 or 162. Two pets land in one band only if they booked overlapping windows under the same tier, and each later window spreads them further. The success criterion 'MatchQueue still works' holds mechanically (tests pass with hand-set stamina) but with the v3 gain scale and 24-hour queue TTL the band matchmaker is unlikely to ever pair real pets. This is a consequence of the chosen f(work) = 2*work, not a coding error; flagging it so the author can pin a band width or a sub-linear f before deploying.","line":236,"path":"src/MatchQueue.sol","reproduction":"Live inputs: Core.roundPage(1867, 1873, 6) returns start.cumulativeWork 143148, end.cumulativeWork 144160 (work 1012). Pet A: mint, feed tier 2, book that window, settle -> stamina 4058, bandOf = 162. Pet B: mint only -> stamina 10, bandOf = 0. A enqueue -> _queues[162]; B enqueue -> _queues[0]; requestRound(162) and requestRound(0) both revert NotEnoughPlayers() forever unless another pet has identical training history. Expected per brief: an on-chain band matchmaker that still pairs pets after training.","severity":"low","snippet":"        return nft.hamster(tokenId).stamina / BAND_WIDTH;","title":"One certified window moves a pet ~100-160 bands, so bands rarely hold two pets and requestRound cannot form rounds between trained and untrained pets"}],"hash":"4fd350358737ef287cefdde4da5ad68e2d81a6eb127242da6b54642466439f0b","nodeId":"dfde1a56-6c56-44a4-ace6-d7a45bebe09c","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds three substantiated findings plus a coverage row for all 30 entry points and two invariants. No project file was modified; the only new files are the findings JSON and a scratch test under `test/scratch/`, which is gitignored.\n\n**What I found**\n\n- **Medium, feed blocked during Training.** `feed()` requires Idle, so a pet that booked a window cannot be fed until the Core certifies it. The booking already snapshots bps and tier, so the lock protects nothing. The live Sepolia Core frontier is at round 1973 while the current round is 2951, and it has not moved for at least 26 hours. A pet fed high and trained ends Hungry after 3 days, and after a 7-day wait settles at body 23, Obese. Reproduced in the scratch test.\n- **Medium, idle damage charged for the certification wait.** Inactivity days are measured from the last settlement, not from the booking. Each day costs 5 body points while the maximum training credit is 16. With any lag of two days or more a fully fed, successfully trained pet still loses ground, contradicting the design claim that only training builds Fit weight. Reproduced in the scratch test.\n- **Low, band fragmentation.** The real window pinned in the repo certified 1012 work, worth 2024 to 4048 stamina. One booking moves a pet from band 0 to band 81 to 162, so bands almost never hold two pets and `requestRound` reverts with NotEnoughPlayers for both.\n\n**What held.** The Core paging logic matches the live contract: `roundPage` rejects windows past the frontier, returns empty pages with equal endpoints for zero-work spans, and reports the truncation round as the mock assumes. Window overlap on re-booking is impossible because the Core only certifies ended rounds. All MatchQueue entry points, the ERC-721 lock on transfers, reentrancy guards, the one-time queue binding, and the quota and activeToken bookkeeping traced cleanly. The static-analysis leads on reentrancy and memory-array edits are false positives.\n\n**Not reached.** I did not scan the full Core history for zero-work records that carry a checkpoint, which would make `_certifiedWork` revert with InvalidCorePage. Sampled pages showed none.","treeHash":null,"usage":{"cachedInputTokens":1162250,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":38823,"runtime":"claude","turns":32,"wallClockMs":597770}},{"artifacts":[],"attempt":1,"bundleHash":"31e8e9d11b60c22a3c5349ceec53d3b17b9f678352371381f52d859721acae28","device":"d2b8b66fa0a1ce68","findings":[],"hash":"5b1292f5cd1612d0eb2d244c4ee2c4ddfb188377d4ee46ea41c2e46b64bf4303","nodeId":"ec1da5f7-5d18-4455-8b79-03a8b70e1c0a","outcome":"completed","summary":"I've updated my test suite for the new HamsterRun implementation, and everything passes with the verifier's fuzz seed. I found no new defects, so I didn't write `.imd-findings.json`. The only file changed is `test/CertifiedWorkOracle.t.sol`, which isn't committed yet.\n\n**What broke:** the new implementation lets an owner feed a pet while it is in Training. My old test `test_trainingAndQueueLocksExcludeEachOther` expected that feed to be refused, and it was the only one of 224 tests that failed on the new code. DESIGN now states that feeding during Training is allowed, so the test was wrong, not the contract.\n\n**Changes:**\n- **That test** now checks that a feed during Training succeeds, leaves the training booking exactly as it was, and renews the 72h feed window. It also checks the pet stays locked, and that a wrong price, an invalid tier or a non-owner are still refused. It now also checks that feeding a queued pet is still refused.\n- **The random-sequence (invariant) handler** now feeds pets in Training as well, and flags any feed that alters an open booking.\n- **New body-score checks across random call sequences**, which compare before and after rather than re-implementing the formula:\n  - time passing never raises a pet's body score;\n  - a pet in Training that is still fed after time passes loses nothing, so the wait for certification isn't charged as inactivity;\n  - cancelling, or settling a window with zero certified work, leaves body score exactly where it was; settling with positive work never lowers it.\n- **Coverage checks** in the fixed-seed walk now fail if a feed during Training, or a fed pet in Training across a time jump, is never actually reached, so these checks can't pass without running.\n\n**Results:**\n- My file: 11 of 11 pass, including 512 fuzz runs and 64 runs × 64 calls of the random-sequence tests with no reverts.\n- All other files except `StatefulInvariants.t.sol`: 221 of 221 pass.\n- The full suite takes about 11 minutes, longer than one run allows here, so I didn't re-run `StatefulInvariants.t.sol` after my edit. It's unchanged and passed against this same contract code in the baseline run.\n\n**Design notes, not defects:**\n- An owner can avoid inactivity damage indefinitely by keeping a pet in Training and never settling it, or by cancelling and booking again, without any real wheel work. SECURITY.md:26 states this is intended, because the pet can't race or be transferred while it's booked. It would be worth a fix only if the requester wants inactivity to keep counting once the booked rounds are certified.\n- The implementer's own new tests already cover the new geometric match bands (500 stamina, then doubling) in detail, so I added nothing there.","treeHash":"03af8ce951e6b94564f4eb4df638d842094f1d87","usage":{"cachedInputTokens":1134543,"inputTokens":47,"model":"claude-opus-5-5","outputTokens":16862,"runtime":"claude","turns":37,"wallClockMs":1070773}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"a7b8747ac077deb9","findings":[{"citation":"resolved","description":"Asymmetry / over-restrictive guard (Pashov Asymmetry step 6, Trust Gap seam access x external dependency). startTraining snapshots lastFeedBps and tier into `training[tokenId]` (line 200), so a later feed cannot alter the booked reward; nothing in settleTraining reads the live feed state. Yet feed() reuses `_requireOwnerIdle`, which rejects Activity.Training with `Locked`. The Training lock has no upper bound: settlement requires `Core.state().settledThroughRound >= trainEndRound` (CoreReader.sol:64) and the live Sepolia SqueekCore (0x74665dAecA35A2303e767E76a2FF1FB6F93e119f) was certified only through round 1973 while the wall-clock current round was 2951 at block timestamp 1793618280 (2026-11-02), i.e. the Reporter is ~978 rounds (~6.8 days) behind. Every pet booked today therefore sits in Training past its 72h feed window. The owner is the only actor who can feed, and the only state the owner can reach is cancelTraining (forfeit all booked work) or wait. While waiting, `_projectBody` charges 5 body points per begun hungry day plus 5 per idle day; a tier-2-fed pet (body 62) reaches body 0 / Obese after 10 days, and a later settlement applies that damage before the at-most +16 training credit (line 212 then 220). The brief keeps 'Feed every 72h' and 'Hungry lockout (no burn)'; DESIGN.md states 'Feeding cannot alter an active training', but the snapshot already guarantees that, so the gate is stricter than the invariant it protects. The queue locks (Queued/Matched) share the gate but are bounded (24h TTL, 258 blocks), so only the Training branch is affected. No funds are at risk; impact is gameplay degradation and a forced forfeit path under the live upstream condition. Minimal fix preserving the design: in feed(), require owner and `activity != Queued && activity != Matched` (or allow Training explicitly), keep startTraining's snapshot as the sole input to settlement, and add a test that feeds during Training and asserts the booked `lastFeedBps`/tier are unchanged.","line":176,"path":"src/HamsterRunNFT.sol","reproduction":"State: Core with genesis 1_799_994_000, settledThroughRound stays 0 (no certification), block.timestamp 1_800_000_000. 1) alice: mint() -> id 1. 2) alice: feed{value: 0.0003 ether}(1, 2) -> bodyScore 62, fedUntil = now + 72h. 3) alice: startTraining(1) -> books rounds 11..16, activity = Training. 4) warp +10 days; Core frontier still 0. 5) alice: feed{value: 0.0003 ether}(1, 2) -> EXPECTED (brief: feed every 72h; the booking already holds its own lastFeedBps=20000, tier=2): feed succeeds and the booking is untouched. ACTUAL: reverts Locked() at HamsterRunNFT.sol:177 via _requireOwnerIdle. 6) anyone: settleTraining(1) -> reverts CoreCertificationLag(0, 16). 7) hamster(1).bodyScore == 0, weight == Obese (10 idle days * 5 + 7 hungry days * 5 = 85 > 62). 8) alice: cancelTraining(1) -> Idle, stamina still 10, body 0: the only exit forfeits the booked work. Verified with a scratch Foundry test (test/scratch/FeedLockedDuringTraining.t.sol, run locally, removed) against the code as is; the live Core lag numbers come from eth_call on Sepolia at timestamp 1793618280.","severity":"low","snippet":"    function feed(uint256 tokenId, uint8 tier) external payable nonReentrant {\n        _requireOwnerIdle(tokenId);","title":"feed() is gated on Idle, so a pet locked in Training cannot be fed for the whole (unbounded) Core certification lag; the brief's 72h feed cadence is impossible and the owner must either absorb hunger "}],"hash":"88a93d51471788608fbf11992e62c4b87c2676e24df726feb4469e759254bb7a","nodeId":"31e3b301-6d22-49c4-ad66-81cc12d33c68","outcome":"completed","summary":"Findings file is written and validated: the snippet matches the tree at the cited line, the scratch test is removed, and the coverage record answers all 30 entry points plus three invariants.\n\n**Outcome: the permission model holds; one low-severity finding.**\n\nI audited `HamsterRunNFT`, `MatchQueue`, `CoreReader`, `GameMath` and `PointsLedger` against the Pashov Access Control, Trust Gap and Asymmetry guides, read the Senior Auditor's Mindset first, ran the full suite (198 tests pass), and probed the live Sepolia SqueekCore by `eth_call`.\n\n**What I checked and found sound**\n- Every state-changing entry point has the guard its effect needs. Owner powers are two-step, non-renounceable, and bounded: food config cannot drop below the default multipliers, fed pets and bookings keep captured bps, withdraw pays only the current owner.\n- The queue-only methods are callable solely by the once-bound queue, and even a dishonestly bound queue is capped by the activity state machine and weekly quota (at most +3 stamina per consumed attempt).\n- Paired surfaces are symmetric: enqueue/leave, lock/unlock, request/fulfil/expire, start/settle/cancel all mirror their state writes, and no lock can become permanent.\n- Live Core paging matches the reader's validation: full pages report `certifiedThroughRound == throughRound`, all 308 certified records strictly increase, so settlement cannot be bricked by the real ledger shape.\n\n**Finding 1 (low), `src/HamsterRunNFT.sol:176`.** `feed` is gated on Idle, so a pet locked in Training cannot be fed for the whole certification lag, which is unbounded. The booking already snapshots its bps and tier, so a feed could not alter the reward. On the live network the Reporter is roughly 978 rounds (about 6.8 days) behind the wall clock, so every pet booked today outlives its 72h feed window. Reproduced: feed reverts `Locked`, settle reverts `CoreCertificationLag`, the body score falls to 0 within 10 days, and cancel (forfeiting all work) is the only exit. DESIGN.md calls the gate intentional, so the judge may treat it as a design decision rather than a defect.\n\n**Not reached in depth:** the randomness and arithmetic leads from static analysis belong to other specialists, and I did not attempt to characterise upstream Core governance beyond the read-only checks above.","treeHash":null,"usage":{"cachedInputTokens":1069888,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":38736,"runtime":"claude","turns":37,"wallClockMs":662848}},{"artifacts":[],"attempt":1,"bundleHash":"1169bfac034b76b438bf2abd1eb6f56dc8c72a16ac5eb178539646e4ee45c882","device":"6a67f34b10f5ad79","findings":[],"hash":"8d1ecded1456d1dd46945f9c58725f427e5075d689c2ef4f578029e23a347930","nodeId":"92b36071-645d-4cb6-a3a9-ba6b879ac844","outcome":"completed","summary":"Implemented HamsterRun v3 with six-round Core-certified training, proportional stamina gains, lag/zero-work handling, preserved MatchQueue, ABIs, and deployment documentation.\n\nVerified: clean `forge build`, 198 Solidity tests with the requested seed, formatting, ABI checks, and 19 tooling tests.\n\nThe versioned Sepolia deployment handoff is ready. New addresses await the network deployer; no transactions were broadcast.","treeHash":"e6bd6e528b1b976f499406091c7cf51ce25eb571","usage":{"cachedInputTokens":5362304,"inputTokens":136787,"model":"gpt-6-astra","outputTokens":61130,"runtime":"codex","turns":9,"wallClockMs":2866522}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"bfdff1f539aaa982","findings":[{"citation":"resolved","description":"_projectBody charges 5 body points per completed day since clock.lastTrainAt (line 418, applied at line 422). startTraining (lines 192-203) does not move or freeze that clock; it is only reset in settleTraining after a positive-work window (lines 221-223), and settleTraining runs _syncBody (line 212) before applying the at-most +16 training credit (line 220). In v2 the Training lock was a fixed 6 hours so no completed day could elapse inside it. In v3 the lock lasts until Core.state().settledThroughRound >= trainEndRound (CoreReader.sol:64), which is unbounded and outside the player's control. Live Sepolia at review time (SqueekCore 0x74665dAecA35A2303e767E76a2FF1FB6F93e119f, read via the public Sepolia RPC at block timestamp 1793618844): settledThroughRound = 1973, genesis 1791847800, roundDuration 600, so the derived current round is 2952 and the frontier is about 979 rounds (6.8 days) behind; it was the same 1973 at the repository's pinned snapshot block 12047523. A booking made today therefore waits at least that long, and every day of the wait is charged as inactivity even though the booked wheel work already happened. With the live lag a tier-2 pet (body 62) loses 35 idle points before the +16 credit, so the paid, certified training is a net body loss and (together with finding 2) ends Obese; DESIGN.md says only mid/high training can build Fit weight. Merged from audit_economics, audit_math, audit_flow and the tester (same mechanism: lastTrainAt not anchored at booking). Minimal fix preserving intent: record the booking time in startTraining and project idle days only up to it while Activity.Training (or set lastTrainAt at booking and treat the window as active time), keeping the zero-work no-reset rule; pin the rule in DESIGN.md.","line":418,"path":"src/HamsterRunNFT.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport { Test } from \"forge-std/Test.sol\";\nimport { HamsterRunNFT } from \"src/HamsterRunNFT.sol\";\nimport { ISqueekCore } from \"src/interfaces/ISqueekCore.sol\";\n\n/// @dev Minimal certified-ledger stand-in with the real roundPage semantics (afterRound exclusive,\n///      throughRound inclusive, start/end are ledger positions at those rounds).\ncontract LagCore is ISqueekCore {\n    CoreConfiguration private _configuration;\n    CoreState private _state;\n    RoundCheckpoint[] private _records;\n\n    constructor(uint64 genesis) {\n        _configuration.genesisTimestamp = genesis;\n        _configuration.roundDuration = 600;\n        _configuration.maxRoundsPerBatch = 16;\n        _configuration.maxWorkPerRound = 10_000;\n    }\n\n    function configuration() external view returns (CoreConfiguration memory) {\n        return _configuration;\n    }\n\n    function state() external view returns (CoreState memory) {\n        return _state;\n    }\n\n    function certify(uint64 throughRound, uint64 work) external {\n        require(throughRound > _state.settledThroughRound, \"frontier must advance\");\n        require(\n            block.timestamp >= uint256(_configuration.genesisTimestamp) + uint256(throughRound) * 600,\n            \"round not ended\"\n        );\n        if (work != 0) {\n            _state.cumulativeWork += work;\n            _records.push(RoundCheckpoint(throughRound, _state.cumulativeWork, 0, 0, bytes32(0)));\n        }\n        _state.settledThroughRound = throughRound;\n    }\n\n    function roundPage(uint64 afterRound, uint64 throughRound, uint256 maxRecords)\n        external\n        view\n        returns (RoundPage memory page)\n    {\n        require(afterRound <= throughRound && throughRound <= _state.settledThroughRound, \"bounds\");\n        uint256 first = _upperBound(afterRound);\n        uint256 last = _upperBound(throughRound);\n        uint256 count = last - first;\n        require(count <= maxRecords, \"page too small for this test\");\n        page.certifiedThroughRound = throughRound;\n        if (first != 0) page.start.cumulativeWork = _records[first - 1].cumulativeWork;\n        if (last != 0) page.end.cumulativeWork = _records[last - 1].cumulativeWork;\n        page.rounds = new RoundCheckpoint[](count);\n        for (uint256 i; i < count; ++i) {\n            page.rounds[i] = _records[first + i];\n        }\n    }\n\n    function _upperBound(uint64 round) private view returns (uint256 low) {\n        uint256 high = _records.length;\n        while (low < high) {\n            uint256 mid = (low + high) / 2;\n            if (_records[mid].roundId <= round) low = mid + 1;\n            else high = mid;\n        }\n    }\n}\n\n/// @notice The inactivity clock (lastTrainAt) is not moved or frozen by startTraining, so every day the\n///         booked window spends waiting for SqueekCore certification is billed as an idle day at settle.\n///         The pet stays fed the whole time here, so hunger plays no part: the only damage is idle decay.\n///         Expected: a fed pet that booked and whose window certified with positive work keeps its score\n///         plus the training credit (62 + 16 = 78). Actual: 62 - 2 idle days * 5 + 16 = 68.\ncontract IdleClockDuringTrainingTest is Test {\n    HamsterRunNFT internal nft;\n    LagCore internal core;\n    address internal owner = makeAddr(\"owner\");\n    address internal alice = makeAddr(\"alice\");\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        vm.roll(1000);\n        core = new LagCore(1_799_994_000);\n        nft = new HamsterRunNFT(owner, address(core));\n        vm.prank(owner);\n        nft.setMintOpen(true);\n        vm.deal(alice, 1 ether);\n    }\n\n    function test_certificationWaitIsNotChargedAsInactivity() public {\n        vm.prank(alice);\n        uint256 id = nft.mint();\n        vm.prank(alice);\n        nft.feed{ value: 0.0003 ether }(id, 2);\n        assertEq(nft.hamster(id).bodyScore, 62, \"high food: 50 + 12\");\n\n        vm.prank(alice);\n        nft.startTraining(id);\n        (, uint64 end,,) = nft.training(id);\n\n        // Core certifies the booked window with positive work two days after it ended; the pet is still fed\n        // (fedUntil = booking time + 72h > end + 2 days, since the window is one hour long).\n        uint256 endedAt = uint256(core.configuration().genesisTimestamp) + uint256(end) * 600;\n        vm.warp(endedAt + 2 days);\n        assertFalse(nft.isHungry(id), \"pet is still inside its 72h feed window\");\n        core.certify(end, 5);\n\n        nft.settleTraining(id);\n        assertEq(nft.hamster(id).stamina, 30, \"10 + 5 work * 2 * 20000 / 10000\");\n        assertGe(nft.hamster(id).bodyScore, 78, \"certification wait charged as inactivity\");\n    }\n}","reproduction":"Core stand-in genesis 1_799_994_000, now 1_800_000_000 (round 11). alice: mint() -> id 1; feed{0.0003 ether}(1, 2) -> bodyScore 62, fedUntil = now + 72h; startTraining(1) -> books rounds 11..16. Warp to end of round 16 + 2 days (pet is still fed: isHungry == false); Core certifies through 16 with 5 work. Anyone: settleTraining(1). Expected: stamina 30 and bodyScore 78 (62 + credit 2 + 2*2 + min(20,10)), since the pet was neither idle nor hungry. Actual: stamina 30 but bodyScore 68 (62 - 2 idle days * 5 + 16). With the live 7-day lag and 1012 work: bodyScore 62 - 35 - 20 (hunger, finding 2) + 16 = 23, Obese. Proof: test/scratch/IdleClockDuringTraining.t.sol fails with '68 < 78'.","severity":"medium","snippet":"        idleDays = (block.timestamp - clock.lastTrainAt) / 1 days;","title":"Inactivity decay keeps running while a pet is locked in Training, so the whole SqueekCore certification wait is billed as idle days at settlement"},{"citation":"resolved","description":"feed() reuses _requireOwnerIdle (line 177), which reverts Locked() for Activity.Training (line 392). startTraining snapshots lastFeedBps and tier into training[tokenId] (line 200) and settleTraining reads only that snapshot (lines 208-211), so a feed during Training cannot change the booked reward; the guard protects nothing and only prevents the kept 72h feed cadence. Because the Training lock lasts until the Core frontier reaches trainEndRound (CoreReader.sol:64) and the live Sepolia frontier is about 6.8 days behind the clock (settledThroughRound 1973 vs current round 2952 at timestamp 1793618844), every pet booked today outlives its 72h food window while locked: isHungry flips true, _projectBody charges 5 per begun hungry day (line 421), and after settlement the pet is Hungry so it cannot enqueue or re-book until fed. The owner's only alternatives are to wait or cancelTraining, which forfeits all booked certified work. Distinct mechanism from finding 1 (feed guard vs idle clock) with a different one-line fix, so kept separate; merged from audit_permissions, audit_flow, the tester and audit_economics. Minimal fix preserving the design: in feed() require the owner and activity != Queued && activity != Matched (allow Training), keep the startTraining snapshot as the sole settlement input, and add a test that feeding during Training leaves training[tokenId] unchanged. Alternatively pause the hunger clock while a booking waits on the frontier; the attached proof assumes the first fix and would need its feed call adjusted for the second.","line":176,"path":"src/HamsterRunNFT.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport { Test } from \"forge-std/Test.sol\";\nimport { HamsterRunNFT } from \"src/HamsterRunNFT.sol\";\nimport { ISqueekCore } from \"src/interfaces/ISqueekCore.sol\";\nimport { CoreReader } from \"src/CoreReader.sol\";\n\n/// @dev Minimal SqueekCore stand-in whose frontier never advances: the booked window is never certified.\ncontract StalledCore is ISqueekCore {\n    CoreConfiguration private _configuration;\n    CoreState private _state;\n\n    constructor(uint64 genesis) {\n        _configuration.genesisTimestamp = genesis;\n        _configuration.roundDuration = 600;\n        _configuration.maxRoundsPerBatch = 16;\n    }\n\n    function configuration() external view returns (CoreConfiguration memory) {\n        return _configuration;\n    }\n\n    function state() external view returns (CoreState memory) {\n        return _state;\n    }\n\n    function roundPage(uint64, uint64, uint256) external pure returns (RoundPage memory page) {\n        revert(\"nothing certified\");\n    }\n}\n\n/// @notice feed() reuses the Idle-only guard, so a pet whose booking waits on Core certification cannot be\n///         fed. The booking already snapshots lastFeedBps and tier at startTraining, so a later feed cannot\n///         change the reward; the guard only forces the pet Hungry. On Sepolia the frontier is ~6.8 days\n///         behind the clock, so every booked pet outlives its 72h food window while waiting.\n///         Expected: the owner can renew food during the wait and the booking is untouched, so the pet is\n///         not Hungry and takes no hunger damage. Actual: feed reverts Locked() and the pet takes 5 body\n///         points per begun hungry day it cannot prevent.\ncontract FeedWhileTrainingTest is Test {\n    HamsterRunNFT internal nft;\n    StalledCore internal core;\n    address internal owner = makeAddr(\"owner\");\n    address internal alice = makeAddr(\"alice\");\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        vm.roll(1000);\n        core = new StalledCore(1_799_994_000);\n        nft = new HamsterRunNFT(owner, address(core));\n        vm.prank(owner);\n        nft.setMintOpen(true);\n        vm.deal(alice, 1 ether);\n    }\n\n    function test_ownerCanKeepABookedPetFedWhileCoreCertificationLags() public {\n        vm.prank(alice);\n        uint256 id = nft.mint();\n        vm.prank(alice);\n        nft.feed{ value: 0.0003 ether }(id, 2);\n        vm.prank(alice);\n        nft.startTraining(id);\n        (uint64 start, uint64 end, uint256 bookedBps, uint8 bookedTier) = nft.training(id);\n        assertEq(bookedBps, 20_000);\n        assertEq(bookedTier, 2);\n\n        // Core certifies nothing for three days; settlement is impossible and cancel forfeits the window.\n        vm.warp(block.timestamp + 3 days + 1);\n        vm.expectRevert(abi.encodeWithSelector(CoreReader.CoreCertificationLag.selector, 0, end));\n        nft.settleTraining(id);\n\n        // The owner renews food exactly as the kept 72h cadence asks. Expected: succeeds, booking unchanged.\n        vm.prank(alice);\n        nft.feed{ value: 0.0003 ether }(id, 2);\n        assertFalse(nft.isHungry(id), \"a fed pet is not Hungry\");\n\n        (uint64 start2, uint64 end2, uint256 bps2, uint8 tier2) = nft.training(id);\n        assertEq(start2, start, \"booking start unchanged by feeding\");\n        assertEq(end2, end, \"booking end unchanged by feeding\");\n        assertEq(bps2, bookedBps, \"booked bps unchanged by feeding\");\n        assertEq(tier2, bookedTier, \"booked tier unchanged by feeding\");\n    }\n}","reproduction":"Core stand-in with genesis 1_799_994_000 whose settledThroughRound stays 0; now 1_800_000_000. alice: mint() -> id 1; feed{0.0003 ether}(1, 2); startTraining(1) -> training(1) = (11, 16, 20000, 2). Warp +3 days + 1 s: settleTraining(1) reverts CoreCertificationLag(0, 16). alice: feed{0.0003 ether}(1, 2). Expected: succeeds, isHungry(1) == false and training(1) still (11, 16, 20000, 2). Actual: reverts Locked() from _requireOwnerIdle at line 177; isHungry(1) == true; after 7 days hamster(1).bodyScore has lost 20 points of hunger damage on top of finding 1's idle charge. Proof: test/scratch/FeedWhileTraining.t.sol fails with 'Locked()'.","severity":"medium","snippet":"    function feed(uint256 tokenId, uint8 tier) external payable nonReentrant {\n        _requireOwnerIdle(tokenId);","title":"feed() requires Idle, so a pet waiting on SqueekCore certification cannot be fed for the whole (unbounded) lag and takes hunger damage it cannot prevent"},{"citation":"resolved","description":"GameMath.trainingGain pays 2 * work * bps / 10000 stamina for one six-round window with no scaling, while MatchQueue keeps v2's band = stamina / 25 (src/MatchQueue.sol:236, BAND_WIDTH = 25 at line 13) and requestRound needs at least two eligible pets in the same band (line 154). v2 gains were about 1-10 stamina per 6h, so 25-wide bands grouped pets of similar strength. I walked the live SqueekCore ledger (310 active records through frontier 1973): the pinned window rounds 1868-1873 (docs/core-sepolia-snapshot.json, confirmed by a live roundPage(1867, 1873, 6) call: start 143148, end 144160) carries 1012 work, single rounds carry up to 1303 work, and the long-run average is about 75 work per round, i.e. roughly 450 work (900-1800 stamina) per window. One session therefore moves a pet from band 0 to band 81-162 (1012 work) or further, and two pets whose windows differed by a few percent land tens of bands apart; a pet is matchable only with another that has an almost identical training history. The match reward (+3/+1) and weight multiplier (+-15%) become numerically irrelevant next to training, and the body credit min(gain, 10) always saturates. No code path reverts wrongly and no funds are involved, but the brief's success criterion 'MatchQueue still works' holds only for untrained pets, which is a broken guarantee of the kept design rather than a coding slip. Existing tests use work 1..21 (and 1012 once) and never enqueue a trained pet. Merged from audit_math, audit_economics and audit_flow. Fix is a design decision for the author: scale f(work) down (e.g. work / 100 or a sub-linear curve) so a typical window yields a few stamina, or widen / log-scale bands; either way pin the expected per-window gain against the live ledger in DESIGN.md. The attached proof is audit_math's and passes with either rescaling.","line":33,"path":"src/GameMath.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport { Test } from \"forge-std/Test.sol\";\nimport { HamsterRunNFT } from \"src/HamsterRunNFT.sol\";\nimport { MatchQueue } from \"src/MatchQueue.sol\";\nimport { ISqueekCore } from \"src/interfaces/ISqueekCore.sol\";\n\n/// @dev Minimal certified ledger with the real roundPage semantics (afterRound exclusive, throughRound inclusive).\ncontract ScaleCore is ISqueekCore {\n    CoreConfiguration private _cfg;\n    CoreState private _st;\n    RoundCheckpoint[] private _recs;\n\n    constructor(uint64 genesis) {\n        _cfg.genesisTimestamp = genesis;\n        _cfg.roundDuration = 600;\n        _cfg.maxRoundsPerBatch = 16;\n    }\n\n    function configuration() external view returns (CoreConfiguration memory) {\n        return _cfg;\n    }\n\n    function state() external view returns (CoreState memory) {\n        return _st;\n    }\n\n    /// @notice Certify through `through`, attaching `work` to that final round (zero rounds have no record).\n    function certify(uint64 through, uint64 work) external {\n        require(through > _st.settledThroughRound, \"frontier\");\n        if (work != 0) {\n            _st.cumulativeWork += work;\n            _recs.push(RoundCheckpoint(through, _st.cumulativeWork, 0, 0, bytes32(0)));\n        }\n        _st.settledThroughRound = through;\n    }\n\n    function roundPage(uint64 afterRound, uint64 throughRound, uint256 maxRecords)\n        external\n        view\n        returns (RoundPage memory page)\n    {\n        require(afterRound <= throughRound && throughRound <= _st.settledThroughRound && maxRecords <= 16);\n        uint256 first = _ub(afterRound);\n        uint256 last = _ub(throughRound);\n        uint256 n = last - first;\n        require(n <= maxRecords, \"unexpected truncation in this test\");\n        page.certifiedThroughRound = throughRound;\n        if (first != 0) page.start.cumulativeWork = _recs[first - 1].cumulativeWork;\n        if (last != 0) page.end.cumulativeWork = _recs[last - 1].cumulativeWork;\n        page.rounds = new RoundCheckpoint[](n);\n        for (uint256 i; i < n; ++i) page.rounds[i] = _recs[first + i];\n    }\n\n    function _ub(uint64 r) private view returns (uint256 lo) {\n        uint256 hi = _recs.length;\n        while (lo < hi) {\n            uint256 mid = (lo + hi) / 2;\n            if (_recs[mid].roundId <= r) lo = mid + 1;\n            else hi = mid;\n        }\n    }\n}\n\n/// @notice One training session at live-Sepolia work levels moves a pet hundreds of 25-wide bands away from\n///         any pet whose window differed by a few percent, so the preserved MatchQueue cannot pair them.\ncontract BandScaleTest is Test {\n    uint64 constant GENESIS = 1_791_847_800; // live SqueekCore genesis\n    HamsterRunNFT nft;\n    MatchQueue queue;\n    ScaleCore core;\n    address owner = makeAddr(\"owner\");\n    address alice = makeAddr(\"alice\");\n    address bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        vm.warp(GENESIS + 2000 * 600); // round 2001\n        vm.roll(1000);\n        core = new ScaleCore(GENESIS);\n        nft = new HamsterRunNFT(owner, address(core));\n        queue = new MatchQueue(address(nft));\n        vm.startPrank(owner);\n        nft.setMatchQueue(address(queue));\n        nft.setMintOpen(true);\n        vm.stopPrank();\n        vm.deal(alice, 1 ether);\n        vm.deal(bob, 1 ether);\n    }\n\n    function _trainOnce(address player, uint64 work) internal returns (uint256 id) {\n        vm.startPrank(player);\n        id = nft.mint();\n        nft.feed{ value: 0.0003 ether }(id, 2);\n        nft.startTraining(id);\n        vm.stopPrank();\n        (, uint64 end,,) = nft.training(id);\n        vm.warp(GENESIS + uint256(end) * 600);\n        core.certify(end, work);\n        nft.settleTraining(id);\n    }\n\n    function test_twoPetsTrainedOnComparableLiveWorkStillShareAQueueBand() public {\n        // Live ledger (331 records, frontier 1973): p90 six-round window = 2213 work, max = 3344.\n        uint256 a = _trainOnce(alice, 2213);\n        uint256 b = _trainOnce(bob, 2000);\n        assertEq(nft.hamster(a).stamina, 10 + 2213 * 2 * 20_000 / 10_000); // 8862\n        assertEq(nft.hamster(b).stamina, 10 + 2000 * 2 * 20_000 / 10_000); // 8010\n\n        // Re-feed so both may enqueue; feed does not change stamina.\n        vm.prank(alice);\n        nft.feed{ value: 0.0003 ether }(a, 2);\n        vm.prank(bob);\n        nft.feed{ value: 0.0003 ether }(b, 2);\n        vm.prank(alice);\n        queue.enqueue(a);\n        vm.prank(bob);\n        queue.enqueue(b);\n        vm.roll(block.number + queue.QUEUE_WAIT_BLOCKS());\n\n        // Pets whose certified work differed by about 10% should still be matchable in one band.\n        // Today they sit 34 bands apart (354 vs 320) and requestRound finds a single player in each.\n        assertEq(queue.bandOf(a), queue.bandOf(b), \"one training session should not split comparable pets\");\n        queue.requestRound(queue.bandOf(a));\n    }\n\n    function test_oneTrainingGainIsOrdersOfMagnitudeAboveEveryOtherStaminaSource() public view {\n        // Band width 25, start stamina 10, match reward 3: a median active live window (about 2000 work)\n        // yields 4000 to 8000 stamina in one hour. The band grid built for 10..24 cannot absorb it.\n        uint256 gainLow = uint256(2000) * nft.STAMINA_PER_WORK() * 10_000 / 10_000;\n        assertLe(gainLow, 10 * queue.BAND_WIDTH(), \"single-session gain should stay within a few bands\");\n    }\n}","reproduction":"Core genesis 1791847800 (live), now = genesis + 2000*600 (round 2001). alice: mint, feed tier 2, startTraining -> books 2001..2006; Core certifies through 2006 with 2213 work; settleTraining -> stamina 10 + 2213*2*20000/10000 = 8862, bandOf = 354. bob does the same with 2000 work -> stamina 8010, bandOf = 320. Both re-feed and enqueue; after 10 blocks requestRound(354) and requestRound(320) each revert NotEnoughPlayers. Same with the pinned live window: 1012 work -> band 81 (tier 0), 121 (tier 1), 162 (tier 2) versus band 0 untrained. Expected: pets with comparable certified work share a band and can be paired. Proof: test/scratch/Proof_809c72522080.t.sol fails with '354 != 320' and '4000 > 250'.","severity":"medium","snippet":"        return uint256(work) * STAMINA_PER_WORK * trainBps / 10_000;","title":"Training gain of 2 stamina per certified work unit is thousands per window at live Sepolia work levels, so the preserved 25-wide MatchQueue bands almost never hold two trained pets"},{"citation":"resolved","description":"The code does what the brief asks (revert on lag, never invent work), so this is a documented dependency, not a defect. Observed live at timestamp 1793618844 via the public Sepolia RPC: Core.state().settledThroughRound = 1973 while the derived current round is 2952, and the frontier did not move between the pinned snapshot block 12047523 and this read. Consequences: a pet books one one-hour window and is then locked (no feed, transfer or queue) until the Reporter certifies about 980 more rounds, so effective throughput is one window per lag period; the only exit is cancelTraining, which forfeits the window. The binding is immutable and Core is an upgradeable proxy (implementationCodeVersion 3): a roundDuration change makes currentRound() revert UnsupportedCoreConfiguration (CoreReader.sol:31) so startTraining is bricked for good, and an ABI change bricks settlement; existing bookings could still be cancelled. No code change is required by this note; the README/UI should state the observed lag, and the author may want to allow a new booking once the previous window's rounds have elapsed if one-window-per-lag is unacceptable.","line":64,"path":"src/CoreReader.sol","reproduction":"State: live Core, block.timestamp 1793618844, settledThroughRound 1973. mint -> feed -> startTraining books rounds 2952..2957 -> settleTraining reverts CoreCertificationLag(1973, 2957) until the Reporter certifies through 2957; feed, transfer and enqueue revert Locked meanwhile; cancelTraining is the only exit and forfeits the window.","severity":"info","snippet":"        if (frontier < endRound) revert CoreCertificationLag(frontier, endRound);","title":"Trust assumption: training throughput and every booked pet's lock depend on the SqueekCore Reporter, whose live frontier is ~6.8 days behind, and the immutable binding to an upgradeable proxy has no o"}],"hash":"8fe4b21821c3ec104e083f5f55f831638efcb1885d42b5c1a3075f025424d961","nodeId":"6d26c51d-b379-40ae-84c3-187cd3ecc3dc","outcome":"completed","summary":"Review complete. The findings file `.imd-findings.json` holds 4 findings and a 32-row coverage record, and git shows no tracked file changed (the findings file and `test/scratch/` are ignored paths).\n\n**What the specialists reported, and what I kept.** The five areas produced 11 findings that collapse into three root causes plus one trust note. I reproduced each against the code and confirmed the live Sepolia numbers myself: SqueekCore's frontier is at round 1973 while the clock is at round 2952, about 6.8 days behind, unchanged since the repo's pinned snapshot.\n\n- **Finding 1, medium.** The inactivity clock is neither anchored nor frozen by `startTraining`, so every day a booking waits for Core certification is billed as an idle day at settlement, before the at-most +16 credit. A fed tier-2 pet settled two days after its window ends at body 68 instead of 78. Merged from economics, math, flow and the tester. My own proof fails with `68 < 78`.\n- **Finding 2, medium.** `feed()` reuses the Idle-only guard, so a pet locked in Training cannot be fed for the whole unbounded lag even though the booking already snapshots bps and tier. The pet goes Hungry and takes damage the owner cannot prevent. Kept separate from finding 1 because the guard and the clock are different mechanisms with different one-line fixes. My own proof fails with `Locked()`.\n- **Finding 3, medium.** Gain of 2 stamina per certified work unit yields thousands of stamina per window at live work levels, so the kept 25-wide bands almost never hold two trained pets and `requestRound` reverts `NotEnoughPlayers`. I walked the full live ledger to confirm the magnitudes. Kept audit_math's proof, which fails with `354 != 320`.\n- **Info.** The upstream dependency itself: one booking per lag period, immutable binding to an upgradeable proxy, and a roundDuration change would brick `startTraining`. No code defect.\n\n**Dropped.** Economics' double-counting note (unreachable with Core's ended-round rule) and the duplicate band and lag reports.\n\n**My own pass found nothing further.** I traced all 30 entry points, checked the constructor and manifest against the factory deploy model, confirmed the page validator's strict checks against all 310 live ledger records, and verified contract sizes are under the limits. The slither and aderyn lines are the documented non-financial PRNG, benign reentrancy after state is settled, and timestamp reads the design requires.","treeHash":null,"usage":{"cachedInputTokens":1253671,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":36837,"runtime":"claude","turns":25,"wallClockMs":576639}},{"artifacts":[],"attempt":1,"bundleHash":"4e0ad07796e61446e199fb76c44fc6ed7a848f50fa4de027a0f834ba170aaf4e","device":"1b657df861f7b08b","findings":[],"hash":"99105bf11d03b710153e313470e07239c1f063fbcc2eadfd03032723e4b1f094","nodeId":"92b36071-645d-4cb6-a3a9-ba6b879ac844","outcome":"completed","summary":"All three reviewer findings reproduced on the starting tree and are fixed. The advisory note is documented. The four reviewer proof tests now pass unmodified, and the full suite is green with the pinned fuzz seed.\n\n**What each finding needed**\n\n- **Idle decay during the certification wait.** `startTraining` now records the booking time in the private care clock, and body projection stops counting idle days at that time while the pet is Training. Positive-work settlement still resets the clock as in v2. Zero-work settlement and cancel resume it by excising the locked span, so the partial day in progress at booking carries over and nothing resets. The hunger clock is deliberately not paused.\n- **Feeding while booked.** `feed` accepts Idle or Training and still refuses Queued and Matched. The booking snapshot is the only input to settlement, so a feed during the wait only renews the food window and sets what the next booking captures. This is checked in unit tests and in a new branch of the stateful world handler that the seeded walk must reach.\n- **Bands that never pair trained pets.** The proofs pin the gain formula in both directions: one asserts 30 stamina for 5 work at high food, the other asserts 8862 for 2213 work. So the gain stays at 2 per work unit and the fix is on the queue side. Bands are now geometric: one band below 500 stamina, then each band spans a factor of two, exposed through a new `bandForStamina` view. Pets at 8862 and 8010 share band 5 and race end to end in a test. Queue mechanics, randomness, quota and points are untouched.\n- **Advisory on Reporter lag and the upgradeable Core proxy.** Documented in DESIGN, README and SECURITY with the observed lag figures, the one-window-per-lag throughput, and the brick scenarios. The suggested re-booking before settlement was not adopted, and the response file says why.\n\n**Verification on this tree**\n\n| Check | Result |\n| --- | --- |\n| forge build, forge fmt --check | pass |\n| forge test with the pinned seed | 214 passed, 0 failed, 13 suites |\n| Reviewer proofs (4 tests, copied under test/scratch) | all pass unmodified |\n| Node ABI export check and tool tests | pass, 19 tests |\n| Deploy script rehearsal, no broadcast | pass |\n\nThe ABI for MatchQueue and the hash file were regenerated. DESIGN pins the paused-clock formulas, the band formula and table, and the live-ledger stamina scale. The validation record carries the new test count, runtime sizes and source digests. Answers to all four findings are in `.imd-responses.json`.\n\nOne design consequence is worth knowing: because the proofs fix the gain scale, certified work still dominates match rewards and the saturating body credit. DESIGN now states this as intended and explains why pairing is by stamina ratio.","treeHash":"22cbb9a1cbddb39a070a02799af510da611f8465","usage":{"cachedInputTokens":6151473,"inputTokens":1028,"model":"claude-fable-5-1","outputTokens":97093,"runtime":"claude","turns":139,"wallClockMs":2827792}},{"artifacts":[],"attempt":1,"bundleHash":"23ede3b6046550ba6711bb1c18178a8cb5df14a00fdcc2736e5bc12fbb3eb8a5","device":"f7cb61cceaa27e78","findings":[],"hash":"e7547d20dce3c657233c4bd825cb256ea700f9e62215595bb4460793d0fdbcb5","nodeId":"f95b9077-2959-4b68-ad07-a5d8081bef88","outcome":"completed","summary":"Created [launch.json](/home/imd-worker/.identitymd/work/46232ab7-1448-4034-985f-5b89ed67d77b/f95b9077-2959-4b68-ad07-a5d8081bef88/launch.json) with both contracts in dependency order, `$owner`, the specified SqueekCore address, and verified constructor arguments.\n\n`forge build` passed with warnings. All 198 tests passed using the supplied fuzz seed. Only `launch.json` changed outside permitted scratch files.","treeHash":"69f2f7ccb840a6d0db5786da99dfd618a9f27008","usage":{"cachedInputTokens":467584,"inputTokens":42888,"model":"gpt-6-astra","outputTokens":4088,"runtime":"codex","turns":4,"wallClockMs":223251}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"bdd9b74dce66953d","findings":[{"citation":"resolved","description":"Flow gap (execution x periphery x first principles). startTraining locks the token in Activity.Training; feed() requires Idle (_requireOwnerIdle, line 177) so the owner cannot renew the 72h food window while waiting. settleTraining first runs _syncBody (line 212), which charges 5 body points per completed day since lastTrainAt (idle days, line 418) and 5 per begun day past fedUntil (hunger days, line 421), and only afterwards resets lastTrainAt (line 222). lastTrainAt is never set at startTraining, so the entire wait for Core certification is billed as inactivity even though the booked wheel work already happened. In v2 the lock lasted 6h and this never mattered; in v3 the lock lasts until Core certifies the booked end round. Live Sepolia at review time (publicnode, block 12047794, timestamp 1793618232): Core.state().settledThroughRound = 1973 while the derived current round is 2951, i.e. the frontier is ~978 rounds (~6.8 days) behind and did not move between the repo snapshot block 12047523 and this read. A pet fed on high food (body 62) that books now and is settled 7 days later with positive work gets 62 - 35 (7 idle days) - 20 (4 begun hungry days) + 16 (max training credit) = 23 -> Obese (race multiplier 8500 vs 11500 bps), and no feed could be made in between. Each training cycle under this lag nets about -27 body points, so the Fit/Normal/Obese economy the brief keeps from v2 cannot be sustained by any care pattern. Expected: time spent in Training is not inactivity. Fix: freeze the inactivity clock while Activity.Training (record the booking timestamp and project idle days only up to it; at a positive-work settle set lastTrainAt = now as today). Merely setting lastTrainAt at startTraining is not enough because the wait itself spans days. Optionally also allow feed while Training without altering the booked lastFeedBps so hunger decay can be prevented. Zero-work windows may keep the no-reset rule.","line":418,"path":"src/HamsterRunNFT.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport { Test } from \"forge-std/Test.sol\";\nimport { HamsterRunNFT } from \"src/HamsterRunNFT.sol\";\nimport { ISqueekCore } from \"src/interfaces/ISqueekCore.sol\";\nimport { WeightClass } from \"src/GameMath.sol\";\n\n/// @dev Minimal certified-ledger stand-in for SqueekCore: one record carries the window's work.\ncontract LagCore is ISqueekCore {\n    CoreConfiguration private _configuration;\n    CoreState private _state;\n    RoundCheckpoint[] private _records;\n\n    constructor(uint64 genesis) {\n        _configuration.genesisTimestamp = genesis;\n        _configuration.roundDuration = 600;\n        _configuration.maxRoundsPerBatch = 16;\n        _configuration.maxWorkPerRound = 10_000;\n    }\n\n    function configuration() external view returns (CoreConfiguration memory) {\n        return _configuration;\n    }\n\n    function state() external view returns (CoreState memory) {\n        return _state;\n    }\n\n    function certify(uint64 throughRound, uint64 work) external {\n        require(throughRound > _state.settledThroughRound, \"frontier must advance\");\n        require(\n            block.timestamp >= uint256(_configuration.genesisTimestamp) + uint256(throughRound) * 600,\n            \"round not ended\"\n        );\n        if (work != 0) {\n            _state.cumulativeWork += work;\n            _records.push(RoundCheckpoint(throughRound, _state.cumulativeWork, 0, 0, bytes32(0)));\n        }\n        _state.settledThroughRound = throughRound;\n    }\n\n    function roundPage(uint64 afterRound, uint64 throughRound, uint256 maxRecords)\n        external\n        view\n        returns (RoundPage memory page)\n    {\n        require(afterRound <= throughRound && throughRound <= _state.settledThroughRound, \"bounds\");\n        uint256 first = _upperBound(afterRound);\n        uint256 last = _upperBound(throughRound);\n        uint256 count = last - first;\n        require(count <= maxRecords, \"page too small for this test\");\n        page.certifiedThroughRound = throughRound;\n        if (first != 0) page.start.cumulativeWork = _records[first - 1].cumulativeWork;\n        if (last != 0) page.end.cumulativeWork = _records[last - 1].cumulativeWork;\n        page.rounds = new RoundCheckpoint[](count);\n        for (uint256 i; i < count; ++i) {\n            page.rounds[i] = _records[first + i];\n        }\n    }\n\n    function _upperBound(uint64 round) private view returns (uint256 low) {\n        uint256 high = _records.length;\n        while (low < high) {\n            uint256 mid = (low + high) / 2;\n            if (_records[mid].roundId <= round) low = mid + 1;\n            else high = mid;\n        }\n    }\n}\n\n/// @notice A pet locked in Training while SqueekCore certification lags is charged inactivity and\n///         hunger decay for the whole wait, and cannot be fed meanwhile. The wait is not inactivity:\n///         the wheel work was done in the booked hour. Expected: no idle-day damage for time spent\n///         in Training; actual: 5 body points per waiting day, applied at settlement.\ncontract TrainingLagDecayTest is Test {\n    HamsterRunNFT internal nft;\n    LagCore internal core;\n    address internal owner = makeAddr(\"owner\");\n    address internal alice = makeAddr(\"alice\");\n\n    function setUp() public {\n        vm.warp(1_800_000_000);\n        vm.roll(1000);\n        core = new LagCore(1_799_994_000);\n        nft = new HamsterRunNFT(owner, address(core));\n        vm.prank(owner);\n        nft.setMintOpen(true);\n        vm.deal(alice, 1 ether);\n    }\n\n    function test_trainingWaitIsNotInactivity() public {\n        vm.prank(alice);\n        uint256 id = nft.mint();\n        vm.prank(alice);\n        nft.feed{ value: 0.0003 ether }(id, 2);\n        assertEq(nft.hamster(id).bodyScore, 62, \"high food: 50 + 12\");\n\n        vm.prank(alice);\n        nft.startTraining(id);\n        (, uint64 end,,) = nft.training(id);\n\n        // Core certifies the booked window with positive work, but only two days later (still fed).\n        uint256 endedAt = uint256(core.configuration().genesisTimestamp) + uint256(end) * 600;\n        vm.warp(endedAt + 2 days);\n        core.certify(end, 5);\n\n        // The owner cannot feed or otherwise care for the pet while it waits.\n        vm.prank(alice);\n        vm.expectRevert(HamsterRunNFT.Locked.selector);\n        nft.feed{ value: 0.0003 ether }(id, 2);\n\n        nft.settleTraining(id);\n        assertEq(nft.hamster(id).stamina, 30, \"10 + 5 work * 2 * 20000 / 10000\");\n        // Expected: 62 + training credit (2 + 4 + min(20,10) = 16) = 78, no inactivity charge for the\n        // certification wait. Actual on current code: 62 - 2 idle days * 5 + 16 = 68.\n        assertGe(nft.hamster(id).bodyScore, 78, \"training wait charged as inactivity\");\n    }\n\n    function test_liveLagMakesEveryTrainedPetObese() public {\n        vm.prank(alice);\n        uint256 id = nft.mint();\n        vm.prank(alice);\n        nft.feed{ value: 0.0003 ether }(id, 2);\n        vm.prank(alice);\n        nft.startTraining(id);\n        (, uint64 end,,) = nft.training(id);\n\n        // Sepolia at review time: frontier 1973 vs current round 2951, about 6.8 days behind.\n        uint256 endedAt = uint256(core.configuration().genesisTimestamp) + uint256(end) * 600;\n        vm.warp(endedAt + 7 days);\n        core.certify(end, 1012);\n        nft.settleTraining(id);\n        assertEq(nft.hamster(id).stamina, 4058);\n        // 62 - 7 idle days * 5 - 4 begun hungry days * 5 = 7, then +16 credit = 23: Obese.\n        assertTrue(nft.hamster(id).weight != WeightClass.Obese, \"high-food pet that trained is Obese\");\n    }\n}","reproduction":"mint -> feed(id,2) (body 62) -> startTraining(id) -> warp 2 days past the booked end round (pet still fed) -> Core certifies the end round with 5 work -> feed(id,2) reverts Locked -> settleTraining(id): stamina 30 as expected, bodyScore 68 (62 - 2*5 + 16). Expected >= 78 (no idle charge for the wait). With a 7-day wait (the live lag) and 1012 work: stamina 4058, bodyScore 23, weight Obese. See proof test test/scratch/TrainingLagDecay.t.sol (both tests fail on current code).","severity":"medium","snippet":"        idleDays = (block.timestamp - clock.lastTrainAt) / 1 days;","title":"Pet locked in Training is charged inactivity and hunger decay for the whole SqueekCore certification wait and cannot be fed; on live Sepolia (frontier ~7 days behind) every trained pet ends Obese"},{"citation":"resolved","description":"Economic / invariant calibration gap between the new training formula and the preserved queue. GameMath.trainingGain (src/GameMath.sol:33) pays 2 * certifiedWork * bps / 10000 stamina per 6-round window with no diminishing term, while MatchQueue.bandOf keeps v2's band = stamina / 25 and requestRound needs >= 2 eligible pets in the same band. v2 gains were ~1-10 stamina per 6h (1 + 100/(10 + stamina/10)), so bands of 25 grouped pets of similar strength. On the real Sepolia ledger (docs/core-sepolia-snapshot.json, rounds 1868-1873) one window certified 1012 work units, i.e. +2024 / +3036 / +4048 stamina for tiers 0/1/2, and the per-window total varies from 0 (three of those six rounds were zero) to several thousand. The live average is ~75 work/round (148986 units over 1973 rounds), ~450 per window, ~900-1800 stamina. After a single training a pet jumps 36-160 bands; two pets that trained the same hour on different food land 81 bands apart; the same food in different hours lands 0 vs 162 bands apart. With bands this sparse requestRound(band) reverts NotEnoughPlayers for almost every trained pet, so the brief's 'MatchQueue still works' holds only for untrained pets (band 0) and the 3/1 match reward is economically irrelevant next to training. This is not a code revert or fund loss, but the pairing guarantee the band mechanism exists for is broken for anyone who uses the new training. Fix options (design decision for the author): rescale STAMINA_PER_WORK / bps to v2-like magnitudes, widen or make bands logarithmic, or band on something other than raw stamina.","line":236,"path":"src/MatchQueue.sol","reproduction":"Two pets, alice tier 0 and bob tier 2, both startTraining in the same current round; Core certifies the booked end round with 1012 work (the real Sepolia window); settle both: stamina 2034 and 4058, bandOf = 81 and 162. Both enqueue, wait 10 blocks: requestRound(81) and requestRound(162) each revert NotEnoughPlayers. Same food, different hours: 1012 work -> band 162 vs 0 work -> band 0, again NotEnoughPlayers. Verified with test/scratch/BandDivergence.t.sol (logs: 'band low food: 81', 'band high food: 162', 'band a: 162', 'band b: 0').","severity":"medium","snippet":"        return nft.hamster(tokenId).stamina / BAND_WIDTH;","title":"Stamina scale of certified-work training (thousands per hour window) makes the 25-wide MatchQueue bands unreachable for other pets: trained pets effectively can never be matched"},{"citation":"resolved","description":"The code behaves exactly as the brief asks (revert with CoreCertificationLag, never invent work), so this is a documented dependency risk rather than a code defect. Observed on Sepolia at review time (block 12047794, timestamp 1793618232): configuration genesis 1791847800, duration 600, state.settledThroughRound 1973, derived currentRound 2951, paused=false; identical frontier at the repo's snapshot block 12047523 ~55 minutes earlier. Consequences: (1) a pet books one 1-hour window and is then locked (no feed, transfer, queue) for the whole lag, so effective training throughput is one window per lag period rather than per hour; (2) the only exit is cancelTraining, which forfeits all booked work; (3) Core is an upgradeable proxy (761-byte proxy, implementationCodeVersion 3) bound immutably: a roundDuration change makes startTraining revert UnsupportedCoreConfiguration forever, and an ABI change makes settle revert forever, with no owner remedy other than a new deployment. Suggest the README/UI state the observed lag and that the design allow a new booking once the previous window's rounds have elapsed (settling each later) if one-window-per-lag throughput is not acceptable.","line":64,"path":"src/CoreReader.sol","reproduction":"State: Core.state().settledThroughRound = 1973 (live), block.timestamp = 1793618232. mint -> feed -> startTraining books rounds 2951..2956 -> settleTraining reverts CoreCertificationLag(1973, 2956) until the Reporter certifies 983 more rounds; feed/transfer/enqueue revert Locked meanwhile; cancelTraining forfeits the window.","severity":"info","snippet":"        if (frontier < endRound) revert CoreCertificationLag(frontier, endRound);","title":"Trust assumption: training throughput and token liquidity depend entirely on the SqueekCore Reporter; live frontier is ~978 rounds behind and a booking made now cannot settle until it advances 983 rou"},{"citation":"resolved","description":"startTraining always books [currentRound, currentRound+5] and settleTraining requires frontier >= end. The contract never records the last settled end round, so the only thing preventing a token from settling [R..R+5] and immediately re-booking a window that starts at R+5 is that Core must not certify round R+5 before it ends (DESIGN.md line 93 states this reliance explicitly). The upstream contract is an upgradeable proxy whose certification rule the NFT cannot verify. A one-line defensive invariant (store lastSettledEnd per token and require startRound > lastSettledEnd) would make the no-double-count property local and independent of upstream behavior.","line":195,"path":"src/HamsterRunNFT.sol","reproduction":"Only reachable if Core's frontier ever reaches the in-progress round: with a Core stand-in that certifies throughRound == currentRound() while that round is still running, book [R..R+5] at time in round R+5, settle (frontier R+5), then startTraining again in round R+5: window [R+5..R+10], round R+5's work is paid twice. With the repo's MockSqueekCore (which enforces the ended-round rule) this is unreachable, hence info.","severity":"info","snippet":"        uint64 startRound = currentRound();","title":"No monotonic guard between a settled window and the next booking: double-counting a round is prevented only by the upstream rule that Core certifies ended rounds"}],"hash":"f15cc523e8f8ec683b203f75e37a557954472fa7d91591f82ee18d86e7f4cef8","nodeId":"bc0459fb-c189-432a-ba98-c47fc61ef778","outcome":"completed","summary":"Review complete. The findings file `.imd-findings.json` is written at the repository root with 4 findings and 36 coverage rows (all 30 listed entry points answered, none unreached). No source or configuration file was changed; the only other writes are the two scratch tests under `test/scratch/`, which is git-ignored.\n\n**What I checked.** I read all five source files, DESIGN.md, the Economic Security, Invariant and Flow Gap guides plus the Senior Auditor's Mindset, the mock Core and the embedded real Core response bytes. The baseline suite passes (198 tests). I also read the live Sepolia SqueekCore proxy over a public RPC to check the periphery assumptions: the decoded `roundPage` snapshot matches CoreReader's validation (page `certifiedThroughRound` equals the requested through-round, cumulative endpoints 143148 to 144160, three records), so the paging semantics hold.\n\n**Findings**\n\n1. **Medium. Training wait is billed as neglect.** A pet in Training cannot be fed, and `settleTraining` charges inactivity and hunger decay for the whole certification wait before resetting the clock (`src/HamsterRunNFT.sol:418`). Live Sepolia at review time has the Core frontier at round 1973 while the current round is 2951, about 6.8 days behind and unchanged across the two reads I made. Under that lag a high-food pet with positive work settles at body 23 and Obese. A proof test is attached (two failing tests: body 68 where 78 is expected after a 2-day wait, and Obese after a 7-day wait).\n\n2. **Medium. Band calibration broken by the new stamina scale.** Gains are now thousands of stamina per one-hour window (the real Sepolia window of 1012 work pays 2024 to 4048), while `MatchQueue.bandOf` keeps v2's 25-wide bands (`src/MatchQueue.sol:236`). Two pets that trained the same hour on different food land 81 bands apart. The same food in different hours lands 0 versus 162 bands apart. `requestRound` reverts `NotEnoughPlayers` in each case, verified by a scratch test. Trained pets effectively never match. This is a design decision for the author, so no proof is attached.\n\n3. **Info. Dependency trust assumption.** Throughput is one window per certification lag, the only exit is a forfeiting cancel, and the immutable binding to an upgradeable proxy means a duration or ABI change bricks booking or settlement permanently. The code conforms to the brief here.\n\n4. **Info. No local no-double-count guard.** Preventing a round from being paid twice relies solely on Core never certifying an in-progress round. A per-token last-settled-end check would make it local.\n\n**Coverage not reached in depth.** Randomness quality of the queue (weak-PRNG leads) and the gas of 32-entry prune loops are outside the economics area and were traced only enough to mark them as holding by design.","treeHash":null,"usage":{"cachedInputTokens":1300135,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":43629,"runtime":"claude","turns":35,"wallClockMs":739889}},{"artifacts":[],"attempt":1,"bundleHash":"545677bba57bffd7c104f9a95867295009d4e0555af57f5317deedb83977a2dc","device":"809ae05b6282abad","findings":[],"hash":"f94d1da2e3bd963854dd53f2182e9b95031fc4b1a9ed8567461c4302c932df7a","nodeId":"f95b9077-2959-4b68-ad07-a5d8081bef88","outcome":"completed","summary":"`launch.json` is complete and valid for the accepted v3 source. It lists two contracts in dependency order: `HamsterRunNFT` with `$owner` and the brief's SqueekCore address, then `MatchQueue` with `$contract:HamsterRunNFT`. The contract list and constructor arguments are unchanged.\n\nI made one notes-only correction. The old text said \"CoreReader and PointsLedger are inherited\" without saying where, so it now attributes CoreReader to the NFT and PointsLedger to MatchQueue. It also notes that care is fused into the NFT, so v2 cannot be patched, and cites `deployments/sepolia.json` and `abi/SHA256.json` alongside DESIGN.md.\n\nVerification:\n- `forge build` succeeds.\n- `forge test` passes with the pinned fuzz seed: 213 passed, 0 failed.\n- The manifest parses as exactly `kind`, `contracts`, and `notes`; names are unique and under 32 characters; each constructor argument count matches the ABI; the contract reference points backward.\n- `git status` shows `launch.json` as the only changed file, with no untracked files and no blocked marker.","treeHash":"68f8afa42607f5a93d204d641f2dc2499dab6ea5","usage":{"cachedInputTokens":374528,"inputTokens":59514,"model":"claude-fable-5-1","outputTokens":20046,"runtime":"claude","turns":34,"wallClockMs":181657}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"9812c5faf226f7c7","findings":[{"citation":"resolved","description":"GameMath.trainingGain pays 2 stamina per certified SqueekCore work unit, times the food bps (1x/1.5x/2x). On the live Sepolia Core (0x74665dAecA35A2303e767E76a2FF1FB6F93e119f, frontier 1973, 331 active records walked with roundPage on 2026-11-02) a single active round carries 1..731 work (median 483) and a six-round booked window carries up to 3344 work (p90 of all windows = 2213). One one-hour session therefore adds 4000..13376 stamina to a pet that starts at 10 and otherwise gains 3 per match win. MatchQueue (kept unchanged by the brief) groups pets by floor(stamina/25) (src/MatchQueue.sol:236, BAND_WIDTH=25 at line 13) and requestRound needs two eligible pets in the same band. Two pets whose windows differed by ~10% (2213 vs 2000 work, both high tier) land at stamina 8862 and 8010, bands 354 and 320, and can never race each other; with 9999 pets spread over thousands of bands the queue degenerates to NotEnoughPlayers. The scale also makes the weight-class multiplier (±15%) and match rewards (+3/+1) numerically irrelevant next to training, and min(gain,10) body credit always saturates. Seam: boundary x precision x invariant — the formula is exact, but at the real input magnitude it breaks the band invariant the queue relies on. Existing tests only use work 1..21 (and 1012 once) and never enqueue a trained pet, so this is untested. Fix options (design decision for the author): scale STAMINA_PER_WORK down (e.g. work/100 or a sqrt/log curve) so a typical window yields a few stamina, or make BAND_WIDTH proportional/log-scaled; either way pin the expected per-window gain range in DESIGN against the live ledger figures.","line":33,"path":"src/GameMath.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport { Test } from \"forge-std/Test.sol\";\nimport { HamsterRunNFT } from \"src/HamsterRunNFT.sol\";\nimport { MatchQueue } from \"src/MatchQueue.sol\";\nimport { ISqueekCore } from \"src/interfaces/ISqueekCore.sol\";\n\n/// @dev Minimal certified ledger with the real roundPage semantics (afterRound exclusive, throughRound inclusive).\ncontract ScaleCore is ISqueekCore {\n    CoreConfiguration private _cfg;\n    CoreState private _st;\n    RoundCheckpoint[] private _recs;\n\n    constructor(uint64 genesis) {\n        _cfg.genesisTimestamp = genesis;\n        _cfg.roundDuration = 600;\n        _cfg.maxRoundsPerBatch = 16;\n    }\n\n    function configuration() external view returns (CoreConfiguration memory) {\n        return _cfg;\n    }\n\n    function state() external view returns (CoreState memory) {\n        return _st;\n    }\n\n    /// @notice Certify through `through`, attaching `work` to that final round (zero rounds have no record).\n    function certify(uint64 through, uint64 work) external {\n        require(through > _st.settledThroughRound, \"frontier\");\n        if (work != 0) {\n            _st.cumulativeWork += work;\n            _recs.push(RoundCheckpoint(through, _st.cumulativeWork, 0, 0, bytes32(0)));\n        }\n        _st.settledThroughRound = through;\n    }\n\n    function roundPage(uint64 afterRound, uint64 throughRound, uint256 maxRecords)\n        external\n        view\n        returns (RoundPage memory page)\n    {\n        require(afterRound <= throughRound && throughRound <= _st.settledThroughRound && maxRecords <= 16);\n        uint256 first = _ub(afterRound);\n        uint256 last = _ub(throughRound);\n        uint256 n = last - first;\n        require(n <= maxRecords, \"unexpected truncation in this test\");\n        page.certifiedThroughRound = throughRound;\n        if (first != 0) page.start.cumulativeWork = _recs[first - 1].cumulativeWork;\n        if (last != 0) page.end.cumulativeWork = _recs[last - 1].cumulativeWork;\n        page.rounds = new RoundCheckpoint[](n);\n        for (uint256 i; i < n; ++i) page.rounds[i] = _recs[first + i];\n    }\n\n    function _ub(uint64 r) private view returns (uint256 lo) {\n        uint256 hi = _recs.length;\n        while (lo < hi) {\n            uint256 mid = (lo + hi) / 2;\n            if (_recs[mid].roundId <= r) lo = mid + 1;\n            else hi = mid;\n        }\n    }\n}\n\n/// @notice One training session at live-Sepolia work levels moves a pet hundreds of 25-wide bands away from\n///         any pet whose window differed by a few percent, so the preserved MatchQueue cannot pair them.\ncontract BandScaleTest is Test {\n    uint64 constant GENESIS = 1_791_847_800; // live SqueekCore genesis\n    HamsterRunNFT nft;\n    MatchQueue queue;\n    ScaleCore core;\n    address owner = makeAddr(\"owner\");\n    address alice = makeAddr(\"alice\");\n    address bob = makeAddr(\"bob\");\n\n    function setUp() public {\n        vm.warp(GENESIS + 2000 * 600); // round 2001\n        vm.roll(1000);\n        core = new ScaleCore(GENESIS);\n        nft = new HamsterRunNFT(owner, address(core));\n        queue = new MatchQueue(address(nft));\n        vm.startPrank(owner);\n        nft.setMatchQueue(address(queue));\n        nft.setMintOpen(true);\n        vm.stopPrank();\n        vm.deal(alice, 1 ether);\n        vm.deal(bob, 1 ether);\n    }\n\n    function _trainOnce(address player, uint64 work) internal returns (uint256 id) {\n        vm.startPrank(player);\n        id = nft.mint();\n        nft.feed{ value: 0.0003 ether }(id, 2);\n        nft.startTraining(id);\n        vm.stopPrank();\n        (, uint64 end,,) = nft.training(id);\n        vm.warp(GENESIS + uint256(end) * 600);\n        core.certify(end, work);\n        nft.settleTraining(id);\n    }\n\n    function test_twoPetsTrainedOnComparableLiveWorkStillShareAQueueBand() public {\n        // Live ledger (331 records, frontier 1973): p90 six-round window = 2213 work, max = 3344.\n        uint256 a = _trainOnce(alice, 2213);\n        uint256 b = _trainOnce(bob, 2000);\n        assertEq(nft.hamster(a).stamina, 10 + 2213 * 2 * 20_000 / 10_000); // 8862\n        assertEq(nft.hamster(b).stamina, 10 + 2000 * 2 * 20_000 / 10_000); // 8010\n\n        // Re-feed so both may enqueue; feed does not change stamina.\n        vm.prank(alice);\n        nft.feed{ value: 0.0003 ether }(a, 2);\n        vm.prank(bob);\n        nft.feed{ value: 0.0003 ether }(b, 2);\n        vm.prank(alice);\n        queue.enqueue(a);\n        vm.prank(bob);\n        queue.enqueue(b);\n        vm.roll(block.number + queue.QUEUE_WAIT_BLOCKS());\n\n        // Pets whose certified work differed by about 10% should still be matchable in one band.\n        // Today they sit 34 bands apart (354 vs 320) and requestRound finds a single player in each.\n        assertEq(queue.bandOf(a), queue.bandOf(b), \"one training session should not split comparable pets\");\n        queue.requestRound(queue.bandOf(a));\n    }\n\n    function test_oneTrainingGainIsOrdersOfMagnitudeAboveEveryOtherStaminaSource() public view {\n        // Band width 25, start stamina 10, match reward 3: a median active live window (about 2000 work)\n        // yields 4000 to 8000 stamina in one hour. The band grid built for 10..24 cannot absorb it.\n        uint256 gainLow = uint256(2000) * nft.STAMINA_PER_WORK() * 10_000 / 10_000;\n        assertLe(gainLow, 10 * queue.BAND_WIDTH(), \"single-session gain should stay within a few bands\");\n    }\n}","reproduction":"State: Core genesis 1791847800, roundDuration 600 (live values). Alice mints, feeds tier 2 (0.0003 ETH), startTraining at round 2001 (books 2001..2006). Core certifies through 2006 with 2213 work in the window; settleTraining -> stamina = 10 + 2213*2*20000/10000 = 8862, bandOf = 354. Bob does the same with 2000 work -> stamina 8010, bandOf = 320. Both re-feed and enqueue; after 10 blocks requestRound(354) reverts NotEnoughPlayers (and so does requestRound(320)). Expected: pets of comparable certified work are matchable within one band; actual: 34 bands apart. See test/scratch/BandScale.t.sol (fails: '354 != 320' and '4000 > 250').","severity":"medium","snippet":"        return uint256(work) * STAMINA_PER_WORK * trainBps / 10_000;","title":"Training gain scale (2 stamina per Core work unit) is incoherent with the preserved 25-wide MatchQueue bands: one real session moves a pet hundreds of bands, so trained pets cannot be matched"},{"citation":"resolved","description":"_projectBody charges 5 body points per completed day since lastTrainAt and 5 per begun hungry day. lastTrainAt is only advanced in settleTraining (line 222) and only when work != 0, so the whole certification wait counts as inactivity even though the pet is in Training. feed() requires Idle (_requireOwnerIdle, line 177), so the brief's kept 72h feed cadence is impossible while Training; after 72h the pet is Hungry and takes hunger damage too. In v2 training was a bounded 6h clock, so these time constants were harmless; in v3 the wait is unbounded and on Sepolia today the Core frontier is 1973 while the current round is ~2951 (state() read 2026-11-02 at timestamp 1793618232; last active record is round 1910), i.e. about 978 rounds / 6.8 days of lag, and no round has been certified for ~7 days. A tier-2 pet (body 62 after feeding) that books now and settles when the Core catches up 6.8 days later with 2213 certified work loses 30 (6 idle days) + 20 (4 hungry days) = 50 before the +16 training credit, ending at 28 Obese; the net effect of a paid, certified, high-tier session is negative once lag exceeds ~3 days (4-day lag: 62 -> 48). This inverts the documented rule that only mid/high training can build Fit weight and leaves the owner the choice of cancelTraining (forfeiting all certified work) or letting the pet starve. Seam: boundary (unbounded external wait) x invariant (training improves body). The suite tests lag only as a revert (test_partialCertificationCannotCashOutEvenNonzeroWork) and never settles non-zero work after a multi-day wait. Minimal fix preserving intent: stop idle accrual during Training (e.g. set lastTrainAt / an anchor at startTraining and treat the booked window as active time), and either allow feeding a Training pet or pause hunger damage for the duration the settle is blocked on the Core frontier; pin the chosen rule in DESIGN.","line":418,"path":"src/HamsterRunNFT.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport { Test } from \"forge-std/Test.sol\";\nimport { HamsterRunNFT } from \"src/HamsterRunNFT.sol\";\nimport { WeightClass } from \"src/GameMath.sol\";\nimport { ISqueekCore } from \"src/interfaces/ISqueekCore.sol\";\n\ncontract LagCore is ISqueekCore {\n    CoreConfiguration private _cfg;\n    CoreState private _st;\n    RoundCheckpoint[] private _recs;\n\n    constructor(uint64 genesis) {\n        _cfg.genesisTimestamp = genesis;\n        _cfg.roundDuration = 600;\n        _cfg.maxRoundsPerBatch = 16;\n    }\n\n    function configuration() external view returns (CoreConfiguration memory) {\n        return _cfg;\n    }\n\n    function state() external view returns (CoreState memory) {\n        return _st;\n    }\n\n    function certify(uint64 through, uint64 work) external {\n        require(through > _st.settledThroughRound, \"frontier\");\n        if (work != 0) {\n            _st.cumulativeWork += work;\n            _recs.push(RoundCheckpoint(through, _st.cumulativeWork, 0, 0, bytes32(0)));\n        }\n        _st.settledThroughRound = through;\n    }\n\n    function roundPage(uint64 afterRound, uint64 throughRound, uint256 maxRecords)\n        external\n        view\n        returns (RoundPage memory page)\n    {\n        require(afterRound <= throughRound && throughRound <= _st.settledThroughRound && maxRecords <= 16);\n        uint256 first = _ub(afterRound);\n        uint256 last = _ub(throughRound);\n        uint256 n = last - first;\n        require(n <= maxRecords);\n        page.certifiedThroughRound = throughRound;\n        if (first != 0) page.start.cumulativeWork = _recs[first - 1].cumulativeWork;\n        if (last != 0) page.end.cumulativeWork = _recs[last - 1].cumulativeWork;\n        page.rounds = new RoundCheckpoint[](n);\n        for (uint256 i; i < n; ++i) page.rounds[i] = _recs[first + i];\n    }\n\n    function _ub(uint64 r) private view returns (uint256 lo) {\n        uint256 hi = _recs.length;\n        while (lo < hi) {\n            uint256 mid = (lo + hi) / 2;\n            if (_recs[mid].roundId <= r) lo = mid + 1;\n            else hi = mid;\n        }\n    }\n}\n\n/// @notice While a pet waits for Core certification it is locked (cannot be fed) yet keeps accruing idle\n///         and hunger damage at 5/day each. At the live Sepolia lag (frontier 1973 vs current round ~2951,\n///         about 6.8 days) a high-tier session with large certified work ends Obese.\ncontract LagDecayTest is Test {\n    uint64 constant GENESIS = 1_791_847_800;\n    HamsterRunNFT nft;\n    LagCore core;\n    address owner = makeAddr(\"owner\");\n    address alice = makeAddr(\"alice\");\n\n    function setUp() public {\n        vm.warp(GENESIS + 2950 * 600); // round 2951, as on Sepolia on 2026-11-02\n        core = new LagCore(GENESIS);\n        core.certify(1973, 1); // live frontier\n        nft = new HamsterRunNFT(owner, address(core));\n        vm.prank(owner);\n        nft.setMintOpen(true);\n        vm.deal(alice, 1 ether);\n    }\n\n    function test_highTierTrainingWithLargeWorkMustNotLeaveThePetObeseBecauseCoreLagged() public {\n        vm.startPrank(alice);\n        uint256 id = nft.mint();\n        nft.feed{ value: 0.0003 ether }(id, 2); // body 50 + 12 = 62, Normal\n        assertEq(nft.hamster(id).bodyScore, 62);\n        nft.startTraining(id); // books rounds 2951..2956\n        vm.stopPrank();\n        (, uint64 end,,) = nft.training(id);\n        assertEq(end, 2956);\n\n        // The pet cannot be fed while Training, so the 72h feed cadence the brief keeps is unreachable.\n        vm.warp(block.timestamp + 3 days);\n        vm.prank(alice);\n        vm.expectRevert(HamsterRunNFT.Locked.selector);\n        nft.feed{ value: 0.0003 ether }(id, 2);\n\n        // Core catches up 6.8 days after booking (today's live lag) and certifies 2213 work in the window.\n        vm.warp(GENESIS + uint256(end) * 600 + 6 days + 19 hours);\n        core.certify(end, 2213);\n        nft.settleTraining(id);\n\n        HamsterRunNFT.Hamster memory ham = nft.hamster(id);\n        assertEq(ham.stamina, 10 + 2213 * 4, \"work was certified and paid\");\n        // idle 7 days (-35) + hungry days 4 (-20) = -55 -> 7, then +16 credit -> 23 Obese.\n        // A successful high-tier training session should at least not demote the pet below where it started.\n        assertGe(ham.bodyScore, 62, \"paid, certified high-tier training should not reduce the body score\");\n        assertTrue(ham.weight != WeightClass.Obese, \"training on real work must not produce an Obese pet\");\n    }\n\n    function test_netBodyEffectTurnsNegativeOnceCertificationLagExceedsThreeDays() public {\n        vm.startPrank(alice);\n        uint256 id = nft.mint();\n        nft.feed{ value: 0.0003 ether }(id, 2);\n        nft.startTraining(id);\n        vm.stopPrank();\n        (, uint64 end,,) = nft.training(id);\n        // Lag of exactly four days after the window ended: idle 4 days (-20), hunger day 1 (-5), credit +16.\n        vm.warp(GENESIS + uint256(end) * 600 + 4 days);\n        core.certify(end, 2213);\n        nft.settleTraining(id);\n        assertGe(nft.hamster(id).bodyScore, 62, \"net effect of certified training is negative after 4 days of lag\");\n    }\n}","reproduction":"vm.warp to genesis + 2950*600 (round 2951, as live), Core frontier 1973. Alice: mint, feed(id,2) -> bodyScore 62, startTraining(id) -> books 2951..2956. +3 days: feed(id,2) reverts Locked. Core certifies through 2956 with 2213 work at end-of-window + 6d19h (today's lag); anyone calls settleTraining(id). Actual: stamina 8862 but bodyScore 28, weight Obese. Expected: a certified high-tier session leaves the body score at least where it started (>= 62, and not Obese). With a 4-day lag the result is 48 (< 62). See test/scratch/LagDecay.t.sol (both tests fail on current code).","severity":"medium","snippet":"        idleDays = (block.timestamp - clock.lastTrainAt) / 1 days;","title":"Body score keeps decaying 5/day idle + 5/day hunger while a pet is locked in Training and cannot be fed; at the live Core certification lag (~6.8 days) a high-tier session with large certified work en"}],"hash":"fc9afe74e3d70a7989e34feb7ab07c98adfdaa539311c3fec2aa8084652136f8","nodeId":"7336e281-174c-4e84-a764-ed843f50ae73","outcome":"completed","summary":"Review complete. Findings are in `.imd-findings.json` at the repository root (2 findings, 34 coverage rows: 29 holds, 4 finding, 1 unreached). The only files I created are that JSON and two scratch tests under `test/scratch/`, which is git-ignored.\n\n**What I found (both medium, both reproduced with failing Foundry tests)**\n\n- **Training gain scale breaks the kept MatchQueue bands.** `trainingGain` pays 2 stamina per Core work unit. I walked the live Sepolia SqueekCore ledger (331 records, frontier 1973): a six-round window carries up to 3344 work, p90 is 2213. One hour of training therefore adds 4000 to 13000 stamina to a pet that starts at 10, while bands are 25 wide. Two high-tier pets with 2213 vs 2000 certified work land in bands 354 and 320 and `requestRound` reverts with `NotEnoughPlayers`. Proof in `test/scratch/BandScale.t.sol`.\n- **Body decays while locked in Training during the Core certification wait.** Idle damage runs from `lastTrainAt`, which only moves at settlement, and `feed` requires Idle. Live Core lag today is about 978 rounds (6.8 days, nothing certified for a week). A tier-2 pet at body 62 that books now and settles when Core catches up with 2213 work ends at body 28, Obese, despite paying for and receiving full stamina. Net effect turns negative beyond roughly 3 days of lag. Proof in `test/scratch/LagDecay.t.sol`.\n\n**What held in my area**\n\n- Gain formula overflow-safe; 5000 bps gaps keep food tiers strictly ordered for any work ≥ 1; zero work yields zero.\n- Round derivation, uint64 guards, inclusive window, and `roundPage` validation match the live Core (afterRound exclusive, throughRound inclusive, certifiedThroughRound equals the request when records fit, reverts beyond frontier or maxRecords > 16). No zero-delta records exist on chain, so the strict `<=` check never falsely rejects today.\n- Body projection counters cannot underflow; hunger, TTL, blockhash and quota-week boundaries behave as DESIGN states; `raceScore` uses full-precision `mulDiv`.\n\n**Not reached:** whether Core's round numbering starts at genesis as DESIGN assumes. The public RPC had pruned the certification-era logs, so this stays an assumption.","treeHash":null,"usage":{"cachedInputTokens":1586006,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":43452,"runtime":"claude","turns":35,"wallClockMs":694948}}],"verification":[{"checks":[{"durationMs":18524,"exitCode":0,"name":"build","output":"Compiling 61 files with Solc 0.8.26\nSolc 0.8.26 finished in 18.27s\nCompiler run successful with warnings:\nWarning (5159): \"selfdestruct\" has been deprecated. Note that, starting from the Cancun hard fork, the underlying opcode no longer deletes the code and data associated with an account and only transfers its Ether to the beneficiary, unless executed in the same transaction in which the contract was created (see EIP-6780). Any use in newly deployed contracts is strongly discouraged even if the new behavior is taken into account. Future changes to the EVM might further reduce the functionality of the opcode.\n  --> test/helpers/Probes.sol:53:9:\n   |\n53 |         selfdestruct(to);\n   |         ^^^^^^^^^^^^\n\n","passed":true},{"durationMs":46496,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/CoreAbi.t.sol:CoreAbiTest\n[PASS] test_historicalWindowSettlesAgainstRawCertifiedCorePage() (gas: 655606)\n[PASS] test_publishedCoreV3AbiMatchesFinalizedSepoliaReadBytes() (gas: 83293)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 5.86ms (569.77µs CPU time)\n\nRan 5 tests for test/MathAndRandomness.t.sol:MathAndRandomnessTest\n[PASS] testFuzz_pairingIsPermutationAndRewardsConserve(uint8,bytes32) (runs: 512, μ: 5490057, ~: 4691849)\n[PASS] testFuzz_raceMathIsOrderedAndSafeAtFullWidth(uint256,uint16) (runs: 512, μ: 7919, ~: 7834)\n[PASS] test_exactRaceFormulaAndNoiseRange() (gas: 60445)\n[PASS] test_fulfillmentCallerAndTimestampCannotChooseResult() (gas: 2626629)\n[PASS] test_futureEntropyActuallyChangesPairingForLargerRoster() (gas: 24415821)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 413.99ms (761.92ms CPU time)\n\nRan 44 tests for test/QueueEdges.t.sol:QueueEdgesTest\n[PASS] testFuzz_exactlyOneResolutionPathExistsAtEveryBlock(uint16) (runs: 512, μ: 2031345, ~: 2188269)\nLogs:\n  Bound result 569\n\n[PASS] testFuzz_twoPlayerRoundMatchesThePinnedFormulas(bytes32) (runs: 512, μ: 2566794, ~: 2566579)\n[PASS] test_aBigStaminaLeadInsideABandOutweighsTheClassGap() (gas: 28146115)\n[PASS] test_anyCallerBuildsTheSameRoster() (gas: 2218585)\n[PASS] test_atEqualStaminaFitBeatsObeseUnderEveryHash() (gas: 49969094)\n[PASS] test_bandEdgesSeparateAt25AndPairInsideTheBand() (gas: 7141829)\n[PASS] test_byeIsSpreadAcrossTheRoster() (gas: 62164258)\n[PASS] test_constantsArePinnedToTheDocumentedValues() (gas: 115551)\n[PASS] test_emptyAndUnknownViewsBehave() (gas: 77593)\n[PASS] test_entriesBecomeLockableExactlyTenBlocksAfterJoining() (gas: 1874066)\n[PASS] test_evictionReportsExpiryAndTheOwnerKeepsThePet() (gas: 747428)\n[PASS] test_expiredOddRoundRefundsNobody() (gas: 2693023)\n[PASS] test_expiredRoundHasNoRacesAndHungryRacersRecoverToo() (gas: 2094548)\n[PASS] test_expiringAFullRosterStaysBoundedAndFreesEveryone() (gas: 25933175)\n[PASS] test_firstRewardFailureRollsBackJustAsTheSecondDoes() (gas: 7037033)\n[PASS] test_fitUsuallyBeatsNormalButTheNoiseKeepsItAContest() (gas: 93646247)\n[PASS] test_fiveExpiredRoundsExhaustTheWeekUntilItTurns() (gas: 7236800)\n[PASS] test_fullBandOfStaleEntriesBlocksEntryUntilOneIsEvicted() (gas: 25292515)\n[PASS] test_identicalLowStaminaPetsStillSplitWinsWhenScoresOftenTie() (gas: 97603655)\n[PASS] test_identicalPetsAreAFairCoinOverManyHashes() (gas: 97636691)\n[PASS] test_idlePetTransferredAwayDoesNotCarryTheWalletLock() (gas: 2497904)\n[PASS] test_leaveAndEvictRejectPetsThatAreNotWaiting() (gas: 2000057)\n[PASS] test_leavingIsAllowedAfterStalenessAndReportsAsVoluntary() (gas: 998243)\n[PASS] test_lockedRacersCannotImproveTheirSnapshotAndNewcomersCannotJoin() (gas: 2532009)\n[PASS] test_mixedStaleAndOddRosterLocksEveryEligiblePetAndLeavesOnlyTheNewcomer() (gas: 4677385)\n[PASS] test_nobodyCanJoinAndLockAgainstALoneWaiterInOneTransaction() (gas: 1507191)\n[PASS] test_normalUsuallyBeatsObeseButTheNoiseKeepsItAContest() (gas: 97644737)\n[PASS] test_oddRoundGivesTheShuffleChosenByeItsAttemptBack() (gas: 3633649)\n[PASS] test_oneFullBandLeavesOtherBandsOpen() (gas: 19105983)\n[PASS] test_oneWalletRacesOnePetAcrossAllBandsUntilSettled() (gas: 3550228)\n[PASS] test_onlyTheBoundQueueCanReleaseABye() (gas: 1766888)\n[PASS] test_pointsStayWithTheRacerAfterThePetIsSold() (gas: 2508863)\n[PASS] test_racesInOneRoundSettleInAnyOrderAndOnlyFreeTheirOwnPair() (gas: 4872407)\n[PASS] test_rejoiningRestartsTheWait() (gas: 1574164)\n[PASS] test_requestIncludesAPetAtExactFedUntilAndPrunesItOneSecondLater() (gas: 3115141)\n[PASS] test_requestIncludesAnEntryAtExactTtlAndPrunesItOneSecondLater() (gas: 1976791)\n[PASS] test_resultDependsOnlyOnTheTargetBlockHashAcrossTheWholeWindow() (gas: 3103339)\n[PASS] test_seedIsBoundToChainContractAndRound() (gas: 2585784)\n[PASS] test_settlementEmitsTheOutcomeAndPointsTotals() (gas: 2444767)\n[PASS] test_settlingYearsLaterChangesNothingAboutTheRaceOrItsWeek() (gas: 2657686)\n[PASS] test_shuffleReachesEveryOpponentAboutEvenly() (gas: 124374169)\n[PASS] test_snapshotUsesWeightAtRoundLockNotAtEnqueue() (gas: 6291091)\n[PASS] test_snapshotWeightDecidesEvenIfTheLivePetWentDownhillAfterLock() (gas: 6817344)\n[PASS] test_trainingPetCannotEnterAndTheFailedEntryLeavesNoTrace() (gas: 768146)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 423.58ms (994.95ms CPU time)\n\nRan 9 tests for test/CertifiedWorkOracle.t.sol:CertifiedWorkOracleTest\n[PASS] testFuzz_settleTimingAndCallerNeverChangeStamina(uint32,address) (runs: 512, μ: 1436341, ~: 1428623)\nLogs:\n  Bound result 1200\n\n[PASS] testFuzz_settledGainEqualsIndependentLedgerSum(uint256,uint16,uint16,uint8,uint8) (runs: 512, μ: 3231600, ~: 3108054)\nLogs:\n  Bound result 3\n  Bound result 107\n  Bound result 24\n\n[PASS] test_frontierExactlyAtEndSettlesAndOneShortDoesNot() (gas: 1792758)\n[PASS] test_hungryBoundaryForBooking() (gas: 676060)\n[PASS] test_mintFeedTrainSettleThenRaceEndToEnd() (gas: 3434455)\n[PASS] test_nonexistentTokenCannotBeBookedSettledOrPreviewed() (gas: 113515)\n[PASS] test_onlyTheHolderStartsOrCancelsNotOperatorsOrStrangers() (gas: 796373)\n[PASS] test_settleIsOnceOnlyAndCancelledBookingsCannotBeSettled() (gas: 2543778)\n[PASS] test_trainingAndQueueLocksExcludeEachOther() (gas: 1511231)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 423.87ms (687.73ms CPU time)\n\nRan 12 tests for test/NFTAdmin.t.sol:NFTAdminTest\n[PASS] test_adminConfigurationAccessAndBounds() (gas: 650102)\n[PASS] test_erc721InterfacesMetadataAndApprovedTransfer() (gas: 568509)\n[PASS] test_mintClosedByDefaultAndOnlyOwnerCanOpen() (gas: 385337)\n[PASS] test_oneFreeMintPerWalletSurvivesTransfers() (gas: 637623)\n[PASS] test_ownerMintWorksWhileClosedButCannotMintToZero() (gas: 516717)\n[PASS] test_ownershipUsesTwoStepAndCannotRenounce() (gas: 194415)\n[PASS] test_queueMustBeConfiguredOnceAndBoundToThisNFT() (gas: 958307)\n[PASS] test_queueOnlyMethodsRejectDirectUsersAndOwner() (gas: 522571)\n[PASS] test_safeMintReceiverCannotReenterAndRejectionRollsBack() (gas: 960667)\n[PASS] test_supplyExactly9999AcrossOwnerAndFreeMints() (gas: 639976)\n[PASS] test_withdrawConservesProceedsAndOnlyPaysOwner() (gas: 889603)\n[PASS] test_withdrawRejectingOwnerRollsBackAndReentryFails() (gas: 823441)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 597.71ms (593.05ms CPU time)\n\nRan 23 tests for test/MatchQueue.t.sol:MatchQueueTest\n[PASS] test_cannotEnqueueAndLockInOneTransaction() (gas: 2500957)\n[PASS] test_cannotEnqueueOthersDuplicateOrTwoPetsForOneWallet() (gas: 1363726)\n[PASS] test_distinctStaminaBandsCannotPair() (gas: 1839290)\n[PASS] test_eligibilityIsPerEntryAndSurvivesSwapRemoval() (gas: 2554397)\n[PASS] test_endToEndMintFeedTrainQueueRandomMatchSettle() (gas: 3428881)\n[PASS] test_expiredOddRoundReleasesEveryoneAndNobodyIsRefunded() (gas: 2625781)\n[PASS] test_expiredRandomnessReleasesBothPetsWithoutRewardAndRetainsQuota() (gas: 2967285)\n[PASS] test_failedRewardRollsBackBothStaminaAndPointsAtomically() (gas: 7372590)\n[PASS] test_fullQueueBoundAndMaximumRoundGas() (gas: 33309048)\nLogs:\n  32-player round lock gas: 6522986\n  32-player round fulfill gas: 5143941\n\n[PASS] test_invalidIdsCannotCreateStateOrRewards() (gas: 135732)\n[PASS] test_lastRandomnessBlockIsUsableAndCannotExpireEarly() (gas: 2414544)\n[PASS] test_leaveMiddleEntryRepairsPositionAndDoesNotConsumeQuota() (gas: 1967934)\n[PASS] test_multipleRoundsInSameBandDoNotInterfere() (gas: 4777619)\n[PASS] test_oddRosterLocksEveryoneAndEntropyChoosesTheBye() (gas: 17183340)\n[PASS] test_queueAndMatchLocksPreventTransfersFeedingTrainingAndCancellation() (gas: 2782503)\n[PASS] test_queueQuotaUsesLockWeekAcrossWeekBoundary() (gas: 1688839)\n[PASS] test_queueTTLAndHungryExpiryCanBeEvictedPermissionlessly() (gas: 1302613)\n[PASS] test_randomnessCannotUseCurrentFutureOrZeroHash() (gas: 2227131)\n[PASS] test_requestLocksWholeEligibleRosterSoLateEntrantCannotFlushTheQueue() (gas: 3220485)\n[PASS] test_requestPrunesStaleEntriesWithoutBlockingHealthyPair() (gas: 2374336)\n[PASS] test_staleOnlyRequestCanBeRecoveredByExplicitEviction() (gas: 1648647)\n[PASS] test_weeklyQuotaIsPerNFTAndSettlementCreditsLockWeek() (gas: 11741878)\n[PASS] test_weightChangesActualRaceOutcomeWithEqualStamina() (gas: 2953475)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 602.65ms (76.57ms CPU time)\n\nRan 25 tests for test/CoreTraining.t.sol:CoreTrainingTest\n[PASS] testFuzz_everyAcceptedBpsConfigStrictlyOrdersPositiveWork(uint64,uint16,uint16,uint16) (runs: 512, μ: 84437, ~: 84632)\nLogs:\n  Bound result 30116\n  Bound result 39545\n  Bound result 48774\n\n[PASS] testFuzz_gainIsExactlyCertifiedWorkTimesCapturedTier(uint64,uint8) (runs: 512, μ: 870890, ~: 884908)\n[PASS] testFuzz_gainIsMonotonicAndRoundingIsDown(uint64,uint16) (runs: 512, μ: 5690, ~: 5700)\n[PASS] testFuzz_malformedPageCannotPartiallyCreditOrUnlock(uint8) (runs: 512, μ: 865987, ~: 865280)\n[PASS] testFuzz_startBooksSixInclusiveRoundsAndCapturesFood(uint16,uint8) (runs: 512, μ: 586668, ~: 597044)\n[PASS] test_approvedSafeTransfersCannotBypassTrainingLock() (gas: 611186)\n[PASS] test_badConfigStopsNewBookingsButCannotTrapOldWork() (gas: 953430)\n[PASS] test_cancelRemainsAvailableWhenCoreDisappears() (gas: 729250)\n[PASS] test_certifiedZeroWorkUnlocksWithoutHealthOrClockReward() (gas: 1030416)\n[PASS] test_configWithCollapsingTierRoundingIsRejected() (gas: 63696)\n[PASS] test_corePauseDoesNotInvalidatePreviouslyCertifiedWork() (gas: 981457)\n[PASS] test_currentRoundUsesCoreGenesisAndOneBasedRounds() (gas: 124854)\n[PASS] test_elapsedTimeAloneNeverSettlesOrCreatesAGain() (gas: 823130)\n[PASS] test_emptyChainConstructorThenClearFirstUseError() (gas: 412611)\n[PASS] test_invalidReadWindowsRevert() (gas: 69723)\n[PASS] test_nextWindowCannotReplayAlreadyCreditedRounds() (gas: 1171669)\n[PASS] test_oneUnitStrictlyOrdersAllDefaultFoodTiers() (gas: 2013918)\n[PASS] test_onlyBookedWorkCountsEvenWithBacklogAndLaterCertification() (gas: 1103080)\n[PASS] test_overlappingPetsUseTheirOwnExactWindow() (gas: 1589139)\n[PASS] test_partialCertificationCannotCashOutEvenNonzeroWork() (gas: 984308)\n[PASS] test_previewCannotInventWorkForAnIdleToken() (gas: 393618)\n[PASS] test_roundAndWindowOverflowAreExplicit() (gas: 466959)\n[PASS] test_roundOneReadsLaunchPositionWithoutUnderflow() (gas: 885301)\n[PASS] test_sixActiveRoundsFitOneCompletePage() (gas: 1168532)\n[PASS] test_unavailableStateOrPageNeverFallsBackToTime() (gas: 966414)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 603.11ms (1.72s CPU time)\n\nRan 3 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_constructorsDoNotNeedDependenciesToExist() (gas: 12863)\n[PASS] test_factoryDeploymentsHaveExplicitOwnerAndNoForbiddenRuntime() (gas: 30330760)\n[PASS] test_scriptsUseArgumentsAndRejectOtherChains() (gas: 13264571)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 603.37ms (104.10ms CPU time)\n\nRan 31 tests for test/CareEdges.t.sol:CareEdgesTest\n[PASS] testFuzz_betterScoreNeverGivesAWorseClass(uint8) (runs: 512, μ: 7119, ~: 6972)\nLogs:\n  Bound result 56\n\n[PASS] testFuzz_feedAlwaysSetsDeadlineFromNowAndNeverShortensIt(uint8,uint8,uint32) (runs: 512, μ: 552334, ~: 549754)\nLogs:\n  Bound result 1\n  Bound result 0\n  Bound result 1\n\n[PASS] testFuzz_feedingAnywhereInTheNewbornWindowCostsOnlyIdleDays(uint32,uint8) (runs: 512, μ: 409278, ~: 407281)\nLogs:\n  Bound result 1\n  Bound result 2960\n\n[PASS] testFuzz_hungryExactlyAfterTheDeadline(uint32) (runs: 512, μ: 386751, ~: 386568)\nLogs:\n  Bound result 62\n\n[PASS] testFuzz_lowFoodAloneNeverMakesAPetFit(uint8) (runs: 512, μ: 5976245, ~: 5205554)\nLogs:\n  Bound result 13\n\n[PASS] testFuzz_neglectIsPathIndependentAndIdempotent(uint8,uint32,uint32) (runs: 512, μ: 591008, ~: 595059)\nLogs:\n  Bound result 163891\n  Bound result 1\n  Bound result 0\n\n[PASS] testFuzz_nonexistentPetsRevertEverywhere(uint256) (runs: 512, μ: 304561, ~: 299204)\nLogs:\n  Bound result 50001\n\n[PASS] testFuzz_scoreNeverRisesFromTimeAlone(uint8,uint32,uint32) (runs: 512, μ: 445925, ~: 448015)\nLogs:\n  Bound result 0\n  Bound result 163891\n  Bound result 1\n\n[PASS] test_aFitPetOnACheapDietTrainingDailyDriftsToNormalNotBelow() (gas: 38364253)\n[PASS] test_cancelDoesNotResetTheIdleClockButSettlingDoes() (gas: 1456229)\n[PASS] test_cancelledTrainingCreditsNothingAndCannotBeReplayed() (gas: 906838)\n[PASS] test_cheaperRefeedDowngradesTheNextTrainingBonus() (gas: 825222)\n[PASS] test_feedingOneSecondAfterTheNewbornWindowPaysOneHungerDay() (gas: 422270)\n[PASS] test_feedingStopsHungerDamageButNeverRefundsIdleDamage() (gas: 661500)\n[PASS] test_largerWorkEarnsMoreBodyCreditOnlyUpToTheDocumentedCap() (gas: 2256504)\n[PASS] test_longNeglectSaturatesAtZeroAndFoodRecoversFromThere() (gas: 695877)\n[PASS] test_lowFoodTrainingStopsAtTheCeilingOfSixty() (gas: 7626885)\n[PASS] test_midFoodTrainingPassesSixtyAndReachesFit() (gas: 5379917)\n[PASS] test_newbornNeglectFollowsThePinnedSchedule() (gas: 579890)\n[PASS] test_operatorsMayMoveAPetButNeverPlayIt() (gas: 669466)\n[PASS] test_paymentRaisedOrLoweredInTheSameBlockNeverOverOrUndercharges() (gas: 469992)\n[PASS] test_rejectedFeedLeavesEveryFieldUntouched() (gas: 633102)\n[PASS] test_repeatedFoodSaturatesBothEndsOfTheBodyRange() (gas: 2095296)\n[PASS] test_settleAndCancelRejectEveryNonTrainingActivity() (gas: 1879970)\n[PASS] test_startingOnTheLastFedSecondSettlesAfterExpiry() (gas: 899469)\n[PASS] test_storedEnumFollowsTheScoreAcrossBoundariesInBothDirections() (gas: 11739326)\n[PASS] test_trainedPetsRankByFoodTierAndBeatUntrainedOnes() (gas: 1849054)\n[PASS] test_trainingAtFullStaminaWidthKeepsGrowingUntilArithmeticStops() (gas: 5746057)\n[PASS] test_transferKeepsAllCareStateAndGivesNoReset() (gas: 1156798)\n[PASS] test_weightClassBoundariesArePinned() (gas: 5914)\n[PASS] test_withoutTrainingEveryFoodRegimeDriftsDownInTierOrder() (gas: 2694338)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 603.64ms (2.90s CPU time)\n\nRan 29 tests for test/NFTGuards.t.sol:NFTGuardsTest\n[PASS] testFuzz_foodConfigAcceptedExactlyWhenStrictlyOrderedAndInBounds(uint256[3],uint256[3]) (runs: 512, μ: 74284, ~: 74095)\nLogs:\n  Bound result 1\n  Bound result 0\n  Bound result 3\n  Bound result 10001\n  Bound result 15000\n\n[PASS] testFuzz_withdrawPaysExactlyTheRequestedAmountOrFails(uint256) (runs: 512, μ: 763321, ~: 764516)\nLogs:\n  Bound result 62\n\n[PASS] test_aSecondQueueAimedAtABoundCollectionGetsNowhere() (gas: 925425)\n[PASS] test_approvalsSetDuringALockCannotMoveThePetUntilItUnlocks() (gas: 909043)\n[PASS] test_bindingRejectsEveryQueueThatDoesNotNameThisCollection() (gas: 348049)\n[PASS] test_boundQueueCanNeverBeReplacedEvenByOwnerOrNextOwner() (gas: 482755)\n[PASS] test_directCallsFromNeitherOwnerNorPlayerCanMoveALockedPet() (gas: 909633)\n[PASS] test_everyQueueMethodFailsBeforeBinding() (gas: 402564)\n[PASS] test_feesFollowOwnershipOnlyAfterAcceptance() (gas: 588783)\n[PASS] test_forcedEthIsWithdrawableAndCreatesNoEntitlement() (gas: 139827)\n[PASS] test_lockMatchAppliesNeglectBeforeTheSnapshot() (gas: 649622)\n[PASS] test_lockMatchGuardsAndReturnsTheLiveSnapshot() (gas: 1081544)\n[PASS] test_lockQueueGuards() (gas: 747334)\n[PASS] test_lockQueueRefusesATrainingPet() (gas: 527037)\n[PASS] test_mintCallbackHitsTheGuardOnEveryGameEntry() (gas: 1056086)\n[PASS] test_mintWindowReopensButNeverRefundsTheAllocation() (gas: 650635)\n[PASS] test_mintingContractThatMovesThePetAwayStillUsedItsAllocation() (gas: 1114384)\n[PASS] test_noContractAcceptsPlainEthAndNonpayableEntriesRefuseValue() (gas: 552651)\n[PASS] test_ownerMintedPetsLeaveTheRecipientsFreeMintAvailable() (gas: 549578)\n[PASS] test_pendingHandoverCanBeCancelledWithTheZeroAddress() (gas: 133181)\n[PASS] test_petEnteredOnItsLastAttemptCanStillLockAfterTheWeekTurns() (gas: 1353989)\n[PASS] test_quotaCountsLocksNotEntriesAndResetsOnlyOnANewWeek() (gas: 2489095)\n[PASS] test_receiverActingInsideASafeTransferStaysBoundByTheLock() (gas: 1034526)\n[PASS] test_renounceFailsForEveryCallerAndChangesNothing() (gas: 39094)\n[PASS] test_rewardCreditsOnceAndOnlyTheDocumentedAmount() (gas: 1283816)\n[PASS] test_tokenUriIsTheExactDocumentAndProjectsNeglect() (gas: 724886)\n[PASS] test_transferFailuresDoNotMoveThePet() (gas: 519432)\n[PASS] test_unlockExpireAndRewardOnlyAcceptTheirOwnActivity() (gas: 938619)\n[PASS] test_withdrawOnAnEmptyContractFails() (gas: 39476)\nSuite result: ok. 29 passed; 0 failed; 0 skipped; finished in 604.47ms (252.55ms CPU time)\n\nRan 20 tests for test/Care.t.sol:CareTest\n[PASS] testFuzz_feedRequiresExactTierPrice(uint8,uint96) (runs: 512, μ: 340679, ~: 340889)\nLogs:\n  Bound result 0\n  Bound result 65\n\n[PASS] test_allTiersFeedAndGiveDistinctTrainingBonus() (gas: 2416125)\n[PASS] test_feedResetsRatherThanStacksAndExactExpiryIsFed() (gas: 571024)\n[PASS] test_fitPetSwitchedToCheapFoodDriftsDownToNormal() (gas: 11791843)\n[PASS] test_hungryGatesTrainingAndQueue() (gas: 1271578)\n[PASS] test_inactivityAndHungerPenaltiesAreNotResetByFrequentTouches() (gas: 1953454)\n[PASS] test_invalidTierAndNonOwnerFeedFail() (gas: 429773)\n[PASS] test_lateTrainingSettlementStillUnlocksAndAccountsNeglect() (gas: 975855)\n[PASS] test_lowFoodOnlyTrainingNeverMakesAPetFit() (gas: 627974007)\n[PASS] test_newbornTakesNoHungerDamageDuringItsFirstFeedWindow() (gas: 1487518)\n[PASS] test_staminaGrowsFarBeyondSmallIntegerLimits() (gas: 5213824)\n[PASS] test_startingStatsAndFeedDefaults() (gas: 375429)\n[PASS] test_sustainedHighFoodWithoutTrainingStillDriftsTowardObese() (gas: 1612354)\n[PASS] test_tierBonusStaysStrictlyOrderedAtHighStamina() (gas: 6851024)\n[PASS] test_trainingCanStartAtFeedExpiryAndSettleAfterCertification() (gas: 893492)\n[PASS] test_trainingCancellationGivesNoRewardAndCannotBeForced() (gas: 1104257)\n[PASS] test_trainingConfigIsSnapshottedAtFeedAndStart() (gas: 1145572)\n[PASS] test_trainingLocksAllActionsAndSettlesExactlyOnce() (gas: 1328729)\n[PASS] test_uint256OverflowRevertsWithoutWrappingAndTrainingCanCancel() (gas: 5289236)\n[PASS] test_weightTransitionsThroughObeseNormalFitAndNeglect() (gas: 2111490)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.00s (1.01s CPU time)\n\nRan 2 tests for test/CertifiedWorkOracle.t.sol:TrainingOracleInvariantTest\n[PASS]\nTrainingOracleInvariantTest invariants:\n[PASS] invariant_bookingRecordMatchesTrainingLockAndStatus\n[PASS] invariant_feeRevenueIsConserved\n[PASS] invariant_staminaIsExactlyCertifiedLedgerWorkTimesFood\n TrainingOracleInvariantTest invariants (runs: 64, calls: 4096, reverts: 0)\n\n╭-----------------------+----------+-------+---------+----------╮\n| Contract              | Selector | Calls | Reverts | Discards |\n+===============================================================+\n| TrainingOracleHandler | advance  | 614   | 0       | 0        |\n|-----------------------+----------+-------+---------+----------|\n| TrainingOracleHandler | cancel   | 576   | 0       | 0        |\n|-----------------------+----------+-------+---------+----------|\n| TrainingOracleHandler | certify  | 618   | 0       | 0        |\n|-----------------------+----------+-------+---------+----------|\n| TrainingOracleHandler | feed     | 563   | 0       | 0        |\n|-----------------------+----------+-------+---------+----------|\n| TrainingOracleHandler | settle   | 567   | 0       | 0        |\n|-----------------------+----------+-------+---------+----------|\n| TrainingOracleHandler | start    | 580   | 0       | 0        |\n|-----------------------+----------+-------+---------+----------|\n| TrainingOracleHandler | withdraw | 578   | 0       | 0        |\n╰-----------------------+----------+-------+---------+----------╯\n\n[PASS] test_seededWalkReachesLagSettleAndCancel() (gas: 413344975)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 3.30s (3.80s CPU time)\n\nRan 1 test for test/Invariants.t.sol:GameInvariantTest\n[PASS]\nGameInvariantTest invariants:\n[PASS] invariant_bodySupplyQuotaAndLocksStayConsistent\n[PASS] invariant_ethConservation\n[PASS] invariant_pointsAndStaminaHaveOnlyEarnedSources\n GameInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-------------+----------------+-------+---------+----------╮\n| Contract    | Selector       | Calls | Reverts | Discards |\n+===========================================================+\n| GameHandler | advance        | 1033  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | cancelTraining | 1013  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | enqueueOrLeave | 1010  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | feed           | 1054  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | request        | 1024  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | resolve        | 1083  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | trainOrClaim   | 1020  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | withdraw       | 955   | 0       | 0        |\n╰-------------+----------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 13.09s (13.08s CPU time)\n\nRan 3 tests for test/StatefulInvariants.t.sol:StatefulInvariantsTest\n[PASS]\nStatefulInvariantsTest invariants:\n[PASS] invariant_bodyAndFoodStayInRange\n[PASS] invariant_ethInEqualsEthHeldPlusEthWithdrawn\n[PASS] invariant_lockedActivityMatchesItsBackingRecord\n[PASS] invariant_pointsComeOnlyFromSettledRaces\n[PASS] invariant_queueAndActivityDescribeTheSameThing\n[PASS] invariant_roundsAndRacesNeverLeaveAFinishedState\n[PASS] invariant_staminaComesOnlyFromTrainingAndRaces\n[PASS] invariant_supplyIsExactlyWhatWasMinted\n[PASS] invariant_walletLockMatchesTheOnePetItNames\n StatefulInvariantsTest invariants (runs: 96, calls: 9216, reverts: 0)\n\n╭--------------+----------------+-------+---------+----------╮\n| Contract     | Selector       | Calls | Reverts | Discards |\n+============================================================+\n| WorldHandler | advanceBlocks  | 494   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | advanceTime    | 432   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | cancelTraining | 449   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | enqueue        | 478   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | evict          | 465   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | expireRound    | 431   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | feed           | 512   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | feedBadly      | 461   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | forceEth       | 457   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | fulfillRound   | 482   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | leaveQueue     | 472   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | rally          | 453   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | requestRound   | 449   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | setFoodConfig  | 435   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | settleMatch    | 467   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | settleTraining | 464   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | startTraining  | 450   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | strangerProbes | 488   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | transferPet    | 440   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | withdraw       | 437   | 0       | 0        |\n╰--------------+----------------+-------+---------+----------╯\n\n[PASS] test_freeMintsKeepTheSupplyAndAllocationLedgers() (gas: 9239104)\n[PASS] test_seededWalkReachesEveryOutcomeAndKeepsEveryInvariant() (gas: 323738674)\nLogs:\n  feedOk: 26\n  feedLocked: 30\n  feedRefused: 65\n  trainOk: 14\n  trainRefused: 48\n  settleTrainingOk: 5\n  settleTrainingRefused: 53\n  cancelOk: 9\n  enqueueOk: 21\n  enqueueRefused: 43\n  leaveOk: 5\n  evictOk: 5\n  requestOk: 4\n  rallyOk: 16\n  requestRefused: 65\n  fulfillOk: 15\n  expireOk: 4\n  settleMatchOk: 18\n  transferOk: 27\n  transferLocked: 23\n  withdrawOk: 37\n  forceOk: 48\n  configOk: 77\n  strangerRefused: 59\n  byeOk: 3\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 46.20s (46.67s CPU time)\n\nRan 14 test suites in 46.21s (68.48s CPU time): 209 tests passed, 0 failed, 0 skipped (209 total tests)\n","passed":true},{"durationMs":185,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"HamsterRunNFT.acceptOwnership()\",\"HamsterRunNFT.approve(address,uint256)\",\"HamsterRunNFT.cancelTraining(uint256)\",\"HamsterRunNFT.expireMatchLock(uint256)\",\"HamsterRunNFT.feed(uint256,uint8)\",\"HamsterRunNFT.lockMatch(uint256)\",\"HamsterRunNFT.lockQueue(uint256,address)\",\"HamsterRunNFT.mint()\",\"HamsterRunNFT.ownerMint(address)\",\"HamsterRunNFT.releaseBye(uint256)\",\"HamsterRunNFT.rewardMatch(uint256,bool)\",\"HamsterRunNFT.safeTransferFrom(address,address,uint256)\",\"HamsterRunNFT.safeTransferFrom(address,address,uint256,bytes)\",\"HamsterRunNFT.setApprovalForAll(address,bool)\",\"HamsterRunNFT.setFoodConfig(uint256[3],uint256[3])\",\"HamsterRunNFT.setMatchQueue(address)\",\"HamsterRunNFT.setMintOpen(bool)\",\"HamsterRunNFT.settleTraining(uint256)\",\"HamsterRunNFT.startTraining(uint256)\",\"HamsterRunNFT.transferFrom(address,address,uint256)\",\"HamsterRunNFT.transferOwnership(address)\",\"HamsterRunNFT.unlockQueue(uint256)\",\"HamsterRunNFT.withdraw(uint256)\",\"MatchQueue.enqueue(uint256)\",\"MatchQueue.evictExpired(uint256)\",\"MatchQueue.expireRound(uint256)\",\"MatchQueue.fulfillRound(uint256)\",\"MatchQueue.leaveQueue(uint256)\",\"MatchQueue.requestRound(uint256)\",\"MatchQueue.settleMatch(uint256)\"],\"files\":{\".gitignore\":3,\"DESIGN.md\":155,\"LICENSE\":21,\"README.md\":121,\"SECURITY.md\":57,\"abi/HamsterRunNFT.json\":1830,\"abi/ISqueekCore.json\":239,\"abi/MatchQueue.json\":999,\"abi/SHA256.json\":6,\"abi/SqueekCore.upstream.json\":902,\"dependencies.json\":18,\"deployments/sepolia-v2.json\":11,\"deployments/sepolia.json\":30,\"docs/PROVENANCE.md\":22,\"docs/VALIDATION.md\":45,\"docs/core-sepolia-snapshot.json\":28,\"foundry.toml\":27,\"remappings.txt\":2,\"script/Deploy.s.sol\":28,\"src/CoreReader.sol\":86,\"src/GameMath.sol\":44,\"src/HamsterRunNFT.sol\":466,\"src/MatchQueue.sol\":361,\"src/PointsLedger.sol\":18,\"src/interfaces/ISqueekCore.sol\":58,\"test/Care.t.sol\":366,\"test/CareEdges.t.sol\":554,\"test/CertifiedWorkOracle.t.sol\":470,\"test/CoreAbi.t.sol\":65,\"test/CoreTraining.t.sol\":391,\"test/Deployment.t.sol\":103,\"test/Invariants.t.sol\":219,\"test/MatchQueue.t.sol\":604,\"test/MathAndRandomness.t.sol\":122,\"test/NFTAdmin.t.sol\":297,\"test/NFTGuards.t.sol\":568,\"test/QueueEdges.t.sol\":965,\"test/StatefulInvariants.t.sol\":1153,\"test/Tools.test.mjs\":129,\"test/helpers/GameTest.sol\":119,\"test/helpers/MockSqueekCore.sol\":109,\"test/helpers/Probes.sol\":115,\"tools/export-abis.mjs\":39,\"tools/record-deployment.mjs\":89,\"tools/rpc.mjs\":55,\"tools/training-status.mjs\":36},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"0b26a086706c85456adb2436e2b85ee2814f41bb57828b28f243cfa8d49c2c8b","verifiedTreeHash":"4199aa39fb9ce438d4011b0a487d041d145fea1c","verifierVersion":"0.1.0+3dcb4df2"},{"checks":[{"durationMs":21192,"exitCode":0,"name":"build","output":"Compiling 62 files with Solc 0.8.26\nSolc 0.8.26 finished in 20.97s\nCompiler run successful with warnings:\nWarning (5159): \"selfdestruct\" has been deprecated. Note that, starting from the Cancun hard fork, the underlying opcode no longer deletes the code and data associated with an account and only transfers its Ether to the beneficiary, unless executed in the same transaction in which the contract was created (see EIP-6780). Any use in newly deployed contracts is strongly discouraged even if the new behavior is taken into account. Future changes to the EVM might further reduce the functionality of the opcode.\n  --> test/helpers/Probes.sol:53:9:\n   |\n53 |         selfdestruct(to);\n   |         ^^^^^^^^^^^^\n\n","passed":true},{"durationMs":47133,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/CoreAbi.t.sol:CoreAbiTest\n[PASS] test_historicalWindowSettlesAgainstRawCertifiedCorePage() (gas: 672527)\n[PASS] test_publishedCoreV3AbiMatchesFinalizedSepoliaReadBytes() (gas: 83293)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 2.40ms (761.18µs CPU time)\n\nRan 23 tests for test/MatchQueue.t.sol:MatchQueueTest\n[PASS] test_cannotEnqueueAndLockInOneTransaction() (gas: 2507905)\n[PASS] test_cannotEnqueueOthersDuplicateOrTwoPetsForOneWallet() (gas: 1369718)\n[PASS] test_distinctStaminaBandsCannotPair() (gas: 6000877)\n[PASS] test_eligibilityIsPerEntryAndSurvivesSwapRemoval() (gas: 2563712)\n[PASS] test_endToEndMintFeedTrainQueueRandomMatchSettle() (gas: 3430825)\n[PASS] test_expiredOddRoundReleasesEveryoneAndNobodyIsRefunded() (gas: 2635833)\n[PASS] test_expiredRandomnessReleasesBothPetsWithoutRewardAndRetainsQuota() (gas: 2976243)\n[PASS] test_failedRewardRollsBackBothStaminaAndPointsAtomically() (gas: 7446552)\n[PASS] test_fullQueueBoundAndMaximumRoundGas() (gas: 33417208)\nLogs:\n  32-player round lock gas: 6529088\n  32-player round fulfill gas: 5143941\n\n[PASS] test_invalidIdsCannotCreateStateOrRewards() (gas: 135776)\n[PASS] test_lastRandomnessBlockIsUsableAndCannotExpireEarly() (gas: 2421382)\n[PASS] test_leaveMiddleEntryRepairsPositionAndDoesNotConsumeQuota() (gas: 1977017)\n[PASS] test_multipleRoundsInSameBandDoNotInterfere() (gas: 4791295)\n[PASS] test_oddRosterLocksEveryoneAndEntropyChoosesTheBye() (gas: 17212162)\n[PASS] test_queueAndMatchLocksPreventTransfersFeedingTrainingAndCancellation() (gas: 2789457)\n[PASS] test_queueQuotaUsesLockWeekAcrossWeekBoundary() (gas: 1695041)\n[PASS] test_queueTTLAndHungryExpiryCanBeEvictedPermissionlessly() (gas: 1306678)\n[PASS] test_randomnessCannotUseCurrentFutureOrZeroHash() (gas: 2233589)\n[PASS] test_requestLocksWholeEligibleRosterSoLateEntrantCannotFlushTheQueue() (gas: 3232977)\n[PASS] test_requestPrunesStaleEntriesWithoutBlockingHealthyPair() (gas: 2383774)\n[PASS] test_staleOnlyRequestCanBeRecoveredByExplicitEviction() (gas: 1655231)\n[PASS] test_weeklyQuotaIsPerNFTAndSettlementCreditsLockWeek() (gas: 11753028)\n[PASS] test_weightChangesActualRaceOutcomeWithEqualStamina() (gas: 2961811)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 138.73ms (135.55ms CPU time)\n\nRan 25 tests for test/CoreTraining.t.sol:CoreTrainingTest\n[PASS] testFuzz_everyAcceptedBpsConfigStrictlyOrdersPositiveWork(uint64,uint16,uint16,uint16) (runs: 512, μ: 84445, ~: 84956)\nLogs:\n  Bound result 30116\n  Bound result 39545\n  Bound result 48774\n\n[PASS] testFuzz_gainIsExactlyCertifiedWorkTimesCapturedTier(uint64,uint8) (runs: 512, μ: 898392, ~: 912211)\n[PASS] testFuzz_gainIsMonotonicAndRoundingIsDown(uint64,uint16) (runs: 512, μ: 5691, ~: 5700)\n[PASS] testFuzz_malformedPageCannotPartiallyCreditOrUnlock(uint8) (runs: 512, μ: 895255, ~: 894669)\n[PASS] testFuzz_startBooksSixInclusiveRoundsAndCapturesFood(uint16,uint8) (runs: 512, μ: 615906, ~: 626433)\n[PASS] test_approvedSafeTransfersCannotBypassTrainingLock() (gas: 636001)\n[PASS] test_badConfigStopsNewBookingsButCannotTrapOldWork() (gas: 980733)\n[PASS] test_cancelRemainsAvailableWhenCoreDisappears() (gas: 756742)\n[PASS] test_certifiedZeroWorkUnlocksWithoutHealthOrClockReward() (gas: 1094380)\n[PASS] test_configWithCollapsingTierRoundingIsRejected() (gas: 63696)\n[PASS] test_corePauseDoesNotInvalidatePreviouslyCertifiedWork() (gas: 1008760)\n[PASS] test_currentRoundUsesCoreGenesisAndOneBasedRounds() (gas: 124854)\n[PASS] test_elapsedTimeAloneNeverSettlesOrCreatesAGain() (gas: 841135)\n[PASS] test_emptyChainConstructorThenClearFirstUseError() (gas: 415255)\n[PASS] test_invalidReadWindowsRevert() (gas: 69723)\n[PASS] test_nextWindowCannotReplayAlreadyCreditedRounds() (gas: 1209904)\n[PASS] test_oneUnitStrictlyOrdersAllDefaultFoodTiers() (gas: 2095827)\n[PASS] test_onlyBookedWorkCountsEvenWithBacklogAndLaterCertification() (gas: 1130383)\n[PASS] test_overlappingPetsUseTheirOwnExactWindow() (gas: 1643745)\n[PASS] test_partialCertificationCannotCashOutEvenNonzeroWork() (gas: 1013898)\n[PASS] test_previewCannotInventWorkForAnIdleToken() (gas: 396072)\n[PASS] test_roundAndWindowOverflowAreExplicit() (gas: 469413)\n[PASS] test_roundOneReadsLaunchPositionWithoutUnderflow() (gas: 912604)\n[PASS] test_sixActiveRoundsFitOneCompletePage() (gas: 1195835)\n[PASS] test_unavailableStateOrPageNeverFallsBackToTime() (gas: 996004)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 476.15ms (612.72ms CPU time)\n\nRan 29 tests for test/NFTGuards.t.sol:NFTGuardsTest\n[PASS] testFuzz_foodConfigAcceptedExactlyWhenStrictlyOrderedAndInBounds(uint256[3],uint256[3]) (runs: 512, μ: 74277, ~: 74083)\nLogs:\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 9999\n  Bound result 15000\n\n[PASS] testFuzz_withdrawPaysExactlyTheRequestedAmountOrFails(uint256) (runs: 512, μ: 768301, ~: 769424)\nLogs:\n  Bound result 30\n\n[PASS] test_aSecondQueueAimedAtABoundCollectionGetsNowhere() (gas: 928837)\n[PASS] test_approvalsSetDuringALockCannotMoveThePetUntilItUnlocks() (gas: 912303)\n[PASS] test_bindingRejectsEveryQueueThatDoesNotNameThisCollection() (gas: 348049)\n[PASS] test_boundQueueCanNeverBeReplacedEvenByOwnerOrNextOwner() (gas: 482755)\n[PASS] test_directCallsFromNeitherOwnerNorPlayerCanMoveALockedPet() (gas: 912723)\n[PASS] test_everyQueueMethodFailsBeforeBinding() (gas: 404797)\n[PASS] test_feesFollowOwnershipOnlyAfterAcceptance() (gas: 591237)\n[PASS] test_forcedEthIsWithdrawableAndCreatesNoEntitlement() (gas: 139827)\n[PASS] test_lockMatchAppliesNeglectBeforeTheSnapshot() (gas: 653026)\n[PASS] test_lockMatchGuardsAndReturnsTheLiveSnapshot() (gas: 1087402)\n[PASS] test_lockQueueGuards() (gas: 750535)\n[PASS] test_lockQueueRefusesATrainingPet() (gas: 551852)\n[PASS] test_mintCallbackHitsTheGuardOnEveryGameEntry() (gas: 1058787)\n[PASS] test_mintWindowReopensButNeverRefundsTheAllocation() (gas: 655101)\n[PASS] test_mintingContractThatMovesThePetAwayStillUsedItsAllocation() (gas: 1117253)\n[PASS] test_noContractAcceptsPlainEthAndNonpayableEntriesRefuseValue() (gas: 555105)\n[PASS] test_ownerMintedPetsLeaveTheRecipientsFreeMintAvailable() (gas: 554424)\n[PASS] test_pendingHandoverCanBeCancelledWithTheZeroAddress() (gas: 133181)\n[PASS] test_petEnteredOnItsLastAttemptCanStillLockAfterTheWeekTurns() (gas: 1359280)\n[PASS] test_quotaCountsLocksNotEntriesAndResetsOnlyOnANewWeek() (gas: 2496856)\n[PASS] test_receiverActingInsideASafeTransferStaysBoundByTheLock() (gas: 1037828)\n[PASS] test_renounceFailsForEveryCallerAndChangesNothing() (gas: 39094)\n[PASS] test_rewardCreditsOnceAndOnlyTheDocumentedAmount() (gas: 1290434)\n[PASS] test_tokenUriIsTheExactDocumentAndProjectsNeglect() (gas: 728321)\n[PASS] test_transferFailuresDoNotMoveThePet() (gas: 522235)\n[PASS] test_unlockExpireAndRewardOnlyAcceptTheirOwnActivity() (gas: 941453)\n[PASS] test_withdrawOnAnEmptyContractFails() (gas: 39476)\nSuite result: ok. 29 passed; 0 failed; 0 skipped; finished in 495.09ms (518.44ms CPU time)\n\nRan 3 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_constructorsDoNotNeedDependenciesToExist() (gas: 12863)\n[PASS] test_factoryDeploymentsHaveExplicitOwnerAndNoForbiddenRuntime() (gas: 30867803)\n[PASS] test_scriptsUseArgumentsAndRejectOtherChains() (gas: 13475107)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 669.74ms (226.59ms CPU time)\n\nRan 9 tests for test/CertifiedWorkOracle.t.sol:CertifiedWorkOracleTest\n[PASS] testFuzz_settleTimingAndCallerNeverChangeStamina(uint32,address) (runs: 512, μ: 1463252, ~: 1455926)\nLogs:\n  Bound result 1200\n\n[PASS] testFuzz_settledGainEqualsIndependentLedgerSum(uint256,uint16,uint16,uint8,uint8) (runs: 512, μ: 3269942, ~: 3152685)\nLogs:\n  Bound result 1\n  Bound result 0\n  Bound result 2\n\n[PASS] test_frontierExactlyAtEndSettlesAndOneShortDoesNot() (gas: 1819871)\n[PASS] test_hungryBoundaryForBooking() (gas: 703363)\n[PASS] test_mintFeedTrainSettleThenRaceEndToEnd() (gas: 3492703)\n[PASS] test_nonexistentTokenCannotBeBookedSettledOrPreviewed() (gas: 113515)\n[PASS] test_onlyTheHolderStartsOrCancelsNotOperatorsOrStrangers() (gas: 823475)\n[PASS] test_settleIsOnceOnlyAndCancelledBookingsCannotBeSettled() (gas: 2600813)\n[PASS] test_trainingAndQueueLocksExcludeEachOther() (gas: 1845630)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 753.51ms (1.33s CPU time)\n\nRan 5 tests for test/MathAndRandomness.t.sol:MathAndRandomnessTest\n[PASS] testFuzz_pairingIsPermutationAndRewardsConserve(uint8,bytes32) (runs: 512, μ: 5608273, ~: 4705795)\n[PASS] testFuzz_raceMathIsOrderedAndSafeAtFullWidth(uint256,uint16) (runs: 512, μ: 7914, ~: 7834)\n[PASS] test_exactRaceFormulaAndNoiseRange() (gas: 60575)\n[PASS] test_fulfillmentCallerAndTimestampCannotChooseResult() (gas: 2633131)\n[PASS] test_futureEntropyActuallyChangesPairingForLargerRoster() (gas: 24441619)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 753.44ms (1.34s CPU time)\n\nRan 44 tests for test/QueueEdges.t.sol:QueueEdgesTest\n[PASS] testFuzz_exactlyOneResolutionPathExistsAtEveryBlock(uint16) (runs: 512, μ: 2041514, ~: 2194715)\nLogs:\n  Bound result 568\n\n[PASS] testFuzz_twoPlayerRoundMatchesThePinnedFormulas(bytes32) (runs: 512, μ: 2574058, ~: 2573850)\n[PASS] test_aBigStaminaLeadInsideABandOutweighsTheClassGap() (gas: 28169707)\n[PASS] test_anyCallerBuildsTheSameRoster() (gas: 2225233)\n[PASS] test_atEqualStaminaFitBeatsObeseUnderEveryHash() (gas: 50050542)\n[PASS] test_bandEdgesSeparateAt500AndPairInsideTheBand() (gas: 7219929)\n[PASS] test_byeIsSpreadAcrossTheRoster() (gas: 62196350)\n[PASS] test_constantsArePinnedToTheDocumentedValues() (gas: 123668)\n[PASS] test_emptyAndUnknownViewsBehave() (gas: 77615)\n[PASS] test_entriesBecomeLockableExactlyTenBlocksAfterJoining() (gas: 1880502)\n[PASS] test_evictionReportsExpiryAndTheOwnerKeepsThePet() (gas: 750431)\n[PASS] test_expiredOddRoundRefundsNobody() (gas: 2703455)\n[PASS] test_expiredRoundHasNoRacesAndHungryRacersRecoverToo() (gas: 2101766)\n[PASS] test_expiringAFullRosterStaysBoundedAndFreesEveryone() (gas: 26043021)\n[PASS] test_firstRewardFailureRollsBackJustAsTheSecondDoes() (gas: 7110615)\n[PASS] test_fitUsuallyBeatsNormalButTheNoiseKeepsItAContest() (gas: 93729909)\n[PASS] test_fiveExpiredRoundsExhaustTheWeekUntilItTurns() (gas: 7253708)\n[PASS] test_fullBandOfStaleEntriesBlocksEntryUntilOneIsEvicted() (gas: 25402715)\n[PASS] test_identicalLowStaminaPetsStillSplitWinsWhenScoresOftenTie() (gas: 97686279)\n[PASS] test_identicalPetsAreAFairCoinOverManyHashes() (gas: 97720353)\n[PASS] test_idlePetTransferredAwayDoesNotCarryTheWalletLock() (gas: 2504698)\n[PASS] test_leaveAndEvictRejectPetsThatAreNotWaiting() (gas: 2031779)\n[PASS] test_leavingIsAllowedAfterStalenessAndReportsAsVoluntary() (gas: 1001780)\n[PASS] test_lockedRacersCannotImproveTheirSnapshotAndNewcomersCannotJoin() (gas: 2541524)\n[PASS] test_mixedStaleAndOddRosterLocksEveryEligiblePetAndLeavesOnlyTheNewcomer() (gas: 4696919)\n[PASS] test_nobodyCanJoinAndLockAgainstALoneWaiterInOneTransaction() (gas: 1513393)\n[PASS] test_normalUsuallyBeatsObeseButTheNoiseKeepsItAContest() (gas: 97728399)\n[PASS] test_oddRoundGivesTheShuffleChosenByeItsAttemptBack() (gas: 3644359)\n[PASS] test_oneFullBandLeavesOtherBandsOpen() (gas: 19221877)\n[PASS] test_oneWalletRacesOnePetAcrossAllBandsUntilSettled() (gas: 7717249)\n[PASS] test_onlyTheBoundQueueCanReleaseABye() (gas: 1773536)\n[PASS] test_pointsStayWithTheRacerAfterThePetIsSold() (gas: 2515891)\n[PASS] test_racesInOneRoundSettleInAnyOrderAndOnlyFreeTheirOwnPair() (gas: 4886229)\n[PASS] test_rejoiningRestartsTheWait() (gas: 1580602)\n[PASS] test_requestIncludesAPetAtExactFedUntilAndPrunesItOneSecondLater() (gas: 3125259)\n[PASS] test_requestIncludesAnEntryAtExactTtlAndPrunesItOneSecondLater() (gas: 1983285)\n[PASS] test_resultDependsOnlyOnTheTargetBlockHashAcrossTheWholeWindow() (gas: 3109841)\n[PASS] test_seedIsBoundToChainContractAndRound() (gas: 2592242)\n[PASS] test_settlementEmitsTheOutcomeAndPointsTotals() (gas: 2451627)\n[PASS] test_settlingYearsLaterChangesNothingAboutTheRaceOrItsWeek() (gas: 2664568)\n[PASS] test_shuffleReachesEveryOpponentAboutEvenly() (gas: 124393151)\n[PASS] test_snapshotUsesWeightAtRoundLockNotAtEnqueue() (gas: 6364205)\n[PASS] test_snapshotWeightDecidesEvenIfTheLivePetWentDownhillAfterLock() (gas: 6891150)\n[PASS] test_trainingPetCannotEnterAndTheFailedEntryLeavesNoTrace() (gas: 795358)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 760.73ms (1.40s CPU time)\n\nRan 31 tests for test/CareEdges.t.sol:CareEdgesTest\n[PASS] testFuzz_betterScoreNeverGivesAWorseClass(uint8) (runs: 512, μ: 7132, ~: 6972)\nLogs:\n  Bound result 20\n\n[PASS] testFuzz_feedAlwaysSetsDeadlineFromNowAndNeverShortensIt(uint8,uint8,uint32) (runs: 512, μ: 555653, ~: 553171)\nLogs:\n  Bound result 2\n  Bound result 0\n  Bound result 9\n\n[PASS] testFuzz_feedingAnywhereInTheNewbornWindowCostsOnlyIdleDays(uint32,uint8) (runs: 512, μ: 412083, ~: 409925)\nLogs:\n  Bound result 1\n  Bound result 2960\n\n[PASS] testFuzz_hungryExactlyAfterTheDeadline(uint32) (runs: 512, μ: 389199, ~: 389022)\nLogs:\n  Bound result 9998\n\n[PASS] testFuzz_lowFoodAloneNeverMakesAPetFit(uint8) (runs: 512, μ: 6409060, ~: 4867094)\nLogs:\n  Bound result 6\n\n[PASS] testFuzz_neglectIsPathIndependentAndIdempotent(uint8,uint32,uint32) (runs: 512, μ: 595490, ~: 598871)\nLogs:\n  Bound result 163891\n  Bound result 1\n  Bound result 0\n\n[PASS] testFuzz_nonexistentPetsRevertEverywhere(uint256) (runs: 512, μ: 304760, ~: 299248)\n[PASS] testFuzz_scoreNeverRisesFromTimeAlone(uint8,uint32,uint32) (runs: 512, μ: 448951, ~: 450849)\nLogs:\n  Bound result 0\n  Bound result 163891\n  Bound result 1\n\n[PASS] test_aFitPetOnACheapDietTrainingDailyDriftsToNormalNotBelow() (gas: 39072274)\n[PASS] test_cancelDoesNotResetTheIdleClockButSettlingDoes() (gas: 1576823)\n[PASS] test_cancelledTrainingCreditsNothingAndCannotBeReplayed() (gas: 936760)\n[PASS] test_cheaperRefeedDowngradesTheNextTrainingBonus() (gas: 850258)\n[PASS] test_feedingOneSecondAfterTheNewbornWindowPaysOneHungerDay() (gas: 424914)\n[PASS] test_feedingStopsHungerDamageButNeverRefundsIdleDamage() (gas: 665271)\n[PASS] test_largerWorkEarnsMoreBodyCreditOnlyUpToTheDocumentedCap() (gas: 2338413)\n[PASS] test_longNeglectSaturatesAtZeroAndFoodRecoversFromThere() (gas: 699488)\n[PASS] test_lowFoodTrainingStopsAtTheCeilingOfSixty() (gas: 7802797)\n[PASS] test_midFoodTrainingPassesSixtyAndReachesFit() (gas: 5474110)\n[PASS] test_newbornNeglectFollowsThePinnedSchedule() (gas: 583833)\n[PASS] test_operatorsMayMoveAPetButNeverPlayIt() (gas: 694281)\n[PASS] test_paymentRaisedOrLoweredInTheSameBlockNeverOverOrUndercharges() (gas: 472287)\n[PASS] test_rejectedFeedLeavesEveryFieldUntouched() (gas: 636091)\n[PASS] test_repeatedFoodSaturatesBothEndsOfTheBodyRange() (gas: 2104531)\n[PASS] test_settleAndCancelRejectEveryNonTrainingActivity() (gas: 1886172)\n[PASS] test_startingOnTheLastFedSecondSettlesAfterExpiry() (gas: 926772)\n[PASS] test_storedEnumFollowsTheScoreAcrossBoundariesInBothDirections() (gas: 11834078)\n[PASS] test_trainedPetsRankByFoodTierAndBeatUntrainedOnes() (gas: 1906684)\n[PASS] test_trainingAtFullStaminaWidthKeepsGrowingUntilArithmeticStops() (gas: 5849895)\n[PASS] test_transferKeepsAllCareStateAndGivesNoReset() (gas: 1189742)\n[PASS] test_weightClassBoundariesArePinned() (gas: 5914)\n[PASS] test_withoutTrainingEveryFoodRegimeDriftsDownInTierOrder() (gas: 2707105)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 761.03ms (3.27s CPU time)\n\nRan 15 tests for test/CertificationWait.t.sol:CertificationWaitTest\n[PASS] testFuzz_lockDurationNeverChangesIdleDamage(uint32,bool) (runs: 512, μ: 912963, ~: 950615)\nLogs:\n  Bound result 6\n\n[PASS] testFuzz_petsInOneBandAreWithinAFactorOfTwoAndBandsAreMonotonic(uint256,uint256) (runs: 512, μ: 43939, ~: 43636)\nLogs:\n  Bound result 2320134807272516332134995716853468048\n  Bound result 169903169\n\n[PASS] test_bandForStaminaTable() (gas: 114371)\n[PASS] test_cancelAfterALagResumesTheIdleClockWithoutAReset() (gas: 715044)\n[PASS] test_certificationWaitIsNotBilledAsInactivity() (gas: 973391)\n[PASS] test_comparableLiveWorkPairsAndRacesAfterOneWindowEach() (gas: 3490627)\n[PASS] test_feedingStaysLockedWhileQueuedOrMatched() (gas: 1751866)\n[PASS] test_feedingWhileBookedIsStillOwnerOnlyAndOpensNoOtherAction() (gas: 945938)\n[PASS] test_hungerDuringTheWaitStaysTheOwnersResponsibility() (gas: 924939)\n[PASS] test_idleDaysCompletedBeforeBookingAreChargedAndThePartialDayCarriesOver() (gas: 985486)\n[PASS] test_ownerCanFeedThroughTheWaitAndTheBookingIsUntouched() (gas: 1317512)\n[PASS] test_pinnedLiveWindowAcrossTiersLandsInNeighbouringBands() (gas: 2437973)\n[PASS] test_sevenDayLagWithThePinnedLiveWindowEndsFitWhenFedOnCadence() (gas: 1078633)\n[PASS] test_untrainedPetsAllShareBandZeroAndCannotMeetATrainedOne() (gas: 2926308)\n[PASS] test_zeroWorkSettleAfterALagResumesTheIdleClockWithoutAReset() (gas: 824816)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 762.33ms (777.41ms CPU time)\n\nRan 12 tests for test/NFTAdmin.t.sol:NFTAdminTest\n[PASS] test_adminConfigurationAccessAndBounds() (gas: 652746)\n[PASS] test_erc721InterfacesMetadataAndApprovedTransfer() (gas: 571122)\n[PASS] test_mintClosedByDefaultAndOnlyOwnerCanOpen() (gas: 387570)\n[PASS] test_oneFreeMintPerWalletSurvivesTransfers() (gas: 642279)\n[PASS] test_ownerMintWorksWhileClosedButCannotMintToZero() (gas: 521183)\n[PASS] test_ownershipUsesTwoStepAndCannotRenounce() (gas: 194415)\n[PASS] test_queueMustBeConfiguredOnceAndBoundToThisNFT() (gas: 961463)\n[PASS] test_queueOnlyMethodsRejectDirectUsersAndOwner() (gas: 525025)\n[PASS] test_safeMintReceiverCannotReenterAndRejectionRollsBack() (gas: 965133)\n[PASS] test_supplyExactly9999AcrossOwnerAndFreeMints() (gas: 642399)\n[PASS] test_withdrawConservesProceedsAndOnlyPaysOwner() (gas: 894511)\n[PASS] test_withdrawRejectingOwnerRollsBackAndReentryFails() (gas: 825895)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 846.47ms (843.37ms CPU time)\n\nRan 20 tests for test/Care.t.sol:CareTest\n[PASS] testFuzz_feedRequiresExactTierPrice(uint8,uint96) (runs: 512, μ: 342953, ~: 343153)\nLogs:\n  Bound result 0\n  Bound result 65\n\n[PASS] test_allTiersFeedAndGiveDistinctTrainingBonus() (gas: 2499255)\n[PASS] test_feedResetsRatherThanStacksAndExactExpiryIsFed() (gas: 574305)\n[PASS] test_fitPetSwitchedToCheapFoodDriftsDownToNormal() (gas: 12011516)\n[PASS] test_hungryGatesTrainingAndQueue() (gas: 1275369)\n[PASS] test_inactivityAndHungerPenaltiesAreNotResetByFrequentTouches() (gas: 1962293)\n[PASS] test_invalidTierAndNonOwnerFeedFail() (gas: 432037)\n[PASS] test_lateTrainingSettlementStillUnlocksAndAccountsNeglect() (gas: 997161)\n[PASS] test_lowFoodOnlyTrainingNeverMakesAPetFit() (gas: 639476007)\n[PASS] test_newbornTakesNoHungerDamageDuringItsFirstFeedWindow() (gas: 1496736)\n[PASS] test_staminaGrowsFarBeyondSmallIntegerLimits() (gas: 5308043)\n[PASS] test_startingStatsAndFeedDefaults() (gas: 377864)\n[PASS] test_sustainedHighFoodWithoutTrainingStillDriftsTowardObese() (gas: 1619442)\n[PASS] test_tierBonusStaysStrictlyOrderedAtHighStamina() (gas: 7000248)\n[PASS] test_trainingCanStartAtFeedExpiryAndSettleAfterCertification() (gas: 921202)\n[PASS] test_trainingCancellationGivesNoRewardAndCannotBeForced() (gas: 1137445)\n[PASS] test_trainingConfigIsSnapshottedAtFeedAndStart() (gas: 1173740)\n[PASS] test_trainingLocksAllActionsAndSettlesExactlyOnce() (gas: 1417275)\n[PASS] test_uint256OverflowRevertsWithoutWrappingAndTrainingCanCancel() (gas: 5390280)\n[PASS] test_weightTransitionsThroughObeseNormalFitAndNeglect() (gas: 2150090)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 960.52ms (1.08s CPU time)\n\nRan 2 tests for test/CertifiedWorkOracle.t.sol:TrainingOracleInvariantTest\n[PASS]\nTrainingOracleInvariantTest invariants:\n[PASS] invariant_bookingRecordMatchesTrainingLockAndStatus\n[PASS] invariant_feeRevenueIsConserved\n[PASS] invariant_staminaIsExactlyCertifiedLedgerWorkTimesFood\n TrainingOracleInvariantTest invariants (runs: 64, calls: 4096, reverts: 0)\n\n╭-----------------------+----------+-------+---------+----------╮\n| Contract              | Selector | Calls | Reverts | Discards |\n+===============================================================+\n| TrainingOracleHandler | advance  | 614   | 0       | 0        |\n|-----------------------+----------+-------+---------+----------|\n| TrainingOracleHandler | cancel   | 576   | 0       | 0        |\n|-----------------------+----------+-------+---------+----------|\n| TrainingOracleHandler | certify  | 618   | 0       | 0        |\n|-----------------------+----------+-------+---------+----------|\n| TrainingOracleHandler | feed     | 563   | 0       | 0        |\n|-----------------------+----------+-------+---------+----------|\n| TrainingOracleHandler | settle   | 567   | 0       | 0        |\n|-----------------------+----------+-------+---------+----------|\n| TrainingOracleHandler | start    | 580   | 0       | 0        |\n|-----------------------+----------+-------+---------+----------|\n| TrainingOracleHandler | withdraw | 578   | 0       | 0        |\n╰-----------------------+----------+-------+---------+----------╯\n\n[PASS] test_seededWalkReachesLagSettleAndCancel() (gas: 459112242)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 4.11s (4.75s CPU time)\n\nRan 1 test for test/Invariants.t.sol:GameInvariantTest\n[PASS]\nGameInvariantTest invariants:\n[PASS] invariant_bodySupplyQuotaAndLocksStayConsistent\n[PASS] invariant_ethConservation\n[PASS] invariant_pointsAndStaminaHaveOnlyEarnedSources\n GameInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-------------+----------------+-------+---------+----------╮\n| Contract    | Selector       | Calls | Reverts | Discards |\n+===========================================================+\n| GameHandler | advance        | 1033  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | cancelTraining | 1013  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | enqueueOrLeave | 1010  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | feed           | 1054  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | request        | 1024  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | resolve        | 1083  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | trainOrClaim   | 1020  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | withdraw       | 955   | 0       | 0        |\n╰-------------+----------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 12.75s (12.74s CPU time)\n\nRan 3 tests for test/StatefulInvariants.t.sol:StatefulInvariantsTest\n[PASS]\nStatefulInvariantsTest invariants:\n[PASS] invariant_bodyAndFoodStayInRange\n[PASS] invariant_ethInEqualsEthHeldPlusEthWithdrawn\n[PASS] invariant_lockedActivityMatchesItsBackingRecord\n[PASS] invariant_pointsComeOnlyFromSettledRaces\n[PASS] invariant_queueAndActivityDescribeTheSameThing\n[PASS] invariant_roundsAndRacesNeverLeaveAFinishedState\n[PASS] invariant_staminaComesOnlyFromTrainingAndRaces\n[PASS] invariant_supplyIsExactlyWhatWasMinted\n[PASS] invariant_walletLockMatchesTheOnePetItNames\n StatefulInvariantsTest invariants (runs: 96, calls: 9216, reverts: 0)\n\n╭--------------+----------------+-------+---------+----------╮\n| Contract     | Selector       | Calls | Reverts | Discards |\n+============================================================+\n| WorldHandler | advanceBlocks  | 494   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | advanceTime    | 432   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | cancelTraining | 449   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | enqueue        | 478   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | evict          | 465   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | expireRound    | 431   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | feed           | 512   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | feedBadly      | 461   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | forceEth       | 457   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | fulfillRound   | 482   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | leaveQueue     | 472   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | rally          | 453   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | requestRound   | 449   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | setFoodConfig  | 435   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | settleMatch    | 467   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | settleTraining | 464   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | startTraining  | 450   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | strangerProbes | 488   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | transferPet    | 440   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | withdraw       | 437   | 0       | 0        |\n╰--------------+----------------+-------+---------+----------╯\n\n[PASS] test_freeMintsKeepTheSupplyAndAllocationLedgers() (gas: 9278722)\n[PASS] test_seededWalkReachesEveryOutcomeAndKeepsEveryInvariant() (gas: 324777322)\nLogs:\n  feedOk: 26\n  feedLocked: 21\n  feedWhileTraining: 9\n  feedRefused: 65\n  trainOk: 13\n  trainRefused: 49\n  settleTrainingOk: 5\n  settleTrainingRefused: 53\n  cancelOk: 8\n  enqueueOk: 18\n  enqueueRefused: 46\n  leaveOk: 4\n  evictOk: 2\n  requestOk: 1\n  rallyOk: 21\n  requestRefused: 68\n  fulfillOk: 16\n  expireOk: 4\n  settleMatchOk: 19\n  transferOk: 27\n  transferLocked: 23\n  withdrawOk: 37\n  forceOk: 48\n  configOk: 77\n  strangerRefused: 59\n  byeOk: 6\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 46.84s (47.36s CPU time)\n\nRan 15 test suites in 46.85s (71.07s CPU time): 224 tests passed, 0 failed, 0 skipped (224 total tests)\n","passed":true},{"durationMs":163,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"HamsterRunNFT.acceptOwnership()\",\"HamsterRunNFT.approve(address,uint256)\",\"HamsterRunNFT.cancelTraining(uint256)\",\"HamsterRunNFT.expireMatchLock(uint256)\",\"HamsterRunNFT.feed(uint256,uint8)\",\"HamsterRunNFT.lockMatch(uint256)\",\"HamsterRunNFT.lockQueue(uint256,address)\",\"HamsterRunNFT.mint()\",\"HamsterRunNFT.ownerMint(address)\",\"HamsterRunNFT.releaseBye(uint256)\",\"HamsterRunNFT.rewardMatch(uint256,bool)\",\"HamsterRunNFT.safeTransferFrom(address,address,uint256)\",\"HamsterRunNFT.safeTransferFrom(address,address,uint256,bytes)\",\"HamsterRunNFT.setApprovalForAll(address,bool)\",\"HamsterRunNFT.setFoodConfig(uint256[3],uint256[3])\",\"HamsterRunNFT.setMatchQueue(address)\",\"HamsterRunNFT.setMintOpen(bool)\",\"HamsterRunNFT.settleTraining(uint256)\",\"HamsterRunNFT.startTraining(uint256)\",\"HamsterRunNFT.transferFrom(address,address,uint256)\",\"HamsterRunNFT.transferOwnership(address)\",\"HamsterRunNFT.unlockQueue(uint256)\",\"HamsterRunNFT.withdraw(uint256)\",\"MatchQueue.enqueue(uint256)\",\"MatchQueue.evictExpired(uint256)\",\"MatchQueue.expireRound(uint256)\",\"MatchQueue.fulfillRound(uint256)\",\"MatchQueue.leaveQueue(uint256)\",\"MatchQueue.requestRound(uint256)\",\"MatchQueue.settleMatch(uint256)\"],\"files\":{\".gitignore\":3,\"DESIGN.md\":187,\"LICENSE\":21,\"README.md\":124,\"SECURITY.md\":60,\"abi/HamsterRunNFT.json\":1830,\"abi/ISqueekCore.json\":239,\"abi/MatchQueue.json\":1018,\"abi/SHA256.json\":6,\"abi/SqueekCore.upstream.json\":902,\"dependencies.json\":18,\"deployments/sepolia-v2.json\":11,\"deployments/sepolia.json\":30,\"docs/PROVENANCE.md\":22,\"docs/VALIDATION.md\":48,\"docs/core-sepolia-snapshot.json\":28,\"foundry.toml\":27,\"remappings.txt\":2,\"script/Deploy.s.sol\":28,\"src/CoreReader.sol\":86,\"src/GameMath.sol\":44,\"src/HamsterRunNFT.sol\":494,\"src/MatchQueue.sol\":372,\"src/PointsLedger.sol\":18,\"src/interfaces/ISqueekCore.sol\":58,\"test/Care.t.sol\":375,\"test/CareEdges.t.sol\":568,\"test/CertificationWait.t.sol\":283,\"test/CertifiedWorkOracle.t.sol\":527,\"test/CoreAbi.t.sol\":65,\"test/CoreTraining.t.sol\":395,\"test/Deployment.t.sol\":103,\"test/Invariants.t.sol\":220,\"test/MatchQueue.t.sol\":611,\"test/MathAndRandomness.t.sol\":122,\"test/NFTAdmin.t.sol\":297,\"test/NFTGuards.t.sol\":568,\"test/QueueEdges.t.sol\":970,\"test/StatefulInvariants.t.sol\":1169,\"test/Tools.test.mjs\":129,\"test/helpers/GameTest.sol\":119,\"test/helpers/MockSqueekCore.sol\":109,\"test/helpers/Probes.sol\":115,\"tools/export-abis.mjs\":39,\"tools/record-deployment.mjs\":89,\"tools/rpc.mjs\":55,\"tools/training-status.mjs\":36},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"5b1292f5cd1612d0eb2d244c4ee2c4ddfb188377d4ee46ea41c2e46b64bf4303","verifiedTreeHash":"03af8ce951e6b94564f4eb4df638d842094f1d87","verifierVersion":"0.1.0+3dcb4df2"},{"checks":[{"durationMs":17970,"exitCode":0,"name":"build","output":"Compiling 60 files with Solc 0.8.26\nSolc 0.8.26 finished in 17.80s\nCompiler run successful with warnings:\nWarning (5159): \"selfdestruct\" has been deprecated. Note that, starting from the Cancun hard fork, the underlying opcode no longer deletes the code and data associated with an account and only transfers its Ether to the beneficiary, unless executed in the same transaction in which the contract was created (see EIP-6780). Any use in newly deployed contracts is strongly discouraged even if the new behavior is taken into account. Future changes to the EVM might further reduce the functionality of the opcode.\n  --> test/helpers/Probes.sol:53:9:\n   |\n53 |         selfdestruct(to);\n   |         ^^^^^^^^^^^^\n\n","passed":true},{"durationMs":47121,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/CoreAbi.t.sol:CoreAbiTest\n[PASS] test_historicalWindowSettlesAgainstRawCertifiedCorePage() (gas: 655606)\n[PASS] test_publishedCoreV3AbiMatchesFinalizedSepoliaReadBytes() (gas: 83293)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 4.05ms (2.31ms CPU time)\n\nRan 3 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_constructorsDoNotNeedDependenciesToExist() (gas: 12863)\n[PASS] test_factoryDeploymentsHaveExplicitOwnerAndNoForbiddenRuntime() (gas: 30330760)\n[PASS] test_scriptsUseArgumentsAndRejectOtherChains() (gas: 13264571)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 77.84ms (79.03ms CPU time)\n\nRan 29 tests for test/NFTGuards.t.sol:NFTGuardsTest\n[PASS] testFuzz_foodConfigAcceptedExactlyWhenStrictlyOrderedAndInBounds(uint256[3],uint256[3]) (runs: 512, μ: 74576, ~: 74084)\nLogs:\n  Bound result 0\n  Bound result 2\n  Bound result 3\n  Bound result 10001\n  Bound result 14999\n\n[PASS] testFuzz_withdrawPaysExactlyTheRequestedAmountOrFails(uint256) (runs: 512, μ: 763307, ~: 764516)\nLogs:\n  Bound result 50001\n\n[PASS] test_aSecondQueueAimedAtABoundCollectionGetsNowhere() (gas: 925425)\n[PASS] test_approvalsSetDuringALockCannotMoveThePetUntilItUnlocks() (gas: 909043)\n[PASS] test_bindingRejectsEveryQueueThatDoesNotNameThisCollection() (gas: 348049)\n[PASS] test_boundQueueCanNeverBeReplacedEvenByOwnerOrNextOwner() (gas: 482755)\n[PASS] test_directCallsFromNeitherOwnerNorPlayerCanMoveALockedPet() (gas: 909633)\n[PASS] test_everyQueueMethodFailsBeforeBinding() (gas: 402564)\n[PASS] test_feesFollowOwnershipOnlyAfterAcceptance() (gas: 588783)\n[PASS] test_forcedEthIsWithdrawableAndCreatesNoEntitlement() (gas: 139827)\n[PASS] test_lockMatchAppliesNeglectBeforeTheSnapshot() (gas: 649622)\n[PASS] test_lockMatchGuardsAndReturnsTheLiveSnapshot() (gas: 1081544)\n[PASS] test_lockQueueGuards() (gas: 747334)\n[PASS] test_lockQueueRefusesATrainingPet() (gas: 527037)\n[PASS] test_mintCallbackHitsTheGuardOnEveryGameEntry() (gas: 1056086)\n[PASS] test_mintWindowReopensButNeverRefundsTheAllocation() (gas: 650635)\n[PASS] test_mintingContractThatMovesThePetAwayStillUsedItsAllocation() (gas: 1114384)\n[PASS] test_noContractAcceptsPlainEthAndNonpayableEntriesRefuseValue() (gas: 552651)\n[PASS] test_ownerMintedPetsLeaveTheRecipientsFreeMintAvailable() (gas: 549578)\n[PASS] test_pendingHandoverCanBeCancelledWithTheZeroAddress() (gas: 133181)\n[PASS] test_petEnteredOnItsLastAttemptCanStillLockAfterTheWeekTurns() (gas: 1353989)\n[PASS] test_quotaCountsLocksNotEntriesAndResetsOnlyOnANewWeek() (gas: 2489095)\n[PASS] test_receiverActingInsideASafeTransferStaysBoundByTheLock() (gas: 1034526)\n[PASS] test_renounceFailsForEveryCallerAndChangesNothing() (gas: 39094)\n[PASS] test_rewardCreditsOnceAndOnlyTheDocumentedAmount() (gas: 1283816)\n[PASS] test_tokenUriIsTheExactDocumentAndProjectsNeglect() (gas: 724886)\n[PASS] test_transferFailuresDoNotMoveThePet() (gas: 519432)\n[PASS] test_unlockExpireAndRewardOnlyAcceptTheirOwnActivity() (gas: 938619)\n[PASS] test_withdrawOnAnEmptyContractFails() (gas: 39476)\nSuite result: ok. 29 passed; 0 failed; 0 skipped; finished in 354.46ms (199.01ms CPU time)\n\nRan 12 tests for test/NFTAdmin.t.sol:NFTAdminTest\n[PASS] test_adminConfigurationAccessAndBounds() (gas: 650102)\n[PASS] test_erc721InterfacesMetadataAndApprovedTransfer() (gas: 568509)\n[PASS] test_mintClosedByDefaultAndOnlyOwnerCanOpen() (gas: 385337)\n[PASS] test_oneFreeMintPerWalletSurvivesTransfers() (gas: 637623)\n[PASS] test_ownerMintWorksWhileClosedButCannotMintToZero() (gas: 516717)\n[PASS] test_ownershipUsesTwoStepAndCannotRenounce() (gas: 194415)\n[PASS] test_queueMustBeConfiguredOnceAndBoundToThisNFT() (gas: 958307)\n[PASS] test_queueOnlyMethodsRejectDirectUsersAndOwner() (gas: 522571)\n[PASS] test_safeMintReceiverCannotReenterAndRejectionRollsBack() (gas: 960667)\n[PASS] test_supplyExactly9999AcrossOwnerAndFreeMints() (gas: 639976)\n[PASS] test_withdrawConservesProceedsAndOnlyPaysOwner() (gas: 889603)\n[PASS] test_withdrawRejectingOwnerRollsBackAndReentryFails() (gas: 823441)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 643.62ms (594.40ms CPU time)\n\nRan 44 tests for test/QueueEdges.t.sol:QueueEdgesTest\n[PASS] testFuzz_exactlyOneResolutionPathExistsAtEveryBlock(uint16) (runs: 512, μ: 2036573, ~: 2188269)\nLogs:\n  Bound result 192\n\n[PASS] testFuzz_twoPlayerRoundMatchesThePinnedFormulas(bytes32) (runs: 512, μ: 2566792, ~: 2566579)\n[PASS] test_aBigStaminaLeadInsideABandOutweighsTheClassGap() (gas: 28146115)\n[PASS] test_anyCallerBuildsTheSameRoster() (gas: 2218585)\n[PASS] test_atEqualStaminaFitBeatsObeseUnderEveryHash() (gas: 49969094)\n[PASS] test_bandEdgesSeparateAt25AndPairInsideTheBand() (gas: 7141829)\n[PASS] test_byeIsSpreadAcrossTheRoster() (gas: 62164258)\n[PASS] test_constantsArePinnedToTheDocumentedValues() (gas: 115551)\n[PASS] test_emptyAndUnknownViewsBehave() (gas: 77593)\n[PASS] test_entriesBecomeLockableExactlyTenBlocksAfterJoining() (gas: 1874066)\n[PASS] test_evictionReportsExpiryAndTheOwnerKeepsThePet() (gas: 747428)\n[PASS] test_expiredOddRoundRefundsNobody() (gas: 2693023)\n[PASS] test_expiredRoundHasNoRacesAndHungryRacersRecoverToo() (gas: 2094548)\n[PASS] test_expiringAFullRosterStaysBoundedAndFreesEveryone() (gas: 25933175)\n[PASS] test_firstRewardFailureRollsBackJustAsTheSecondDoes() (gas: 7037033)\n[PASS] test_fitUsuallyBeatsNormalButTheNoiseKeepsItAContest() (gas: 93646247)\n[PASS] test_fiveExpiredRoundsExhaustTheWeekUntilItTurns() (gas: 7236800)\n[PASS] test_fullBandOfStaleEntriesBlocksEntryUntilOneIsEvicted() (gas: 25292515)\n[PASS] test_identicalLowStaminaPetsStillSplitWinsWhenScoresOftenTie() (gas: 97603655)\n[PASS] test_identicalPetsAreAFairCoinOverManyHashes() (gas: 97636691)\n[PASS] test_idlePetTransferredAwayDoesNotCarryTheWalletLock() (gas: 2497904)\n[PASS] test_leaveAndEvictRejectPetsThatAreNotWaiting() (gas: 2000057)\n[PASS] test_leavingIsAllowedAfterStalenessAndReportsAsVoluntary() (gas: 998243)\n[PASS] test_lockedRacersCannotImproveTheirSnapshotAndNewcomersCannotJoin() (gas: 2532009)\n[PASS] test_mixedStaleAndOddRosterLocksEveryEligiblePetAndLeavesOnlyTheNewcomer() (gas: 4677385)\n[PASS] test_nobodyCanJoinAndLockAgainstALoneWaiterInOneTransaction() (gas: 1507191)\n[PASS] test_normalUsuallyBeatsObeseButTheNoiseKeepsItAContest() (gas: 97644737)\n[PASS] test_oddRoundGivesTheShuffleChosenByeItsAttemptBack() (gas: 3633649)\n[PASS] test_oneFullBandLeavesOtherBandsOpen() (gas: 19105983)\n[PASS] test_oneWalletRacesOnePetAcrossAllBandsUntilSettled() (gas: 3550228)\n[PASS] test_onlyTheBoundQueueCanReleaseABye() (gas: 1766888)\n[PASS] test_pointsStayWithTheRacerAfterThePetIsSold() (gas: 2508863)\n[PASS] test_racesInOneRoundSettleInAnyOrderAndOnlyFreeTheirOwnPair() (gas: 4872407)\n[PASS] test_rejoiningRestartsTheWait() (gas: 1574164)\n[PASS] test_requestIncludesAPetAtExactFedUntilAndPrunesItOneSecondLater() (gas: 3115141)\n[PASS] test_requestIncludesAnEntryAtExactTtlAndPrunesItOneSecondLater() (gas: 1976791)\n[PASS] test_resultDependsOnlyOnTheTargetBlockHashAcrossTheWholeWindow() (gas: 3103339)\n[PASS] test_seedIsBoundToChainContractAndRound() (gas: 2585784)\n[PASS] test_settlementEmitsTheOutcomeAndPointsTotals() (gas: 2444767)\n[PASS] test_settlingYearsLaterChangesNothingAboutTheRaceOrItsWeek() (gas: 2657686)\n[PASS] test_shuffleReachesEveryOpponentAboutEvenly() (gas: 124374169)\n[PASS] test_snapshotUsesWeightAtRoundLockNotAtEnqueue() (gas: 6291091)\n[PASS] test_snapshotWeightDecidesEvenIfTheLivePetWentDownhillAfterLock() (gas: 6817344)\n[PASS] test_trainingPetCannotEnterAndTheFailedEntryLeavesNoTrace() (gas: 768146)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 646.38ms (1.57s CPU time)\n\nRan 5 tests for test/MathAndRandomness.t.sol:MathAndRandomnessTest\n[PASS] testFuzz_pairingIsPermutationAndRewardsConserve(uint8,bytes32) (runs: 512, μ: 5515402, ~: 4691849)\n[PASS] testFuzz_raceMathIsOrderedAndSafeAtFullWidth(uint256,uint16) (runs: 512, μ: 7919, ~: 7834)\n[PASS] test_exactRaceFormulaAndNoiseRange() (gas: 60445)\n[PASS] test_fulfillmentCallerAndTimestampCannotChooseResult() (gas: 2626629)\n[PASS] test_futureEntropyActuallyChangesPairingForLargerRoster() (gas: 24415821)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 646.76ms (999.58ms CPU time)\n\nRan 25 tests for test/CoreTraining.t.sol:CoreTrainingTest\n[PASS] testFuzz_everyAcceptedBpsConfigStrictlyOrdersPositiveWork(uint64,uint16,uint16,uint16) (runs: 512, μ: 84446, ~: 84694)\nLogs:\n  Bound result 30116\n  Bound result 39545\n  Bound result 48774\n\n[PASS] testFuzz_gainIsExactlyCertifiedWorkTimesCapturedTier(uint64,uint8) (runs: 512, μ: 871029, ~: 884910)\n[PASS] testFuzz_gainIsMonotonicAndRoundingIsDown(uint64,uint16) (runs: 512, μ: 5688, ~: 5700)\n[PASS] testFuzz_malformedPageCannotPartiallyCreditOrUnlock(uint8) (runs: 512, μ: 865994, ~: 865280)\n[PASS] testFuzz_startBooksSixInclusiveRoundsAndCapturesFood(uint16,uint8) (runs: 512, μ: 586818, ~: 597044)\n[PASS] test_approvedSafeTransfersCannotBypassTrainingLock() (gas: 611186)\n[PASS] test_badConfigStopsNewBookingsButCannotTrapOldWork() (gas: 953430)\n[PASS] test_cancelRemainsAvailableWhenCoreDisappears() (gas: 729250)\n[PASS] test_certifiedZeroWorkUnlocksWithoutHealthOrClockReward() (gas: 1030416)\n[PASS] test_configWithCollapsingTierRoundingIsRejected() (gas: 63696)\n[PASS] test_corePauseDoesNotInvalidatePreviouslyCertifiedWork() (gas: 981457)\n[PASS] test_currentRoundUsesCoreGenesisAndOneBasedRounds() (gas: 124854)\n[PASS] test_elapsedTimeAloneNeverSettlesOrCreatesAGain() (gas: 823130)\n[PASS] test_emptyChainConstructorThenClearFirstUseError() (gas: 412611)\n[PASS] test_invalidReadWindowsRevert() (gas: 69723)\n[PASS] test_nextWindowCannotReplayAlreadyCreditedRounds() (gas: 1171669)\n[PASS] test_oneUnitStrictlyOrdersAllDefaultFoodTiers() (gas: 2013918)\n[PASS] test_onlyBookedWorkCountsEvenWithBacklogAndLaterCertification() (gas: 1103080)\n[PASS] test_overlappingPetsUseTheirOwnExactWindow() (gas: 1589139)\n[PASS] test_partialCertificationCannotCashOutEvenNonzeroWork() (gas: 984308)\n[PASS] test_previewCannotInventWorkForAnIdleToken() (gas: 393618)\n[PASS] test_roundAndWindowOverflowAreExplicit() (gas: 466959)\n[PASS] test_roundOneReadsLaunchPositionWithoutUnderflow() (gas: 885301)\n[PASS] test_sixActiveRoundsFitOneCompletePage() (gas: 1168532)\n[PASS] test_unavailableStateOrPageNeverFallsBackToTime() (gas: 966414)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 646.88ms (2.16s CPU time)\n\nRan 31 tests for test/CareEdges.t.sol:CareEdgesTest\n[PASS] testFuzz_betterScoreNeverGivesAWorseClass(uint8) (runs: 512, μ: 7119, ~: 6972)\nLogs:\n  Bound result 56\n\n[PASS] testFuzz_feedAlwaysSetsDeadlineFromNowAndNeverShortensIt(uint8,uint8,uint32) (runs: 512, μ: 552338, ~: 549754)\nLogs:\n  Bound result 1\n  Bound result 0\n  Bound result 1\n\n[PASS] testFuzz_feedingAnywhereInTheNewbornWindowCostsOnlyIdleDays(uint32,uint8) (runs: 512, μ: 409397, ~: 407281)\nLogs:\n  Bound result 0\n  Bound result 111708\n\n[PASS] testFuzz_hungryExactlyAfterTheDeadline(uint32) (runs: 512, μ: 386745, ~: 386568)\nLogs:\n  Bound result 56\n\n[PASS] testFuzz_lowFoodAloneNeverMakesAPetFit(uint8) (runs: 512, μ: 5966190, ~: 4768150)\nLogs:\n  Bound result 16\n\n[PASS] testFuzz_neglectIsPathIndependentAndIdempotent(uint8,uint32,uint32) (runs: 512, μ: 591274, ~: 595059)\nLogs:\n  Bound result 663\n  Bound result 244\n  Bound result 2\n\n[PASS] testFuzz_nonexistentPetsRevertEverywhere(uint256) (runs: 512, μ: 304617, ~: 299204)\n[PASS] testFuzz_scoreNeverRisesFromTimeAlone(uint8,uint32,uint32) (runs: 512, μ: 445920, ~: 448015)\nLogs:\n  Bound result 0\n  Bound result 163891\n  Bound result 1\n\n[PASS] test_aFitPetOnACheapDietTrainingDailyDriftsToNormalNotBelow() (gas: 38364253)\n[PASS] test_cancelDoesNotResetTheIdleClockButSettlingDoes() (gas: 1456229)\n[PASS] test_cancelledTrainingCreditsNothingAndCannotBeReplayed() (gas: 906838)\n[PASS] test_cheaperRefeedDowngradesTheNextTrainingBonus() (gas: 825222)\n[PASS] test_feedingOneSecondAfterTheNewbornWindowPaysOneHungerDay() (gas: 422270)\n[PASS] test_feedingStopsHungerDamageButNeverRefundsIdleDamage() (gas: 661500)\n[PASS] test_largerWorkEarnsMoreBodyCreditOnlyUpToTheDocumentedCap() (gas: 2256504)\n[PASS] test_longNeglectSaturatesAtZeroAndFoodRecoversFromThere() (gas: 695877)\n[PASS] test_lowFoodTrainingStopsAtTheCeilingOfSixty() (gas: 7626885)\n[PASS] test_midFoodTrainingPassesSixtyAndReachesFit() (gas: 5379917)\n[PASS] test_newbornNeglectFollowsThePinnedSchedule() (gas: 579890)\n[PASS] test_operatorsMayMoveAPetButNeverPlayIt() (gas: 669466)\n[PASS] test_paymentRaisedOrLoweredInTheSameBlockNeverOverOrUndercharges() (gas: 469992)\n[PASS] test_rejectedFeedLeavesEveryFieldUntouched() (gas: 633102)\n[PASS] test_repeatedFoodSaturatesBothEndsOfTheBodyRange() (gas: 2095296)\n[PASS] test_settleAndCancelRejectEveryNonTrainingActivity() (gas: 1879970)\n[PASS] test_startingOnTheLastFedSecondSettlesAfterExpiry() (gas: 899469)\n[PASS] test_storedEnumFollowsTheScoreAcrossBoundariesInBothDirections() (gas: 11739326)\n[PASS] test_trainedPetsRankByFoodTierAndBeatUntrainedOnes() (gas: 1849054)\n[PASS] test_trainingAtFullStaminaWidthKeepsGrowingUntilArithmeticStops() (gas: 5746057)\n[PASS] test_transferKeepsAllCareStateAndGivesNoReset() (gas: 1156798)\n[PASS] test_weightClassBoundariesArePinned() (gas: 5914)\n[PASS] test_withoutTrainingEveryFoodRegimeDriftsDownInTierOrder() (gas: 2694338)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 646.92ms (2.85s CPU time)\n\nRan 23 tests for test/MatchQueue.t.sol:MatchQueueTest\n[PASS] test_cannotEnqueueAndLockInOneTransaction() (gas: 2500957)\n[PASS] test_cannotEnqueueOthersDuplicateOrTwoPetsForOneWallet() (gas: 1363726)\n[PASS] test_distinctStaminaBandsCannotPair() (gas: 1839290)\n[PASS] test_eligibilityIsPerEntryAndSurvivesSwapRemoval() (gas: 2554397)\n[PASS] test_endToEndMintFeedTrainQueueRandomMatchSettle() (gas: 3428881)\n[PASS] test_expiredOddRoundReleasesEveryoneAndNobodyIsRefunded() (gas: 2625781)\n[PASS] test_expiredRandomnessReleasesBothPetsWithoutRewardAndRetainsQuota() (gas: 2967285)\n[PASS] test_failedRewardRollsBackBothStaminaAndPointsAtomically() (gas: 7372590)\n[PASS] test_fullQueueBoundAndMaximumRoundGas() (gas: 33309048)\nLogs:\n  32-player round lock gas: 6522986\n  32-player round fulfill gas: 5143941\n\n[PASS] test_invalidIdsCannotCreateStateOrRewards() (gas: 135732)\n[PASS] test_lastRandomnessBlockIsUsableAndCannotExpireEarly() (gas: 2414544)\n[PASS] test_leaveMiddleEntryRepairsPositionAndDoesNotConsumeQuota() (gas: 1967934)\n[PASS] test_multipleRoundsInSameBandDoNotInterfere() (gas: 4777619)\n[PASS] test_oddRosterLocksEveryoneAndEntropyChoosesTheBye() (gas: 17183340)\n[PASS] test_queueAndMatchLocksPreventTransfersFeedingTrainingAndCancellation() (gas: 2782503)\n[PASS] test_queueQuotaUsesLockWeekAcrossWeekBoundary() (gas: 1688839)\n[PASS] test_queueTTLAndHungryExpiryCanBeEvictedPermissionlessly() (gas: 1302613)\n[PASS] test_randomnessCannotUseCurrentFutureOrZeroHash() (gas: 2227131)\n[PASS] test_requestLocksWholeEligibleRosterSoLateEntrantCannotFlushTheQueue() (gas: 3220485)\n[PASS] test_requestPrunesStaleEntriesWithoutBlockingHealthyPair() (gas: 2374336)\n[PASS] test_staleOnlyRequestCanBeRecoveredByExplicitEviction() (gas: 1648647)\n[PASS] test_weeklyQuotaIsPerNFTAndSettlementCreditsLockWeek() (gas: 11741878)\n[PASS] test_weightChangesActualRaceOutcomeWithEqualStamina() (gas: 2953475)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 865.88ms (79.43ms CPU time)\n\nRan 20 tests for test/Care.t.sol:CareTest\n[PASS] testFuzz_feedRequiresExactTierPrice(uint8,uint96) (runs: 512, μ: 340680, ~: 340889)\nLogs:\n  Bound result 0\n  Bound result 65\n\n[PASS] test_allTiersFeedAndGiveDistinctTrainingBonus() (gas: 2416125)\n[PASS] test_feedResetsRatherThanStacksAndExactExpiryIsFed() (gas: 571024)\n[PASS] test_fitPetSwitchedToCheapFoodDriftsDownToNormal() (gas: 11791843)\n[PASS] test_hungryGatesTrainingAndQueue() (gas: 1271578)\n[PASS] test_inactivityAndHungerPenaltiesAreNotResetByFrequentTouches() (gas: 1953454)\n[PASS] test_invalidTierAndNonOwnerFeedFail() (gas: 429773)\n[PASS] test_lateTrainingSettlementStillUnlocksAndAccountsNeglect() (gas: 975855)\n[PASS] test_lowFoodOnlyTrainingNeverMakesAPetFit() (gas: 627974007)\n[PASS] test_newbornTakesNoHungerDamageDuringItsFirstFeedWindow() (gas: 1487518)\n[PASS] test_staminaGrowsFarBeyondSmallIntegerLimits() (gas: 5213824)\n[PASS] test_startingStatsAndFeedDefaults() (gas: 375429)\n[PASS] test_sustainedHighFoodWithoutTrainingStillDriftsTowardObese() (gas: 1612354)\n[PASS] test_tierBonusStaysStrictlyOrderedAtHighStamina() (gas: 6851024)\n[PASS] test_trainingCanStartAtFeedExpiryAndSettleAfterCertification() (gas: 893492)\n[PASS] test_trainingCancellationGivesNoRewardAndCannotBeForced() (gas: 1104257)\n[PASS] test_trainingConfigIsSnapshottedAtFeedAndStart() (gas: 1145572)\n[PASS] test_trainingLocksAllActionsAndSettlesExactlyOnce() (gas: 1328729)\n[PASS] test_uint256OverflowRevertsWithoutWrappingAndTrainingCanCancel() (gas: 5289236)\n[PASS] test_weightTransitionsThroughObeseNormalFitAndNeglect() (gas: 2111490)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 866.12ms (1.50s CPU time)\n\nRan 1 test for test/Invariants.t.sol:GameInvariantTest\n[PASS]\nGameInvariantTest invariants:\n[PASS] invariant_bodySupplyQuotaAndLocksStayConsistent\n[PASS] invariant_ethConservation\n[PASS] invariant_pointsAndStaminaHaveOnlyEarnedSources\n GameInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-------------+----------------+-------+---------+----------╮\n| Contract    | Selector       | Calls | Reverts | Discards |\n+===========================================================+\n| GameHandler | advance        | 1033  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | cancelTraining | 1013  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | enqueueOrLeave | 1010  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | feed           | 1054  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | request        | 1024  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | resolve        | 1083  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | trainOrClaim   | 1020  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | withdraw       | 955   | 0       | 0        |\n╰-------------+----------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 12.87s (12.86s CPU time)\n\nRan 3 tests for test/StatefulInvariants.t.sol:StatefulInvariantsTest\n[PASS]\nStatefulInvariantsTest invariants:\n[PASS] invariant_bodyAndFoodStayInRange\n[PASS] invariant_ethInEqualsEthHeldPlusEthWithdrawn\n[PASS] invariant_lockedActivityMatchesItsBackingRecord\n[PASS] invariant_pointsComeOnlyFromSettledRaces\n[PASS] invariant_queueAndActivityDescribeTheSameThing\n[PASS] invariant_roundsAndRacesNeverLeaveAFinishedState\n[PASS] invariant_staminaComesOnlyFromTrainingAndRaces\n[PASS] invariant_supplyIsExactlyWhatWasMinted\n[PASS] invariant_walletLockMatchesTheOnePetItNames\n StatefulInvariantsTest invariants (runs: 96, calls: 9216, reverts: 0)\n\n╭--------------+----------------+-------+---------+----------╮\n| Contract     | Selector       | Calls | Reverts | Discards |\n+============================================================+\n| WorldHandler | advanceBlocks  | 494   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | advanceTime    | 432   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | cancelTraining | 449   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | enqueue        | 478   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | evict          | 465   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | expireRound    | 431   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | feed           | 512   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | feedBadly      | 461   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | forceEth       | 457   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | fulfillRound   | 482   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | leaveQueue     | 472   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | rally          | 453   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | requestRound   | 449   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | setFoodConfig  | 435   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | settleMatch    | 467   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | settleTraining | 464   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | startTraining  | 450   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | strangerProbes | 488   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | transferPet    | 440   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | withdraw       | 437   | 0       | 0        |\n╰--------------+----------------+-------+---------+----------╯\n\n[PASS] test_freeMintsKeepTheSupplyAndAllocationLedgers() (gas: 9239104)\n[PASS] test_seededWalkReachesEveryOutcomeAndKeepsEveryInvariant() (gas: 323738674)\nLogs:\n  feedOk: 26\n  feedLocked: 30\n  feedRefused: 65\n  trainOk: 14\n  trainRefused: 48\n  settleTrainingOk: 5\n  settleTrainingRefused: 53\n  cancelOk: 9\n  enqueueOk: 21\n  enqueueRefused: 43\n  leaveOk: 5\n  evictOk: 5\n  requestOk: 4\n  rallyOk: 16\n  requestRefused: 65\n  fulfillOk: 15\n  expireOk: 4\n  settleMatchOk: 18\n  transferOk: 27\n  transferLocked: 23\n  withdrawOk: 37\n  forceOk: 48\n  configOk: 77\n  strangerRefused: 59\n  byeOk: 3\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 46.90s (47.37s CPU time)\n\nRan 12 test suites in 46.91s (65.17s CPU time): 198 tests passed, 0 failed, 0 skipped (198 total tests)\n","passed":true},{"durationMs":136,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"HamsterRunNFT.acceptOwnership()\",\"HamsterRunNFT.approve(address,uint256)\",\"HamsterRunNFT.cancelTraining(uint256)\",\"HamsterRunNFT.expireMatchLock(uint256)\",\"HamsterRunNFT.feed(uint256,uint8)\",\"HamsterRunNFT.lockMatch(uint256)\",\"HamsterRunNFT.lockQueue(uint256,address)\",\"HamsterRunNFT.mint()\",\"HamsterRunNFT.ownerMint(address)\",\"HamsterRunNFT.releaseBye(uint256)\",\"HamsterRunNFT.rewardMatch(uint256,bool)\",\"HamsterRunNFT.safeTransferFrom(address,address,uint256)\",\"HamsterRunNFT.safeTransferFrom(address,address,uint256,bytes)\",\"HamsterRunNFT.setApprovalForAll(address,bool)\",\"HamsterRunNFT.setFoodConfig(uint256[3],uint256[3])\",\"HamsterRunNFT.setMatchQueue(address)\",\"HamsterRunNFT.setMintOpen(bool)\",\"HamsterRunNFT.settleTraining(uint256)\",\"HamsterRunNFT.startTraining(uint256)\",\"HamsterRunNFT.transferFrom(address,address,uint256)\",\"HamsterRunNFT.transferOwnership(address)\",\"HamsterRunNFT.unlockQueue(uint256)\",\"HamsterRunNFT.withdraw(uint256)\",\"MatchQueue.enqueue(uint256)\",\"MatchQueue.evictExpired(uint256)\",\"MatchQueue.expireRound(uint256)\",\"MatchQueue.fulfillRound(uint256)\",\"MatchQueue.leaveQueue(uint256)\",\"MatchQueue.requestRound(uint256)\",\"MatchQueue.settleMatch(uint256)\"],\"files\":{\".gitignore\":3,\"DESIGN.md\":155,\"LICENSE\":21,\"README.md\":121,\"SECURITY.md\":57,\"abi/HamsterRunNFT.json\":1830,\"abi/ISqueekCore.json\":239,\"abi/MatchQueue.json\":999,\"abi/SHA256.json\":6,\"abi/SqueekCore.upstream.json\":902,\"dependencies.json\":18,\"deployments/sepolia-v2.json\":11,\"deployments/sepolia.json\":30,\"docs/PROVENANCE.md\":22,\"docs/VALIDATION.md\":45,\"docs/core-sepolia-snapshot.json\":28,\"foundry.toml\":27,\"remappings.txt\":2,\"script/Deploy.s.sol\":28,\"src/CoreReader.sol\":86,\"src/GameMath.sol\":44,\"src/HamsterRunNFT.sol\":466,\"src/MatchQueue.sol\":361,\"src/PointsLedger.sol\":18,\"src/interfaces/ISqueekCore.sol\":58,\"test/Care.t.sol\":366,\"test/CareEdges.t.sol\":554,\"test/CoreAbi.t.sol\":65,\"test/CoreTraining.t.sol\":391,\"test/Deployment.t.sol\":103,\"test/Invariants.t.sol\":219,\"test/MatchQueue.t.sol\":604,\"test/MathAndRandomness.t.sol\":122,\"test/NFTAdmin.t.sol\":297,\"test/NFTGuards.t.sol\":568,\"test/QueueEdges.t.sol\":965,\"test/StatefulInvariants.t.sol\":1153,\"test/Tools.test.mjs\":129,\"test/helpers/GameTest.sol\":119,\"test/helpers/MockSqueekCore.sol\":109,\"test/helpers/Probes.sol\":115,\"tools/export-abis.mjs\":39,\"tools/record-deployment.mjs\":89,\"tools/rpc.mjs\":55,\"tools/training-status.mjs\":36},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":4050,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/MatchQueue.sol:293: MatchQueue._createMatch(uint256,bytes32,uint256,MatchQueue.Snapshot,MatchQueue.Snapshot) (src/MatchQueue.sol#293-310) uses a weak PRNG: \"noiseA = uint256(keccak256(bytes)(abi.encode(seed,NOISE,pairIndex,a.tokenId))) % 2001 (src/MatchQueue.sol#301)\"\n[high/medium] weak-prng at src/MatchQueue.sol:174: MatchQueue.fulfillRound(uint256) (src/MatchQueue.sol#174-202) uses a weak PRNG: \"paired = shuffled.length - shuffled.length % 2 (src/MatchQueue.sol#189)\"\n[high/medium] weak-prng at src/MatchQueue.sol:174: MatchQueue.fulfillRound(uint256) (src/MatchQueue.sol#174-202) uses a weak PRNG: \"j = uint256(keccak256(bytes)(abi.encode(seed,PAIR,i))) % (i + 1) (src/MatchQueue.sol#186)\"\n[high/medium] weak-prng at src/MatchQueue.sol:293: MatchQueue._createMatch(uint256,bytes32,uint256,MatchQueue.Snapshot,MatchQueue.Snapshot) (src/MatchQueue.sol#293-310) uses a weak PRNG: \"aWins = scoreA > scoreB || (scoreA == scoreB && uint256(keccak256(bytes)(abi.encode(seed,TIE,pairIndex))) % 2 == 0) (src/MatchQueue.sol#305-306)\"\n[high/medium] weak-prng at src/MatchQueue.sol:293: MatchQueue._createMatch(uint256,bytes32,uint256,MatchQueue.Snapshot,MatchQueue.Snapshot) (src/MatchQueue.sol#293-310) uses a weak PRNG: \"noiseB = uint256(keccak256(bytes)(abi.encode(seed,NOISE,pairIndex,b.tokenId))) % 2001 (src/MatchQueue.sol#302)\"\n[medium/high] incorrect-equality at src/HamsterRunNFT.sol:450: HamsterRunNFT._setBody(uint256,uint256) (src/HamsterRunNFT.sol#450-456) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/HamsterRunNFT.sol:360: HamsterRunNFT.tokenURI(uint256) (src/HamsterRunNFT.sol#360-379) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/HamsterRunNFT.sol:325: HamsterRunNFT.matchesThisWeek(uint256) (src/HamsterRunNFT.sol#325-329) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/HamsterRunNFT.sol:360: HamsterRunNFT.tokenURI(uint256) (src/HamsterRunNFT.sol#360-379) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/MatchQueue.sol:338: Reentrancy in MatchQueue._prune(uint256) (src/MatchQueue.sol#338-348):\n[medium/medium] reentrancy-no-eth at src/MatchQueue.sol:146: Reentrancy in MatchQueue.requestRound(uint256) (src/MatchQueue.sol#146-170):\n[medium/medium] reentrancy-no-eth at src/MatchQueue.sol:205: Reentrancy in MatchQueue.expireRound(uint256) (src/MatchQueue.sol#205-215):\n[medium/medium] uninitialized-local at src/MatchQueue.sol:150: MatchQueue.requestRound(uint256).count (src/MatchQueue.sol#150) is a local variable never initialized\n[low/medium] calls-loop at src/MatchQueue.sol:146: MatchQueue.requestRound(uint256) (src/MatchQueue.sol#146-170) has external calls inside a loop: (player,stamina,weight) = nft.lockMatch(tokenId) (src/MatchQueue.sol#166)\n[low/medium] calls-loop at src/MatchQueue.sol:324: MatchQueue._unlockEntry(MatchQueue.Entry,bool) (src/MatchQueue.sol#324-328) has external calls inside a loop: nft.unlockQueue(entry.tokenId) (src/MatchQueue.sol#327)\n[low/medium] calls-loop at src/MatchQueue.sol:330: MatchQueue._expired(MatchQueue.Entry) (src/MatchQueue.sol#330-332) has external calls inside a loop: block.timestamp > entry.joinedAt + QUEUE_TTL || nft.isHungry(entry.tokenId) (src/MatchQueue.sol#331)\n[low/medium] calls-loop at src/MatchQueue.sol:330: MatchQueue._expired(MatchQueue.Entry) (src/MatchQueue.sol#330-332) has external calls inside a loop: block.timestamp > entry.joinedAt + QUEUE_TTL || nft.isHungry(entry.tokenId) (src/MatchQueue.sol#331)\n[low/medium] calls-loop at src/MatchQueue.sol:205: MatchQueue.expireRound(uint256) (src/MatchQueue.sol#205-215) has external calls inside a loop: nft.expireMatchLock(racer.tokenId) (src/MatchQueue.sol#212)\n[low/medium] reentrancy-benign at src/MatchQueue.sol:146: Reentrancy in MatchQueue.requestRound(uint256) (src/MatchQueue.sol#146-170):\n[low/medium] timestamp at src/CoreReader.sol:28: CoreReader.currentRound() (src/CoreReader.sol#28-38) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:444: HamsterRunNFT._improveBody(uint256,uint256,uint256) (src/HamsterRunNFT.sol#444-448) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:450: HamsterRunNFT._setBody(uint256,uint256) (src/HamsterRunNFT.sol#450-456) uses timestamp for comparisons\n[low/medium] timestamp at src/MatchQueue.sol:244: MatchQueue.eligibleCount(uint256) (src/MatchQueue.sol#244-249) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:434: HamsterRunNFT._damageBody(uint256,uint256) (src/HamsterRunNFT.sol#434-437) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:360: HamsterRunNFT.tokenURI(uint256) (src/HamsterRunNFT.sol#360-379) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:325: HamsterRunNFT.matchesThisWeek(uint256) (src/HamsterRunNFT.sol#325-329) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:411: HamsterRunNFT._projectBody(uint256) (src/HamsterRunNFT.sol#411-424) uses timestamp for comparisons\n[low/medium] timestamp at src/MatchQueue.sol:330: MatchQueue._expired(MatchQueue.Entry) (src/MatchQueue.sol#330-332) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:320: HamsterRunNFT.isHungry(uint256) (src/HamsterRunNFT.sol#320-323) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:250: HamsterRunNFT.lockMatch(uint256) (src/HamsterRunNFT.sol#250-272) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:192: HamsterRunNFT.startTraining(uint256) (src/HamsterRunNFT.sol#192-203) uses timestamp for comparisons","passed":true},{"durationMs":807,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/HamsterRunNFT.sol:159: Reentrancy: State change after external call (4 places)\n[high] storage-array-memory-edit at src/MatchQueue.sol:152: Storage Array Edited with Memory (4 places)\n[low] centralization-risk at src/HamsterRunNFT.sol:20: Centralization Risk (7 places)\n[low] costly-loop at src/MatchQueue.sol:163: Costly operations inside loop (4 places)\n[low] large-numeric-literal at src/GameMath.sol:33: Large Numeric Literal (8 places)\n[low] literal-instead-of-constant at src/GameMath.sol:33: Literal Instead of Constant (16 places)\n[low] require-revert-in-loop at src/CoreReader.sol:73: Loop Contains `require`/`revert` (2 places)\n[low] unchecked-return at src/HamsterRunNFT.sol:207: Unchecked Return (10 places)\n[low] uninitialized-local-variable at src/CoreReader.sol:73: Uninitialized Local Variable","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"8d1ecded1456d1dd46945f9c58725f427e5075d689c2ef4f578029e23a347930","verifiedTreeHash":"e6bd6e528b1b976f499406091c7cf51ce25eb571","verifierVersion":"0.1.0+3dcb4df2"},{"checks":[{"durationMs":18177,"exitCode":0,"name":"build","output":"Compiling 61 files with Solc 0.8.26\nSolc 0.8.26 finished in 17.91s\nCompiler run successful with warnings:\nWarning (5159): \"selfdestruct\" has been deprecated. Note that, starting from the Cancun hard fork, the underlying opcode no longer deletes the code and data associated with an account and only transfers its Ether to the beneficiary, unless executed in the same transaction in which the contract was created (see EIP-6780). Any use in newly deployed contracts is strongly discouraged even if the new behavior is taken into account. Future changes to the EVM might further reduce the functionality of the opcode.\n  --> test/helpers/Probes.sol:53:9:\n   |\n53 |         selfdestruct(to);\n   |         ^^^^^^^^^^^^\n\n","passed":true},{"durationMs":49289,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/CoreAbi.t.sol:CoreAbiTest\n[PASS] test_historicalWindowSettlesAgainstRawCertifiedCorePage() (gas: 672527)\n[PASS] test_publishedCoreV3AbiMatchesFinalizedSepoliaReadBytes() (gas: 83293)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 2.74ms (780.57µs CPU time)\n\nRan 29 tests for test/NFTGuards.t.sol:NFTGuardsTest\n[PASS] testFuzz_foodConfigAcceptedExactlyWhenStrictlyOrderedAndInBounds(uint256[3],uint256[3]) (runs: 512, μ: 74281, ~: 74075)\nLogs:\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 9999\n  Bound result 15000\n\n[PASS] testFuzz_withdrawPaysExactlyTheRequestedAmountOrFails(uint256) (runs: 512, μ: 768286, ~: 769424)\nLogs:\n  Bound result 25\n\n[PASS] test_aSecondQueueAimedAtABoundCollectionGetsNowhere() (gas: 928837)\n[PASS] test_approvalsSetDuringALockCannotMoveThePetUntilItUnlocks() (gas: 912303)\n[PASS] test_bindingRejectsEveryQueueThatDoesNotNameThisCollection() (gas: 348049)\n[PASS] test_boundQueueCanNeverBeReplacedEvenByOwnerOrNextOwner() (gas: 482755)\n[PASS] test_directCallsFromNeitherOwnerNorPlayerCanMoveALockedPet() (gas: 912723)\n[PASS] test_everyQueueMethodFailsBeforeBinding() (gas: 404797)\n[PASS] test_feesFollowOwnershipOnlyAfterAcceptance() (gas: 591237)\n[PASS] test_forcedEthIsWithdrawableAndCreatesNoEntitlement() (gas: 139827)\n[PASS] test_lockMatchAppliesNeglectBeforeTheSnapshot() (gas: 653026)\n[PASS] test_lockMatchGuardsAndReturnsTheLiveSnapshot() (gas: 1087402)\n[PASS] test_lockQueueGuards() (gas: 750535)\n[PASS] test_lockQueueRefusesATrainingPet() (gas: 551852)\n[PASS] test_mintCallbackHitsTheGuardOnEveryGameEntry() (gas: 1058787)\n[PASS] test_mintWindowReopensButNeverRefundsTheAllocation() (gas: 655101)\n[PASS] test_mintingContractThatMovesThePetAwayStillUsedItsAllocation() (gas: 1117253)\n[PASS] test_noContractAcceptsPlainEthAndNonpayableEntriesRefuseValue() (gas: 555105)\n[PASS] test_ownerMintedPetsLeaveTheRecipientsFreeMintAvailable() (gas: 554424)\n[PASS] test_pendingHandoverCanBeCancelledWithTheZeroAddress() (gas: 133181)\n[PASS] test_petEnteredOnItsLastAttemptCanStillLockAfterTheWeekTurns() (gas: 1359280)\n[PASS] test_quotaCountsLocksNotEntriesAndResetsOnlyOnANewWeek() (gas: 2496856)\n[PASS] test_receiverActingInsideASafeTransferStaysBoundByTheLock() (gas: 1037828)\n[PASS] test_renounceFailsForEveryCallerAndChangesNothing() (gas: 39094)\n[PASS] test_rewardCreditsOnceAndOnlyTheDocumentedAmount() (gas: 1290434)\n[PASS] test_tokenUriIsTheExactDocumentAndProjectsNeglect() (gas: 728321)\n[PASS] test_transferFailuresDoNotMoveThePet() (gas: 522235)\n[PASS] test_unlockExpireAndRewardOnlyAcceptTheirOwnActivity() (gas: 941453)\n[PASS] test_withdrawOnAnEmptyContractFails() (gas: 39476)\nSuite result: ok. 29 passed; 0 failed; 0 skipped; finished in 207.74ms (214.96ms CPU time)\n\nRan 44 tests for test/QueueEdges.t.sol:QueueEdgesTest\n[PASS] testFuzz_exactlyOneResolutionPathExistsAtEveryBlock(uint16) (runs: 512, μ: 2044252, ~: 2194715)\nLogs:\n  Bound result 568\n\n[PASS] testFuzz_twoPlayerRoundMatchesThePinnedFormulas(bytes32) (runs: 512, μ: 2574066, ~: 2573850)\n[PASS] test_aBigStaminaLeadInsideABandOutweighsTheClassGap() (gas: 28169707)\n[PASS] test_anyCallerBuildsTheSameRoster() (gas: 2225233)\n[PASS] test_atEqualStaminaFitBeatsObeseUnderEveryHash() (gas: 50050542)\n[PASS] test_bandEdgesSeparateAt500AndPairInsideTheBand() (gas: 7219929)\n[PASS] test_byeIsSpreadAcrossTheRoster() (gas: 62196350)\n[PASS] test_constantsArePinnedToTheDocumentedValues() (gas: 123668)\n[PASS] test_emptyAndUnknownViewsBehave() (gas: 77615)\n[PASS] test_entriesBecomeLockableExactlyTenBlocksAfterJoining() (gas: 1880502)\n[PASS] test_evictionReportsExpiryAndTheOwnerKeepsThePet() (gas: 750431)\n[PASS] test_expiredOddRoundRefundsNobody() (gas: 2703455)\n[PASS] test_expiredRoundHasNoRacesAndHungryRacersRecoverToo() (gas: 2101766)\n[PASS] test_expiringAFullRosterStaysBoundedAndFreesEveryone() (gas: 26043021)\n[PASS] test_firstRewardFailureRollsBackJustAsTheSecondDoes() (gas: 7110615)\n[PASS] test_fitUsuallyBeatsNormalButTheNoiseKeepsItAContest() (gas: 93729909)\n[PASS] test_fiveExpiredRoundsExhaustTheWeekUntilItTurns() (gas: 7253708)\n[PASS] test_fullBandOfStaleEntriesBlocksEntryUntilOneIsEvicted() (gas: 25402715)\n[PASS] test_identicalLowStaminaPetsStillSplitWinsWhenScoresOftenTie() (gas: 97686279)\n[PASS] test_identicalPetsAreAFairCoinOverManyHashes() (gas: 97720353)\n[PASS] test_idlePetTransferredAwayDoesNotCarryTheWalletLock() (gas: 2504698)\n[PASS] test_leaveAndEvictRejectPetsThatAreNotWaiting() (gas: 2031779)\n[PASS] test_leavingIsAllowedAfterStalenessAndReportsAsVoluntary() (gas: 1001780)\n[PASS] test_lockedRacersCannotImproveTheirSnapshotAndNewcomersCannotJoin() (gas: 2541524)\n[PASS] test_mixedStaleAndOddRosterLocksEveryEligiblePetAndLeavesOnlyTheNewcomer() (gas: 4696919)\n[PASS] test_nobodyCanJoinAndLockAgainstALoneWaiterInOneTransaction() (gas: 1513393)\n[PASS] test_normalUsuallyBeatsObeseButTheNoiseKeepsItAContest() (gas: 97728399)\n[PASS] test_oddRoundGivesTheShuffleChosenByeItsAttemptBack() (gas: 3644359)\n[PASS] test_oneFullBandLeavesOtherBandsOpen() (gas: 19221877)\n[PASS] test_oneWalletRacesOnePetAcrossAllBandsUntilSettled() (gas: 7717249)\n[PASS] test_onlyTheBoundQueueCanReleaseABye() (gas: 1773536)\n[PASS] test_pointsStayWithTheRacerAfterThePetIsSold() (gas: 2515891)\n[PASS] test_racesInOneRoundSettleInAnyOrderAndOnlyFreeTheirOwnPair() (gas: 4886229)\n[PASS] test_rejoiningRestartsTheWait() (gas: 1580602)\n[PASS] test_requestIncludesAPetAtExactFedUntilAndPrunesItOneSecondLater() (gas: 3125259)\n[PASS] test_requestIncludesAnEntryAtExactTtlAndPrunesItOneSecondLater() (gas: 1983285)\n[PASS] test_resultDependsOnlyOnTheTargetBlockHashAcrossTheWholeWindow() (gas: 3109841)\n[PASS] test_seedIsBoundToChainContractAndRound() (gas: 2592242)\n[PASS] test_settlementEmitsTheOutcomeAndPointsTotals() (gas: 2451627)\n[PASS] test_settlingYearsLaterChangesNothingAboutTheRaceOrItsWeek() (gas: 2664568)\n[PASS] test_shuffleReachesEveryOpponentAboutEvenly() (gas: 124393151)\n[PASS] test_snapshotUsesWeightAtRoundLockNotAtEnqueue() (gas: 6364205)\n[PASS] test_snapshotWeightDecidesEvenIfTheLivePetWentDownhillAfterLock() (gas: 6891150)\n[PASS] test_trainingPetCannotEnterAndTheFailedEntryLeavesNoTrace() (gas: 795358)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 354.20ms (831.87ms CPU time)\n\nRan 5 tests for test/MathAndRandomness.t.sol:MathAndRandomnessTest\n[PASS] testFuzz_pairingIsPermutationAndRewardsConserve(uint8,bytes32) (runs: 512, μ: 5604035, ~: 4705795)\n[PASS] testFuzz_raceMathIsOrderedAndSafeAtFullWidth(uint256,uint16) (runs: 512, μ: 7914, ~: 7834)\n[PASS] test_exactRaceFormulaAndNoiseRange() (gas: 60575)\n[PASS] test_fulfillmentCallerAndTimestampCannotChooseResult() (gas: 2633131)\n[PASS] test_futureEntropyActuallyChangesPairingForLargerRoster() (gas: 24441619)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 355.07ms (403.17ms CPU time)\n\nRan 25 tests for test/CoreTraining.t.sol:CoreTrainingTest\n[PASS] testFuzz_everyAcceptedBpsConfigStrictlyOrdersPositiveWork(uint64,uint16,uint16,uint16) (runs: 512, μ: 84449, ~: 84632)\nLogs:\n  Bound result 30116\n  Bound result 39545\n  Bound result 48774\n\n[PASS] testFuzz_gainIsExactlyCertifiedWorkTimesCapturedTier(uint64,uint8) (runs: 512, μ: 898439, ~: 912211)\n[PASS] testFuzz_gainIsMonotonicAndRoundingIsDown(uint64,uint16) (runs: 512, μ: 5691, ~: 5700)\n[PASS] testFuzz_malformedPageCannotPartiallyCreditOrUnlock(uint8) (runs: 512, μ: 895283, ~: 894669)\n[PASS] testFuzz_startBooksSixInclusiveRoundsAndCapturesFood(uint16,uint8) (runs: 512, μ: 615956, ~: 626433)\n[PASS] test_approvedSafeTransfersCannotBypassTrainingLock() (gas: 636001)\n[PASS] test_badConfigStopsNewBookingsButCannotTrapOldWork() (gas: 980733)\n[PASS] test_cancelRemainsAvailableWhenCoreDisappears() (gas: 756742)\n[PASS] test_certifiedZeroWorkUnlocksWithoutHealthOrClockReward() (gas: 1094380)\n[PASS] test_configWithCollapsingTierRoundingIsRejected() (gas: 63696)\n[PASS] test_corePauseDoesNotInvalidatePreviouslyCertifiedWork() (gas: 1008760)\n[PASS] test_currentRoundUsesCoreGenesisAndOneBasedRounds() (gas: 124854)\n[PASS] test_elapsedTimeAloneNeverSettlesOrCreatesAGain() (gas: 841135)\n[PASS] test_emptyChainConstructorThenClearFirstUseError() (gas: 415255)\n[PASS] test_invalidReadWindowsRevert() (gas: 69723)\n[PASS] test_nextWindowCannotReplayAlreadyCreditedRounds() (gas: 1209904)\n[PASS] test_oneUnitStrictlyOrdersAllDefaultFoodTiers() (gas: 2095827)\n[PASS] test_onlyBookedWorkCountsEvenWithBacklogAndLaterCertification() (gas: 1130383)\n[PASS] test_overlappingPetsUseTheirOwnExactWindow() (gas: 1643745)\n[PASS] test_partialCertificationCannotCashOutEvenNonzeroWork() (gas: 1013898)\n[PASS] test_previewCannotInventWorkForAnIdleToken() (gas: 396072)\n[PASS] test_roundAndWindowOverflowAreExplicit() (gas: 469413)\n[PASS] test_roundOneReadsLaunchPositionWithoutUnderflow() (gas: 912604)\n[PASS] test_sixActiveRoundsFitOneCompletePage() (gas: 1195835)\n[PASS] test_unavailableStateOrPageNeverFallsBackToTime() (gas: 996004)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 609.32ms (1.65s CPU time)\n\nRan 23 tests for test/MatchQueue.t.sol:MatchQueueTest\n[PASS] test_cannotEnqueueAndLockInOneTransaction() (gas: 2507905)\n[PASS] test_cannotEnqueueOthersDuplicateOrTwoPetsForOneWallet() (gas: 1369718)\n[PASS] test_distinctStaminaBandsCannotPair() (gas: 6000877)\n[PASS] test_eligibilityIsPerEntryAndSurvivesSwapRemoval() (gas: 2563712)\n[PASS] test_endToEndMintFeedTrainQueueRandomMatchSettle() (gas: 3430825)\n[PASS] test_expiredOddRoundReleasesEveryoneAndNobodyIsRefunded() (gas: 2635833)\n[PASS] test_expiredRandomnessReleasesBothPetsWithoutRewardAndRetainsQuota() (gas: 2976243)\n[PASS] test_failedRewardRollsBackBothStaminaAndPointsAtomically() (gas: 7446552)\n[PASS] test_fullQueueBoundAndMaximumRoundGas() (gas: 33417208)\nLogs:\n  32-player round lock gas: 6529088\n  32-player round fulfill gas: 5143941\n\n[PASS] test_invalidIdsCannotCreateStateOrRewards() (gas: 135776)\n[PASS] test_lastRandomnessBlockIsUsableAndCannotExpireEarly() (gas: 2421382)\n[PASS] test_leaveMiddleEntryRepairsPositionAndDoesNotConsumeQuota() (gas: 1977017)\n[PASS] test_multipleRoundsInSameBandDoNotInterfere() (gas: 4791295)\n[PASS] test_oddRosterLocksEveryoneAndEntropyChoosesTheBye() (gas: 17212162)\n[PASS] test_queueAndMatchLocksPreventTransfersFeedingTrainingAndCancellation() (gas: 2789457)\n[PASS] test_queueQuotaUsesLockWeekAcrossWeekBoundary() (gas: 1695041)\n[PASS] test_queueTTLAndHungryExpiryCanBeEvictedPermissionlessly() (gas: 1306678)\n[PASS] test_randomnessCannotUseCurrentFutureOrZeroHash() (gas: 2233589)\n[PASS] test_requestLocksWholeEligibleRosterSoLateEntrantCannotFlushTheQueue() (gas: 3232977)\n[PASS] test_requestPrunesStaleEntriesWithoutBlockingHealthyPair() (gas: 2383774)\n[PASS] test_staleOnlyRequestCanBeRecoveredByExplicitEviction() (gas: 1655231)\n[PASS] test_weeklyQuotaIsPerNFTAndSettlementCreditsLockWeek() (gas: 11753028)\n[PASS] test_weightChangesActualRaceOutcomeWithEqualStamina() (gas: 2961811)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 614.26ms (79.51ms CPU time)\n\nRan 3 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_constructorsDoNotNeedDependenciesToExist() (gas: 12863)\n[PASS] test_factoryDeploymentsHaveExplicitOwnerAndNoForbiddenRuntime() (gas: 30867803)\n[PASS] test_scriptsUseArgumentsAndRejectOtherChains() (gas: 13475107)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 614.44ms (209.25ms CPU time)\n\nRan 12 tests for test/NFTAdmin.t.sol:NFTAdminTest\n[PASS] test_adminConfigurationAccessAndBounds() (gas: 652746)\n[PASS] test_erc721InterfacesMetadataAndApprovedTransfer() (gas: 571122)\n[PASS] test_mintClosedByDefaultAndOnlyOwnerCanOpen() (gas: 387570)\n[PASS] test_oneFreeMintPerWalletSurvivesTransfers() (gas: 642279)\n[PASS] test_ownerMintWorksWhileClosedButCannotMintToZero() (gas: 521183)\n[PASS] test_ownershipUsesTwoStepAndCannotRenounce() (gas: 194415)\n[PASS] test_queueMustBeConfiguredOnceAndBoundToThisNFT() (gas: 961463)\n[PASS] test_queueOnlyMethodsRejectDirectUsersAndOwner() (gas: 525025)\n[PASS] test_safeMintReceiverCannotReenterAndRejectionRollsBack() (gas: 965133)\n[PASS] test_supplyExactly9999AcrossOwnerAndFreeMints() (gas: 642399)\n[PASS] test_withdrawConservesProceedsAndOnlyPaysOwner() (gas: 894511)\n[PASS] test_withdrawRejectingOwnerRollsBackAndReentryFails() (gas: 825895)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 633.93ms (583.93ms CPU time)\n\nRan 31 tests for test/CareEdges.t.sol:CareEdgesTest\n[PASS] testFuzz_betterScoreNeverGivesAWorseClass(uint8) (runs: 512, μ: 7134, ~: 6972)\nLogs:\n  Bound result 20\n\n[PASS] testFuzz_feedAlwaysSetsDeadlineFromNowAndNeverShortensIt(uint8,uint8,uint32) (runs: 512, μ: 555721, ~: 553171)\nLogs:\n  Bound result 1\n  Bound result 0\n  Bound result 1\n\n[PASS] testFuzz_feedingAnywhereInTheNewbornWindowCostsOnlyIdleDays(uint32,uint8) (runs: 512, μ: 412010, ~: 409925)\nLogs:\n  Bound result 1\n  Bound result 2960\n\n[PASS] testFuzz_hungryExactlyAfterTheDeadline(uint32) (runs: 512, μ: 389195, ~: 389022)\nLogs:\n  Bound result 30\n\n[PASS] testFuzz_lowFoodAloneNeverMakesAPetFit(uint8) (runs: 512, μ: 6316563, ~: 4866410)\nLogs:\n  Bound result 32\n\n[PASS] testFuzz_neglectIsPathIndependentAndIdempotent(uint8,uint32,uint32) (runs: 512, μ: 594295, ~: 593784)\nLogs:\n  Bound result 664\n  Bound result 49152\n  Bound result 0\n\n[PASS] testFuzz_nonexistentPetsRevertEverywhere(uint256) (runs: 512, μ: 304547, ~: 299248)\nLogs:\n  Bound result 25\n\n[PASS] testFuzz_scoreNeverRisesFromTimeAlone(uint8,uint32,uint32) (runs: 512, μ: 448972, ~: 450849)\nLogs:\n  Bound result 0\n  Bound result 664\n  Bound result 49152\n\n[PASS] test_aFitPetOnACheapDietTrainingDailyDriftsToNormalNotBelow() (gas: 39072274)\n[PASS] test_cancelDoesNotResetTheIdleClockButSettlingDoes() (gas: 1576823)\n[PASS] test_cancelledTrainingCreditsNothingAndCannotBeReplayed() (gas: 936760)\n[PASS] test_cheaperRefeedDowngradesTheNextTrainingBonus() (gas: 850258)\n[PASS] test_feedingOneSecondAfterTheNewbornWindowPaysOneHungerDay() (gas: 424914)\n[PASS] test_feedingStopsHungerDamageButNeverRefundsIdleDamage() (gas: 665271)\n[PASS] test_largerWorkEarnsMoreBodyCreditOnlyUpToTheDocumentedCap() (gas: 2338413)\n[PASS] test_longNeglectSaturatesAtZeroAndFoodRecoversFromThere() (gas: 699488)\n[PASS] test_lowFoodTrainingStopsAtTheCeilingOfSixty() (gas: 7802797)\n[PASS] test_midFoodTrainingPassesSixtyAndReachesFit() (gas: 5474110)\n[PASS] test_newbornNeglectFollowsThePinnedSchedule() (gas: 583833)\n[PASS] test_operatorsMayMoveAPetButNeverPlayIt() (gas: 694281)\n[PASS] test_paymentRaisedOrLoweredInTheSameBlockNeverOverOrUndercharges() (gas: 472287)\n[PASS] test_rejectedFeedLeavesEveryFieldUntouched() (gas: 636091)\n[PASS] test_repeatedFoodSaturatesBothEndsOfTheBodyRange() (gas: 2104531)\n[PASS] test_settleAndCancelRejectEveryNonTrainingActivity() (gas: 1886172)\n[PASS] test_startingOnTheLastFedSecondSettlesAfterExpiry() (gas: 926772)\n[PASS] test_storedEnumFollowsTheScoreAcrossBoundariesInBothDirections() (gas: 11834078)\n[PASS] test_trainedPetsRankByFoodTierAndBeatUntrainedOnes() (gas: 1906684)\n[PASS] test_trainingAtFullStaminaWidthKeepsGrowingUntilArithmeticStops() (gas: 5849895)\n[PASS] test_transferKeepsAllCareStateAndGivesNoReset() (gas: 1189742)\n[PASS] test_weightClassBoundariesArePinned() (gas: 5914)\n[PASS] test_withoutTrainingEveryFoodRegimeDriftsDownInTierOrder() (gas: 2707105)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 634.01ms (2.93s CPU time)\n\nRan 20 tests for test/Care.t.sol:CareTest\n[PASS] testFuzz_feedRequiresExactTierPrice(uint8,uint96) (runs: 512, μ: 342952, ~: 343153)\nLogs:\n  Bound result 2\n  Bound result 10\n\n[PASS] test_allTiersFeedAndGiveDistinctTrainingBonus() (gas: 2499255)\n[PASS] test_feedResetsRatherThanStacksAndExactExpiryIsFed() (gas: 574305)\n[PASS] test_fitPetSwitchedToCheapFoodDriftsDownToNormal() (gas: 12011516)\n[PASS] test_hungryGatesTrainingAndQueue() (gas: 1275369)\n[PASS] test_inactivityAndHungerPenaltiesAreNotResetByFrequentTouches() (gas: 1962293)\n[PASS] test_invalidTierAndNonOwnerFeedFail() (gas: 432037)\n[PASS] test_lateTrainingSettlementStillUnlocksAndAccountsNeglect() (gas: 997161)\n[PASS] test_lowFoodOnlyTrainingNeverMakesAPetFit() (gas: 639476007)\n[PASS] test_newbornTakesNoHungerDamageDuringItsFirstFeedWindow() (gas: 1496736)\n[PASS] test_staminaGrowsFarBeyondSmallIntegerLimits() (gas: 5308043)\n[PASS] test_startingStatsAndFeedDefaults() (gas: 377864)\n[PASS] test_sustainedHighFoodWithoutTrainingStillDriftsTowardObese() (gas: 1619442)\n[PASS] test_tierBonusStaysStrictlyOrderedAtHighStamina() (gas: 7000248)\n[PASS] test_trainingCanStartAtFeedExpiryAndSettleAfterCertification() (gas: 921202)\n[PASS] test_trainingCancellationGivesNoRewardAndCannotBeForced() (gas: 1137445)\n[PASS] test_trainingConfigIsSnapshottedAtFeedAndStart() (gas: 1173740)\n[PASS] test_trainingLocksAllActionsAndSettlesExactlyOnce() (gas: 1417275)\n[PASS] test_uint256OverflowRevertsWithoutWrappingAndTrainingCanCancel() (gas: 5390280)\n[PASS] test_weightTransitionsThroughObeseNormalFitAndNeglect() (gas: 2150090)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 881.12ms (1.53s CPU time)\n\nRan 15 tests for test/CertificationWait.t.sol:CertificationWaitTest\n[PASS] testFuzz_lockDurationNeverChangesIdleDamage(uint32,bool) (runs: 512, μ: 912968, ~: 950615)\nLogs:\n  Bound result 6\n\n[PASS] testFuzz_petsInOneBandAreWithinAFactorOfTwoAndBandsAreMonotonic(uint256,uint256) (runs: 512, μ: 43950, ~: 43636)\nLogs:\n  Bound result 2320134807272516332134995716853468048\n  Bound result 169903169\n\n[PASS] test_bandForStaminaTable() (gas: 114371)\n[PASS] test_cancelAfterALagResumesTheIdleClockWithoutAReset() (gas: 715044)\n[PASS] test_certificationWaitIsNotBilledAsInactivity() (gas: 973391)\n[PASS] test_comparableLiveWorkPairsAndRacesAfterOneWindowEach() (gas: 3490627)\n[PASS] test_feedingStaysLockedWhileQueuedOrMatched() (gas: 1751866)\n[PASS] test_feedingWhileBookedIsStillOwnerOnlyAndOpensNoOtherAction() (gas: 945938)\n[PASS] test_hungerDuringTheWaitStaysTheOwnersResponsibility() (gas: 924939)\n[PASS] test_idleDaysCompletedBeforeBookingAreChargedAndThePartialDayCarriesOver() (gas: 985486)\n[PASS] test_ownerCanFeedThroughTheWaitAndTheBookingIsUntouched() (gas: 1317512)\n[PASS] test_pinnedLiveWindowAcrossTiersLandsInNeighbouringBands() (gas: 2437973)\n[PASS] test_sevenDayLagWithThePinnedLiveWindowEndsFitWhenFedOnCadence() (gas: 1078633)\n[PASS] test_untrainedPetsAllShareBandZeroAndCannotMeetATrainedOne() (gas: 2926308)\n[PASS] test_zeroWorkSettleAfterALagResumesTheIdleClockWithoutAReset() (gas: 824816)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 881.00ms (852.80ms CPU time)\n\nRan 1 test for test/Invariants.t.sol:GameInvariantTest\n[PASS]\nGameInvariantTest invariants:\n[PASS] invariant_bodySupplyQuotaAndLocksStayConsistent\n[PASS] invariant_ethConservation\n[PASS] invariant_pointsAndStaminaHaveOnlyEarnedSources\n GameInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-------------+----------------+-------+---------+----------╮\n| Contract    | Selector       | Calls | Reverts | Discards |\n+===========================================================+\n| GameHandler | advance        | 1033  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | cancelTraining | 1013  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | enqueueOrLeave | 1010  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | feed           | 1054  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | request        | 1024  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | resolve        | 1083  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | trainOrClaim   | 1020  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | withdraw       | 955   | 0       | 0        |\n╰-------------+----------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 14.12s (14.10s CPU time)\n\nRan 3 tests for test/StatefulInvariants.t.sol:StatefulInvariantsTest\n[PASS]\nStatefulInvariantsTest invariants:\n[PASS] invariant_bodyAndFoodStayInRange\n[PASS] invariant_ethInEqualsEthHeldPlusEthWithdrawn\n[PASS] invariant_lockedActivityMatchesItsBackingRecord\n[PASS] invariant_pointsComeOnlyFromSettledRaces\n[PASS] invariant_queueAndActivityDescribeTheSameThing\n[PASS] invariant_roundsAndRacesNeverLeaveAFinishedState\n[PASS] invariant_staminaComesOnlyFromTrainingAndRaces\n[PASS] invariant_supplyIsExactlyWhatWasMinted\n[PASS] invariant_walletLockMatchesTheOnePetItNames\n StatefulInvariantsTest invariants (runs: 96, calls: 9216, reverts: 0)\n\n╭--------------+----------------+-------+---------+----------╮\n| Contract     | Selector       | Calls | Reverts | Discards |\n+============================================================+\n| WorldHandler | advanceBlocks  | 494   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | advanceTime    | 432   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | cancelTraining | 449   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | enqueue        | 478   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | evict          | 465   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | expireRound    | 431   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | feed           | 512   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | feedBadly      | 461   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | forceEth       | 457   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | fulfillRound   | 482   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | leaveQueue     | 472   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | rally          | 453   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | requestRound   | 449   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | setFoodConfig  | 435   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | settleMatch    | 467   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | settleTraining | 464   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | startTraining  | 450   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | strangerProbes | 488   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | transferPet    | 440   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | withdraw       | 437   | 0       | 0        |\n╰--------------+----------------+-------+---------+----------╯\n\n[PASS] test_freeMintsKeepTheSupplyAndAllocationLedgers() (gas: 9278722)\n[PASS] test_seededWalkReachesEveryOutcomeAndKeepsEveryInvariant() (gas: 324777322)\nLogs:\n  feedOk: 26\n  feedLocked: 21\n  feedWhileTraining: 9\n  feedRefused: 65\n  trainOk: 13\n  trainRefused: 49\n  settleTrainingOk: 5\n  settleTrainingRefused: 53\n  cancelOk: 8\n  enqueueOk: 18\n  enqueueRefused: 46\n  leaveOk: 4\n  evictOk: 2\n  requestOk: 1\n  rallyOk: 21\n  requestRefused: 68\n  fulfillOk: 16\n  expireOk: 4\n  settleMatchOk: 19\n  transferOk: 27\n  transferLocked: 23\n  withdrawOk: 37\n  forceOk: 48\n  configOk: 77\n  strangerRefused: 59\n  byeOk: 6\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 49.02s (49.46s CPU time)\n\nRan 13 test suites in 49.03s (68.92s CPU time): 213 tests passed, 0 failed, 0 skipped (213 total tests)\n","passed":true},{"durationMs":310,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"HamsterRunNFT.acceptOwnership()\",\"HamsterRunNFT.approve(address,uint256)\",\"HamsterRunNFT.cancelTraining(uint256)\",\"HamsterRunNFT.expireMatchLock(uint256)\",\"HamsterRunNFT.feed(uint256,uint8)\",\"HamsterRunNFT.lockMatch(uint256)\",\"HamsterRunNFT.lockQueue(uint256,address)\",\"HamsterRunNFT.mint()\",\"HamsterRunNFT.ownerMint(address)\",\"HamsterRunNFT.releaseBye(uint256)\",\"HamsterRunNFT.rewardMatch(uint256,bool)\",\"HamsterRunNFT.safeTransferFrom(address,address,uint256)\",\"HamsterRunNFT.safeTransferFrom(address,address,uint256,bytes)\",\"HamsterRunNFT.setApprovalForAll(address,bool)\",\"HamsterRunNFT.setFoodConfig(uint256[3],uint256[3])\",\"HamsterRunNFT.setMatchQueue(address)\",\"HamsterRunNFT.setMintOpen(bool)\",\"HamsterRunNFT.settleTraining(uint256)\",\"HamsterRunNFT.startTraining(uint256)\",\"HamsterRunNFT.transferFrom(address,address,uint256)\",\"HamsterRunNFT.transferOwnership(address)\",\"HamsterRunNFT.unlockQueue(uint256)\",\"HamsterRunNFT.withdraw(uint256)\",\"MatchQueue.enqueue(uint256)\",\"MatchQueue.evictExpired(uint256)\",\"MatchQueue.expireRound(uint256)\",\"MatchQueue.fulfillRound(uint256)\",\"MatchQueue.leaveQueue(uint256)\",\"MatchQueue.requestRound(uint256)\",\"MatchQueue.settleMatch(uint256)\"],\"files\":{\".gitignore\":3,\"DESIGN.md\":187,\"LICENSE\":21,\"README.md\":124,\"SECURITY.md\":60,\"abi/HamsterRunNFT.json\":1830,\"abi/ISqueekCore.json\":239,\"abi/MatchQueue.json\":1018,\"abi/SHA256.json\":6,\"abi/SqueekCore.upstream.json\":902,\"dependencies.json\":18,\"deployments/sepolia-v2.json\":11,\"deployments/sepolia.json\":30,\"docs/PROVENANCE.md\":22,\"docs/VALIDATION.md\":48,\"docs/core-sepolia-snapshot.json\":28,\"foundry.toml\":27,\"remappings.txt\":2,\"script/Deploy.s.sol\":28,\"src/CoreReader.sol\":86,\"src/GameMath.sol\":44,\"src/HamsterRunNFT.sol\":494,\"src/MatchQueue.sol\":372,\"src/PointsLedger.sol\":18,\"src/interfaces/ISqueekCore.sol\":58,\"test/Care.t.sol\":375,\"test/CareEdges.t.sol\":568,\"test/CertificationWait.t.sol\":283,\"test/CoreAbi.t.sol\":65,\"test/CoreTraining.t.sol\":395,\"test/Deployment.t.sol\":103,\"test/Invariants.t.sol\":220,\"test/MatchQueue.t.sol\":611,\"test/MathAndRandomness.t.sol\":122,\"test/NFTAdmin.t.sol\":297,\"test/NFTGuards.t.sol\":568,\"test/QueueEdges.t.sol\":970,\"test/StatefulInvariants.t.sol\":1169,\"test/Tools.test.mjs\":129,\"test/helpers/GameTest.sol\":119,\"test/helpers/MockSqueekCore.sol\":109,\"test/helpers/Probes.sol\":115,\"tools/export-abis.mjs\":39,\"tools/record-deployment.mjs\":89,\"tools/rpc.mjs\":55,\"tools/training-status.mjs\":36},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":5060,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/MatchQueue.sol:304: MatchQueue._createMatch(uint256,bytes32,uint256,MatchQueue.Snapshot,MatchQueue.Snapshot) (src/MatchQueue.sol#304-321) uses a weak PRNG: \"noiseA = uint256(keccak256(bytes)(abi.encode(seed,NOISE,pairIndex,a.tokenId))) % 2001 (src/MatchQueue.sol#312)\"\n[high/medium] weak-prng at src/MatchQueue.sol:178: MatchQueue.fulfillRound(uint256) (src/MatchQueue.sol#178-206) uses a weak PRNG: \"j = uint256(keccak256(bytes)(abi.encode(seed,PAIR,i))) % (i + 1) (src/MatchQueue.sol#190)\"\n[high/medium] weak-prng at src/MatchQueue.sol:304: MatchQueue._createMatch(uint256,bytes32,uint256,MatchQueue.Snapshot,MatchQueue.Snapshot) (src/MatchQueue.sol#304-321) uses a weak PRNG: \"noiseB = uint256(keccak256(bytes)(abi.encode(seed,NOISE,pairIndex,b.tokenId))) % 2001 (src/MatchQueue.sol#313)\"\n[high/medium] weak-prng at src/MatchQueue.sol:304: MatchQueue._createMatch(uint256,bytes32,uint256,MatchQueue.Snapshot,MatchQueue.Snapshot) (src/MatchQueue.sol#304-321) uses a weak PRNG: \"aWins = scoreA > scoreB || (scoreA == scoreB && uint256(keccak256(bytes)(abi.encode(seed,TIE,pairIndex))) % 2 == 0) (src/MatchQueue.sol#316-317)\"\n[high/medium] weak-prng at src/MatchQueue.sol:178: MatchQueue.fulfillRound(uint256) (src/MatchQueue.sol#178-206) uses a weak PRNG: \"paired = shuffled.length - shuffled.length % 2 (src/MatchQueue.sol#193)\"\n[medium/high] incorrect-equality at src/HamsterRunNFT.sol:369: HamsterRunNFT.tokenURI(uint256) (src/HamsterRunNFT.sol#369-388) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/HamsterRunNFT.sol:369: HamsterRunNFT.tokenURI(uint256) (src/HamsterRunNFT.sol#369-388) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/HamsterRunNFT.sol:334: HamsterRunNFT.matchesThisWeek(uint256) (src/HamsterRunNFT.sol#334-338) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/HamsterRunNFT.sol:478: HamsterRunNFT._setBody(uint256,uint256) (src/HamsterRunNFT.sol#478-484) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/MatchQueue.sol:349: Reentrancy in MatchQueue._prune(uint256) (src/MatchQueue.sol#349-359):\n[medium/medium] reentrancy-no-eth at src/MatchQueue.sol:209: Reentrancy in MatchQueue.expireRound(uint256) (src/MatchQueue.sol#209-219):\n[medium/medium] reentrancy-no-eth at src/MatchQueue.sol:150: Reentrancy in MatchQueue.requestRound(uint256) (src/MatchQueue.sol#150-174):\n[medium/medium] uninitialized-local at src/MatchQueue.sol:154: MatchQueue.requestRound(uint256).count (src/MatchQueue.sol#154) is a local variable never initialized\n[low/medium] calls-loop at src/MatchQueue.sol:150: MatchQueue.requestRound(uint256) (src/MatchQueue.sol#150-174) has external calls inside a loop: (player,stamina,weight) = nft.lockMatch(tokenId) (src/MatchQueue.sol#170)\n[low/medium] calls-loop at src/MatchQueue.sol:335: MatchQueue._unlockEntry(MatchQueue.Entry,bool) (src/MatchQueue.sol#335-339) has external calls inside a loop: nft.unlockQueue(entry.tokenId) (src/MatchQueue.sol#338)\n[low/medium] calls-loop at src/MatchQueue.sol:341: MatchQueue._expired(MatchQueue.Entry) (src/MatchQueue.sol#341-343) has external calls inside a loop: block.timestamp > entry.joinedAt + QUEUE_TTL || nft.isHungry(entry.tokenId) (src/MatchQueue.sol#342)\n[low/medium] calls-loop at src/MatchQueue.sol:341: MatchQueue._expired(MatchQueue.Entry) (src/MatchQueue.sol#341-343) has external calls inside a loop: block.timestamp > entry.joinedAt + QUEUE_TTL || nft.isHungry(entry.tokenId) (src/MatchQueue.sol#342)\n[low/medium] calls-loop at src/MatchQueue.sol:209: MatchQueue.expireRound(uint256) (src/MatchQueue.sol#209-219) has external calls inside a loop: nft.expireMatchLock(racer.tokenId) (src/MatchQueue.sol#216)\n[low/medium] reentrancy-benign at src/MatchQueue.sol:150: Reentrancy in MatchQueue.requestRound(uint256) (src/MatchQueue.sol#150-174):\n[low/medium] timestamp at src/HamsterRunNFT.sol:259: HamsterRunNFT.lockMatch(uint256) (src/HamsterRunNFT.sol#259-281) uses timestamp for comparisons\n[low/medium] timestamp at src/CoreReader.sol:28: CoreReader.currentRound() (src/CoreReader.sol#28-38) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:196: HamsterRunNFT.startTraining(uint256) (src/HamsterRunNFT.sol#196-209) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:334: HamsterRunNFT.matchesThisWeek(uint256) (src/HamsterRunNFT.sol#334-338) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:472: HamsterRunNFT._improveBody(uint256,uint256,uint256) (src/HamsterRunNFT.sol#472-476) uses timestamp for comparisons\n[low/medium] timestamp at src/MatchQueue.sol:255: MatchQueue.eligibleCount(uint256) (src/MatchQueue.sol#255-260) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:369: HamsterRunNFT.tokenURI(uint256) (src/HamsterRunNFT.sol#369-388) uses timestamp for comparisons\n[low/medium] timestamp at src/MatchQueue.sol:341: MatchQueue._expired(MatchQueue.Entry) (src/MatchQueue.sol#341-343) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:428: HamsterRunNFT._projectBody(uint256) (src/HamsterRunNFT.sol#428-443) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:478: HamsterRunNFT._setBody(uint256,uint256) (src/HamsterRunNFT.sol#478-484) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:462: HamsterRunNFT._damageBody(uint256,uint256) (src/HamsterRunNFT.sol#462-465) uses timestamp for comparisons\n[low/medium] timestamp at src/HamsterRunNFT.sol:329: HamsterRunNFT.isHungry(uint256) (src/HamsterRunNFT.sol#329-332) uses timestamp for comparisons","passed":true},{"durationMs":919,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/HamsterRunNFT.sol:161: Reentrancy: State change after external call (4 places)\n[high] storage-array-memory-edit at src/MatchQueue.sol:156: Storage Array Edited with Memory (4 places)\n[low] centralization-risk at src/HamsterRunNFT.sol:20: Centralization Risk (7 places)\n[low] costly-loop at src/MatchQueue.sol:167: Costly operations inside loop (4 places)\n[low] large-numeric-literal at src/GameMath.sol:33: Large Numeric Literal (8 places)\n[low] literal-instead-of-constant at src/GameMath.sol:33: Literal Instead of Constant (16 places)\n[low] require-revert-in-loop at src/CoreReader.sol:73: Loop Contains `require`/`revert` (2 places)\n[low] unchecked-return at src/HamsterRunNFT.sol:213: Unchecked Return (10 places)\n[low] uninitialized-local-variable at src/CoreReader.sol:73: Uninitialized Local Variable","passed":true},{"durationMs":5070,"exitCode":0,"name":"proof a399f1ae9409","output":"Compiling 47 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.70s\nCompiler run successful with warnings:\nWarning (5159): \"selfdestruct\" has been deprecated. Note that, starting from the Cancun hard fork, the underlying opcode no longer deletes the code and data associated with an account and only transfers its Ether to the beneficiary, unless executed in the same transaction in which the contract was created (see EIP-6780). Any use in newly deployed contracts is strongly discouraged even if the new behavior is taken into account. Future changes to the EVM might further reduce the functionality of the opcode.\n  --> test/helpers/Probes.sol:53:9:\n   |\n53 |         selfdestruct(to);\n   |         ^^^^^^^^^^^^\n\n\nRan 1 test for test/imd-proof-22d721f2/Proof_a399f1ae9409.t.sol:IdleClockDuringTrainingTest\n[PASS] test_certificationWaitIsNotChargedAsInactivity() (gas: 854094)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.92ms (706.13µs CPU time)\n\nRan 1 test suite in 6.68ms (1.92ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true},{"durationMs":3107,"exitCode":0,"name":"proof 0f38d5c545bc","output":"2026-11-02T12:36:30.619858Z ERROR foundry_compilers_artifacts_solc::sources: error=\"/tmp/imd-verify-s1W4N5/repo/test/imd-proof-22d721f2/Proof_a399f1ae9409.t.sol\": No such file or directory (os error 2)\nCompiling 1 files with Solc 0.8.26\nSolc 0.8.26 finished in 1.93s\nCompiler run successful with warnings:\nWarning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning.\n  --> test/imd-proof-9b3294c8/Proof_0f38d5c545bc.t.sol:28:72:\n   |\n28 |     function roundPage(uint64, uint64, uint256) external pure returns (RoundPage memory page) {\n   |                                                                        ^^^^^^^^^^^^^^^^^^^^^\n\n\nRan 1 test for test/imd-proof-9b3294c8/Proof_0f38d5c545bc.t.sol:FeedWhileTrainingTest\n[PASS] test_ownerCanKeepABookedPetFedWhileCoreCertificationLags() (gas: 697597)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.27ms (316.58µs CPU time)\n\nRan 1 test suite in 5.06ms (1.27ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true},{"durationMs":3306,"exitCode":0,"name":"proof 0b5b9f3ebd8c","output":"2026-11-02T12:36:33.755135Z ERROR foundry_compilers_artifacts_solc::sources: error=\"/tmp/imd-verify-s1W4N5/repo/test/imd-proof-9b3294c8/Proof_0f38d5c545bc.t.sol\": No such file or directory (os error 2)\nCompiling 1 files with Solc 0.8.26\nSolc 0.8.26 finished in 2.19s\nCompiler run successful!\n\nRan 2 tests for test/imd-proof-d0d9e02a/Proof_0b5b9f3ebd8c.t.sol:BandScaleTest\n[PASS] test_oneTrainingGainIsOrdersOfMagnitudeAboveEveryOtherStaminaSource() (gas: 14353)\n[PASS] test_twoPetsTrainedOnComparableLiveWorkStillShareAQueueBand() (gas: 2663907)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 3.35ms (1.58ms CPU time)\n\nRan 1 test suite in 7.32ms (3.35ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"99105bf11d03b710153e313470e07239c1f063fbcc2eadfd03032723e4b1f094","verifiedTreeHash":"22cbb9a1cbddb39a070a02799af510da611f8465","verifierVersion":"0.1.0+3dcb4df2"},{"checks":[{"durationMs":16289,"exitCode":0,"name":"build","output":"Compiling 60 files with Solc 0.8.26\nSolc 0.8.26 finished in 16.10s\nCompiler run successful with warnings:\nWarning (5159): \"selfdestruct\" has been deprecated. Note that, starting from the Cancun hard fork, the underlying opcode no longer deletes the code and data associated with an account and only transfers its Ether to the beneficiary, unless executed in the same transaction in which the contract was created (see EIP-6780). Any use in newly deployed contracts is strongly discouraged even if the new behavior is taken into account. Future changes to the EVM might further reduce the functionality of the opcode.\n  --> test/helpers/Probes.sol:53:9:\n   |\n53 |         selfdestruct(to);\n   |         ^^^^^^^^^^^^\n\n","passed":true},{"durationMs":43683,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 23 tests for test/MatchQueue.t.sol:MatchQueueTest\n[PASS] test_cannotEnqueueAndLockInOneTransaction() (gas: 2500957)\n[PASS] test_cannotEnqueueOthersDuplicateOrTwoPetsForOneWallet() (gas: 1363726)\n[PASS] test_distinctStaminaBandsCannotPair() (gas: 1839290)\n[PASS] test_eligibilityIsPerEntryAndSurvivesSwapRemoval() (gas: 2554397)\n[PASS] test_endToEndMintFeedTrainQueueRandomMatchSettle() (gas: 3428881)\n[PASS] test_expiredOddRoundReleasesEveryoneAndNobodyIsRefunded() (gas: 2625781)\n[PASS] test_expiredRandomnessReleasesBothPetsWithoutRewardAndRetainsQuota() (gas: 2967285)\n[PASS] test_failedRewardRollsBackBothStaminaAndPointsAtomically() (gas: 7372590)\n[PASS] test_fullQueueBoundAndMaximumRoundGas() (gas: 33309048)\nLogs:\n  32-player round lock gas: 6522986\n  32-player round fulfill gas: 5143941\n\n[PASS] test_invalidIdsCannotCreateStateOrRewards() (gas: 135732)\n[PASS] test_lastRandomnessBlockIsUsableAndCannotExpireEarly() (gas: 2414544)\n[PASS] test_leaveMiddleEntryRepairsPositionAndDoesNotConsumeQuota() (gas: 1967934)\n[PASS] test_multipleRoundsInSameBandDoNotInterfere() (gas: 4777619)\n[PASS] test_oddRosterLocksEveryoneAndEntropyChoosesTheBye() (gas: 17183340)\n[PASS] test_queueAndMatchLocksPreventTransfersFeedingTrainingAndCancellation() (gas: 2782503)\n[PASS] test_queueQuotaUsesLockWeekAcrossWeekBoundary() (gas: 1688839)\n[PASS] test_queueTTLAndHungryExpiryCanBeEvictedPermissionlessly() (gas: 1302613)\n[PASS] test_randomnessCannotUseCurrentFutureOrZeroHash() (gas: 2227131)\n[PASS] test_requestLocksWholeEligibleRosterSoLateEntrantCannotFlushTheQueue() (gas: 3220485)\n[PASS] test_requestPrunesStaleEntriesWithoutBlockingHealthyPair() (gas: 2374336)\n[PASS] test_staleOnlyRequestCanBeRecoveredByExplicitEviction() (gas: 1648647)\n[PASS] test_weeklyQuotaIsPerNFTAndSettlementCreditsLockWeek() (gas: 11741878)\n[PASS] test_weightChangesActualRaceOutcomeWithEqualStamina() (gas: 2953475)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 269.28ms (55.23ms CPU time)\n\nRan 5 tests for test/MathAndRandomness.t.sol:MathAndRandomnessTest\n[PASS] testFuzz_pairingIsPermutationAndRewardsConserve(uint8,bytes32) (runs: 512, μ: 5515402, ~: 4691849)\n[PASS] testFuzz_raceMathIsOrderedAndSafeAtFullWidth(uint256,uint16) (runs: 512, μ: 7919, ~: 7834)\n[PASS] test_exactRaceFormulaAndNoiseRange() (gas: 60445)\n[PASS] test_fulfillmentCallerAndTimestampCannotChooseResult() (gas: 2626629)\n[PASS] test_futureEntropyActuallyChangesPairingForLargerRoster() (gas: 24415821)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 293.96ms (554.00ms CPU time)\n\nRan 44 tests for test/QueueEdges.t.sol:QueueEdgesTest\n[PASS] testFuzz_exactlyOneResolutionPathExistsAtEveryBlock(uint16) (runs: 512, μ: 2036573, ~: 2188269)\nLogs:\n  Bound result 198\n\n[PASS] testFuzz_twoPlayerRoundMatchesThePinnedFormulas(bytes32) (runs: 512, μ: 2566792, ~: 2566579)\n[PASS] test_aBigStaminaLeadInsideABandOutweighsTheClassGap() (gas: 28146115)\n[PASS] test_anyCallerBuildsTheSameRoster() (gas: 2218585)\n[PASS] test_atEqualStaminaFitBeatsObeseUnderEveryHash() (gas: 49969094)\n[PASS] test_bandEdgesSeparateAt25AndPairInsideTheBand() (gas: 7141829)\n[PASS] test_byeIsSpreadAcrossTheRoster() (gas: 62164258)\n[PASS] test_constantsArePinnedToTheDocumentedValues() (gas: 115551)\n[PASS] test_emptyAndUnknownViewsBehave() (gas: 77593)\n[PASS] test_entriesBecomeLockableExactlyTenBlocksAfterJoining() (gas: 1874066)\n[PASS] test_evictionReportsExpiryAndTheOwnerKeepsThePet() (gas: 747428)\n[PASS] test_expiredOddRoundRefundsNobody() (gas: 2693023)\n[PASS] test_expiredRoundHasNoRacesAndHungryRacersRecoverToo() (gas: 2094548)\n[PASS] test_expiringAFullRosterStaysBoundedAndFreesEveryone() (gas: 25933175)\n[PASS] test_firstRewardFailureRollsBackJustAsTheSecondDoes() (gas: 7037033)\n[PASS] test_fitUsuallyBeatsNormalButTheNoiseKeepsItAContest() (gas: 93646247)\n[PASS] test_fiveExpiredRoundsExhaustTheWeekUntilItTurns() (gas: 7236800)\n[PASS] test_fullBandOfStaleEntriesBlocksEntryUntilOneIsEvicted() (gas: 25292515)\n[PASS] test_identicalLowStaminaPetsStillSplitWinsWhenScoresOftenTie() (gas: 97603655)\n[PASS] test_identicalPetsAreAFairCoinOverManyHashes() (gas: 97636691)\n[PASS] test_idlePetTransferredAwayDoesNotCarryTheWalletLock() (gas: 2497904)\n[PASS] test_leaveAndEvictRejectPetsThatAreNotWaiting() (gas: 2000057)\n[PASS] test_leavingIsAllowedAfterStalenessAndReportsAsVoluntary() (gas: 998243)\n[PASS] test_lockedRacersCannotImproveTheirSnapshotAndNewcomersCannotJoin() (gas: 2532009)\n[PASS] test_mixedStaleAndOddRosterLocksEveryEligiblePetAndLeavesOnlyTheNewcomer() (gas: 4677385)\n[PASS] test_nobodyCanJoinAndLockAgainstALoneWaiterInOneTransaction() (gas: 1507191)\n[PASS] test_normalUsuallyBeatsObeseButTheNoiseKeepsItAContest() (gas: 97644737)\n[PASS] test_oddRoundGivesTheShuffleChosenByeItsAttemptBack() (gas: 3633649)\n[PASS] test_oneFullBandLeavesOtherBandsOpen() (gas: 19105983)\n[PASS] test_oneWalletRacesOnePetAcrossAllBandsUntilSettled() (gas: 3550228)\n[PASS] test_onlyTheBoundQueueCanReleaseABye() (gas: 1766888)\n[PASS] test_pointsStayWithTheRacerAfterThePetIsSold() (gas: 2508863)\n[PASS] test_racesInOneRoundSettleInAnyOrderAndOnlyFreeTheirOwnPair() (gas: 4872407)\n[PASS] test_rejoiningRestartsTheWait() (gas: 1574164)\n[PASS] test_requestIncludesAPetAtExactFedUntilAndPrunesItOneSecondLater() (gas: 3115141)\n[PASS] test_requestIncludesAnEntryAtExactTtlAndPrunesItOneSecondLater() (gas: 1976791)\n[PASS] test_resultDependsOnlyOnTheTargetBlockHashAcrossTheWholeWindow() (gas: 3103339)\n[PASS] test_seedIsBoundToChainContractAndRound() (gas: 2585784)\n[PASS] test_settlementEmitsTheOutcomeAndPointsTotals() (gas: 2444767)\n[PASS] test_settlingYearsLaterChangesNothingAboutTheRaceOrItsWeek() (gas: 2657686)\n[PASS] test_shuffleReachesEveryOpponentAboutEvenly() (gas: 124374169)\n[PASS] test_snapshotUsesWeightAtRoundLockNotAtEnqueue() (gas: 6291091)\n[PASS] test_snapshotWeightDecidesEvenIfTheLivePetWentDownhillAfterLock() (gas: 6817344)\n[PASS] test_trainingPetCannotEnterAndTheFailedEntryLeavesNoTrace() (gas: 768146)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 565.90ms (758.44ms CPU time)\n\nRan 2 tests for test/CoreAbi.t.sol:CoreAbiTest\n[PASS] test_historicalWindowSettlesAgainstRawCertifiedCorePage() (gas: 655606)\n[PASS] test_publishedCoreV3AbiMatchesFinalizedSepoliaReadBytes() (gas: 83293)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 576.43ms (779.22µs CPU time)\n\nRan 3 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_constructorsDoNotNeedDependenciesToExist() (gas: 12863)\n[PASS] test_factoryDeploymentsHaveExplicitOwnerAndNoForbiddenRuntime() (gas: 30330760)\n[PASS] test_scriptsUseArgumentsAndRejectOtherChains() (gas: 13264571)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 576.62ms (85.42ms CPU time)\n\nRan 12 tests for test/NFTAdmin.t.sol:NFTAdminTest\n[PASS] test_adminConfigurationAccessAndBounds() (gas: 650102)\n[PASS] test_erc721InterfacesMetadataAndApprovedTransfer() (gas: 568509)\n[PASS] test_mintClosedByDefaultAndOnlyOwnerCanOpen() (gas: 385337)\n[PASS] test_oneFreeMintPerWalletSurvivesTransfers() (gas: 637623)\n[PASS] test_ownerMintWorksWhileClosedButCannotMintToZero() (gas: 516717)\n[PASS] test_ownershipUsesTwoStepAndCannotRenounce() (gas: 194415)\n[PASS] test_queueMustBeConfiguredOnceAndBoundToThisNFT() (gas: 958307)\n[PASS] test_queueOnlyMethodsRejectDirectUsersAndOwner() (gas: 522571)\n[PASS] test_safeMintReceiverCannotReenterAndRejectionRollsBack() (gas: 960667)\n[PASS] test_supplyExactly9999AcrossOwnerAndFreeMints() (gas: 639976)\n[PASS] test_withdrawConservesProceedsAndOnlyPaysOwner() (gas: 889603)\n[PASS] test_withdrawRejectingOwnerRollsBackAndReentryFails() (gas: 823441)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 579.79ms (577.87ms CPU time)\n\nRan 31 tests for test/CareEdges.t.sol:CareEdgesTest\n[PASS] testFuzz_betterScoreNeverGivesAWorseClass(uint8) (runs: 512, μ: 7119, ~: 6972)\nLogs:\n  Bound result 56\n\n[PASS] testFuzz_feedAlwaysSetsDeadlineFromNowAndNeverShortensIt(uint8,uint8,uint32) (runs: 512, μ: 552338, ~: 549754)\nLogs:\n  Bound result 1\n  Bound result 0\n  Bound result 1\n\n[PASS] testFuzz_feedingAnywhereInTheNewbornWindowCostsOnlyIdleDays(uint32,uint8) (runs: 512, μ: 409397, ~: 407281)\nLogs:\n  Bound result 0\n  Bound result 111708\n\n[PASS] testFuzz_hungryExactlyAfterTheDeadline(uint32) (runs: 512, μ: 386745, ~: 386568)\nLogs:\n  Bound result 56\n\n[PASS] testFuzz_lowFoodAloneNeverMakesAPetFit(uint8) (runs: 512, μ: 5966190, ~: 4768150)\nLogs:\n  Bound result 32\n\n[PASS] testFuzz_neglectIsPathIndependentAndIdempotent(uint8,uint32,uint32) (runs: 512, μ: 591274, ~: 595059)\nLogs:\n  Bound result 663\n  Bound result 244\n  Bound result 2\n\n[PASS] testFuzz_nonexistentPetsRevertEverywhere(uint256) (runs: 512, μ: 304617, ~: 299204)\nLogs:\n  Bound result 213425765662389412870663262861274874516872496619794121926435104156037\n\n[PASS] testFuzz_scoreNeverRisesFromTimeAlone(uint8,uint32,uint32) (runs: 512, μ: 445920, ~: 448015)\nLogs:\n  Bound result 0\n  Bound result 163891\n  Bound result 1\n\n[PASS] test_aFitPetOnACheapDietTrainingDailyDriftsToNormalNotBelow() (gas: 38364253)\n[PASS] test_cancelDoesNotResetTheIdleClockButSettlingDoes() (gas: 1456229)\n[PASS] test_cancelledTrainingCreditsNothingAndCannotBeReplayed() (gas: 906838)\n[PASS] test_cheaperRefeedDowngradesTheNextTrainingBonus() (gas: 825222)\n[PASS] test_feedingOneSecondAfterTheNewbornWindowPaysOneHungerDay() (gas: 422270)\n[PASS] test_feedingStopsHungerDamageButNeverRefundsIdleDamage() (gas: 661500)\n[PASS] test_largerWorkEarnsMoreBodyCreditOnlyUpToTheDocumentedCap() (gas: 2256504)\n[PASS] test_longNeglectSaturatesAtZeroAndFoodRecoversFromThere() (gas: 695877)\n[PASS] test_lowFoodTrainingStopsAtTheCeilingOfSixty() (gas: 7626885)\n[PASS] test_midFoodTrainingPassesSixtyAndReachesFit() (gas: 5379917)\n[PASS] test_newbornNeglectFollowsThePinnedSchedule() (gas: 579890)\n[PASS] test_operatorsMayMoveAPetButNeverPlayIt() (gas: 669466)\n[PASS] test_paymentRaisedOrLoweredInTheSameBlockNeverOverOrUndercharges() (gas: 469992)\n[PASS] test_rejectedFeedLeavesEveryFieldUntouched() (gas: 633102)\n[PASS] test_repeatedFoodSaturatesBothEndsOfTheBodyRange() (gas: 2095296)\n[PASS] test_settleAndCancelRejectEveryNonTrainingActivity() (gas: 1879970)\n[PASS] test_startingOnTheLastFedSecondSettlesAfterExpiry() (gas: 899469)\n[PASS] test_storedEnumFollowsTheScoreAcrossBoundariesInBothDirections() (gas: 11739326)\n[PASS] test_trainedPetsRankByFoodTierAndBeatUntrainedOnes() (gas: 1849054)\n[PASS] test_trainingAtFullStaminaWidthKeepsGrowingUntilArithmeticStops() (gas: 5746057)\n[PASS] test_transferKeepsAllCareStateAndGivesNoReset() (gas: 1156798)\n[PASS] test_weightClassBoundariesArePinned() (gas: 5914)\n[PASS] test_withoutTrainingEveryFoodRegimeDriftsDownInTierOrder() (gas: 2694338)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 580.13ms (1.97s CPU time)\n\nRan 29 tests for test/NFTGuards.t.sol:NFTGuardsTest\n[PASS] testFuzz_foodConfigAcceptedExactlyWhenStrictlyOrderedAndInBounds(uint256[3],uint256[3]) (runs: 512, μ: 74576, ~: 74084)\nLogs:\n  Bound result 0\n  Bound result 2\n  Bound result 3\n  Bound result 10001\n  Bound result 14999\n\n[PASS] testFuzz_withdrawPaysExactlyTheRequestedAmountOrFails(uint256) (runs: 512, μ: 763307, ~: 764516)\nLogs:\n  Bound result 56\n\n[PASS] test_aSecondQueueAimedAtABoundCollectionGetsNowhere() (gas: 925425)\n[PASS] test_approvalsSetDuringALockCannotMoveThePetUntilItUnlocks() (gas: 909043)\n[PASS] test_bindingRejectsEveryQueueThatDoesNotNameThisCollection() (gas: 348049)\n[PASS] test_boundQueueCanNeverBeReplacedEvenByOwnerOrNextOwner() (gas: 482755)\n[PASS] test_directCallsFromNeitherOwnerNorPlayerCanMoveALockedPet() (gas: 909633)\n[PASS] test_everyQueueMethodFailsBeforeBinding() (gas: 402564)\n[PASS] test_feesFollowOwnershipOnlyAfterAcceptance() (gas: 588783)\n[PASS] test_forcedEthIsWithdrawableAndCreatesNoEntitlement() (gas: 139827)\n[PASS] test_lockMatchAppliesNeglectBeforeTheSnapshot() (gas: 649622)\n[PASS] test_lockMatchGuardsAndReturnsTheLiveSnapshot() (gas: 1081544)\n[PASS] test_lockQueueGuards() (gas: 747334)\n[PASS] test_lockQueueRefusesATrainingPet() (gas: 527037)\n[PASS] test_mintCallbackHitsTheGuardOnEveryGameEntry() (gas: 1056086)\n[PASS] test_mintWindowReopensButNeverRefundsTheAllocation() (gas: 650635)\n[PASS] test_mintingContractThatMovesThePetAwayStillUsedItsAllocation() (gas: 1114384)\n[PASS] test_noContractAcceptsPlainEthAndNonpayableEntriesRefuseValue() (gas: 552651)\n[PASS] test_ownerMintedPetsLeaveTheRecipientsFreeMintAvailable() (gas: 549578)\n[PASS] test_pendingHandoverCanBeCancelledWithTheZeroAddress() (gas: 133181)\n[PASS] test_petEnteredOnItsLastAttemptCanStillLockAfterTheWeekTurns() (gas: 1353989)\n[PASS] test_quotaCountsLocksNotEntriesAndResetsOnlyOnANewWeek() (gas: 2489095)\n[PASS] test_receiverActingInsideASafeTransferStaysBoundByTheLock() (gas: 1034526)\n[PASS] test_renounceFailsForEveryCallerAndChangesNothing() (gas: 39094)\n[PASS] test_rewardCreditsOnceAndOnlyTheDocumentedAmount() (gas: 1283816)\n[PASS] test_tokenUriIsTheExactDocumentAndProjectsNeglect() (gas: 724886)\n[PASS] test_transferFailuresDoNotMoveThePet() (gas: 519432)\n[PASS] test_unlockExpireAndRewardOnlyAcceptTheirOwnActivity() (gas: 938619)\n[PASS] test_withdrawOnAnEmptyContractFails() (gas: 39476)\nSuite result: ok. 29 passed; 0 failed; 0 skipped; finished in 580.13ms (653.60ms CPU time)\n\nRan 20 tests for test/Care.t.sol:CareTest\n[PASS] testFuzz_feedRequiresExactTierPrice(uint8,uint96) (runs: 512, μ: 340680, ~: 340889)\nLogs:\n  Bound result 2\n  Bound result 10\n\n[PASS] test_allTiersFeedAndGiveDistinctTrainingBonus() (gas: 2416125)\n[PASS] test_feedResetsRatherThanStacksAndExactExpiryIsFed() (gas: 571024)\n[PASS] test_fitPetSwitchedToCheapFoodDriftsDownToNormal() (gas: 11791843)\n[PASS] test_hungryGatesTrainingAndQueue() (gas: 1271578)\n[PASS] test_inactivityAndHungerPenaltiesAreNotResetByFrequentTouches() (gas: 1953454)\n[PASS] test_invalidTierAndNonOwnerFeedFail() (gas: 429773)\n[PASS] test_lateTrainingSettlementStillUnlocksAndAccountsNeglect() (gas: 975855)\n[PASS] test_lowFoodOnlyTrainingNeverMakesAPetFit() (gas: 627974007)\n[PASS] test_newbornTakesNoHungerDamageDuringItsFirstFeedWindow() (gas: 1487518)\n[PASS] test_staminaGrowsFarBeyondSmallIntegerLimits() (gas: 5213824)\n[PASS] test_startingStatsAndFeedDefaults() (gas: 375429)\n[PASS] test_sustainedHighFoodWithoutTrainingStillDriftsTowardObese() (gas: 1612354)\n[PASS] test_tierBonusStaysStrictlyOrderedAtHighStamina() (gas: 6851024)\n[PASS] test_trainingCanStartAtFeedExpiryAndSettleAfterCertification() (gas: 893492)\n[PASS] test_trainingCancellationGivesNoRewardAndCannotBeForced() (gas: 1104257)\n[PASS] test_trainingConfigIsSnapshottedAtFeedAndStart() (gas: 1145572)\n[PASS] test_trainingLocksAllActionsAndSettlesExactlyOnce() (gas: 1328729)\n[PASS] test_uint256OverflowRevertsWithoutWrappingAndTrainingCanCancel() (gas: 5289236)\n[PASS] test_weightTransitionsThroughObeseNormalFitAndNeglect() (gas: 2111490)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 772.30ms (1.38s CPU time)\n\nRan 25 tests for test/CoreTraining.t.sol:CoreTrainingTest\n[PASS] testFuzz_everyAcceptedBpsConfigStrictlyOrdersPositiveWork(uint64,uint16,uint16,uint16) (runs: 512, μ: 84446, ~: 84694)\nLogs:\n  Bound result 30116\n  Bound result 39545\n  Bound result 48774\n\n[PASS] testFuzz_gainIsExactlyCertifiedWorkTimesCapturedTier(uint64,uint8) (runs: 512, μ: 871029, ~: 884910)\n[PASS] testFuzz_gainIsMonotonicAndRoundingIsDown(uint64,uint16) (runs: 512, μ: 5688, ~: 5700)\n[PASS] testFuzz_malformedPageCannotPartiallyCreditOrUnlock(uint8) (runs: 512, μ: 865994, ~: 865280)\n[PASS] testFuzz_startBooksSixInclusiveRoundsAndCapturesFood(uint16,uint8) (runs: 512, μ: 586818, ~: 597044)\n[PASS] test_approvedSafeTransfersCannotBypassTrainingLock() (gas: 611186)\n[PASS] test_badConfigStopsNewBookingsButCannotTrapOldWork() (gas: 953430)\n[PASS] test_cancelRemainsAvailableWhenCoreDisappears() (gas: 729250)\n[PASS] test_certifiedZeroWorkUnlocksWithoutHealthOrClockReward() (gas: 1030416)\n[PASS] test_configWithCollapsingTierRoundingIsRejected() (gas: 63696)\n[PASS] test_corePauseDoesNotInvalidatePreviouslyCertifiedWork() (gas: 981457)\n[PASS] test_currentRoundUsesCoreGenesisAndOneBasedRounds() (gas: 124854)\n[PASS] test_elapsedTimeAloneNeverSettlesOrCreatesAGain() (gas: 823130)\n[PASS] test_emptyChainConstructorThenClearFirstUseError() (gas: 412611)\n[PASS] test_invalidReadWindowsRevert() (gas: 69723)\n[PASS] test_nextWindowCannotReplayAlreadyCreditedRounds() (gas: 1171669)\n[PASS] test_oneUnitStrictlyOrdersAllDefaultFoodTiers() (gas: 2013918)\n[PASS] test_onlyBookedWorkCountsEvenWithBacklogAndLaterCertification() (gas: 1103080)\n[PASS] test_overlappingPetsUseTheirOwnExactWindow() (gas: 1589139)\n[PASS] test_partialCertificationCannotCashOutEvenNonzeroWork() (gas: 984308)\n[PASS] test_previewCannotInventWorkForAnIdleToken() (gas: 393618)\n[PASS] test_roundAndWindowOverflowAreExplicit() (gas: 466959)\n[PASS] test_roundOneReadsLaunchPositionWithoutUnderflow() (gas: 885301)\n[PASS] test_sixActiveRoundsFitOneCompletePage() (gas: 1168532)\n[PASS] test_unavailableStateOrPageNeverFallsBackToTime() (gas: 966414)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 772.31ms (2.21s CPU time)\n\nRan 1 test for test/Invariants.t.sol:GameInvariantTest\n[PASS]\nGameInvariantTest invariants:\n[PASS] invariant_bodySupplyQuotaAndLocksStayConsistent\n[PASS] invariant_ethConservation\n[PASS] invariant_pointsAndStaminaHaveOnlyEarnedSources\n GameInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-------------+----------------+-------+---------+----------╮\n| Contract    | Selector       | Calls | Reverts | Discards |\n+===========================================================+\n| GameHandler | advance        | 1033  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | cancelTraining | 1013  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | enqueueOrLeave | 1010  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | feed           | 1054  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | request        | 1024  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | resolve        | 1083  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | trainOrClaim   | 1020  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | withdraw       | 955   | 0       | 0        |\n╰-------------+----------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 12.63s (12.61s CPU time)\n\nRan 3 tests for test/StatefulInvariants.t.sol:StatefulInvariantsTest\n[PASS]\nStatefulInvariantsTest invariants:\n[PASS] invariant_bodyAndFoodStayInRange\n[PASS] invariant_ethInEqualsEthHeldPlusEthWithdrawn\n[PASS] invariant_lockedActivityMatchesItsBackingRecord\n[PASS] invariant_pointsComeOnlyFromSettledRaces\n[PASS] invariant_queueAndActivityDescribeTheSameThing\n[PASS] invariant_roundsAndRacesNeverLeaveAFinishedState\n[PASS] invariant_staminaComesOnlyFromTrainingAndRaces\n[PASS] invariant_supplyIsExactlyWhatWasMinted\n[PASS] invariant_walletLockMatchesTheOnePetItNames\n StatefulInvariantsTest invariants (runs: 96, calls: 9216, reverts: 0)\n\n╭--------------+----------------+-------+---------+----------╮\n| Contract     | Selector       | Calls | Reverts | Discards |\n+============================================================+\n| WorldHandler | advanceBlocks  | 494   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | advanceTime    | 432   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | cancelTraining | 449   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | enqueue        | 478   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | evict          | 465   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | expireRound    | 431   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | feed           | 512   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | feedBadly      | 461   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | forceEth       | 457   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | fulfillRound   | 482   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | leaveQueue     | 472   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | rally          | 453   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | requestRound   | 449   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | setFoodConfig  | 435   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | settleMatch    | 467   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | settleTraining | 464   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | startTraining  | 450   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | strangerProbes | 488   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | transferPet    | 440   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | withdraw       | 437   | 0       | 0        |\n╰--------------+----------------+-------+---------+----------╯\n\n[PASS] test_freeMintsKeepTheSupplyAndAllocationLedgers() (gas: 9239104)\n[PASS] test_seededWalkReachesEveryOutcomeAndKeepsEveryInvariant() (gas: 323738674)\nLogs:\n  feedOk: 26\n  feedLocked: 30\n  feedRefused: 65\n  trainOk: 14\n  trainRefused: 48\n  settleTrainingOk: 5\n  settleTrainingRefused: 53\n  cancelOk: 9\n  enqueueOk: 21\n  enqueueRefused: 43\n  leaveOk: 5\n  evictOk: 5\n  requestOk: 4\n  rallyOk: 16\n  requestRefused: 65\n  fulfillOk: 15\n  expireOk: 4\n  settleMatchOk: 18\n  transferOk: 27\n  transferLocked: 23\n  withdrawOk: 37\n  forceOk: 48\n  configOk: 77\n  strangerRefused: 59\n  byeOk: 3\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 43.48s (43.81s CPU time)\n\nRan 12 test suites in 43.49s (61.68s CPU time): 198 tests passed, 0 failed, 0 skipped (198 total tests)\n","passed":true},{"durationMs":157,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"HamsterRunNFT.acceptOwnership()\",\"HamsterRunNFT.approve(address,uint256)\",\"HamsterRunNFT.cancelTraining(uint256)\",\"HamsterRunNFT.expireMatchLock(uint256)\",\"HamsterRunNFT.feed(uint256,uint8)\",\"HamsterRunNFT.lockMatch(uint256)\",\"HamsterRunNFT.lockQueue(uint256,address)\",\"HamsterRunNFT.mint()\",\"HamsterRunNFT.ownerMint(address)\",\"HamsterRunNFT.releaseBye(uint256)\",\"HamsterRunNFT.rewardMatch(uint256,bool)\",\"HamsterRunNFT.safeTransferFrom(address,address,uint256)\",\"HamsterRunNFT.safeTransferFrom(address,address,uint256,bytes)\",\"HamsterRunNFT.setApprovalForAll(address,bool)\",\"HamsterRunNFT.setFoodConfig(uint256[3],uint256[3])\",\"HamsterRunNFT.setMatchQueue(address)\",\"HamsterRunNFT.setMintOpen(bool)\",\"HamsterRunNFT.settleTraining(uint256)\",\"HamsterRunNFT.startTraining(uint256)\",\"HamsterRunNFT.transferFrom(address,address,uint256)\",\"HamsterRunNFT.transferOwnership(address)\",\"HamsterRunNFT.unlockQueue(uint256)\",\"HamsterRunNFT.withdraw(uint256)\",\"MatchQueue.enqueue(uint256)\",\"MatchQueue.evictExpired(uint256)\",\"MatchQueue.expireRound(uint256)\",\"MatchQueue.fulfillRound(uint256)\",\"MatchQueue.leaveQueue(uint256)\",\"MatchQueue.requestRound(uint256)\",\"MatchQueue.settleMatch(uint256)\"],\"files\":{\".gitignore\":3,\"DESIGN.md\":155,\"LICENSE\":21,\"README.md\":121,\"SECURITY.md\":57,\"abi/HamsterRunNFT.json\":1830,\"abi/ISqueekCore.json\":239,\"abi/MatchQueue.json\":999,\"abi/SHA256.json\":6,\"abi/SqueekCore.upstream.json\":902,\"dependencies.json\":18,\"deployments/sepolia-v2.json\":11,\"deployments/sepolia.json\":30,\"docs/PROVENANCE.md\":22,\"docs/VALIDATION.md\":45,\"docs/core-sepolia-snapshot.json\":28,\"foundry.toml\":27,\"launch.json\":19,\"remappings.txt\":2,\"script/Deploy.s.sol\":28,\"src/CoreReader.sol\":86,\"src/GameMath.sol\":44,\"src/HamsterRunNFT.sol\":466,\"src/MatchQueue.sol\":361,\"src/PointsLedger.sol\":18,\"src/interfaces/ISqueekCore.sol\":58,\"test/Care.t.sol\":366,\"test/CareEdges.t.sol\":554,\"test/CoreAbi.t.sol\":65,\"test/CoreTraining.t.sol\":391,\"test/Deployment.t.sol\":103,\"test/Invariants.t.sol\":219,\"test/MatchQueue.t.sol\":604,\"test/MathAndRandomness.t.sol\":122,\"test/NFTAdmin.t.sol\":297,\"test/NFTGuards.t.sol\":568,\"test/QueueEdges.t.sol\":965,\"test/StatefulInvariants.t.sol\":1153,\"test/Tools.test.mjs\":129,\"test/helpers/GameTest.sol\":119,\"test/helpers/MockSqueekCore.sol\":109,\"test/helpers/Probes.sol\":115,\"tools/export-abis.mjs\":39,\"tools/record-deployment.mjs\":89,\"tools/rpc.mjs\":55,\"tools/training-status.mjs\":36},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"e7547d20dce3c657233c4bd825cb256ea700f9e62215595bb4460793d0fdbcb5","verifiedTreeHash":"69f2f7ccb840a6d0db5786da99dfd618a9f27008","verifierVersion":"0.1.0+3dcb4df2"},{"checks":[{"durationMs":18810,"exitCode":0,"name":"build","output":"Compiling 61 files with Solc 0.8.26\nSolc 0.8.26 finished in 18.59s\nCompiler run successful with warnings:\nWarning (5159): \"selfdestruct\" has been deprecated. Note that, starting from the Cancun hard fork, the underlying opcode no longer deletes the code and data associated with an account and only transfers its Ether to the beneficiary, unless executed in the same transaction in which the contract was created (see EIP-6780). Any use in newly deployed contracts is strongly discouraged even if the new behavior is taken into account. Future changes to the EVM might further reduce the functionality of the opcode.\n  --> test/helpers/Probes.sol:53:9:\n   |\n53 |         selfdestruct(to);\n   |         ^^^^^^^^^^^^\n\n","passed":true},{"durationMs":48058,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/CoreAbi.t.sol:CoreAbiTest\n[PASS] test_historicalWindowSettlesAgainstRawCertifiedCorePage() (gas: 672527)\n[PASS] test_publishedCoreV3AbiMatchesFinalizedSepoliaReadBytes() (gas: 83293)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 2.43ms (837.48µs CPU time)\n\nRan 23 tests for test/MatchQueue.t.sol:MatchQueueTest\n[PASS] test_cannotEnqueueAndLockInOneTransaction() (gas: 2507905)\n[PASS] test_cannotEnqueueOthersDuplicateOrTwoPetsForOneWallet() (gas: 1369718)\n[PASS] test_distinctStaminaBandsCannotPair() (gas: 6000877)\n[PASS] test_eligibilityIsPerEntryAndSurvivesSwapRemoval() (gas: 2563712)\n[PASS] test_endToEndMintFeedTrainQueueRandomMatchSettle() (gas: 3430825)\n[PASS] test_expiredOddRoundReleasesEveryoneAndNobodyIsRefunded() (gas: 2635833)\n[PASS] test_expiredRandomnessReleasesBothPetsWithoutRewardAndRetainsQuota() (gas: 2976243)\n[PASS] test_failedRewardRollsBackBothStaminaAndPointsAtomically() (gas: 7446552)\n[PASS] test_fullQueueBoundAndMaximumRoundGas() (gas: 33417208)\nLogs:\n  32-player round lock gas: 6529088\n  32-player round fulfill gas: 5143941\n\n[PASS] test_invalidIdsCannotCreateStateOrRewards() (gas: 135776)\n[PASS] test_lastRandomnessBlockIsUsableAndCannotExpireEarly() (gas: 2421382)\n[PASS] test_leaveMiddleEntryRepairsPositionAndDoesNotConsumeQuota() (gas: 1977017)\n[PASS] test_multipleRoundsInSameBandDoNotInterfere() (gas: 4791295)\n[PASS] test_oddRosterLocksEveryoneAndEntropyChoosesTheBye() (gas: 17212162)\n[PASS] test_queueAndMatchLocksPreventTransfersFeedingTrainingAndCancellation() (gas: 2789457)\n[PASS] test_queueQuotaUsesLockWeekAcrossWeekBoundary() (gas: 1695041)\n[PASS] test_queueTTLAndHungryExpiryCanBeEvictedPermissionlessly() (gas: 1306678)\n[PASS] test_randomnessCannotUseCurrentFutureOrZeroHash() (gas: 2233589)\n[PASS] test_requestLocksWholeEligibleRosterSoLateEntrantCannotFlushTheQueue() (gas: 3232977)\n[PASS] test_requestPrunesStaleEntriesWithoutBlockingHealthyPair() (gas: 2383774)\n[PASS] test_staleOnlyRequestCanBeRecoveredByExplicitEviction() (gas: 1655231)\n[PASS] test_weeklyQuotaIsPerNFTAndSettlementCreditsLockWeek() (gas: 11753028)\n[PASS] test_weightChangesActualRaceOutcomeWithEqualStamina() (gas: 2961811)\nSuite result: ok. 23 passed; 0 failed; 0 skipped; finished in 89.58ms (55.35ms CPU time)\n\nRan 29 tests for test/NFTGuards.t.sol:NFTGuardsTest\n[PASS] testFuzz_foodConfigAcceptedExactlyWhenStrictlyOrderedAndInBounds(uint256[3],uint256[3]) (runs: 512, μ: 74281, ~: 74075)\nLogs:\n  Bound result 0\n  Bound result 0\n  Bound result 2\n  Bound result 9999\n  Bound result 15000\n\n[PASS] testFuzz_withdrawPaysExactlyTheRequestedAmountOrFails(uint256) (runs: 512, μ: 768286, ~: 769424)\nLogs:\n  Bound result 25\n\n[PASS] test_aSecondQueueAimedAtABoundCollectionGetsNowhere() (gas: 928837)\n[PASS] test_approvalsSetDuringALockCannotMoveThePetUntilItUnlocks() (gas: 912303)\n[PASS] test_bindingRejectsEveryQueueThatDoesNotNameThisCollection() (gas: 348049)\n[PASS] test_boundQueueCanNeverBeReplacedEvenByOwnerOrNextOwner() (gas: 482755)\n[PASS] test_directCallsFromNeitherOwnerNorPlayerCanMoveALockedPet() (gas: 912723)\n[PASS] test_everyQueueMethodFailsBeforeBinding() (gas: 404797)\n[PASS] test_feesFollowOwnershipOnlyAfterAcceptance() (gas: 591237)\n[PASS] test_forcedEthIsWithdrawableAndCreatesNoEntitlement() (gas: 139827)\n[PASS] test_lockMatchAppliesNeglectBeforeTheSnapshot() (gas: 653026)\n[PASS] test_lockMatchGuardsAndReturnsTheLiveSnapshot() (gas: 1087402)\n[PASS] test_lockQueueGuards() (gas: 750535)\n[PASS] test_lockQueueRefusesATrainingPet() (gas: 551852)\n[PASS] test_mintCallbackHitsTheGuardOnEveryGameEntry() (gas: 1058787)\n[PASS] test_mintWindowReopensButNeverRefundsTheAllocation() (gas: 655101)\n[PASS] test_mintingContractThatMovesThePetAwayStillUsedItsAllocation() (gas: 1117253)\n[PASS] test_noContractAcceptsPlainEthAndNonpayableEntriesRefuseValue() (gas: 555105)\n[PASS] test_ownerMintedPetsLeaveTheRecipientsFreeMintAvailable() (gas: 554424)\n[PASS] test_pendingHandoverCanBeCancelledWithTheZeroAddress() (gas: 133181)\n[PASS] test_petEnteredOnItsLastAttemptCanStillLockAfterTheWeekTurns() (gas: 1359280)\n[PASS] test_quotaCountsLocksNotEntriesAndResetsOnlyOnANewWeek() (gas: 2496856)\n[PASS] test_receiverActingInsideASafeTransferStaysBoundByTheLock() (gas: 1037828)\n[PASS] test_renounceFailsForEveryCallerAndChangesNothing() (gas: 39094)\n[PASS] test_rewardCreditsOnceAndOnlyTheDocumentedAmount() (gas: 1290434)\n[PASS] test_tokenUriIsTheExactDocumentAndProjectsNeglect() (gas: 728321)\n[PASS] test_transferFailuresDoNotMoveThePet() (gas: 522235)\n[PASS] test_unlockExpireAndRewardOnlyAcceptTheirOwnActivity() (gas: 941453)\n[PASS] test_withdrawOnAnEmptyContractFails() (gas: 39476)\nSuite result: ok. 29 passed; 0 failed; 0 skipped; finished in 231.41ms (238.42ms CPU time)\n\nRan 3 tests for test/Deployment.t.sol:DeploymentTest\n[PASS] test_constructorsDoNotNeedDependenciesToExist() (gas: 12863)\n[PASS] test_factoryDeploymentsHaveExplicitOwnerAndNoForbiddenRuntime() (gas: 30867803)\n[PASS] test_scriptsUseArgumentsAndRejectOtherChains() (gas: 13475107)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 280.34ms (87.51ms CPU time)\n\nRan 12 tests for test/NFTAdmin.t.sol:NFTAdminTest\n[PASS] test_adminConfigurationAccessAndBounds() (gas: 652746)\n[PASS] test_erc721InterfacesMetadataAndApprovedTransfer() (gas: 571122)\n[PASS] test_mintClosedByDefaultAndOnlyOwnerCanOpen() (gas: 387570)\n[PASS] test_oneFreeMintPerWalletSurvivesTransfers() (gas: 642279)\n[PASS] test_ownerMintWorksWhileClosedButCannotMintToZero() (gas: 521183)\n[PASS] test_ownershipUsesTwoStepAndCannotRenounce() (gas: 194415)\n[PASS] test_queueMustBeConfiguredOnceAndBoundToThisNFT() (gas: 961463)\n[PASS] test_queueOnlyMethodsRejectDirectUsersAndOwner() (gas: 525025)\n[PASS] test_safeMintReceiverCannotReenterAndRejectionRollsBack() (gas: 965133)\n[PASS] test_supplyExactly9999AcrossOwnerAndFreeMints() (gas: 642399)\n[PASS] test_withdrawConservesProceedsAndOnlyPaysOwner() (gas: 894511)\n[PASS] test_withdrawRejectingOwnerRollsBackAndReentryFails() (gas: 825895)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 554.71ms (554.17ms CPU time)\n\nRan 15 tests for test/CertificationWait.t.sol:CertificationWaitTest\n[PASS] testFuzz_lockDurationNeverChangesIdleDamage(uint32,bool) (runs: 512, μ: 912968, ~: 950615)\nLogs:\n  Bound result 6\n\n[PASS] testFuzz_petsInOneBandAreWithinAFactorOfTwoAndBandsAreMonotonic(uint256,uint256) (runs: 512, μ: 43950, ~: 43636)\nLogs:\n  Bound result 2320134807272516332134995716853468048\n  Bound result 169903169\n\n[PASS] test_bandForStaminaTable() (gas: 114371)\n[PASS] test_cancelAfterALagResumesTheIdleClockWithoutAReset() (gas: 715044)\n[PASS] test_certificationWaitIsNotBilledAsInactivity() (gas: 973391)\n[PASS] test_comparableLiveWorkPairsAndRacesAfterOneWindowEach() (gas: 3490627)\n[PASS] test_feedingStaysLockedWhileQueuedOrMatched() (gas: 1751866)\n[PASS] test_feedingWhileBookedIsStillOwnerOnlyAndOpensNoOtherAction() (gas: 945938)\n[PASS] test_hungerDuringTheWaitStaysTheOwnersResponsibility() (gas: 924939)\n[PASS] test_idleDaysCompletedBeforeBookingAreChargedAndThePartialDayCarriesOver() (gas: 985486)\n[PASS] test_ownerCanFeedThroughTheWaitAndTheBookingIsUntouched() (gas: 1317512)\n[PASS] test_pinnedLiveWindowAcrossTiersLandsInNeighbouringBands() (gas: 2437973)\n[PASS] test_sevenDayLagWithThePinnedLiveWindowEndsFitWhenFedOnCadence() (gas: 1078633)\n[PASS] test_untrainedPetsAllShareBandZeroAndCannotMeetATrainedOne() (gas: 2926308)\n[PASS] test_zeroWorkSettleAfterALagResumesTheIdleClockWithoutAReset() (gas: 824816)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 632.19ms (365.62ms CPU time)\n\nRan 44 tests for test/QueueEdges.t.sol:QueueEdgesTest\n[PASS] testFuzz_exactlyOneResolutionPathExistsAtEveryBlock(uint16) (runs: 512, μ: 2044252, ~: 2194715)\nLogs:\n  Bound result 257\n\n[PASS] testFuzz_twoPlayerRoundMatchesThePinnedFormulas(bytes32) (runs: 512, μ: 2574066, ~: 2573850)\n[PASS] test_aBigStaminaLeadInsideABandOutweighsTheClassGap() (gas: 28169707)\n[PASS] test_anyCallerBuildsTheSameRoster() (gas: 2225233)\n[PASS] test_atEqualStaminaFitBeatsObeseUnderEveryHash() (gas: 50050542)\n[PASS] test_bandEdgesSeparateAt500AndPairInsideTheBand() (gas: 7219929)\n[PASS] test_byeIsSpreadAcrossTheRoster() (gas: 62196350)\n[PASS] test_constantsArePinnedToTheDocumentedValues() (gas: 123668)\n[PASS] test_emptyAndUnknownViewsBehave() (gas: 77615)\n[PASS] test_entriesBecomeLockableExactlyTenBlocksAfterJoining() (gas: 1880502)\n[PASS] test_evictionReportsExpiryAndTheOwnerKeepsThePet() (gas: 750431)\n[PASS] test_expiredOddRoundRefundsNobody() (gas: 2703455)\n[PASS] test_expiredRoundHasNoRacesAndHungryRacersRecoverToo() (gas: 2101766)\n[PASS] test_expiringAFullRosterStaysBoundedAndFreesEveryone() (gas: 26043021)\n[PASS] test_firstRewardFailureRollsBackJustAsTheSecondDoes() (gas: 7110615)\n[PASS] test_fitUsuallyBeatsNormalButTheNoiseKeepsItAContest() (gas: 93729909)\n[PASS] test_fiveExpiredRoundsExhaustTheWeekUntilItTurns() (gas: 7253708)\n[PASS] test_fullBandOfStaleEntriesBlocksEntryUntilOneIsEvicted() (gas: 25402715)\n[PASS] test_identicalLowStaminaPetsStillSplitWinsWhenScoresOftenTie() (gas: 97686279)\n[PASS] test_identicalPetsAreAFairCoinOverManyHashes() (gas: 97720353)\n[PASS] test_idlePetTransferredAwayDoesNotCarryTheWalletLock() (gas: 2504698)\n[PASS] test_leaveAndEvictRejectPetsThatAreNotWaiting() (gas: 2031779)\n[PASS] test_leavingIsAllowedAfterStalenessAndReportsAsVoluntary() (gas: 1001780)\n[PASS] test_lockedRacersCannotImproveTheirSnapshotAndNewcomersCannotJoin() (gas: 2541524)\n[PASS] test_mixedStaleAndOddRosterLocksEveryEligiblePetAndLeavesOnlyTheNewcomer() (gas: 4696919)\n[PASS] test_nobodyCanJoinAndLockAgainstALoneWaiterInOneTransaction() (gas: 1513393)\n[PASS] test_normalUsuallyBeatsObeseButTheNoiseKeepsItAContest() (gas: 97728399)\n[PASS] test_oddRoundGivesTheShuffleChosenByeItsAttemptBack() (gas: 3644359)\n[PASS] test_oneFullBandLeavesOtherBandsOpen() (gas: 19221877)\n[PASS] test_oneWalletRacesOnePetAcrossAllBandsUntilSettled() (gas: 7717249)\n[PASS] test_onlyTheBoundQueueCanReleaseABye() (gas: 1773536)\n[PASS] test_pointsStayWithTheRacerAfterThePetIsSold() (gas: 2515891)\n[PASS] test_racesInOneRoundSettleInAnyOrderAndOnlyFreeTheirOwnPair() (gas: 4886229)\n[PASS] test_rejoiningRestartsTheWait() (gas: 1580602)\n[PASS] test_requestIncludesAPetAtExactFedUntilAndPrunesItOneSecondLater() (gas: 3125259)\n[PASS] test_requestIncludesAnEntryAtExactTtlAndPrunesItOneSecondLater() (gas: 1983285)\n[PASS] test_resultDependsOnlyOnTheTargetBlockHashAcrossTheWholeWindow() (gas: 3109841)\n[PASS] test_seedIsBoundToChainContractAndRound() (gas: 2592242)\n[PASS] test_settlementEmitsTheOutcomeAndPointsTotals() (gas: 2451627)\n[PASS] test_settlingYearsLaterChangesNothingAboutTheRaceOrItsWeek() (gas: 2664568)\n[PASS] test_shuffleReachesEveryOpponentAboutEvenly() (gas: 124393151)\n[PASS] test_snapshotUsesWeightAtRoundLockNotAtEnqueue() (gas: 6364205)\n[PASS] test_snapshotWeightDecidesEvenIfTheLivePetWentDownhillAfterLock() (gas: 6891150)\n[PASS] test_trainingPetCannotEnterAndTheFailedEntryLeavesNoTrace() (gas: 795358)\nSuite result: ok. 44 passed; 0 failed; 0 skipped; finished in 632.51ms (1.08s CPU time)\n\nRan 31 tests for test/CareEdges.t.sol:CareEdgesTest\n[PASS] testFuzz_betterScoreNeverGivesAWorseClass(uint8) (runs: 512, μ: 7134, ~: 6972)\nLogs:\n  Bound result 20\n\n[PASS] testFuzz_feedAlwaysSetsDeadlineFromNowAndNeverShortensIt(uint8,uint8,uint32) (runs: 512, μ: 555721, ~: 553171)\nLogs:\n  Bound result 1\n  Bound result 0\n  Bound result 1\n\n[PASS] testFuzz_feedingAnywhereInTheNewbornWindowCostsOnlyIdleDays(uint32,uint8) (runs: 512, μ: 412010, ~: 409925)\nLogs:\n  Bound result 0\n  Bound result 111708\n\n[PASS] testFuzz_hungryExactlyAfterTheDeadline(uint32) (runs: 512, μ: 389195, ~: 389022)\nLogs:\n  Bound result 30\n\n[PASS] testFuzz_lowFoodAloneNeverMakesAPetFit(uint8) (runs: 512, μ: 6316563, ~: 4866410)\nLogs:\n  Bound result 32\n\n[PASS] testFuzz_neglectIsPathIndependentAndIdempotent(uint8,uint32,uint32) (runs: 512, μ: 594295, ~: 593784)\nLogs:\n  Bound result 664\n  Bound result 49152\n  Bound result 0\n\n[PASS] testFuzz_nonexistentPetsRevertEverywhere(uint256) (runs: 512, μ: 304547, ~: 299248)\nLogs:\n  Bound result 4294967295\n\n[PASS] testFuzz_scoreNeverRisesFromTimeAlone(uint8,uint32,uint32) (runs: 512, μ: 448972, ~: 450849)\nLogs:\n  Bound result 0\n  Bound result 163891\n  Bound result 1\n\n[PASS] test_aFitPetOnACheapDietTrainingDailyDriftsToNormalNotBelow() (gas: 39072274)\n[PASS] test_cancelDoesNotResetTheIdleClockButSettlingDoes() (gas: 1576823)\n[PASS] test_cancelledTrainingCreditsNothingAndCannotBeReplayed() (gas: 936760)\n[PASS] test_cheaperRefeedDowngradesTheNextTrainingBonus() (gas: 850258)\n[PASS] test_feedingOneSecondAfterTheNewbornWindowPaysOneHungerDay() (gas: 424914)\n[PASS] test_feedingStopsHungerDamageButNeverRefundsIdleDamage() (gas: 665271)\n[PASS] test_largerWorkEarnsMoreBodyCreditOnlyUpToTheDocumentedCap() (gas: 2338413)\n[PASS] test_longNeglectSaturatesAtZeroAndFoodRecoversFromThere() (gas: 699488)\n[PASS] test_lowFoodTrainingStopsAtTheCeilingOfSixty() (gas: 7802797)\n[PASS] test_midFoodTrainingPassesSixtyAndReachesFit() (gas: 5474110)\n[PASS] test_newbornNeglectFollowsThePinnedSchedule() (gas: 583833)\n[PASS] test_operatorsMayMoveAPetButNeverPlayIt() (gas: 694281)\n[PASS] test_paymentRaisedOrLoweredInTheSameBlockNeverOverOrUndercharges() (gas: 472287)\n[PASS] test_rejectedFeedLeavesEveryFieldUntouched() (gas: 636091)\n[PASS] test_repeatedFoodSaturatesBothEndsOfTheBodyRange() (gas: 2104531)\n[PASS] test_settleAndCancelRejectEveryNonTrainingActivity() (gas: 1886172)\n[PASS] test_startingOnTheLastFedSecondSettlesAfterExpiry() (gas: 926772)\n[PASS] test_storedEnumFollowsTheScoreAcrossBoundariesInBothDirections() (gas: 11834078)\n[PASS] test_trainedPetsRankByFoodTierAndBeatUntrainedOnes() (gas: 1906684)\n[PASS] test_trainingAtFullStaminaWidthKeepsGrowingUntilArithmeticStops() (gas: 5849895)\n[PASS] test_transferKeepsAllCareStateAndGivesNoReset() (gas: 1189742)\n[PASS] test_weightClassBoundariesArePinned() (gas: 5914)\n[PASS] test_withoutTrainingEveryFoodRegimeDriftsDownInTierOrder() (gas: 2707105)\nSuite result: ok. 31 passed; 0 failed; 0 skipped; finished in 633.03ms (2.45s CPU time)\n\nRan 20 tests for test/Care.t.sol:CareTest\n[PASS] testFuzz_feedRequiresExactTierPrice(uint8,uint96) (runs: 512, μ: 342952, ~: 343153)\nLogs:\n  Bound result 0\n  Bound result 65\n\n[PASS] test_allTiersFeedAndGiveDistinctTrainingBonus() (gas: 2499255)\n[PASS] test_feedResetsRatherThanStacksAndExactExpiryIsFed() (gas: 574305)\n[PASS] test_fitPetSwitchedToCheapFoodDriftsDownToNormal() (gas: 12011516)\n[PASS] test_hungryGatesTrainingAndQueue() (gas: 1275369)\n[PASS] test_inactivityAndHungerPenaltiesAreNotResetByFrequentTouches() (gas: 1962293)\n[PASS] test_invalidTierAndNonOwnerFeedFail() (gas: 432037)\n[PASS] test_lateTrainingSettlementStillUnlocksAndAccountsNeglect() (gas: 997161)\n[PASS] test_lowFoodOnlyTrainingNeverMakesAPetFit() (gas: 639476007)\n[PASS] test_newbornTakesNoHungerDamageDuringItsFirstFeedWindow() (gas: 1496736)\n[PASS] test_staminaGrowsFarBeyondSmallIntegerLimits() (gas: 5308043)\n[PASS] test_startingStatsAndFeedDefaults() (gas: 377864)\n[PASS] test_sustainedHighFoodWithoutTrainingStillDriftsTowardObese() (gas: 1619442)\n[PASS] test_tierBonusStaysStrictlyOrderedAtHighStamina() (gas: 7000248)\n[PASS] test_trainingCanStartAtFeedExpiryAndSettleAfterCertification() (gas: 921202)\n[PASS] test_trainingCancellationGivesNoRewardAndCannotBeForced() (gas: 1137445)\n[PASS] test_trainingConfigIsSnapshottedAtFeedAndStart() (gas: 1173740)\n[PASS] test_trainingLocksAllActionsAndSettlesExactlyOnce() (gas: 1417275)\n[PASS] test_uint256OverflowRevertsWithoutWrappingAndTrainingCanCancel() (gas: 5390280)\n[PASS] test_weightTransitionsThroughObeseNormalFitAndNeglect() (gas: 2150090)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 882.26ms (884.61ms CPU time)\n\nRan 5 tests for test/MathAndRandomness.t.sol:MathAndRandomnessTest\n[PASS] testFuzz_pairingIsPermutationAndRewardsConserve(uint8,bytes32) (runs: 512, μ: 5604035, ~: 4705795)\n[PASS] testFuzz_raceMathIsOrderedAndSafeAtFullWidth(uint256,uint16) (runs: 512, μ: 7914, ~: 7834)\n[PASS] test_exactRaceFormulaAndNoiseRange() (gas: 60575)\n[PASS] test_fulfillmentCallerAndTimestampCannotChooseResult() (gas: 2633131)\n[PASS] test_futureEntropyActuallyChangesPairingForLargerRoster() (gas: 24441619)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 882.39ms (329.94ms CPU time)\n\nRan 25 tests for test/CoreTraining.t.sol:CoreTrainingTest\n[PASS] testFuzz_everyAcceptedBpsConfigStrictlyOrdersPositiveWork(uint64,uint16,uint16,uint16) (runs: 512, μ: 84449, ~: 84632)\nLogs:\n  Bound result 30116\n  Bound result 39545\n  Bound result 48774\n\n[PASS] testFuzz_gainIsExactlyCertifiedWorkTimesCapturedTier(uint64,uint8) (runs: 512, μ: 898439, ~: 912211)\n[PASS] testFuzz_gainIsMonotonicAndRoundingIsDown(uint64,uint16) (runs: 512, μ: 5691, ~: 5700)\n[PASS] testFuzz_malformedPageCannotPartiallyCreditOrUnlock(uint8) (runs: 512, μ: 895283, ~: 894669)\n[PASS] testFuzz_startBooksSixInclusiveRoundsAndCapturesFood(uint16,uint8) (runs: 512, μ: 615956, ~: 626433)\n[PASS] test_approvedSafeTransfersCannotBypassTrainingLock() (gas: 636001)\n[PASS] test_badConfigStopsNewBookingsButCannotTrapOldWork() (gas: 980733)\n[PASS] test_cancelRemainsAvailableWhenCoreDisappears() (gas: 756742)\n[PASS] test_certifiedZeroWorkUnlocksWithoutHealthOrClockReward() (gas: 1094380)\n[PASS] test_configWithCollapsingTierRoundingIsRejected() (gas: 63696)\n[PASS] test_corePauseDoesNotInvalidatePreviouslyCertifiedWork() (gas: 1008760)\n[PASS] test_currentRoundUsesCoreGenesisAndOneBasedRounds() (gas: 124854)\n[PASS] test_elapsedTimeAloneNeverSettlesOrCreatesAGain() (gas: 841135)\n[PASS] test_emptyChainConstructorThenClearFirstUseError() (gas: 415255)\n[PASS] test_invalidReadWindowsRevert() (gas: 69723)\n[PASS] test_nextWindowCannotReplayAlreadyCreditedRounds() (gas: 1209904)\n[PASS] test_oneUnitStrictlyOrdersAllDefaultFoodTiers() (gas: 2095827)\n[PASS] test_onlyBookedWorkCountsEvenWithBacklogAndLaterCertification() (gas: 1130383)\n[PASS] test_overlappingPetsUseTheirOwnExactWindow() (gas: 1643745)\n[PASS] test_partialCertificationCannotCashOutEvenNonzeroWork() (gas: 1013898)\n[PASS] test_previewCannotInventWorkForAnIdleToken() (gas: 396072)\n[PASS] test_roundAndWindowOverflowAreExplicit() (gas: 469413)\n[PASS] test_roundOneReadsLaunchPositionWithoutUnderflow() (gas: 912604)\n[PASS] test_sixActiveRoundsFitOneCompletePage() (gas: 1195835)\n[PASS] test_unavailableStateOrPageNeverFallsBackToTime() (gas: 996004)\nSuite result: ok. 25 passed; 0 failed; 0 skipped; finished in 882.25ms (1.89s CPU time)\n\nRan 1 test for test/Invariants.t.sol:GameInvariantTest\n[PASS]\nGameInvariantTest invariants:\n[PASS] invariant_bodySupplyQuotaAndLocksStayConsistent\n[PASS] invariant_ethConservation\n[PASS] invariant_pointsAndStaminaHaveOnlyEarnedSources\n GameInvariantTest invariants (runs: 128, calls: 8192, reverts: 0)\n\n╭-------------+----------------+-------+---------+----------╮\n| Contract    | Selector       | Calls | Reverts | Discards |\n+===========================================================+\n| GameHandler | advance        | 1033  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | cancelTraining | 1013  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | enqueueOrLeave | 1010  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | feed           | 1054  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | request        | 1024  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | resolve        | 1083  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | trainOrClaim   | 1020  | 0       | 0        |\n|-------------+----------------+-------+---------+----------|\n| GameHandler | withdraw       | 955   | 0       | 0        |\n╰-------------+----------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 13.51s (13.50s CPU time)\n\nRan 3 tests for test/StatefulInvariants.t.sol:StatefulInvariantsTest\n[PASS]\nStatefulInvariantsTest invariants:\n[PASS] invariant_bodyAndFoodStayInRange\n[PASS] invariant_ethInEqualsEthHeldPlusEthWithdrawn\n[PASS] invariant_lockedActivityMatchesItsBackingRecord\n[PASS] invariant_pointsComeOnlyFromSettledRaces\n[PASS] invariant_queueAndActivityDescribeTheSameThing\n[PASS] invariant_roundsAndRacesNeverLeaveAFinishedState\n[PASS] invariant_staminaComesOnlyFromTrainingAndRaces\n[PASS] invariant_supplyIsExactlyWhatWasMinted\n[PASS] invariant_walletLockMatchesTheOnePetItNames\n StatefulInvariantsTest invariants (runs: 96, calls: 9216, reverts: 0)\n\n╭--------------+----------------+-------+---------+----------╮\n| Contract     | Selector       | Calls | Reverts | Discards |\n+============================================================+\n| WorldHandler | advanceBlocks  | 494   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | advanceTime    | 432   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | cancelTraining | 449   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | enqueue        | 478   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | evict          | 465   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | expireRound    | 431   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | feed           | 512   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | feedBadly      | 461   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | forceEth       | 457   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | fulfillRound   | 482   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | leaveQueue     | 472   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | rally          | 453   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | requestRound   | 449   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | setFoodConfig  | 435   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | settleMatch    | 467   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | settleTraining | 464   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | startTraining  | 450   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | strangerProbes | 488   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | transferPet    | 440   | 0       | 0        |\n|--------------+----------------+-------+---------+----------|\n| WorldHandler | withdraw       | 437   | 0       | 0        |\n╰--------------+----------------+-------+---------+----------╯\n\n[PASS] test_freeMintsKeepTheSupplyAndAllocationLedgers() (gas: 9278722)\n[PASS] test_seededWalkReachesEveryOutcomeAndKeepsEveryInvariant() (gas: 324777322)\nLogs:\n  feedOk: 26\n  feedLocked: 21\n  feedWhileTraining: 9\n  feedRefused: 65\n  trainOk: 13\n  trainRefused: 49\n  settleTrainingOk: 5\n  settleTrainingRefused: 53\n  cancelOk: 8\n  enqueueOk: 18\n  enqueueRefused: 46\n  leaveOk: 4\n  evictOk: 2\n  requestOk: 1\n  rallyOk: 21\n  requestRefused: 68\n  fulfillOk: 16\n  expireOk: 4\n  settleMatchOk: 19\n  transferOk: 27\n  transferLocked: 23\n  withdrawOk: 37\n  forceOk: 48\n  configOk: 77\n  strangerRefused: 59\n  byeOk: 6\n\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 47.77s (48.20s CPU time)\n\nRan 13 test suites in 47.78s (66.99s CPU time): 213 tests passed, 0 failed, 0 skipped (213 total tests)\n","passed":true},{"durationMs":203,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"HamsterRunNFT.acceptOwnership()\",\"HamsterRunNFT.approve(address,uint256)\",\"HamsterRunNFT.cancelTraining(uint256)\",\"HamsterRunNFT.expireMatchLock(uint256)\",\"HamsterRunNFT.feed(uint256,uint8)\",\"HamsterRunNFT.lockMatch(uint256)\",\"HamsterRunNFT.lockQueue(uint256,address)\",\"HamsterRunNFT.mint()\",\"HamsterRunNFT.ownerMint(address)\",\"HamsterRunNFT.releaseBye(uint256)\",\"HamsterRunNFT.rewardMatch(uint256,bool)\",\"HamsterRunNFT.safeTransferFrom(address,address,uint256)\",\"HamsterRunNFT.safeTransferFrom(address,address,uint256,bytes)\",\"HamsterRunNFT.setApprovalForAll(address,bool)\",\"HamsterRunNFT.setFoodConfig(uint256[3],uint256[3])\",\"HamsterRunNFT.setMatchQueue(address)\",\"HamsterRunNFT.setMintOpen(bool)\",\"HamsterRunNFT.settleTraining(uint256)\",\"HamsterRunNFT.startTraining(uint256)\",\"HamsterRunNFT.transferFrom(address,address,uint256)\",\"HamsterRunNFT.transferOwnership(address)\",\"HamsterRunNFT.unlockQueue(uint256)\",\"HamsterRunNFT.withdraw(uint256)\",\"MatchQueue.enqueue(uint256)\",\"MatchQueue.evictExpired(uint256)\",\"MatchQueue.expireRound(uint256)\",\"MatchQueue.fulfillRound(uint256)\",\"MatchQueue.leaveQueue(uint256)\",\"MatchQueue.requestRound(uint256)\",\"MatchQueue.settleMatch(uint256)\"],\"files\":{\".gitignore\":3,\"DESIGN.md\":187,\"LICENSE\":21,\"README.md\":124,\"SECURITY.md\":60,\"abi/HamsterRunNFT.json\":1830,\"abi/ISqueekCore.json\":239,\"abi/MatchQueue.json\":1018,\"abi/SHA256.json\":6,\"abi/SqueekCore.upstream.json\":902,\"dependencies.json\":18,\"deployments/sepolia-v2.json\":11,\"deployments/sepolia.json\":30,\"docs/PROVENANCE.md\":22,\"docs/VALIDATION.md\":48,\"docs/core-sepolia-snapshot.json\":28,\"foundry.toml\":27,\"launch.json\":19,\"remappings.txt\":2,\"script/Deploy.s.sol\":28,\"src/CoreReader.sol\":86,\"src/GameMath.sol\":44,\"src/HamsterRunNFT.sol\":494,\"src/MatchQueue.sol\":372,\"src/PointsLedger.sol\":18,\"src/interfaces/ISqueekCore.sol\":58,\"test/Care.t.sol\":375,\"test/CareEdges.t.sol\":568,\"test/CertificationWait.t.sol\":283,\"test/CoreAbi.t.sol\":65,\"test/CoreTraining.t.sol\":395,\"test/Deployment.t.sol\":103,\"test/Invariants.t.sol\":220,\"test/MatchQueue.t.sol\":611,\"test/MathAndRandomness.t.sol\":122,\"test/NFTAdmin.t.sol\":297,\"test/NFTGuards.t.sol\":568,\"test/QueueEdges.t.sol\":970,\"test/StatefulInvariants.t.sol\":1169,\"test/Tools.test.mjs\":129,\"test/helpers/GameTest.sol\":119,\"test/helpers/MockSqueekCore.sol\":109,\"test/helpers/Probes.sol\":115,\"tools/export-abis.mjs\":39,\"tools/record-deployment.mjs\":89,\"tools/rpc.mjs\":55,\"tools/training-status.mjs\":36},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"f94d1da2e3bd963854dd53f2182e9b95031fc4b1a9ed8567461c4302c932df7a","verifiedTreeHash":"68f8afa42607f5a93d204d641f2dc2499dab6ea5","verifierVersion":"0.1.0+3dcb4df2"}]}