{"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":"196532f7-c9a8-41e8-aa51-d9e9497f1b23","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"0f759d34bc7364e1d40f51e6446f19397e1abf07af5173f5f9746639393d3383","dependsOn":["audit_imported_code"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"a2cea02e8b33e91eeb784e0e5eaeb571cd62cd69e768d335d5834e24b3aa46e5","skillId":"adapt-contract-project","tools":[]},"key":"adapt_contract_project","kind":"code","role":"implement","skillHash":"a2cea02e8b33e91eeb784e0e5eaeb571cd62cd69e768d335d5834e24b3aa46e5","skillId":"adapt-contract-project","state":"accepted"},{"acceptedSubmissionHash":"a6e327bd85c4cc4f61e0dfa672dc6cc1419e2f53610908c1f9e3a01abd5d1640","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"f0945a74dcddaf34073a59eb557d912b02fb9e5edf1492e698120991015a29fa","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"c9a6069c83038ef7690da2b5dac7d779aba0903b8b2e179f78023b0ea80408fa","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","tools":[]},"key":"audit_imported_code","kind":"code","role":"review","skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","state":"accepted"},{"acceptedSubmissionHash":"363a51dea49901c4d2afd7b07563954cc272b70bafd18136f8a89ba323fdf454","dependsOn":["adapt_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"09efb38ebdd14756da5a8c699c17c9481d680fafa090af66bb3173a923fa98e7","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"c7d61f1d02dd5749f7ea7572e179e4bf49bea308939a815f6595f109fadbc8f3","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"4295fc3a1958787b7c1eeda5494bec376f30f5a346c2516860142c12b6b433d2","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"48620cf1e48e4460f90714f2a094ed4817403765a3a16f7d5e0ec8c98daf71b0","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"PLANT ORGANISM, second attempt: the repository is launch 1003 (8 nodes accepted, 102 tests; admission parked on one finding in the birth logic). keep it as it is and change only this. deploy PlantOrganism alone on robinhood chain, constructor as in launch.json (IMD, Intake, action, signer, ORIGIN_CELL, deployer = $owner).\n\n1. NO BIRTH. the plant starts with a location: location = ORIGIN_CELL from deployment. delete everything that exists for location == 0: birthSettles, FALLBACK_CELL, the empty birth settles, the heartbeat skip, the question() special case, and the live-stake branch in votingStake() that the judge flagged. the first heartbeat is for the first full utc day after bind; days before bind still settle empty in one bounded call.\n2. ORIGIN is YOUR choice, builder: one real town or city on land, anywhere on earth, fitting for a plant that strangers will move around. derive its cell from real coordinates (cell = uint16(int16 lat, quarter degrees)<<16 | uint16(int16 lon); round-trip test cell ↔ centre), put it in launch.json as ORIGIN_CELL, and put one sentence about why — about the place, not about us — in a public constant string ORIGIN = \"<place>: <why>\" and in the README.\n3. ONE STAKE RULE for every vote, stated once: stake[cell] = PLANT parked behind the cell since the previous successful settle (parked mid-day counts from the next settle; unparked drops out at once); never live balances. the move at settle, the challenger nomination, the 5% threshold and the gardener pool all use it. a flash park/unpark must never move the plant or earn rewards (test).\n4. the judge's lows: (a) a request cleared as unanswered after 24h counts as a strike like an incomplete result, so three silent days settle the day empty with a READ and the plant can be moved away; (b) rotate() takes a deadline inside the signed struct, expired → revert; (c) heartbeat(maxAdvance): revert if the fee advance pulled from the caller would exceed it; (d) the 5% threshold uses PLANT.totalSupply() − burned; (e) the oracle signer may be an ERC-1271 contract for attestations and rotate (SignatureChecker). a test for each.\n5. unchanged: hours, sips, pot/backing/owed accounting, the oracle body and question text byte for byte, callback ≤ 200k gas, settle ≤ 400k gas, bind once by the deployer, dead plant, no admin/upgrade/pause, no delegatecall/selfdestruct/proxy/ownable/pausable/roles. update the README (one page, names the origin and why) and drop the birth tests.","parentJobId":null,"planHash":"19b2c17869de45b37c3869cf90f3324dc917e72f26f3d3b355104b0a2579cc02","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"196532f7-c9a8-41e8-aa51-d9e9497f1b23","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1107-plant-organism-second-attempt"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51481","feedbackHash":"3d6c96521a35419b8df68f23b5585fa1c8031f0443f9bb574dfdccb75b8b4b3e","nodeKey":"adapt_contract_project","submissionHash":"0f759d34bc7364e1d40f51e6446f19397e1abf07af5173f5f9746639393d3383","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52010","feedbackHash":"4f5a55da242beadf66f034f9e51cd81729b7fdb0d7698145779ee7bb467921da","nodeKey":"adapt_contract_project","submissionHash":"f49120bc135b3e9c592dc485cdc9218015e256816acc1b0ccbf2752176e9e14b","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"50981","feedbackHash":"94be3f9b1bb67d75422c76f48fe038add7813011595875209d2084565d2d9aeb","nodeKey":"audit_economics","submissionHash":"a6e327bd85c4cc4f61e0dfa672dc6cc1419e2f53610908c1f9e3a01abd5d1640","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52230","feedbackHash":"051d00bf7eabd5ca198aec09a44881f0631adb6381f46179a98bf1167aaa2483","nodeKey":"audit_flow","submissionHash":"f0945a74dcddaf34073a59eb557d912b02fb9e5edf1492e698120991015a29fa","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51347","feedbackHash":"d3637e9e4c97fb8db1e5f4678e10165051421edb3baeb3fa97f55c53a9c40dbb","nodeKey":"audit_imported_code","submissionHash":"c9a6069c83038ef7690da2b5dac7d779aba0903b8b2e179f78023b0ea80408fa","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52135","feedbackHash":"64881485b11831281bec11dd9450bbab5cd7e13572589d08993165f3cd1f02ab","nodeKey":"audit_judge","submissionHash":"363a51dea49901c4d2afd7b07563954cc272b70bafd18136f8a89ba323fdf454","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52207","feedbackHash":"6eafd4353893d60dff57bdf2645aac6e9a4c58eedf0ab0c23e44c97890df9107","nodeKey":"audit_judge","submissionHash":"c0c93b4b665112522e1af50a08877103030778ef778bced32ee316baceb85226","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52396","feedbackHash":"c0f5d866e706163e27de919c6fb61e7399972c85069f3b060f4a77d53b5b81e4","nodeKey":"audit_math","submissionHash":"09efb38ebdd14756da5a8c699c17c9481d680fafa090af66bb3173a923fa98e7","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52391","feedbackHash":"4e9fb49f7eb2bac539032c2ec62267d365be9ea9253b3e348c0fddae3da30a9a","nodeKey":"audit_permissions","submissionHash":"c7d61f1d02dd5749f7ea7572e179e4bf49bea308939a815f6595f109fadbc8f3","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52193","feedbackHash":"e9607cd57f4984c42438ba36f043e3102674cff5bb55abb94cae68459748c7dd","nodeKey":"manifest","submissionHash":"4295fc3a1958787b7c1eeda5494bec376f30f5a346c2516860142c12b6b433d2","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52094","feedbackHash":"dfff74516cf0d7cbc1ae462f5777b002c709a2e191c878a924ad77f96c54ce86","nodeKey":"manifest","submissionHash":"69d0bd24554a734d9eb1ed8f6bb23e236ff4b70232f08a96bb92ee54f4a8198d","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51300","feedbackHash":"90b2c4c9e99aeada3c8cdf6e2150de8b7ceacb2c32b1247666c27077de5f127f","nodeKey":"write_foundry_tests","submissionHash":"c2e807ae0ca5f16d119cd33c7833e5ee8fe7a0defaf4b53f4d8de9e7113425ec","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52254","feedbackHash":"cabb4df78161e92456f2e81e99ab05a58337ec01e7cdd7e04e710afd05d4bc3d","nodeKey":"write_foundry_tests","submissionHash":"48620cf1e48e4460f90714f2a094ed4817403765a3a16f7d5e0ec8c98daf71b0","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"3a2e1503e87e2a2df6afb4be393e541250b3f0679264de91b7fc113c1b2aec77","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f9a9196633a6ffa8","findings":[{"citation":"resolved","description":"Boundary x precision seam. redeem() guards amount == 0 and amount > remaining but never guards payout == 0. floor() is backing*1e18/supply and is exactly 0 for every bound plant until the first sunny hour settles (backing starts at 0 and only sips raise it), and stays 0 for as long as every settled day is rainy, empty or incomplete. payout = mulDiv(amount, 0, 1e18) = 0, then mulDiv(0, 9, 10) = 0. The function still pulls the PLANT, increments burned, skips the IMD transfer (line 568 'if (payout != 0)') and emits Redeemed(..., 0, ...). The surrendered PLANT is held forever (README: 'surrendered PLANT stays permanently in custody'), so the holder loses the full amount for 0 IMD, while the remaining holders gain the dilution. The same truncation path pays 0 for small amounts whenever amount * floor < 1e18 (e.g. floor = 5e15 and amount < 200 wei). This is a user-facing footgun rather than an exploit; a one-line guard 'if (payout == 0) revert InvalidAmount();' (or a documented decision) closes it without touching the pricing, the 90%/100% rule or terminalFloor. Note the terminalFloor assignment on line 567 also runs on this path, so a final zero-payout redemption pins terminalFloor to 0.","line":561,"path":"src/PlantOrganism.sol","reproduction":"Deploy PlantOrganism and bind a hook (fixture: alice holds 1000e18 PLANT). Transfer 1000e18 IMD to the organism so pot() = 1000e18 but backing == 0 and no day has settled. Observe organism.floor() == 0. alice calls redeem(500e18). Expected: revert (nothing is paid). Actual: returns 0, burned() == 500e18, plant.balanceOf(alice) == 500e18, imd.balanceOf(alice) == 0, Redeemed(alice, 500e18, 0, false) emitted; the 500e18 PLANT can never be recovered. Verified with a scratch Foundry test (RedeemZeroProbeTest.test_redeemWithZeroBackingBurnsPlantForNothing) on this tree.","severity":"low","snippet":"        uint256 currentFloor = floor();\n        payout = Math.mulDiv(amount, currentFloor, SCALE);\n        if (!dead) payout = Math.mulDiv(payout, 9, 10);","title":"redeem() accepts a zero-payout redemption and permanently surrenders the PLANT"},{"citation":"resolved","description":"Precision observation, dust-level by construction, recorded so the judge can see it was checked rather than missed. (1) delta = floor(pool*1e18/stake) is 0 whenever pool < stake/1e18 wei, and the entire pool is then routed to backing (line 483) with gardenerReserve unchanged: with 901e18 PLANT parked and a 99 wei pool the gardeners receive nothing. (2) _checkpoint credits floor(points/1e18) and sets p.paid = rpt without carrying the remainder (line 502), and checkpoint(uint32,address) on line 511 is callable by anyone for any holder, so a third party can repeatedly truncate another holder's fractional accrual. Each call loses strictly less than 1 wei of IMD and the dust is conserved into backing (line 505), so it is not a loss-of-funds path; 1e18 calls would be needed to move 1 IMD. No change is required; if the author wants exactness, carry a per-position remainder in points instead of credits.","line":478,"path":"src/PlantOrganism.sol","reproduction":"Fixture PlantTestBase: park carol 1e18, alice 600e18, bob 300e18 at ORIGIN_CELL; run one complete day to activate. Set the intake price to spendablePot()-2999 and heartbeat so exactly 2999 wei of pot remains; deliver sun=1; settle. sip = 299, pool = 99, delta = 99e18/901e18 = 0: gardenerReserve() == 0 and cellRewards(ORIGIN_CELL).rewardPerToken == 0 although the pool was 99 wei; backing absorbed all 99. Then with a 30000 wei pot (sip 3000, pool 1000, delta 1) checkpoint(ORIGIN_CELL, carol) credits exactly 1 wei. Verified with scratch test TruncationProbeTest on this tree.","severity":"info","snippet":"            uint256 delta = Math.mulDiv(pool, SCALE, stake);\n            c.rewardPerToken += delta;\n            gardenerPoints += delta * stake;","title":"Gardener pool truncates to zero for sub-1e18 ratios and per-holder remainders are dropped on every public checkpoint"}],"hash":"09efb38ebdd14756da5a8c699c17c9481d680fafa090af66bb3173a923fa98e7","nodeId":"1da1f6b4-9a49-4842-b708-e29f62c6a9f6","outcome":"completed","summary":"The review is complete. The findings file is at the repository root, scratch tests are removed, and no tracked file was changed.\n\n**Outcome: no material math defect.** The area assigned to me (Math Precision, Boundary, Numerical Gap) holds. The two items I recorded are a low and an informational one.\n\n**What I verified in depth**\n\n- **Hourly sips and the gardener pool.** Sips drain one tenth of the positive pot per sunny hour, one third of each sip goes to the pool, and backing receives `sips − reserved`. I showed algebraically that `reserved ≤ pool` and that the ceil-based reserve minus the floor-based credit never underflows, so the dust always lands in backing. The 1000-run fuzz already pins this against an independent model.\n- **Reward accumulators.** The cell total `active + queued` always equals `parkedTotal`, holder positions sum to the cell total after lazy rolling, and activation checkpoints are written at every roll a holder can depend on. The `min` in `votingStake` is redundant but harmless. Overflow needs more IMD than can exist.\n- **Floor and redemption.** Two downward roundings keep every payout at or below backing and keep the floor monotonic. Dead and alive branches agree with the view.\n- **The 5% threshold and death boundary.** `ceilDiv(totalSupply − burned, 20)` cannot underflow because custody is bounded by supply. Death flips exactly at day 30, and the catch-up path is a single bounded write.\n- **Date and coordinates.** I fuzzed the Gregorian routine over all days from 1970 to 9999 against an independent year-and-month walk, and round-tripped all 1440 quarter-degree indices. The Sintra cell 10223578 decodes to indices 155 and −38 with centre 38.875, −9.375, as the README states.\n- **Static-analysis leads.** The heartbeat reentrancy lead is the intentional post-call exact-transfer check under a guard. The divide-before-multiply lead is the correct Hinnant algorithm. The remaining leads are false positives.\n\n**Findings reported**\n\n1. **Low.** `redeem()` accepts a zero-payout redemption. Before the first sunny hour settles the floor is exactly 0, so redeeming 500e18 PLANT returns 0 IMD, increments `burned`, and the PLANT is held forever. Small amounts below one wei of value hit the same path. A `payout == 0` revert closes it without touching pricing.\n2. **Info.** A pool smaller than `stake / 1e18` wei rounds the per-token delta to zero and routes the whole pool to backing, and the public `checkpoint` lets anyone drop another holder's sub-wei remainder. Loss is strictly under 1 wei per call and conserved, so this is recorded only for completeness.\n\n**Coverage.** All 15 entry points have a row, plus four rows for invariants, the weather library and the manifest. Nothing was left unreached.","treeHash":null,"usage":{"cachedInputTokens":2212473,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":61772,"runtime":"claude","turns":36,"wallClockMs":1001120}},{"artifacts":[],"attempt":1,"bundleHash":"fafebbed73d4380c2968e722bc6ab357da751b16c66f15b5283b0535584abbb4","device":"3f91b58cf7cd2d45","findings":[],"hash":"0f759d34bc7364e1d40f51e6446f19397e1abf07af5173f5f9746639393d3383","nodeId":"4b3e0a6b-a286-407e-b102-b2f1832f7f4a","outcome":"completed","summary":"All 123 tests pass, including the reviewer's proof run from the scratch directory. The revision is complete.\n\n**What was wrong.** Stake batches were keyed to the settle counter, so any successful settle matured every pending deposit. When settlement lagged the calendar, a deposit made after a day had fully ended still matured in time to take that day's gardener pool. The proof reproduced this exactly as reported.\n\n**What changed in `src/PlantOrganism.sol`:**\n- Stake is now batched by the UTC day it was parked. A batch parked on day T matures once that day has settled, so it votes and earns only for days after T, whatever the settle lag. Bind-day deposits still wait for the first full day's settle, as accepted before.\n- Nomination rolls the nominated cell and the READ rolls the candidate, so every settle matures at most one day per cell. Four cold settles after a 28-day lag with daily deposits stay within the 400k stipend.\n- Fee advances lock per request: an earlier advance that already unlocked is no longer re-locked when the keeper funds the next day.\n- Redemptions that would pay nothing revert instead of surrendering PLANT.\n- The named-day settle overload reverts when an empty catch-up would pass the named day.\n\n**Findings answered in `.imd-responses.json`.** All six reproduced. Four are fixed in code with a test each. The two info items about attestation binding and the signer's rotation power are documented as trust assumptions in the README, as those findings themselves recommend, with no behaviour change.\n\n**Tests.** New file `test/PlantSettleLag.t.sol` holds eight tests covering the proof scenario for rewards and votes, exact per-day shares across a lag, newest-first withdrawal, bind-day deposits, the long-lag gas budget, the fee re-lock, zero-payout redemption, and the named-day settle. The state-machine ghost ledger now tracks each deposit's day and promotes it only when that day settles. Seven existing tests that asserted lag deposits counting one day early were updated with comments explaining why. ADAPTATION.md, README.md and test/README.md describe the revision.\n\nBuild configuration, dependencies, launch.json and the oracle question source are untouched.","treeHash":"a04044f61feb66f5f46e170b9518ba1c531f8b54","usage":{"cachedInputTokens":2798281,"inputTokens":514,"model":"claude-fable-5-1","outputTokens":98674,"runtime":"claude","turns":56,"wallClockMs":1637533}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"b97527597dd934a0","findings":[],"hash":"363a51dea49901c4d2afd7b07563954cc272b70bafd18136f8a89ba323fdf454","nodeId":"99f5987e-8bdc-4aa9-b211-b5f86f41cc08","outcome":"completed","summary":"The review is complete. Every finding from my first round is fixed, and I found no new reproducible defect in the revised code. The report is in `.imd-findings.json` with an empty findings list and 22 coverage rows.\n\n**Settled prior findings**\n\n- **Medium, stake maturation keyed to the settle counter.** Fixed. Stake is now batched by the UTC day it was parked and matures only once that day has settled. My attached proof and the economics specialist's proof both fail on the old tree and pass here. My own lazy-holder probe across a three-day lag with a mid-lag partial withdrawal matched exact per-day shares and conserved custody.\n- **Low, heartbeat re-locks an unlocked advance.** Fixed with a separate locked-advance bucket. The attached proof passes.\n- **Low, zero-payout redeem surrenders PLANT.** Fixed. Redeem now reverts when the quote is zero, with a regression test.\n- **Info, settle(day) overshoots in catch-up.** Fixed. The named-day overload reverts unless the catch-up ends exactly on that day.\n- **Info, attestation binding and rotate repricing the pot.** No code change was recommended. The README now states both trust assumptions. Behaviour is unchanged.\n\n**What I checked beyond the fixes**\n\n- Full suite: 139 tests pass, including three stateful invariant suites with zero reverts and the cold 400k settle and 200k callback stipend tests.\n- Six scratch probes of my own on the new code passed: lazy holders across a lag, multi-day newest-first unpark, three timeouts settling the day empty with a READ, a same-day park before the previous day's settle earning nothing, the rotate deadline boundary and nonce, and a pending request surviving a rotation.\n- The specialists' remaining items are the ones I already merged last round or are informational observations I reproduced without a loss path. The tester's stranded-PLANT note describes custody by design, as it says itself.\n- The manifest has only the three schema keys, one contract, six arguments in declaration order, and the origin cell derives correctly from Sintra's coordinates and round-trips through its centre, which is on land.\n\nThe scratch directory was removed, so the working tree holds only the findings file.","treeHash":null,"usage":{"cachedInputTokens":1751293,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":37547,"runtime":"claude","turns":24,"wallClockMs":920618}},{"artifacts":[],"attempt":2,"bundleHash":"2debc53d2f831f05919ba9d70fc70ca9f1e27fc343df67d05092f193a2e4facf","device":"5d667e4b0751bcb5","findings":[],"hash":"4295fc3a1958787b7c1eeda5494bec376f30f5a346c2516860142c12b6b433d2","nodeId":"5c0acb42-8e0f-40f1-8ac8-a20954dfd435","outcome":"completed","summary":"Done. launch.json is updated and verified, and it is the only tracked file that changed.\n\n**What changed in the manifest**\n- The three dependency addresses now use EIP-55 checksum form, spelled exactly as the accepted deployment test rehearses them. The values themselves are unchanged.\n- The notes were rewritten to label each constructor argument by index, type and decoded meaning, including the action word decoded to `oracle.request@oracle-1` and the Sintra cell derivation. They stay well under the limit.\n\n**What stayed the same**\n- Kind, the single contract PlantOrganism, six string arguments in declaration order, ORIGIN_CELL 10223578, and `$owner` for the deployer so bind control goes to the launch owner rather than the factory.\n\n**Verification**\n- A schema check confirmed exactly the keys kind, contracts and notes, a valid identifier, string arguments, and a notes length of 3,116 characters.\n- A scratch test on chain 4663 constructed PlantOrganism through a factory caller with the manifest's exact arguments. The deployer resolved to the owner, the origin cell and location matched, the IMD, Intake and signer addresses matched the accepted source, and the runtime stayed under the EIP-170 size limit.\n- The full suite passes: 122 accepted tests plus the scratch test, no failures. The scratch file lives in test/scratch and is discarded before submission.\n\nThe earlier rejection came from submitting with no diff. This revision carries a real, correct change to the manifest and nothing else.","treeHash":"dd3702dc825a21ed604e53988c13aa60b1b4bcc0","usage":{"cachedInputTokens":315762,"inputTokens":258,"model":"claude-fable-5-1","outputTokens":6511,"runtime":"claude","turns":9,"wallClockMs":339134}},{"artifacts":[],"attempt":1,"bundleHash":"12e32d361c675e55bcb137ba302a8682c7ce036c7ad6dab5464fd7b400ddec90","device":"584bd638e7e022f0","findings":[{"description":"The stake rule is implemented exactly as the launch states it: votingStake, nomination, READ, the 5% threshold and the gardener pool read only parked stake, never live balances, and test_livePlantBalancesNeverCountAsStakeAnywhere plus the stake-rule invariant confirm it. One consequence worth recording: PLANT transferred directly to the organism (not via park) belongs to nobody. It is not parked, so it votes and earns nothing and cannot be unparked, and it is not burned, so floor() and the READ threshold keep dividing by it as part of PLANT.totalSupply() - burned. The backing share behind it can never be redeemed because amount == remaining never becomes true for any holder, so terminalFloor is never set and that share stays in the body. This is by design (no admin, no sweep) and only harms a sender who bypasses park; no other holder loses value. No change is requested; recorded so the README's custody description is read with it in mind.","line":221,"path":"src/PlantOrganism.sol","reproduction":"Fixture from test/PlantOrganism.t.sol. alice: plant.transfer(organism, 600 ether); carol parks 60 ether at OTHER; one activation day; challenge(OTHER); one weather day. Expected and actual: votingStake(ORIGIN_CELL) == 0, votingStake(OTHER) == 60 ether, plant moves to OTHER, plant.balanceOf(organism) == 660 ether while totalParked + burned == 60 ether; alice can never recover the 600 ether and remaining supply for floor() and the threshold stays 1000 ether.","severity":"info","title":"PLANT sent straight to the body is stranded and keeps counting toward remaining supply"}],"hash":"48620cf1e48e4460f90714f2a094ed4817403765a3a16f7d5e0ec8c98daf71b0","nodeId":"a651ca03-a64b-4a10-babe-0e93e1284942","outcome":"completed","summary":"Build exits 0. The lint notes are on the existing source files, not on anything I wrote.\n\n**Outcome.** The full suite passes with the two new files, and nothing outside the test tree changed.\n\n| Check | Result |\n|---|---|\n| `forge build` | exit 0 |\n| `forge test` | 140 passed, 0 failed (129 before, 10 added, 1 scratch) |\n| Paths changed | `test/README.md`, two new files under `test/` |\n\n**What the rejected attempt lost, redone here.** The tree already held the accepted revision tests from eight nodes plus my earlier atomicity and reward-ownership work. I added what the brief's items still lacked rather than rewriting any of it.\n\n- **`test/PlantOriginRegression.t.sol`** (9 tests). Birth selectors and every admin, upgrade, pause, ownership and role selector are absent, and plain value is refused. The origin constant is one sentence of the form place-colon-why and matches launch.json. A fuzz packs every valid quarter-degree cell, prints its centre through the question's own coordinate text, parses it back and floors it to the same cell at both edges. The constructor accepts every valid cell as the location with an unspecialised question and rejects every invalid cell and zero dependency. PLANT sent straight to the body or held in a wallet never votes, nominates, defends or earns. One transaction that parks, nominates, asks, delivers, settles and withdraws cannot move the plant or earn credit at either the destination or the location. A rotation deadline is bound into the signed struct and expires one second late. The heartbeat cap is exact and a refusal leaves no pending request.\n- **`test/PlantStakeRuleInvariant.t.sol`**. A handler keeps its own ledger of dated deposits written from the brief's one stake rule, without reading the body's positions or batches. Over 200 sequences of 64 calls it mixes parks, withdrawals, nominations, complete days, three-strike silent days and same-call flashes by a holder richer than all gardeners. After every call it checks that voting stake equals the ledger per cell, that nomination and READ follow the ledger with the remaining-supply threshold, that a pool with no settled stake reserves nothing, and that the flasher never holds stake or credit. A scratch run confirmed the handler reaches real moves, a silent-day move, flashes and nominations, so the invariant is not vacuous.\n\n**Findings.** No defect found. I recorded one info-level note in `.imd-findings.json`: PLANT transferred directly to the body rather than parked is stranded and still counts in the remaining supply used by the floor and the threshold. That is by design and harms only the sender, so no change is requested.\n\n**Still owed outside this offline suite.** Fork runs against the live Robinhood IMD and Intake contracts and the future PLANT and hook deployment, as before.","treeHash":"6361e6f3a7bb32ca834f19af4060467c2e2099f1","usage":{"cachedInputTokens":2227366,"inputTokens":610,"model":"claude-fable-5-1","outputTokens":61225,"runtime":"claude","turns":43,"wallClockMs":964795}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"a7581259169534a1","findings":[],"hash":"602d650adf9b9753bd027758f9f074de8dfe2d8a5cda3e524f3ae7e1db713aea","nodeId":"a651ca03-a64b-4a10-babe-0e93e1284942","outcome":"failed","summary":"clone failed: Cloning into '/Users/zhangtao/.identitymd-seat2/work/196532f7-c9a8-41e8-aa51-d9e9497f1b23/a651ca03-a64b-4a10-babe-0e93e1284942'...\nfatal: unable to access 'https://github.com/identity-md-launches/launch-1003-plant-organism-one.git/': Error in the HTTP2 framing layer\n","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":null,"outputTokens":0,"runtime":"codex","turns":0,"wallClockMs":125385}},{"artifacts":[],"attempt":1,"bundleHash":"3816cb7c86142fdcc5a0811b8722fe86e1722488a33a0b2363298170c4816c5c","device":"cd33e6f138d75a0c","findings":[],"hash":"69d0bd24554a734d9eb1ed8f6bb23e236ff4b70232f08a96bb92ee54f4a8198d","nodeId":"5c0acb42-8e0f-40f1-8ac8-a20954dfd435","outcome":"completed","summary":"Updated only `launch.json`, preserving PlantOrganism’s six constructor arguments, Sintra origin cell `10223578`, and `$owner` deployer. Notes now describe the accepted revised behavior.\n\nManifest and compiled ABI checks passed. `forge build` succeeded; `forge test` passed all 113 tests.","treeHash":"cce20f15125a0616e027435d9776be3b3b1b53f6","usage":{"cachedInputTokens":530944,"inputTokens":40930,"model":"gpt-6.1-sol","outputTokens":4007,"runtime":"codex","turns":4,"wallClockMs":117617}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"5835e48821d8827d","findings":[],"hash":"a33c14f55ead824dad0970baca27c790dcbca39e6337c6aa2c55462f1581fa11","nodeId":"5c0acb42-8e0f-40f1-8ac8-a20954dfd435","outcome":"failed","summary":"the task produced no changes; the agent's last message was: The manifest is verified and needs no change. The working tree is clean apart from the scratch test, which is discarded before submission.\n\n**Outcome:** launch.json already describes the accepted PlantOrganism implementation correctly, so I left it as it is.\n\n**What I checked:**\n- **Schema:** exactly the keys kind, contracts and notes. One contract, PlantOrganism, with six string constructor arguments. Notes are 2,477 characters, under the limit.\n- **Constructor order:** IMD, Intake, action, signer, ORIGIN_CELL, deployer, matching the declaration at `src/PlantOrganism.sol:153`. The deployer argument is `$owner`, so bind control goes to the launch owner rather than the factory.\n- **Action word:** the bytes32 hex decodes to `oracle.request@oracle-1`, the same constant the test suite uses.\n- **Origin cell:** 10223578 equals 0x009bffda, which packs quarter-degree indices 155 and minus 38 for Sintra. The source constant ORIGIN and the README both carry the same place and sentence.\n- **Dependency addresses:** the IMD, Intake and signer addresses match the ones the accepted deployment test rehearses.\n- **Deployment rehearsal:** a scratch test mirrored the protected probe on chain 4663 with the manifest's exact arguments. The constructor succeeded through a factory caller, the deployer resolved to the owner, the runtime stayed under the EIP-170 size limit and contained no forbidden opcodes.\n- **Suite:** forge build and the full forge test run pass with 122 tests and no failures.\n\nNo file other than the manifest is touched, and the manifest itself is unchanged from the accepted revision.","treeHash":null,"usage":{"cachedInputTokens":227351,"inputTokens":194,"model":"claude-fable-5-1","outputTokens":5217,"runtime":"claude","turns":12,"wallClockMs":199315}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"5739ce0d803a43cd","findings":[{"citation":"resolved","description":"Maturation of queued stake is keyed to the settle counter (epoch), not to the day being settled. _rollCell matures every queued deposit as soon as `c.epoch < epoch`, i.e. after any successful settle, and _distribute pays the pool for day D to votingStake(location) at settle(D). Nothing ties a deposit to the day it was made. If settle(D-1) has not been called by the time day D ends (the result for D-1 can sit `received` indefinitely; only heartbeat callers have a bounty incentive to settle, and the attacker can be that caller), anyone can read day D's real weather, park at the plant's current cell, call settle(D-1) in the same transaction so the deposit matures, then heartbeat(D) and settle(D) pay them a pro-rata share of day D's pool (one third of all sips). Exposure is a few hours with the outcome already known; the loss is borne by the gardeners who held through day D, whose share is diluted. The README's rule 'mid-day deposits become eligible after the next settle' silently assumes settle(D-1) runs before day D ends; the code does not enforce that. This does not violate the flash-park tests, which only cover a park and unpark around a single settle.","line":458,"path":"src/PlantOrganism.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {PlantOrganism} from \"src/PlantOrganism.sol\";\nimport {OracleAttestation} from \"src/OracleAttestation.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\n\ncontract ProofToken is IERC20 {\n    uint256 public totalSupply;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 amount) external {\n        balanceOf[to] += amount;\n        totalSupply += amount;\n    }\n\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        emit Approval(msg.sender, spender, amount);\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        balanceOf[msg.sender] -= amount;\n        balanceOf[to] += amount;\n        emit Transfer(msg.sender, to, amount);\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        allowance[from][msg.sender] -= amount;\n        balanceOf[from] -= amount;\n        balanceOf[to] += amount;\n        emit Transfer(from, to, amount);\n        return true;\n    }\n}\n\ncontract ProofHook {\n    address public immutable organism;\n    address public immutable plant;\n\n    constructor(address organism_, address plant_) {\n        organism = organism_;\n        plant = plant_;\n    }\n}\n\ncontract ProofIntake is IIntake {\n    uint256 public sequence;\n    bytes32 public lastId;\n    Callback public callback;\n\n    function priceOf(bytes32, address) external pure returns (uint256) {\n        return 0;\n    }\n\n    function request(bytes32, bytes calldata, Callback calldata cb, address, uint256)\n        external\n        payable\n        returns (bytes32 id)\n    {\n        callback = cb;\n        id = keccak256(abi.encode(address(this), ++sequence));\n        lastId = id;\n    }\n\n    function deliver(bytes32 id, OracleAttestation.Attestation calldata a, bytes calldata sig) external {\n        (bool ok, bytes memory reason) =\n            callback.target.call{gas: 200000}(abi.encodeWithSelector(callback.selector, id, a, sig));\n        if (!ok) {\n            assembly (\"memory-safe\") {\n                revert(add(reason, 32), mload(reason))\n            }\n        }\n    }\n}\n\n/// @notice Day D's weather is public once day D ends. If settle(D-1) has not yet been called by then,\n/// a holder who parks at the plant's cell *after* day D ended still matures at settle(D-1) and\n/// receives day D's gardener pool. Expected: stake parked after a day ended earns nothing for it.\ncontract LateSettleForeknowledgeProof is Test {\n    uint256 internal constant KEY = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d;\n    uint32 internal constant ORIGIN_CELL = 10223578;\n    uint32 internal constant START = 20000;\n    address internal alice = address(0xa11ce);\n    address internal bob = address(0xb0b);\n    address internal keeper = address(0xbee);\n    ProofToken internal imd;\n    ProofToken internal plant;\n    ProofIntake internal intake;\n    PlantOrganism internal organism;\n    uint256 internal serial;\n\n    function setUp() public {\n        vm.chainId(4663);\n        vm.warp(uint256(START) * 1 days + 123);\n        imd = new ProofToken();\n        plant = new ProofToken();\n        intake = new ProofIntake();\n        plant.mint(alice, 100 ether);\n        plant.mint(bob, 300 ether);\n        organism = new PlantOrganism(\n            address(imd), address(intake), bytes32(\"oracle.request@oracle-1\"), vm.addr(KEY), ORIGIN_CELL, address(this)\n        );\n        organism.bind(address(new ProofHook(address(organism), address(plant))));\n        imd.mint(address(organism), 1000 ether);\n        vm.prank(alice);\n        plant.approve(address(organism), type(uint256).max);\n        vm.prank(bob);\n        plant.approve(address(organism), type(uint256).max);\n    }\n\n    function _ask() internal {\n        uint256 time = uint256(organism.lastSettledDay() + 2) * 1 days;\n        if (vm.getBlockTimestamp() < time) vm.warp(time);\n        vm.prank(keeper);\n        organism.heartbeat(0);\n    }\n\n    function _deliver(uint24 sun) internal {\n        OracleAttestation.Attestation memory a;\n        a.requestId = keccak256(abi.encode(\"uuid\", ++serial));\n        a.chainId = 4663;\n        a.answerType = 2;\n        a.answer = abi.encode(\n            bytes32(uint256(sun) | uint256(1) << 48 | uint256(organism.lastSettledDay() + 1) << 96)\n        );\n        a.panelSize = 15;\n        a.quorum = 10;\n        a.agreed = 12;\n        a.issuedAt = uint64(vm.getBlockTimestamp());\n        a.expiresAt = uint64(vm.getBlockTimestamp() + 1 days);\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(KEY, organism.attestationDigest(a));\n        intake.deliver(intake.lastId(), a, abi.encodePacked(r, s, v));\n    }\n\n    function test_parkAfterDayEndedMustNotEarnThatDaysPool() public {\n        // Alice is the only gardener and has held through a full settled day.\n        vm.prank(alice);\n        organism.park(ORIGIN_CELL, 100 ether);\n        _ask(); // day START+1\n        _deliver(0);\n        organism.settle();\n        assertEq(organism.epoch(), 1);\n        assertEq(organism.votingStake(ORIGIN_CELL), 100 ether);\n\n        // Day START+2 is asked and answered on day START+3, but nobody settles it that day.\n        _ask();\n        _deliver(0);\n\n        // Day START+3 has fully ended: its weather (24 sunny hours) is public knowledge.\n        vm.warp(uint256(START + 4) * 1 days + 1);\n        vm.prank(bob);\n        organism.park(ORIGIN_CELL, 300 ether);\n        organism.settle(); // settles START+2; bob's stake matures here\n        assertEq(organism.lastSettledDay(), START + 2);\n        _ask(); // asks day START+3, whose outcome bob already knew when he parked\n        _deliver(0xffffff);\n        organism.settle();\n\n        vm.prank(bob);\n        organism.unpark(ORIGIN_CELL, 300 ether);\n        vm.prank(bob);\n        organism.claim();\n        vm.prank(alice);\n        organism.claim();\n\n        assertGt(imd.balanceOf(alice), 0, \"the gardener who held through the day earns\");\n        assertEq(imd.balanceOf(bob), 0, \"stake parked after day START+3 ended must not share its pool\");\n    }\n}","reproduction":"State: bound plant, pot 1000 IMD, Alice the only gardener with 100 PLANT at ORIGIN_CELL and one settled day (epoch 1). Calls: (1) on day START+3 heartbeat(0) for day START+2, oracle delivers a complete word, nobody calls settle; (2) warp to START+4 days + 1 (day START+3 fully ended, its 24 sunny hours are public); (3) Bob park(ORIGIN_CELL, 300e18); (4) settle() -> settles START+2, epoch 2, votingStake(ORIGIN_CELL)=400e18 including Bob; (5) heartbeat(0) for day START+3, deliver sun=0xffffff, settle(); (6) Bob unpark and claim. Expected: Bob, who parked after day START+3 ended, earns nothing for it. Actual: Bob is credited 225.48 IMD (3/4 of the day's pool); Alice gets 75.16 IMD instead of the whole pool. test/scratch/LateSettleForeknowledge.t.sol fails on this code with '225480227285089313100 != 0'.","severity":"medium","snippet":"    function _rollCell(uint32 cell) private {\n        CellRewards storage c = cellRewards[cell];\n        if (c.epoch < epoch) {\n            if (c.queued != 0) {\n                activationCheckpoint[cell][c.epoch] = c.rewardPerToken;\n                c.active += c.queued;\n                c.queued = 0;\n            }\n            c.epoch = epoch;\n        }\n    }","title":"Stake parked after a day has ended still earns that day's gardener pool when the previous settle is late"}],"hash":"a6e327bd85c4cc4f61e0dfa672dc6cc1419e2f53610908c1f9e3a01abd5d1640","nodeId":"566f4a8b-8bfe-45d6-b8ee-dab4e7038c49","outcome":"completed","summary":"The review is done. The working tree is clean apart from the findings file and my scratch tests, which are ignored and deleted before submission.\n\n**Outcome.** The economics of the plant hold up well under the Economic Security, Invariant and Flow Gap checklists. I found one reproducible defect, rated medium, and recorded it in `.imd-findings.json` with a self-contained Foundry proof that fails on the current code.\n\n**The finding.** Stake maturation is keyed to the settle counter, not to the day being settled. If the result for day D-1 is delivered but nobody calls settle before day D ends, anyone can read day D's real weather, park at the plant's cell, settle D-1 in the same transaction so the deposit matures, and then share day D's gardener pool with full foreknowledge. In the proof, Bob parks after day START+3 has ended and still takes about three quarters of that day's pool from Alice, who held through it. The flash-park tests do not catch this because it spans two settles, not one. The heartbeat caller is the only party with a bounty incentive to settle promptly, and that caller can be the attacker, so the condition is cheap to attempt every day. A fix needs to tie maturation to the day a deposit was made rather than to the next settle, which touches the agreed stake rule, so I framed it as a design decision for the judge.\n\n**What held.** I traced every one of the 15 entry points and wrote a coverage row for each, plus rows for four invariants: IMD conservation, monotone floor, flash-park immunity, and the 5% threshold on outstanding supply. Fee advances stay senior to sips and bounty, payouts are always funded because the pot never falls below minus the advance total, reward accounting closes to zero on full checkpoint, and the challenger can never equal the location. Leads I ran down and dropped as self-inflicted or dust: the fee-unlock epoch being overwritten by a keeper's own later heartbeat, and permissionless checkpointing rounding at most one wei per day. The static-analysis lines on reentrancy, strict equality and divide-before-multiply are benign on inspection. PLANT fixed supply, Intake pricing and signer honesty remain documented trust assumptions, not defects.","treeHash":null,"usage":{"cachedInputTokens":1646441,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":70602,"runtime":"claude","turns":33,"wallClockMs":1299599}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"f009de0ce52c7b3a","findings":[{"citation":"resolved","description":"Merged from audit_economics (ea5c55a2a456); reproduced by running its proof on this tree. _rollCell matures every queued deposit as soon as any successful settle has advanced `epoch`, and _distribute (line 476, `uint256 stake = votingStake(cell);`) pays day D's pool to whatever is active at settle(D). Nothing ties a deposit to the day it was made. The oracle result for day D-1 can sit `received` indefinitely because settle() is permissionless but only the heartbeat caller has a bounty incentive, and that caller can be the attacker. Once day D has fully ended its weather is public. Anyone can then park at the plant's cell, call settle(D-1) so the deposit matures, let heartbeat(D) be answered, settle(D) and unpark: their stake, committed with full knowledge of day D's outcome and at no risk, takes a pro-rata share of day D's pool (one third of all sips, up to about 30% of the pot on a fully sunny day). The honest gardeners who held through day D are diluted. The README guarantee 'Flash parking cannot gain voting power or gardening rewards' holds only literally; the stake rule's 'parked mid-day counts from the next settle' silently assumes settle(D-1) runs before day D ends and the code does not enforce it. Severity medium: funds go to a party that bore no exposure, but only under an observable precondition (a lagging settle) and only for that day's pool, never principal. Minimal fix preserving the stated rule: record the UTC day at which a cell's queued batch was made (or the day being settled when it matures) and let _rollCell/votingStake mature at settle(D) only batches queued before day D ended, i.e. queued while today() <= D; the proof below then passes.","line":460,"path":"src/PlantOrganism.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {PlantOrganism} from \"src/PlantOrganism.sol\";\nimport {OracleAttestation} from \"src/OracleAttestation.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\n\ncontract ProofToken is IERC20 {\n    uint256 public totalSupply;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 amount) external {\n        balanceOf[to] += amount;\n        totalSupply += amount;\n    }\n\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        emit Approval(msg.sender, spender, amount);\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        balanceOf[msg.sender] -= amount;\n        balanceOf[to] += amount;\n        emit Transfer(msg.sender, to, amount);\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        allowance[from][msg.sender] -= amount;\n        balanceOf[from] -= amount;\n        balanceOf[to] += amount;\n        emit Transfer(from, to, amount);\n        return true;\n    }\n}\n\ncontract ProofHook {\n    address public immutable organism;\n    address public immutable plant;\n\n    constructor(address organism_, address plant_) {\n        organism = organism_;\n        plant = plant_;\n    }\n}\n\ncontract ProofIntake is IIntake {\n    uint256 public sequence;\n    bytes32 public lastId;\n    Callback public callback;\n\n    function priceOf(bytes32, address) external pure returns (uint256) {\n        return 0;\n    }\n\n    function request(bytes32, bytes calldata, Callback calldata cb, address, uint256)\n        external\n        payable\n        returns (bytes32 id)\n    {\n        callback = cb;\n        id = keccak256(abi.encode(address(this), ++sequence));\n        lastId = id;\n    }\n\n    function deliver(bytes32 id, OracleAttestation.Attestation calldata a, bytes calldata sig) external {\n        (bool ok, bytes memory reason) =\n            callback.target.call{gas: 200000}(abi.encodeWithSelector(callback.selector, id, a, sig));\n        if (!ok) {\n            assembly (\"memory-safe\") {\n                revert(add(reason, 32), mload(reason))\n            }\n        }\n    }\n}\n\n/// @notice Day D's weather is public once day D ends. If settle(D-1) has not yet been called by then,\n/// a holder who parks at the plant's cell *after* day D ended still matures at settle(D-1) and\n/// receives day D's gardener pool. Expected: stake parked after a day ended earns nothing for it.\ncontract LateSettleForeknowledgeProof is Test {\n    uint256 internal constant KEY = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d;\n    uint32 internal constant ORIGIN_CELL = 10223578;\n    uint32 internal constant START = 20000;\n    address internal alice = address(0xa11ce);\n    address internal bob = address(0xb0b);\n    address internal keeper = address(0xbee);\n    ProofToken internal imd;\n    ProofToken internal plant;\n    ProofIntake internal intake;\n    PlantOrganism internal organism;\n    uint256 internal serial;\n\n    function setUp() public {\n        vm.chainId(4663);\n        vm.warp(uint256(START) * 1 days + 123);\n        imd = new ProofToken();\n        plant = new ProofToken();\n        intake = new ProofIntake();\n        plant.mint(alice, 100 ether);\n        plant.mint(bob, 300 ether);\n        organism = new PlantOrganism(\n            address(imd), address(intake), bytes32(\"oracle.request@oracle-1\"), vm.addr(KEY), ORIGIN_CELL, address(this)\n        );\n        organism.bind(address(new ProofHook(address(organism), address(plant))));\n        imd.mint(address(organism), 1000 ether);\n        vm.prank(alice);\n        plant.approve(address(organism), type(uint256).max);\n        vm.prank(bob);\n        plant.approve(address(organism), type(uint256).max);\n    }\n\n    function _ask() internal {\n        uint256 time = uint256(organism.lastSettledDay() + 2) * 1 days;\n        if (vm.getBlockTimestamp() < time) vm.warp(time);\n        vm.prank(keeper);\n        organism.heartbeat(0);\n    }\n\n    function _deliver(uint24 sun) internal {\n        OracleAttestation.Attestation memory a;\n        a.requestId = keccak256(abi.encode(\"uuid\", ++serial));\n        a.chainId = 4663;\n        a.answerType = 2;\n        a.answer = abi.encode(\n            bytes32(uint256(sun) | uint256(1) << 48 | uint256(organism.lastSettledDay() + 1) << 96)\n        );\n        a.panelSize = 15;\n        a.quorum = 10;\n        a.agreed = 12;\n        a.issuedAt = uint64(vm.getBlockTimestamp());\n        a.expiresAt = uint64(vm.getBlockTimestamp() + 1 days);\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(KEY, organism.attestationDigest(a));\n        intake.deliver(intake.lastId(), a, abi.encodePacked(r, s, v));\n    }\n\n    function test_parkAfterDayEndedMustNotEarnThatDaysPool() public {\n        // Alice is the only gardener and has held through a full settled day.\n        vm.prank(alice);\n        organism.park(ORIGIN_CELL, 100 ether);\n        _ask(); // day START+1\n        _deliver(0);\n        organism.settle();\n        assertEq(organism.epoch(), 1);\n        assertEq(organism.votingStake(ORIGIN_CELL), 100 ether);\n\n        // Day START+2 is asked and answered on day START+3, but nobody settles it that day.\n        _ask();\n        _deliver(0);\n\n        // Day START+3 has fully ended: its weather (24 sunny hours) is public knowledge.\n        vm.warp(uint256(START + 4) * 1 days + 1);\n        vm.prank(bob);\n        organism.park(ORIGIN_CELL, 300 ether);\n        organism.settle(); // settles START+2; bob's stake matures here\n        assertEq(organism.lastSettledDay(), START + 2);\n        _ask(); // asks day START+3, whose outcome bob already knew when he parked\n        _deliver(0xffffff);\n        organism.settle();\n\n        vm.prank(bob);\n        organism.unpark(ORIGIN_CELL, 300 ether);\n        vm.prank(bob);\n        organism.claim();\n        vm.prank(alice);\n        organism.claim();\n\n        assertGt(imd.balanceOf(alice), 0, \"the gardener who held through the day earns\");\n        assertEq(imd.balanceOf(bob), 0, \"stake parked after day START+3 ended must not share its pool\");\n    }\n}","reproduction":"Bound plant, pot 1000 IMD, alice the only gardener with 100 PLANT at ORIGIN_CELL and one settled complete day (epoch 1). (1) On day START+3 heartbeat(0) asks day START+2; the oracle delivers a complete word; nobody settles. (2) Warp to START+4 days + 1 second: day START+3 has fully ended, its 24 sunny hours are known. (3) bob park(ORIGIN_CELL, 300e18). (4) settle(): settles START+2, epoch 2; votingStake(ORIGIN_CELL) is now 400e18 including bob. (5) heartbeat(0) asks START+3, oracle delivers sun = 0xffffff, settle(). (6) bob unpark and claim; alice claim. Expected: imd.balanceOf(bob) == 0 because bob parked after day START+3 ended. Actual: bob is credited 225480227285089313100 wei (three quarters of the day's pool) and alice receives only a quarter. test/scratch copy of the attached proof fails on this code with 'stake parked after day START+3 ended must not share its pool: 225480227285089313100 != 0'.","severity":"medium","snippet":"        if (c.epoch < epoch) {\n            if (c.queued != 0) {\n                activationCheckpoint[cell][c.epoch] = c.rewardPerToken;\n                c.active += c.queued;","title":"Stake maturation is keyed to the settle counter, so stake parked after a day has ended still earns that day's gardener pool when the previous settle lags"},{"citation":"resolved","description":"Merged from audit_flow (0ca7fcdc9c0f); reproduced by running its proof on this tree. README: a spent fee advance 'unlocks at the next successful settle and remains owed until funded'. heartbeat stores feeUnlockEpoch[msg.sender] = epoch + 1 unconditionally, so a keeper whose earlier advance already unlocked (epoch >= feeUnlockEpoch) but could not be repaid because the pot was empty has that whole debt re-locked the moment they fund the next day's request. _pay (line 534, `if (epoch >= feeUnlockEpoch[holder] || dead) {`) then refuses to repay any of their advances until another settle, even when unreserved IMD has arrived, and other keepers who advanced later can be repaid first. Impact is a delay of at least one settle, indefinitely while the same keeper keeps funding requests, not a loss. Minimal fix: track locked and unlocked advances separately (per-epoch bucket), or only set feeUnlockEpoch when feeAdvances[msg.sender] was zero before this pull.","line":296,"path":"src/PlantOrganism.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PlantOrganism} from \"src/PlantOrganism.sol\";\nimport {OracleAttestation} from \"src/OracleAttestation.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ncontract PToken is IERC20 {\n    uint256 public totalSupply;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n    function mint(address to, uint256 a) external { balanceOf[to] += a; totalSupply += a; }\n    function approve(address s, uint256 a) external returns (bool) { allowance[msg.sender][s] = a; return true; }\n    function transfer(address to, uint256 a) external returns (bool) { balanceOf[msg.sender] -= a; balanceOf[to] += a; return true; }\n    function transferFrom(address f, address to, uint256 a) external returns (bool) {\n        allowance[f][msg.sender] -= a; balanceOf[f] -= a; balanceOf[to] += a; return true;\n    }\n}\n\ncontract PHook { address public organism; address public plant; constructor(address o, address p) { organism = o; plant = p; } }\n\ncontract PIntake is IIntake {\n    uint256 public price = 10 ether;\n    uint256 public seq;\n    Callback public cb;\n    bytes32 public lastId;\n    function priceOf(bytes32, address) external view returns (uint256) { return price; }\n    function request(bytes32, bytes calldata, Callback calldata c, address asset, uint256 amount) external payable returns (bytes32 id) {\n        require(IERC20(asset).transferFrom(msg.sender, address(this), amount));\n        cb = c; id = keccak256(abi.encode(++seq)); lastId = id;\n    }\n    function deliver(bytes32 id, OracleAttestation.Attestation calldata a, bytes calldata sig) external returns (bool ok) {\n        (ok,) = cb.target.call{gas: 200000}(abi.encodeWithSelector(cb.selector, id, a, sig));\n    }\n}\n\n/// A fee advance that already unlocked at a successful settle (feeUnlockEpoch <= epoch) but could\n/// not be repaid for lack of funds is re-locked when the same keeper advances again, because\n/// heartbeat overwrites feeUnlockEpoch[msg.sender] = epoch + 1. Expected: an unlocked advance stays\n/// claimable as soon as unreserved IMD arrives.\ncontract RelockProofTest is Test {\n    uint256 constant KEY = 0xA11CE;\n    uint32 constant ORIGIN = 10223578;\n    uint32 constant START = 20000;\n    PToken imd; PToken plant; PIntake intake; PlantOrganism org;\n    address keeperA = address(0xAAA);\n    uint256 serial;\n\n    function setUp() public {\n        vm.chainId(4663);\n        vm.warp(uint256(START) * 1 days + 100);\n        imd = new PToken(); plant = new PToken(); intake = new PIntake();\n        plant.mint(address(this), 1000 ether);\n        org = new PlantOrganism(address(imd), address(intake), bytes32(\"act\"), vm.addr(KEY), ORIGIN, address(this));\n        org.bind(address(new PHook(address(org), address(plant))));\n        imd.mint(keeperA, 100 ether);\n        vm.prank(keeperA); imd.approve(address(org), type(uint256).max);\n    }\n\n    function _att() internal returns (OracleAttestation.Attestation memory a) {\n        a.requestId = keccak256(abi.encode(++serial));\n        a.chainId = 4663; a.answerType = 2;\n        a.answer = abi.encode(bytes32((uint256(1) << 48) | uint256(org.lastSettledDay() + 1) << 96));\n        a.panelSize = 15; a.quorum = 10; a.agreed = 12;\n        a.issuedAt = uint64(block.timestamp); a.expiresAt = uint64(block.timestamp + 1 days);\n    }\n\n    function _sign(OracleAttestation.Attestation memory a) internal view returns (bytes memory) {\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(KEY, org.attestationDigest(a));\n        return abi.encodePacked(r, s, v);\n    }\n\n    function test_unlockedAdvanceStaysClaimableAfterNextAdvance() public {\n        // Day 1: empty pot, keeper A advances the full 10 IMD fee; the day settles successfully.\n        vm.warp(uint256(org.lastSettledDay() + 2) * 1 days);\n        vm.prank(keeperA); org.heartbeat(type(uint256).max);\n        OracleAttestation.Attestation memory a = _att();\n        assertTrue(intake.deliver(intake.lastId(), a, _sign(a)));\n        org.settle();\n        assertEq(org.epoch(), 1);\n        assertEq(org.feeAdvances(keeperA), 10 ether);\n        assertEq(org.feeUnlockEpoch(keeperA), 1, \"day-1 advance unlocked at the settle\");\n        assertEq(imd.balanceOf(keeperA), 90 ether, \"nothing repaid yet: the pot is empty\");\n\n        // Day 2: A advances again before anyone funds the pot.\n        vm.warp(uint256(org.lastSettledDay() + 2) * 1 days);\n        vm.prank(keeperA); org.heartbeat(type(uint256).max);\n        assertEq(org.feeAdvances(keeperA), 20 ether);\n\n        // A donor funds exactly the day-1 debt. The unlocked day-1 advance should be repayable now.\n        imd.mint(address(org), 10 ether);\n        vm.prank(keeperA); org.claim();\n        assertEq(imd.balanceOf(keeperA), 90 ether, \"the already unlocked day-1 advance must be repaid\");\n        assertEq(org.feeAdvances(keeperA), 10 ether);\n    }\n}","reproduction":"Bound plant, pot 0, intake price 10 IMD, keeper A holds 100 IMD. Day 1: A heartbeat(max) advances 10 (feeAdvances[A]=10, feeUnlockEpoch[A]=1); oracle delivers a complete word; settle(): epoch=1, nothing repaid (held - senior == 0), A's advance is unlocked (1 >= 1). Day 2: A heartbeat(max) again, advances 10 more: feeUnlockEpoch[A] becomes 2. A donor transfers 10 IMD to the organism. A calls claim(). Expected: the unlocked day-1 advance is repaid, A's balance 90 IMD, feeAdvances[A] 10. Actual: epoch (1) < feeUnlockEpoch[A] (2) so nothing is paid; balance stays 80 IMD and feeAdvances[A] stays 20 until the next settle. Attached proof fails on this code with 'the already unlocked day-1 advance must be repaid: 80000000000000000000 != 90000000000000000000'.","severity":"low","snippet":"            feeUnlockEpoch[msg.sender] = epoch + 1;","title":"heartbeat() overwrites feeUnlockEpoch, re-locking a keeper's already unlocked but still unpaid fee advance"},{"citation":"resolved","description":"Merged from audit_math (099cd49f16bf); reproduced with a scratch test on this tree. redeem guards amount == 0 and amount > remaining but never payout == 0. floor() is backing*1e18/supply, which is exactly 0 for every bound plant until the first sunny hour settles and for as long as every settled day is rainy, empty or incomplete; it also truncates to 0 whenever amount * floor < 1e18. The function still pulls the PLANT, increments burned, skips the transfer (line 568) and emits Redeemed(..., 0, ...). Surrendered PLANT stays permanently in custody (README), so the holder loses the full amount for 0 IMD while the other holders gain the dilution. A last-holder zero-payout redemption also pins terminalFloor to 0 (line 567). User-facing footgun rather than an exploit. Minimal fix: `if (payout == 0) revert InvalidAmount();` after line 563; this does not touch pricing, the 90%/100% rule or terminalFloor.","line":562,"path":"src/PlantOrganism.sol","reproduction":"Deploy and bind with alice holding 1000e18 PLANT; transfer 1000e18 IMD to the organism so pot() == 1000e18 but backing == 0 and no day has settled; observe organism.floor() == 0. alice calls redeem(500e18). Expected: revert, nothing is paid. Actual: returns 0, burned() == 500e18, plant.balanceOf(alice) == 500e18, imd.balanceOf(alice) == 0, Redeemed(alice, 500e18, 0, false) emitted; the 500e18 PLANT can never be recovered. Verified by test_redeemZeroPayoutBurnsPlant in a scratch file on this tree.","severity":"low","snippet":"        payout = Math.mulDiv(amount, currentFloor, SCALE);\n        if (!dead) payout = Math.mulDiv(payout, 9, 10);\n        _pullExact(PLANT, msg.sender, amount);","title":"redeem() accepts a zero-payout redemption and permanently surrenders the PLANT"},{"citation":"resolved","description":"Merged from audit_permissions (6b0e9293ac0d); reproduced with a scratch test. onOracleResult accepts any attestation signed in this consumer's domain whose word carries the pending day, provided the Intake passes the pending requestId as the first argument. a.requestId is consumed only for replay and a.questionHash is never tied to requestBody(location, day); the word carries the day but not the cell. Anyone can submit a request to the Intake with callback = this organism for another cell on the same day and obtain a signed attestation in this organism's domain; only the Intake forwarding it under its own different requestId keeps that answer out, and the organism itself cannot tell the two apart. This is a trust assumption on the Intake's delivery binding that the README does not state (it lists oracle truth, signer behaviour, pricing and guards acceptance). Not a reproduced loss: no fix is proposed that changes the oracle body or attestation layout; if the Intake's requestId is the oracle UUID, `a.requestId == requestId` would close it at no cost, otherwise document the assumption.","line":320,"path":"src/PlantOrganism.sol","reproduction":"Bound fixture; keeper heartbeat(max) once START+2 begins; build the usual complete attestation for day START+1 but set a.requestId = keccak256('some other request\\'s uuid') and a.questionHash = keccak256('weather at a completely different cell'); sign with the oracle key; intake.deliver(intake.lastId(), a, sig). Expected if the organism pinned its question: BadSignature or InvalidAttestation. Actual: callback succeeds, consumed[a.requestId] is true, settle() applies the word and backing() becomes > 0. Verified by test_attestationWithForeignQuestionHashAccepted in a scratch file on this tree.","severity":"info","snippet":"        if (!p.exists || p.received || requestId != p.requestId) revert UnknownRequest();","title":"Attestation is bound to the pending request only by the Intake's requestId argument; a.requestId and a.questionHash are never compared to the request"},{"citation":"resolved","description":"Merged from audit_permissions (6bf020f0877e); reproduced with a scratch test. Privileged-power documentation, not a bypass: the brief trusts the oracle signer with rotate. The signer-chosen Intake sets the fee through priceOf, and heartbeat spends spendablePot() on it before asking the caller for any advance; maxAdvance protects only the caller's wallet, never the pot. One signed rotation plus a permissionless heartbeat(0) therefore transfers the entire positive pot to an address the signer picked. Backing, gardener reserves, credits and fee advances are unreachable this way (pot() is net of owed() and backing), so holder exits are unaffected. Recorded so the actor (oracle signer) and amplifier (any keeper) are explicit; no code change is recommended under the brief's trust model.","line":624,"path":"src/PlantOrganism.sol","reproduction":"Bound fixture with pot = 1000 IMD and no pending request; the signer signs rotate(signer, maliciousIntake, ACTION, 0, deadline) where maliciousIntake.priceOf returns 1000e18 (MockIntake.setPrice(1000 ether)). Any address then calls heartbeat(0) once a day has ended. Expected under a pot-protective design: a cap on pot spend. Actual: the request is placed, the organism's IMD balance drops by 1000e18 to the Intake, spendablePot() == 0, feeAdvanceTotal == 0. Verified by test_rotatedIntakeDrainsPot in a scratch file on this tree; the project's own test_repricingCannotExceedAdvanceCapAndZeroCapUsesPot asserts the same outcome as intended.","severity":"info","snippet":"        intake = IIntake(newIntake);\n        action = newAction;","title":"Oracle signer's rotate() power includes repricing the fee sink: a rotated-in Intake priced at spendablePot lets any heartbeat(0) move the whole positive pot to it"},{"citation":"resolved","description":"Merged from audit_flow (8a7890982f93); reproduced with a scratch test. The explicit-day overload only guards that `day` is the next unsettled day, then calls _settle(false), whose pre-bind / through-bind-day branch (line 376) advances lastSettledDay to today()-1 or bindDay in one step. A caller naming one day therefore settles every ended day up to the catch-up end. The skipped days are empty so no accounting changes; cosmetic, but the overload's WrongDay guard does not deliver the 'exactly this day' semantics its name suggests. Either state in the README that catch-up ignores the named day, or have the overload revert when more than one empty day is pending.","line":368,"path":"src/PlantOrganism.sol","reproduction":"Deploy PlantOrganism unbound on UTC day d0; warp to day d0+10; call settle(d0+1). Expected by the overload's contract: lastSettledDay == d0+1 or a revert. Actual: lastSettledDay == d0+9 and EmptyCatchUp(d0+1, d0+9) is emitted. Verified by test_settleNamedDayOvershootsInCatchUp in a scratch file on this tree.","severity":"info","snippet":"        if (day != lastSettledDay + 1) revert WrongDay();\n        _settle(false);","title":"settle(uint32 day) settles past its named day during the empty catch-up"}],"hash":"c0c93b4b665112522e1af50a08877103030778ef778bced32ee316baceb85226","nodeId":"99f5987e-8bdc-4aa9-b211-b5f86f41cc08","outcome":"completed","summary":"The review is complete. The findings file is written at the repository root and the scratch directory is removed, so no tracked file changed.\n\n**Outcome.** Every specialist finding reproduced against the code. I kept six, merged by root cause, and found nothing new that all four missed. The full suite passes offline with 120 tests, the weather source is byte-identical to the first accepted commit, and the manifest and origin cell check out.\n\n**Findings reported, in severity order:**\n\n1. **Medium, settle path.** Stake maturation is keyed to the settle counter, not the day. If settle(D-1) has not run by the time day D ends, anyone can park with full knowledge of day D's weather, settle D-1 to mature, and take a pro-rata share of day D's gardener pool with no exposure. The specialist proof fails on this tree with bob credited about 225 IMD instead of 0. The proof is attached.\n2. **Low, heartbeat.** The unlock epoch is overwritten on every advance, so a keeper's already unlocked but unpaid advance is re-locked when they fund the next request. Proof attached and failing here.\n3. **Low, redeem.** A redemption whose payout rounds to zero still surrenders the PLANT permanently. Verified with a scratch test.\n4. **Info, callback.** The attestation is bound to the pending request only through the Intake's requestId argument. This is an unstated trust assumption on the Intake, not a loss.\n5. **Info, rotate.** The trusted signer can rotate in an Intake priced at the whole pot, which any heartbeat(0) then pays. Documented as a privileged power.\n6. **Info, settle(uint32).** The named-day overload overshoots during empty catch-up. Cosmetic.\n\nI dropped the specialist's dust-truncation note since it is not a defect and the test README already documents that rounding.\n\n**Coverage.** All 15 entry points are answered, plus rows for the conservation invariant, the manifest, and the brief's unchanged-surface requirements. Four entry points carry a finding reference and the rest hold.","treeHash":null,"usage":{"cachedInputTokens":1226129,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":47076,"runtime":"claude","turns":21,"wallClockMs":959406}},{"artifacts":[],"attempt":2,"bundleHash":"cbf7d67ee55bc7842c6909a8e730d34d997f1b5c5a9b74edec842af1da6cae5d","device":"05778e691c371384","findings":[],"hash":"c2e807ae0ca5f16d119cd33c7833e5ee8fe7a0defaf4b53f4d8de9e7113425ec","nodeId":"a651ca03-a64b-4a10-babe-0e93e1284942","outcome":"completed","summary":"Added seven checks covering failed-operation rollback, exact fee caps, and individual gardener rewards across random call sequences. Updated `test/README.md`.\n\nOffline `forge build` and `forge test` passed: **120 tests, zero failures**.\n\nOnly `test/` changed. No reproducible defects found; live-chain integration remains unverified.","treeHash":"a1dae5960358e652ac3788c82ed2690766345756","usage":{"cachedInputTokens":1502464,"inputTokens":126958,"model":"gpt-6-astra","outputTokens":11247,"runtime":"codex","turns":6,"wallClockMs":341100}},{"artifacts":[],"attempt":2,"bundleHash":null,"device":"743b05d8a235188d","findings":[{"citation":"resolved","description":"Trust-gap note (access x asymmetry), not a reproduced loss. onOracleResult accepts any attestation signed in this consumer's domain whose word carries the pending day, provided the Intake passes the pending requestId as the first argument. The attestation's own requestId (consumed only for replay) and questionHash are never tied to the pending request or to requestBody(location, day). Anyone can submit a request to the Intake with callback = this organism and a different body (another cell, same day) and obtain a signed attestation in this organism's domain. The only thing that stops that answer from settling the plant's day is the Intake forwarding it under its own, different requestId; the organism itself cannot tell the two apart. With the mock Intake the organism accepts an attestation with a random a.requestId and a random questionHash for the pending request. This is already true of the accepted prior revision; it is recorded so the judge can weigh it as the trust assumption on the Intake's delivery binding, which the README does not state. No fix is proposed that changes the oracle body or the attestation layout; if the Intake's requestId is the oracle UUID, comparing a.requestId == requestId would close the gap at no cost.","line":320,"path":"src/PlantOrganism.sol","reproduction":"Bound fixture, keeper calls heartbeat(max) once START+2 begins; then build the usual attestation for day START+1 but set a.requestId = keccak256(\"some other request's uuid\") and a.questionHash = keccak256(\"weather at a completely different cell\"), sign with the oracle key, and call intake.deliver(intake.lastId(), a, sig). Expected if the organism pinned its question: BadSignature/InvalidAttestation. Actual: the callback succeeds, consumed[a.requestId] is true, and settle() applies the word (backing becomes > 0). Verified with a scratch test on this tree.","severity":"info","snippet":"        if (!p.exists || p.received || requestId != p.requestId) revert UnknownRequest();\n        if (msg.sender != p.intake) revert NotTheIntake();","title":"Attestation is bound to the pending request only by the Intake's requestId argument; a.requestId and a.questionHash are never compared to the request"},{"citation":"resolved","description":"Privileged-power documentation, not a permission bypass. The only privileged roles after deployment are the deployer (bind once) and the oracle signer (rotate: signer, Intake, action). The signer-chosen Intake sets the fee through priceOf, and heartbeat spends spendablePot() on it before asking the caller for any advance; maxAdvance protects only the caller's own wallet, never the pot. So one signed rotation plus a permissionless heartbeat(0) can transfer the whole positive pot to an address the signer picked. Backing, gardener reserves, credits and fee advances are not reachable this way (pot() is net of owed() and backing), so holder exits are not affected. README lists endpoint pricing as an external trust assumption; this entry makes the actor (oracle signer) and the amplifier (any keeper's heartbeat) explicit for the judge. No code change is recommended if the signer is trusted as the brief states.","line":624,"path":"src/PlantOrganism.sol","reproduction":"Bound fixture with pot = 1000 IMD and no pending request; signer signs rotate(newSigner, maliciousIntake, ACTION, nonce, deadline) where maliciousIntake.priceOf returns 1000e18 (the mock Intake with setPrice(1000 ether) models this). Any address then calls heartbeat(0) once a day has ended. Expected under a pot-protective design: AdvanceTooLarge or a cap on pot spend. Actual: the request is placed, IMD balance of the organism drops by 1000e18 to the Intake, pot() == 0, feeAdvanceTotal == 0 (see test_repricingCannotExceedAdvanceCapAndZeroCapUsesPot, which asserts exactly this outcome as intended behavior).","severity":"info","snippet":"        intake = IIntake(newIntake);\n        action = newAction;","title":"Oracle signer's rotate() power includes repricing the fee sink: a rotated-in Intake with priceOf == spendablePot lets any heartbeat(0) move the entire positive pot to that Intake"}],"hash":"c7d61f1d02dd5749f7ea7572e179e4bf49bea308939a815f6595f109fadbc8f3","nodeId":"1020bf89-8912-488a-93f1-d7eeb39a75b5","outcome":"completed","summary":"The review is complete. The findings file is valid JSON, both quoted snippets match the tree at the cited lines, the scratch directory is removed, and the working tree is clean apart from the findings file itself.\n\n**Outcome: no reproducible permission defect in the assigned area.** The Access Control, Trust Gap and Asymmetry passes found nothing that opens a revision. Two informational entries are recorded so the judge can weigh them as trust assumptions.\n\n**What I checked**\n\n- **Permission map.** After deployment only two privileges exist: the deployer may call `bind` once, and the oracle signer may authorize `rotate`. Every other entry point is public by design and gated by state or time. No admin, pause, upgrade, proxy or role code is present.\n- **Rotation and signer paths.** Only the current signer, EOA or ERC-1271, can rotate. The nonce is consumed after the check and the deadline sits inside the signed struct. Previous signers keep attestation grace only. A scratch test confirmed that a prefixed signature cannot authorize an outsider, whether the prefix names the current signer, an accept-all contract that was never a signer, or a random address. Rotating to the same signer is harmless.\n- **One stake rule.** Nomination, the READ on both sides, the 5% threshold and the gardener pool all read the same retained-stake view. Flash and atomic parks cannot move the plant or earn, and unparking drops stake out at once. The reward-epoch bookkeeping mirrors that view exactly, so no asymmetry between the view and the write path exists.\n- **Public helpers.** A stranger checkpointing another holder repeatedly leaves that holder's eventual claim identical to an untouched peer. The unbound guards, the dead-plant guards, the catch-up branch and both strike paths behave as the brief requires.\n- **Judge's lows.** All five are implemented and each has a regression test in the suite. The full suite passes with 113 tests.\n\n**Informational entries in the file**\n\n1. The attestation is tied to the pending request only by the Intake's `requestId` argument. The attestation's own request id and question hash are never compared to the request, so the organism relies entirely on the Intake binding delivery correctly. This was already true in the prior accepted revision.\n2. The signer's rotate power includes choosing the Intake, and the Intake sets the fee. Any keeper's `heartbeat(0)` will then pay that fee from the whole positive pot. Backing, reserves and credits are not reachable this way. The README already lists endpoint pricing as external trust.\n\n**Coverage.** All 15 verifier entry points have a row, 13 as holds and 2 pointing at the informational entries, plus three invariant rows. Nothing was left unreached.","treeHash":null,"usage":{"cachedInputTokens":1362556,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":65184,"runtime":"claude","turns":32,"wallClockMs":939115}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"af9a875696459139","findings":[{"citation":"resolved","description":"While `location == 0` the plant is 'unborn' and every vote reads live balances: `votingStake` returns `parkedTotal[cell]` (line 455), `_challenge` (line 278) therefore promotes any cell with a momentarily larger live balance, and `_settle` (lines 398-422) runs `_read(candidate)` against that live figure, falling back to `FALLBACK_CELL` after three failed birth settles (lines 418-422). Nothing in this path requires stake to be retained across a settle, which is exactly the rule the located plant enforces (`c.active + queued-from-earlier-epochs`). Consequences, both reproducible with no capital held past one transaction: (1) whoever holds or borrows 5% of PLANT for one transaction chooses where the plant is born; (2) whoever parks one wei more than the honest candidate at any decoy cell, unparks and calls `settle()` in the same transaction makes that settle read a challenger with zero stake, so the birth fails that day; honest holders can only answer by winning the race to be the first settle of the day with a `challenge(X)` repair in front of it, and three lost days force the plant to `FALLBACK_CELL`. An attacker who parked one wei at the chosen cell a day earlier is then the only retained gardener there and captures the whole gardener pool (one third of every sip) until other holders mature a day later. The located path is unaffected: `test/PlantVotingCommitment.t.sol` shows the same loan at heartbeat and settle neither moves the plant nor earns, so the fix is deletion of the birth special cases (lines 229, 289, 386-387's `bindDay - 1`, 398, 418-422, 455 and the `FALLBACK_CELL`/`birthSettles` state) with `location` set from the constructor, not a redesign of `votingStake`. The current suite asserts the defective behaviour as intended in `test/PlantOrganism.t.sol:230` (`test_birthMovesAtFivePercentWithoutMinimumStay`) and `:219`, and `test/PlantAdversarial.t.sol:300`; those tests must go with the birth logic.","line":455,"path":"src/PlantOrganism.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {PlantOrganism} from \"src/PlantOrganism.sol\";\n\n/// @dev Minimal exact-transfer ERC-20 used for both IMD and PLANT in this proof.\ncontract ProofToken is IERC20 {\n    uint256 public totalSupply;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 amount) external {\n        balanceOf[to] += amount;\n        totalSupply += amount;\n    }\n\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        emit Approval(msg.sender, spender, amount);\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        balanceOf[msg.sender] -= amount;\n        balanceOf[to] += amount;\n        emit Transfer(msg.sender, to, amount);\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        allowance[from][msg.sender] -= amount;\n        balanceOf[from] -= amount;\n        balanceOf[to] += amount;\n        emit Transfer(from, to, amount);\n        return true;\n    }\n}\n\ncontract ProofHook {\n    address public immutable organism;\n    address public immutable plant;\n\n    constructor(address organism_, address plant_) {\n        organism = organism_;\n        plant = plant_;\n    }\n}\n\n/// @dev Never asked in this proof; only needed because the constructor requires a non-zero intake.\ncontract ProofIntake {\n    function priceOf(bytes32, address) external pure returns (uint256) {\n        return 0;\n    }\n}\n\n/// @dev Parks, settles and unparks inside one external call: a flash commitment that holds nothing.\ncontract FlashParker {\n    function run(PlantOrganism organism, IERC20 plant, uint32 cell, uint256 amount) external {\n        plant.approve(address(organism), amount);\n        organism.park(cell, amount);\n        organism.settle();\n        organism.unpark(cell, amount);\n        plant.transfer(msg.sender, amount);\n    }\n}\n\n/// @notice A park/settle/unpark sequence that retains no stake across any settle must never move the plant.\n/// On the code as it is, the birth READ reads live balances (`votingStake` returns `parkedTotal` while\n/// `location == 0`), so a flash park of 5% of supply chooses the plant's location and gets its tokens back\n/// in the same transaction.\ncontract BirthFlashProofTest is Test {\n    // -89.875 / -179.875: a valid cell in the Antarctic ocean, not a town anyone would choose as origin.\n    uint32 internal constant FLASH_TARGET = (uint32(uint16(int16(-360))) << 16) | uint16(int16(-720));\n\n    function test_flashParkSettleUnparkCannotMoveThePlant() public {\n        vm.chainId(4663);\n        vm.warp(uint256(20000) * 1 days + 123);\n        ProofToken imd = new ProofToken();\n        ProofToken plant = new ProofToken();\n        ProofIntake intake = new ProofIntake();\n        PlantOrganism organism = new PlantOrganism(\n            address(imd), address(intake), bytes32(\"oracle.request@oracle-1\"), vm.addr(0xA11CE), 10223579, address(this)\n        );\n        plant.mint(address(this), 1000 ether);\n        organism.bind(address(new ProofHook(address(organism), address(plant))));\n        imd.mint(address(organism), 1000 ether);\n\n        uint32 locationBefore = organism.location();\n        FlashParker flash = new FlashParker();\n        plant.transfer(address(flash), 50 ether); // exactly 5% of supply, held for one transaction only\n\n        vm.warp(uint256(20002) * 1 days); // day 20001, the first day after bind, has ended and can be settled\n        (bool ok,) = address(flash).call(abi.encodeCall(flash.run, (organism, plant, FLASH_TARGET, 50 ether)));\n        if (ok) assertEq(plant.balanceOf(address(this)), 1000 ether, \"flash parker returned every token\");\n\n        assertTrue(organism.location() != FLASH_TARGET, \"a flash park/settle/unpark chose the plant's location\");\n        assertEq(organism.location(), locationBefore, \"the plant moved without any retained stake\");\n        assertEq(organism.parkedTotal(FLASH_TARGET), 0);\n    }\n}","reproduction":"State: organism deployed on UTC day 20000 and bound the same day; PLANT supply 1000e18; no stake anywhere; day 20001 has ended (block.timestamp = 20002 days). Attacker contract holds 50e18 PLANT (5%) for one transaction. Call sequence inside one transaction: plant.approve(organism, 50e18); organism.park(cell=-89.875/-179.875 i.e. 0xFE98FD30, 50e18); organism.settle(); organism.unpark(same cell, 50e18); plant.transfer(back). Expected: a park that is unparked in the same transaction retains nothing and cannot move the plant, so location is unchanged after the call. Actual: `_read` sees votingStake(cell) = parkedTotal = 50e18 > votingStake(0) = 0 and >= ceilDiv(1000e18, 20) = 50e18, so location becomes the attacker's cell and `challenger` is reset, while the attacker's 50e18 is back in its wallet before the transaction ends. Decoy variant: honest holders park 100e18 at X during birth; on each of the next three ended days the attacker is the first to settle, with park(Y, 100e18 + 1), unpark(Y, 100e18 + 1), settle() in one transaction -> at that settle challenger == Y with parkedTotal 0, `_read(Y)` fails and `challenger == candidate` skips the fallback read, so X is never read; the third such settle sets location = FALLBACK_CELL (10223579) although X held 10% of supply throughout. Expected: a cell whose stake was unparked in the same transaction cannot be the candidate, and X's retained 10% moves the plant.","severity":"medium","snippet":"        if (location == 0) return parkedTotal[cell];","title":"Birth READ and challenger nomination read live balances: a flash park/settle/unpark places (or vetoes) the plant"},{"citation":"resolved","description":"`clearPending` has two branches. A delivered-but-incomplete result goes through `_settle`, which increments `incompletes[day]` and, on the third one, settles the day empty with a READ and advances `lastSettledDay`/`epoch` (lines 405-409, 423-424). An undelivered request (lines 361-362) only `_clear`s: no strike, no settle, no READ. `lastSettledDay` never moves, so `isDead()` (line 186) becomes true 30 days after the last successful settle regardless of how many requests were paid for (each one costs the full intake price, 0.5 IMD on the live intake today, plus a 6-hour retry wait). Holders cannot move the plant away from a cell the oracle will not answer for, and a keeper who advanced fees for the silent requests stays locked until a successful settle advances `epoch` or the plant dies (`feeUnlockEpoch`, line 553). The README documents this (`Continued non-delivery can therefore lead to death without a relocation vote`) and `test/PlantAssumptions.t.sol:16` locks it in with 23 timeouts ending in death. Fix: count a timeout clear as a strike like an incomplete result and let the third one settle the day empty with the same READ; drop `test_timeoutsDoNotCountAndEventuallyDie`.","line":361,"path":"src/PlantOrganism.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {PlantOrganism} from \"src/PlantOrganism.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\n\ncontract ProofToken is IERC20 {\n    uint256 public totalSupply;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 amount) external {\n        balanceOf[to] += amount;\n        totalSupply += amount;\n    }\n\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        emit Approval(msg.sender, spender, amount);\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        balanceOf[msg.sender] -= amount;\n        balanceOf[to] += amount;\n        emit Transfer(msg.sender, to, amount);\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        allowance[from][msg.sender] -= amount;\n        balanceOf[from] -= amount;\n        balanceOf[to] += amount;\n        emit Transfer(from, to, amount);\n        return true;\n    }\n}\n\ncontract ProofHook {\n    address public immutable organism;\n    address public immutable plant;\n\n    constructor(address organism_, address plant_) {\n        organism = organism_;\n        plant = plant_;\n    }\n}\n\n/// @dev An intake that takes the fee and never answers.\ncontract SilentIntake is IIntake {\n    uint256 public price = 0.5 ether;\n    uint256 public sequence;\n\n    function priceOf(bytes32, address) external view returns (uint256) {\n        return price;\n    }\n\n    function request(bytes32, bytes calldata, Callback calldata, address asset, uint256 amount)\n        external\n        payable\n        returns (bytes32 id)\n    {\n        require(msg.value == 0 && amount == price, \"price\");\n        require(IERC20(asset).transferFrom(msg.sender, address(this), amount), \"pull\");\n        id = keccak256(abi.encode(address(this), ++sequence));\n    }\n}\n\n/// @notice A request the oracle never answers is cleared after 24 hours; that clear must count as a strike\n/// like an incomplete result, so three silent requests settle the day empty (with a READ) instead of\n/// leaving `lastSettledDay` frozen until the 30-day death clock kills the plant.\ncontract SilentOracleProofTest is Test {\n    PlantOrganism internal organism;\n    ProofToken internal imd;\n    ProofToken internal plant;\n    SilentIntake internal intake;\n\n    function _heartbeat() internal {\n        // Tolerate the bounded-advance signature as well as the current one.\n        (bool ok,) = address(organism).call(abi.encodeWithSignature(\"heartbeat(uint256)\", type(uint256).max));\n        if (!ok) (ok,) = address(organism).call(abi.encodeWithSignature(\"heartbeat()\"));\n        require(ok, \"heartbeat failed\");\n    }\n\n    function test_threeUnansweredRequestsSettleTheDayEmpty() public {\n        vm.chainId(4663);\n        vm.warp(uint256(20000) * 1 days + 123);\n        imd = new ProofToken();\n        plant = new ProofToken();\n        intake = new SilentIntake();\n        organism = new PlantOrganism(\n            address(imd), address(intake), bytes32(\"oracle.request@oracle-1\"), vm.addr(0xA11CE), 10223579, address(this)\n        );\n        plant.mint(address(this), 1000 ether);\n        organism.bind(address(new ProofHook(address(organism), address(plant))));\n        imd.mint(address(organism), 1000 ether);\n\n        // Reach a located plant on the code as it is (three empty settles fall back to the fallback cell);\n        // a plant that already has a location from deployment skips this loop.\n        for (uint256 i; i < 3 && organism.location() == 0; ++i) {\n            vm.warp(uint256(organism.lastSettledDay() + 2) * 1 days);\n            organism.settle();\n        }\n        assertTrue(organism.location() != 0, \"plant has no location\");\n\n        vm.warp(uint256(organism.lastSettledDay() + 2) * 1 days);\n        uint32 silentDay = organism.lastSettledDay() + 1;\n        for (uint256 i; i < 3; ++i) {\n            _heartbeat();\n            vm.warp(vm.getBlockTimestamp() + 1 days); // 24 h without an answer\n            organism.clearPending();\n            if (i < 2) vm.warp(organism.retryAt());\n        }\n        // If the implementation settles the day on the next explicit settle rather than inside the third clear,\n        // give it that chance; on the code as it is this call reverts with NoResult.\n        if (organism.lastSettledDay() == silentDay - 1) {\n            (bool settled,) = address(organism).call(abi.encodeWithSignature(\"settle()\"));\n            settled;\n        }\n\n        assertFalse(organism.isDead(), \"silent oracle must not be a death sentence within a few days\");\n        assertEq(organism.lastSettledDay(), silentDay, \"three unanswered requests did not settle the day empty\");\n        assertEq(organism.water(), 50, \"an empty day has no weather\");\n    }\n}","reproduction":"State: located plant (any cell), lastSettledDay = 20003, pot funded, intake takes the fee and never calls back. Sequence, three times: heartbeat() on day 20005 (asks day 20004); warp +24h; clearPending(); warp to retryAt. Expected after the third clear (or the settle() that follows it): lastSettledDay == 20004, water still 50, plant alive, READ performed so a retained 5% candidate could have moved it. Actual: lastSettledDay stays 20003 (`settle()` reverts NoResult), incompletes[20004] == 0, 1.5 IMD of fees spent, and after 23 repetitions (`test_timeoutsDoNotCountAndEventuallyDie`) `isDead()` is true with the plant still at its old cell.","severity":"low","snippet":"            if (block.timestamp < uint256(pending.askedAt) + ORACLE_TIMEOUT) revert NotTimedOut();\n            _clear();","title":"A request cleared as unanswered after 24h is not a strike: a silent oracle freezes lastSettledDay until the 30-day death clock, with no READ"},{"citation":"resolved","description":"Redeemed PLANT stays in the organism's custody forever (`burned`, line 584) and can never be parked again, yet `_read` requires `candidateStake >= ceilDiv(PLANT.totalSupply(), 20)` (line 469) against the original supply. The share of supply able to vote shrinks with every redemption while the bar does not, so once more than 95% has been redeemed no candidate can ever reach it, even one holding every remaining token against a current cell with zero stake. `floor()` and `redeem` already use `PLANT.totalSupply() - burned` (lines 218, 578); `_read` should use the same remaining supply. The README states the present behaviour as an assumption and `test/PlantAssumptions.t.sol:37` (`test_redeemedSupplyStillCountsInThreshold`) asserts it; that test must be inverted.","line":469,"path":"src/PlantOrganism.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {PlantOrganism} from \"src/PlantOrganism.sol\";\nimport {OracleAttestation} from \"src/OracleAttestation.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\n\ncontract ProofToken is IERC20 {\n    uint256 public totalSupply;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    function mint(address to, uint256 amount) external {\n        balanceOf[to] += amount;\n        totalSupply += amount;\n    }\n\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        emit Approval(msg.sender, spender, amount);\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        balanceOf[msg.sender] -= amount;\n        balanceOf[to] += amount;\n        emit Transfer(msg.sender, to, amount);\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        allowance[from][msg.sender] -= amount;\n        balanceOf[from] -= amount;\n        balanceOf[to] += amount;\n        emit Transfer(from, to, amount);\n        return true;\n    }\n}\n\ncontract ProofHook {\n    address public immutable organism;\n    address public immutable plant;\n\n    constructor(address organism_, address plant_) {\n        organism = organism_;\n        plant = plant_;\n    }\n}\n\ncontract ProofIntake is IIntake {\n    uint256 public price = 0.5 ether;\n    uint256 public sequence;\n    bytes32 public lastId;\n    Callback public callback;\n\n    function priceOf(bytes32, address) external view returns (uint256) {\n        return price;\n    }\n\n    function request(bytes32, bytes calldata, Callback calldata cb, address asset, uint256 amount)\n        external\n        payable\n        returns (bytes32 id)\n    {\n        require(msg.value == 0 && amount == price, \"price\");\n        require(IERC20(asset).transferFrom(msg.sender, address(this), amount), \"pull\");\n        callback = cb;\n        id = keccak256(abi.encode(address(this), ++sequence));\n        lastId = id;\n    }\n\n    function deliver(OracleAttestation.Attestation calldata a, bytes calldata sig) external returns (bool ok) {\n        (ok,) = callback.target.call{gas: 200000}(abi.encodeWithSelector(callback.selector, lastId, a, sig));\n    }\n}\n\n/// @notice The 5% relocation threshold must be measured against PLANT that can still vote, i.e.\n/// `totalSupply() - burned`. On the code as it is `_read` uses `PLANT.totalSupply()`, so once 96% of the\n/// supply has been redeemed the remaining 4% can never move the plant, even when it is 100% of what is left.\ncontract ThresholdProofTest is Test {\n    uint256 internal constant KEY = 0xA11CE;\n    uint32 internal constant OTHER = (156 << 16) | 65500;\n    address internal alice = address(0xa11ce);\n    address internal bob = address(0xb0b);\n    address internal carol = address(0xca201);\n    PlantOrganism internal organism;\n    ProofToken internal imd;\n    ProofToken internal plant;\n    ProofIntake internal intake;\n    uint256 internal serial;\n\n    function _heartbeat() internal {\n        (bool ok,) = address(organism).call(abi.encodeWithSignature(\"heartbeat(uint256)\", type(uint256).max));\n        if (!ok) (ok,) = address(organism).call(abi.encodeWithSignature(\"heartbeat()\"));\n        require(ok, \"heartbeat failed\");\n    }\n\n    /// @dev One complete, weatherless day: ask, deliver a signed `complete` word with empty masks, settle.\n    function _emptyWeatherDay() internal {\n        vm.warp(uint256(organism.lastSettledDay() + 2) * 1 days);\n        _heartbeat();\n        OracleAttestation.Attestation memory a;\n        a.requestId = keccak256(abi.encode(\"threshold proof\", ++serial));\n        a.chainId = 4663;\n        a.answerType = 2;\n        a.answer = abi.encode(bytes32(uint256(1) << 48 | uint256(organism.lastSettledDay() + 1) << 96));\n        a.panelSize = 15;\n        a.quorum = 10;\n        a.agreed = 12;\n        a.issuedAt = uint64(vm.getBlockTimestamp());\n        a.expiresAt = uint64(vm.getBlockTimestamp() + 1 days);\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(KEY, organism.attestationDigest(a));\n        require(intake.deliver(a, abi.encodePacked(r, s, v)), \"delivery rejected\");\n        organism.settle();\n    }\n\n    function test_remainingSupplyCanStillMoveThePlantAfterRedemptions() public {\n        vm.chainId(4663);\n        vm.warp(uint256(20000) * 1 days + 123);\n        imd = new ProofToken();\n        plant = new ProofToken();\n        intake = new ProofIntake();\n        organism = new PlantOrganism(\n            address(imd), address(intake), bytes32(\"oracle.request@oracle-1\"), vm.addr(KEY), 10223579, address(this)\n        );\n        plant.mint(alice, 600 ether);\n        plant.mint(bob, 300 ether);\n        plant.mint(carol, 100 ether);\n        organism.bind(address(new ProofHook(address(organism), address(plant))));\n        imd.mint(address(organism), 1000 ether);\n        vm.prank(alice);\n        plant.approve(address(organism), type(uint256).max);\n        vm.prank(bob);\n        plant.approve(address(organism), type(uint256).max);\n        vm.prank(carol);\n        plant.approve(address(organism), type(uint256).max);\n\n        // Reach a located plant on the code as it is (three empty settles fall back to the fallback cell);\n        // a plant that already has a location from deployment skips this loop.\n        for (uint256 i; i < 3 && organism.location() == 0; ++i) {\n            vm.warp(uint256(organism.lastSettledDay() + 2) * 1 days);\n            organism.settle();\n        }\n        uint32 home = organism.location();\n        assertTrue(home != 0 && home != OTHER, \"plant has no location\");\n\n        // 96% of the supply leaves for good; 40 PLANT is everything that can still vote.\n        vm.prank(alice);\n        organism.redeem(600 ether);\n        vm.prank(bob);\n        organism.redeem(300 ether);\n        vm.prank(carol);\n        organism.redeem(60 ether);\n        assertEq(plant.totalSupply() - organism.burned(), 40 ether);\n\n        vm.prank(carol);\n        organism.park(OTHER, 40 ether);\n        _emptyWeatherDay(); // the deposit is retained across one successful settle and now votes\n        organism.challenge(OTHER);\n        assertEq(organism.votingStake(OTHER), 40 ether);\n        assertEq(organism.votingStake(home), 0);\n        _emptyWeatherDay(); // READ: 40 of 40 remaining PLANT, against a current cell with no stake at all\n        assertEq(organism.location(), OTHER, \"100% of the remaining supply could not move the plant\");\n    }\n}","reproduction":"State: PLANT supply 1000e18 (alice 600e18, bob 300e18, carol 100e18), located plant with no stake at its current cell. alice.redeem(600e18), bob.redeem(300e18), carol.redeem(60e18) -> burned = 960e18, remaining = 40e18. carol.park(OTHER, 40e18); one complete weather day so the deposit is retained across a settle; challenge(OTHER) -> votingStake(OTHER) = 40e18, votingStake(current) = 0; next complete day. Expected: 100% of the remaining supply (and 40e18 >= ceilDiv(40e18, 20) = 2e18) moves the plant to OTHER. Actual: 40e18 < ceilDiv(1000e18, 20) = 50e18, `_read` returns false and location stays at the current cell; no future vote can ever succeed since at most 40e18 can be parked.","severity":"low","snippet":"                && candidateStake >= Math.ceilDiv(PLANT.totalSupply(), 20)","title":"5% relocation threshold is measured against PLANT.totalSupply() including redeemed (burned) PLANT, so the plant becomes permanently immovable as supply is redeemed"},{"citation":"resolved","description":"The inherited `OracleAttestationConsumer._verifyAttestation` already verifies through `SignatureChecker`, and its NatSpec names the protocol's `OracleSignerRegistry` (an ERC-1271 contract) as the natural signer. `PlantOrganism` disables that path three times: the constructor reverts with InvalidConfiguration for any signer with code (line 155), `rotate` refuses a contract `newSigner` (line 624), and `onOracleResult` reverts BadSignature if `oracleSigner` has code (line 333) because its 30-day grace mechanism works by temporarily writing a recovered EOA into `oracleSigner` (lines 327-335), which cannot represent a contract signer. At review time `eth_getCode(0x5598aa9146215bc13eb26f2c692ad1461fd32982)` on chain 4663 returned `0x`, so the configured signer is an EOA and deployment is not blocked today, but the oracle cannot ever rotate this consumer to its registry, and the only way to accept a registry is to replace the recover-and-swap grace logic. Fix: drop the three code-length checks; verify attestations and the rotation digest with `SignatureChecker.isValidSignatureNow(Calldata)` against `oracleSigner`, and give the grace path an explicit candidate (e.g. check the old signer with the same helper) instead of ECDSA recovery; keep the callback inside its 200k stipend with the extra staticcall.","line":155,"path":"src/PlantOrganism.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {IERC1271} from \"@openzeppelin/contracts/interfaces/IERC1271.sol\";\nimport {ECDSA} from \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport {PlantOrganism} from \"src/PlantOrganism.sol\";\n\n/// @dev The protocol's documented rotation story: a registry that answers ERC-1271 for the keys it lists.\ncontract SignerRegistry is IERC1271 {\n    mapping(address => bool) public listed;\n\n    constructor(address key) {\n        listed[key] = true;\n    }\n\n    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4) {\n        (address recovered, ECDSA.RecoverError err,) = ECDSA.tryRecover(hash, signature);\n        return err == ECDSA.RecoverError.NoError && listed[recovered] ? IERC1271.isValidSignature.selector : bytes4(0);\n    }\n}\n\ncontract ProofIntake {\n    function priceOf(bytes32, address) external pure returns (uint256) {\n        return 0;\n    }\n}\n\n/// @notice The oracle signer may be an ERC-1271 contract. On the code as it is, the constructor refuses any\n/// signer with code (`signer_.code.length != 0` -> InvalidConfiguration), so a launch whose signer is the\n/// protocol's registry contract cannot deploy at all.\ncontract ContractSignerProofTest is Test {\n    function test_constructorAcceptsAnErc1271SignerContract() public {\n        vm.chainId(4663);\n        vm.warp(uint256(20000) * 1 days + 123);\n        SignerRegistry registry = new SignerRegistry(vm.addr(0xA11CE));\n        address imd = address(new ProofIntake()); // any contract address works for the token argument here\n        PlantOrganism organism = new PlantOrganism(\n            imd, address(new ProofIntake()), bytes32(\"oracle.request@oracle-1\"), address(registry), 10223579, address(this)\n        );\n        assertEq(organism.oracleSigner(), address(registry));\n    }\n}","reproduction":"Input: `new PlantOrganism(imd, intake, action, signer = address(registry), 10223579, deployer)` where `registry` is any contract implementing `isValidSignature`. Expected: the organism deploys and `oracleSigner() == registry`; attestations signed by a key the registry lists verify. Actual: the constructor reverts with InvalidConfiguration(). Same shape for `rotate(newSigner = registry, ...)` -> InvalidConfiguration(), and if `oracleSigner` could ever hold code the callback would revert BadSignature() at line 333 before `_verifyAttestation` runs.","severity":"low","snippet":"                || signer_.code.length != 0","title":"Oracle signer cannot be an ERC-1271 contract: constructor, rotate and the callback all reject a signer with code"},{"citation":"resolved","description":"`ROTATE_TYPEHASH` (lines 28-30) binds organism, chain id, new signer, new intake, new action and nonce, but no deadline. Anyone may relay the signature (line 619), so an authorization that was signed and never submitted, or that leaked, can be submitted at any later time as long as `rotationNonce` has not moved: the only defence is for the signer to burn the nonce with another rotation. Because a rotation also repoints `intake` and `action`, a stale authorization can later switch the organism to an intake that has since been repriced or retired. The README documents the absence of a deadline and `test/PlantAssumptions.t.sol:29` (`test_oldRotationSignatureAccepted`) asserts acceptance after 400 days; that test must be inverted. Fix: add `uint256 deadline` to the signed struct and revert when `block.timestamp > deadline`.","line":627,"path":"src/PlantOrganism.sol","reproduction":"State: oracleSigner = S, rotationNonce = 0. At time T, S signs rotationDigest(newSigner = N, newIntake = I2, newAction = A, nonce = 0). No rotation happens for 400 days. At T + 400 days anyone calls rotate(N, I2, A, 0, sig). Expected (with a deadline in the struct): revert because the authorization has expired. Actual: the rotation is applied, oracleSigner becomes N, intake becomes I2, and S keeps a fresh 30-day attestation grace from the submission time, not from T.","severity":"low","snippet":"        if (nonce != rotationNonce) revert InvalidNonce();","title":"rotate() authorizations never expire: a signed Rotate struct is valid until its nonce is consumed"},{"citation":"resolved","description":"The advance is `intake.priceOf(action, IMD) - spendablePot()` read inside the call (lines 291-295), and the whole difference is pulled with `_pullExact` up to whatever allowance the caller has given the organism. The caller has no parameter to bound it. The live intake at 0x1397434cd35e8a9c8ac312a61d3a285eb31dea56 quotes 0.5 IMD today but is owner-administered (its runtime bytecode carries the `transferOwnership` selector), and a signer-authorized rotation can repoint `intake` to any contract, so the price a keeper simulated is not the price their transaction pays. Keepers that run with a standing approval (the pattern every test in this repository uses: `approve(organism, type(uint256).max)`) are exposed to the full repricing; the README's advice to approve only the shortfall is the only mitigation. `test/PlantAssumptions.t.sol:57` (`test_rotatedIntakeCanPriceAbovePotAndPullAdvance`) asserts the 9000 IMD pull as intended; it must be inverted. Fix: `heartbeat(uint256 maxAdvance)` reverting when `advance > maxAdvance`.","line":294,"path":"src/PlantOrganism.sol","reproduction":"State: pot 1000 IMD, keeper approval type(uint256).max, keeper has quoted priceOf == 1000 IMD and intends to advance at most 0 (or a few) IMD. Before the keeper's transaction is included the intake price becomes 10000 IMD (owner repricing, or a rotation to another intake). Keeper calls heartbeat(). Expected: revert, because the advance (9000 IMD) exceeds anything the keeper agreed to. Actual: `_pullExact(IMD, keeper, 9000e18)` succeeds, feeAdvances[keeper] = 9000e18, pot() = -9000e18, and repayment depends on future donations ever exceeding the deficit.","severity":"low","snippet":"            uint256 advance = price - available;\n            _pullExact(IMD, msg.sender, advance);","title":"heartbeat() pulls an unbounded fee advance from the caller: the keeper cannot cap what the current intake price takes from their approval"},{"citation":"resolved","description":"`heartbeat` only requires `day >= bindDay` (line 289) and the pre-bind catch-up settles up to `bindDay - 1` (lines 386-387), so the first weather question is for the UTC day on which `bind` was called, a day during most of which the plant did not exist and nobody could have parked. The brief for the next revision asks for the first heartbeat to be the first full UTC day after bind, with every earlier day (including the bind day) settling empty in one bounded call; that is a one-line change in both places (`day <= bindDay` -> NoRequest, catch-up end = `min(today() - 1, bindDay)`). Not a safety defect in itself.","line":289,"path":"src/PlantOrganism.sol","reproduction":"State: deployed on day 20000, settle() catch-up run on day 20010 (lastSettledDay = 20009), bind(hook) at 23:59 UTC on day 20010. On day 20011, heartbeat() is accepted for day 20010 and `requestBody(location, 20010)` asks the oracle for all 24 hours of a day the plant existed for one minute of. Expected under the new rule: NoRequest for day 20010, which settles empty; first request is for day 20011.","severity":"info","snippet":"        if (day < bindDay || location == 0) revert NoRequest();","title":"First oracle day is the partial bind day: heartbeat accepts day == bindDay and pre-bind catch-up stops at bindDay - 1"},{"citation":"resolved","description":"The launch recipe prefers everything configured in the constructor; `bind` is the one post-deployment call, restricted to `deployer` (= $owner in launch.json) and usable once, and the brief explicitly keeps it. It is therefore a trust assumption rather than a defect, but its reach should be stated: the hook's `plant()` becomes `PLANT`, and every custody guarantee (`floor`, `redeem`, the 5% threshold, exact-transfer parking) rests on that token having a fixed supply and plain balances. A hook whose token can be minted, or whose supply can shrink below `burned`, respectively lets its minter redeem the whole `backing` or makes `floor()`/`redeem` revert for everyone. Until bind, IMD donated to the organism has no exit at all (`test/PlantAssumptions.t.sol:79`). No owner, pause, upgrade, mint, blacklist, DELEGATECALL, CALLCODE or SELFDESTRUCT exists; `test/GasAndDeployment.t.sol:43` scans the runtime for the three forbidden opcodes and the pinned protected test (`.imd/reads/protected/evm_contracts/Contracts.protected.t.sol`) repeats that at admission.","line":170,"path":"src/PlantOrganism.sol","reproduction":"Scenario (privileged, deployer-only): deployer binds a hook returning a PLANT token with an open `mint`; 1000 IMD has been donated and 24 sunny hours have moved ~920 IMD into `backing`. Minter mints 10^30 PLANT and calls redeem(10^30): payout = mulDiv(10^30, floor, 1e18) * 9/10 approaches the entire backing, paid to the minter. Expected: not possible with a fixed-supply PLANT; the next launch (token + hook) must guarantee that property before `bind`.","severity":"info","snippet":"    function bind(address hook_) external nonReentrant {","title":"Trust assumptions to carry into the panel review: bind() is a post-deployment configuration step and the bound PLANT token decides the floor's safety"},{"citation":"resolved","description":"The suite is otherwise strong (102 tests, two stateful invariant harnesses with ghost ledgers, 1000-run fuzzing of the hour model and custody), but it encodes each of the items above as a passing assertion, so a fix that is correct will break them and a fix that is wrong may not. Birth: `test/PlantOrganism.t.sol` `test_birthMovesAtFivePercentWithoutMinimumStay` (230), `test_birthFallbackAfterExactlyThreeEmptyDays` (219), `test_preBindDaysSkipInOneCallWithoutRead` (200), `test_unboundCatchUpIsBoundedAndDoesNotRunBirth` (184, reads `birthSettles`), the `_birth`/`_birthWithCommittedCandidate` helpers in `PlantTestBase` (73-89), `test/PlantAdversarial.t.sol` `test_moveThresholdRoundsUpWhenSupplyNotDivisibleByTwenty` (300), `test/PlantVotingRevision.t.sol` `test_questionIsEmptyBeforeBindAndDuringBirth` (8), and the `location() == 0 ? cellSum : ...` branch in `test/PlantStateMachine.t.sol` (312). Judge's lows: `test/PlantAssumptions.t.sol` `test_timeoutsDoNotCountAndEventuallyDie` (16), `test_oldRotationSignatureAccepted` (29), `test_redeemedSupplyStillCountsInThreshold` (37), `test_rotatedIntakeCanPriceAbovePotAndPullAdvance` (57), plus every `heartbeat()` call site once the bounded-advance signature lands. Missing today and expected by the brief: a flash park/unpark test on the located plant that also covers the first epoch after bind, a cell <-> centre round-trip test for ORIGIN_CELL, and one test per low.","line":230,"path":"test/PlantOrganism.t.sol","reproduction":"Run `forge test --offline` after applying only the fix for finding 1 (location set in the constructor, live-stake branch removed): the listed birth tests fail with assertion errors such as `location() == 0` expected, which is the intended outcome, not a regression.","severity":"info","snippet":"    function test_birthMovesAtFivePercentWithoutMinimumStay() public {","title":"Tests that assert the flagged behaviours as intended and must be removed or inverted alongside the fixes"},{"citation":"resolved","description":"Read in full: src/PlantOrganism.sol (every external/public function traced: bind, park, unpark, challenge, heartbeat, onOracleResult, clearPending, settle, settle(uint32), checkpoint, claim, claim(uint32[]), redeem, die, rotate; accounting identities pot+backing+owed == balance and held >= backing+gardenerReserve+creditTotal re-derived by hand for every writer), src/OracleAttestation.sol (verified unchanged in substance against the protocol vector in test/OracleConsumerConformance.t.sol), src/WeatherQuestion.sol, src/interfaces/IIntake.sol, all 10 test files and test/mocks/Mocks.sol, README.md, launch.json, foundry.toml, DEPENDENCIES.md, and the pinned protected test. Existing suite: 102 passed offline. Checked live on chain 4663 via eth_getCode/eth_call at review time: signer 0x5598aa91...2982 has no code (EOA); intake 0x1397434c...ea56 has code, answers priceOf(action, IMD) = 0.5e18 and priceOf(action, 0) = 0; IMD 0x5f7bb593...7127 reports name Identity.md, symbol IMD, 18 decimals, totalSupply ~52,626 IMD. Not reachable or not verifiable: the intake's `request`/callback implementation (id namespace, body validation, whether it will accept the mandated `guards` field, synchronous-callback behaviour), the IMD token's transfer semantics beyond its metadata (verified source not retrievable from the explorer API), the oracle's domain derivation for a callback target that differs from the requester, the future PLANT token and hook (not written yet), and real IMD transfer gas inside the 400k settle budget. No Slither; via-IR optimized build only. Reentrancy, signature replay, rounding direction, overflow in reward math (bounded by pool*1e18 per day), death/retry/timeout boundaries and the launch-forbidden list were checked and produced no further findings.","line":19,"path":"src/PlantOrganism.sol","reproduction":"Not applicable: coverage statement. Commands used: `forge test --offline` (102 passed); `forge test --offline --match-path 'test/scratch/*'` (4 proofs fail on this tree, pass on a patched copy); JSON-RPC eth_getCode/eth_call against https://rpc.mainnet.chain.robinhood.com.","severity":"info","snippet":"contract PlantOrganism is OracleAttestationConsumer, ReentrancyGuard {","title":"Review coverage: what was read, what was checked live, what could not be reached"}],"hash":"c9a6069c83038ef7690da2b5dac7d779aba0903b8b2e179f78023b0ea80408fa","nodeId":"fb9c9ef7-4cab-4538-a010-1e58a4a1d9ac","outcome":"completed","summary":"Nothing further is needed: the findings file is complete, every anchor matches the tree, the four embedded proofs are byte-identical to the scratch tests that fail on this code and pass on a patched copy, and git confirms no tracked file changed (the harness's own `.git/info/exclude` hides `.imd-findings.json` and `test/scratch/`, which is why `git status` was empty).\n\n**Outcome:** the review is written to `.imd-findings.json` with 10 findings, ranked. No critical or high defect exists in the code as it stands. The accounting (pot + backing + owed equals the IMD balance, senior reserves always funded) held up under hand re-derivation of every writer, and the located-plant voting path already enforces the one-stake rule the brief asks for.\n\n**Findings, most severe first**\n\n- **Medium, birth logic (line 455).** While `location == 0`, votes read live balances, so a park, settle and unpark inside one transaction chooses the plant's birth cell with 5% of supply held for one block, and an atomic decoy park can make a birth settle fail. Proof attached; it fails now and passes once location is set from the constructor and the live-stake branch is gone.\n- **Low, silent oracle (line 361).** A request cleared as unanswered is not a strike, so an oracle that never answers freezes `lastSettledDay` until the 30-day death, with no READ. Proof attached.\n- **Low, threshold (line 469).** The 5% bar uses `PLANT.totalSupply()` including burned PLANT, so after 96% is redeemed the remaining 4% can never move the plant even as 100% of what is left. Proof attached.\n- **Low, signer (lines 155, 333, 624).** A contract signer is rejected at construction, rotation and callback, so the oracle can never point this consumer at its ERC-1271 registry. The live signer is an EOA today, so deployment is not blocked. Proof attached.\n- **Low, rotate (line 627).** No deadline in the signed struct; the repo's own test accepts a 400-day-old authorization.\n- **Low, heartbeat (line 294).** The fee advance pulled from the caller is unbounded by any caller parameter. The live intake is owner-administered, so its price can move between quote and inclusion.\n- **Info.** The first oracle day is the partial bind day; bind is the sole post-deployment trust step and the bound PLANT's fixed supply underwrites the floor; a list of the 13 existing tests that assert the flagged behaviours and must be dropped or inverted.\n\n**Coverage.** Read in full: all three source files, the interface, all ten test files and mocks, README, launch.json, foundry.toml and the pinned protected test. The existing suite passes offline with 102 tests. Checked live on chain 4663 over JSON-RPC: the signer has no code, the intake answers `priceOf` at 0.5 IMD, and the IMD token reports its metadata. Not reachable: the intake's request and callback implementation, IMD's transfer semantics beyond metadata, the oracle's domain derivation, and the future PLANT token and hook.\n\nSources used for the RPC endpoints: [Quicknode guide](https://www.quicknode.com/de/leitfaden-fur-bauherren/am-besten/top-10-robinhood-chain-rpc-providers), [NodeFlare](https://nodeflare.app/chains/robinhood).","treeHash":null,"usage":{"cachedInputTokens":3668265,"inputTokens":578,"model":"claude-fable-5-1","outputTokens":110534,"runtime":"claude","turns":54,"wallClockMs":1970963}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"3b260b68e9ad6a37","findings":[],"hash":"ed6cd0fad6da73813713a9ba9b80c20f09a4dcddf326e9a9ac578cfef3c63f8b","nodeId":"c07d5b13-3a2f-4f13-88e0-ae5ac5216274","outcome":"failed","summary":"wall-clock budget exhausted","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":"claude-fable-5-1","outputTokens":0,"runtime":"claude","turns":0,"wallClockMs":6806741}},{"artifacts":[],"attempt":2,"bundleHash":null,"device":"04f946173ab09bec","findings":[{"citation":"resolved","description":"README and the design say a spent fee advance 'unlocks at the next successful settle and remains owed until funded'. heartbeat() stores feeUnlockEpoch[msg.sender] = epoch + 1 unconditionally, so a keeper whose earlier advance already unlocked (epoch >= feeUnlockEpoch) but could not be repaid because the pot was empty has that debt re-locked the moment they fund the next day's request. _pay() (line 534: `if (epoch >= feeUnlockEpoch[holder] || dead)`) then refuses to repay any of their advances until another settle, even when unreserved IMD is now present. Other keepers who advanced earlier are not affected, so the first keeper is pushed behind them in the first-come repayment queue for funds that should already have been theirs to claim. Impact is a delay of at least one settle (and indefinitely while the keeper keeps being the only one funding requests), not a loss, hence low. Minimal fix: only raise the unlock epoch, e.g. keep per-epoch advance buckets, or set feeUnlockEpoch only when feeAdvances[msg.sender] == 0 before this pull, or track unlocked and locked advances separately.","line":296,"path":"src/PlantOrganism.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PlantOrganism} from \"src/PlantOrganism.sol\";\nimport {OracleAttestation} from \"src/OracleAttestation.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ncontract PToken is IERC20 {\n    uint256 public totalSupply;\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n    function mint(address to, uint256 a) external { balanceOf[to] += a; totalSupply += a; }\n    function approve(address s, uint256 a) external returns (bool) { allowance[msg.sender][s] = a; return true; }\n    function transfer(address to, uint256 a) external returns (bool) { balanceOf[msg.sender] -= a; balanceOf[to] += a; return true; }\n    function transferFrom(address f, address to, uint256 a) external returns (bool) {\n        allowance[f][msg.sender] -= a; balanceOf[f] -= a; balanceOf[to] += a; return true;\n    }\n}\n\ncontract PHook { address public organism; address public plant; constructor(address o, address p) { organism = o; plant = p; } }\n\ncontract PIntake is IIntake {\n    uint256 public price = 10 ether;\n    uint256 public seq;\n    Callback public cb;\n    bytes32 public lastId;\n    function priceOf(bytes32, address) external view returns (uint256) { return price; }\n    function request(bytes32, bytes calldata, Callback calldata c, address asset, uint256 amount) external payable returns (bytes32 id) {\n        require(IERC20(asset).transferFrom(msg.sender, address(this), amount));\n        cb = c; id = keccak256(abi.encode(++seq)); lastId = id;\n    }\n    function deliver(bytes32 id, OracleAttestation.Attestation calldata a, bytes calldata sig) external returns (bool ok) {\n        (ok,) = cb.target.call{gas: 200000}(abi.encodeWithSelector(cb.selector, id, a, sig));\n    }\n}\n\n/// A fee advance that already unlocked at a successful settle (feeUnlockEpoch <= epoch) but could\n/// not be repaid for lack of funds is re-locked when the same keeper advances again, because\n/// heartbeat overwrites feeUnlockEpoch[msg.sender] = epoch + 1. Expected: an unlocked advance stays\n/// claimable as soon as unreserved IMD arrives.\ncontract RelockProofTest is Test {\n    uint256 constant KEY = 0xA11CE;\n    uint32 constant ORIGIN = 10223578;\n    uint32 constant START = 20000;\n    PToken imd; PToken plant; PIntake intake; PlantOrganism org;\n    address keeperA = address(0xAAA);\n    uint256 serial;\n\n    function setUp() public {\n        vm.chainId(4663);\n        vm.warp(uint256(START) * 1 days + 100);\n        imd = new PToken(); plant = new PToken(); intake = new PIntake();\n        plant.mint(address(this), 1000 ether);\n        org = new PlantOrganism(address(imd), address(intake), bytes32(\"act\"), vm.addr(KEY), ORIGIN, address(this));\n        org.bind(address(new PHook(address(org), address(plant))));\n        imd.mint(keeperA, 100 ether);\n        vm.prank(keeperA); imd.approve(address(org), type(uint256).max);\n    }\n\n    function _att() internal returns (OracleAttestation.Attestation memory a) {\n        a.requestId = keccak256(abi.encode(++serial));\n        a.chainId = 4663; a.answerType = 2;\n        a.answer = abi.encode(bytes32((uint256(1) << 48) | uint256(org.lastSettledDay() + 1) << 96));\n        a.panelSize = 15; a.quorum = 10; a.agreed = 12;\n        a.issuedAt = uint64(block.timestamp); a.expiresAt = uint64(block.timestamp + 1 days);\n    }\n\n    function _sign(OracleAttestation.Attestation memory a) internal view returns (bytes memory) {\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(KEY, org.attestationDigest(a));\n        return abi.encodePacked(r, s, v);\n    }\n\n    function test_unlockedAdvanceStaysClaimableAfterNextAdvance() public {\n        // Day 1: empty pot, keeper A advances the full 10 IMD fee; the day settles successfully.\n        vm.warp(uint256(org.lastSettledDay() + 2) * 1 days);\n        vm.prank(keeperA); org.heartbeat(type(uint256).max);\n        OracleAttestation.Attestation memory a = _att();\n        assertTrue(intake.deliver(intake.lastId(), a, _sign(a)));\n        org.settle();\n        assertEq(org.epoch(), 1);\n        assertEq(org.feeAdvances(keeperA), 10 ether);\n        assertEq(org.feeUnlockEpoch(keeperA), 1, \"day-1 advance unlocked at the settle\");\n        assertEq(imd.balanceOf(keeperA), 90 ether, \"nothing repaid yet: the pot is empty\");\n\n        // Day 2: A advances again before anyone funds the pot.\n        vm.warp(uint256(org.lastSettledDay() + 2) * 1 days);\n        vm.prank(keeperA); org.heartbeat(type(uint256).max);\n        assertEq(org.feeAdvances(keeperA), 20 ether);\n\n        // A donor funds exactly the day-1 debt. The unlocked day-1 advance should be repayable now.\n        imd.mint(address(org), 10 ether);\n        vm.prank(keeperA); org.claim();\n        assertEq(imd.balanceOf(keeperA), 90 ether, \"the already unlocked day-1 advance must be repaid\");\n        assertEq(org.feeAdvances(keeperA), 10 ether);\n    }\n}","reproduction":"State: bound plant, pot 0, intake price 10 IMD, keeper A holds 100 IMD. Day 1: A calls heartbeat(max) and advances 10 (feeAdvances[A]=10, feeUnlockEpoch[A]=1); the oracle delivers a complete word; settle() runs: epoch=1, _pay(A) finds held-senior == 0 so nothing is repaid, A's advance is unlocked (1 >= 1). Day 2: A calls heartbeat(max) again and advances 10 more: feeUnlockEpoch[A] is overwritten to 2. A donor transfers 10 IMD to the organism. A calls claim(). Expected: the unlocked day-1 advance is repaid, A's balance 90 IMD, feeAdvances[A] 10. Actual: _pay skips the advance branch because epoch (1) < feeUnlockEpoch[A] (2); A's balance stays 80 IMD and feeAdvances[A] stays 20 until the next settle.","severity":"low","snippet":"            feeUnlockEpoch[msg.sender] = epoch + 1;","title":"heartbeat() overwrites feeUnlockEpoch, re-locking a keeper's already unlocked but unpaid fee advance"},{"citation":"resolved","description":"The explicit-day overload only guards that `day` is the next unsettled day and then calls _settle(false), whose pre-bind / through-bind-day branch advances lastSettledDay to today()-1 (or bindDay) in one step. A caller naming a single day therefore settles every ended day up to the catch-up end. The skipped days are empty, so no accounting changes, but the overload's guard does not deliver the 'exactly this day' semantics its name and WrongDay error suggest. Cosmetic; mention so the README or the overload can state that catch-up ignores the named day.","line":368,"path":"src/PlantOrganism.sol","reproduction":"Deploy PlantOrganism (unbound) on UTC day d0; warp to day d0+10; call settle(d0+1). Expected by the overload's contract: lastSettledDay == d0+1 (or a revert if more than one day is pending). Actual: lastSettledDay == d0+9 and EmptyCatchUp(d0+1, d0+9) is emitted.","severity":"info","snippet":"        if (day != lastSettledDay + 1) revert WrongDay();","title":"settle(uint32 day) settles past its named day during the empty catch-up"}],"hash":"f0945a74dcddaf34073a59eb557d912b02fb9e5edf1492e698120991015a29fa","nodeId":"c07d5b13-3a2f-4f13-88e0-ae5ac5216274","outcome":"completed","summary":"Review complete. The findings file is written and the working tree is otherwise untouched (scratch tests removed).\n\n**Outcome:** the revision holds up in the assigned area. Two defects, neither serious, are in `.imd-findings.json` with full coverage rows for all 15 entry points.\n\n**What I traced (Execution Trace, Periphery, First Principles):**\n- Birth logic is fully gone, and the git diff against the last accepted commit shows WeatherQuestion.sol is byte-identical, so the question text and body are unchanged.\n- The origin cell round-trips correctly: Sintra at 38.78333, -9.41667 floors to quarter indices (155, -38), packs to 10223578, and the centre 38.875, -9.375 is inland Portugal.\n- The one stake rule is consistent across nomination, both sides of the READ, the 5% threshold on remaining supply, and the gardener pool. The cell and position bookkeeping stay coupled, and a flash park earns nothing and cannot move the plant.\n- The new timeout strike path, the fee cap, the signed rotation deadline, and the ERC-1271 plus grace signature path all behave as specified. The catch-up branch cannot revive a dead plant.\n- Conservation holds: the IMD balance always covers backing, reserves and credits, so no payment path can overdraw.\n- The launch manifest matches the constructor order and schema.\n\n**Findings:**\n1. **Low, with a failing proof test.** A later fee advance by the same keeper overwrites their unlock epoch, re-locking an advance that already unlocked but was unpaid for lack of funds. The keeper is pushed behind others for one or more settles. Delay only, no loss.\n2. **Info.** The named-day settle overload settles every ended day during catch-up instead of only the named day. Cosmetic.\n\n**Leads I checked and dropped:** the slither reentrancy lines (every state-changing function is guarded), the strict-equality and uninitialized-local lines (benign), the unpinned questionHash (the day check and the per-day fixed location make it redundant), and the 30-day grace for replaced signers (documented design).","treeHash":null,"usage":{"cachedInputTokens":1284668,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":65029,"runtime":"claude","turns":25,"wallClockMs":2891583}},{"artifacts":[],"attempt":1,"bundleHash":"a15a862e7af5f97a56a69e9d0cd48f24071b5b29beb0baf38ab2867ce839f8e5","device":"868942acc8b75a51","findings":[],"hash":"f49120bc135b3e9c592dc485cdc9218015e256816acc1b0ccbf2752176e9e14b","nodeId":"4b3e0a6b-a286-407e-b102-b2f1832f7f4a","outcome":"completed","summary":"Implemented the launch revision with Sintra origin (`10223578`), removed birth logic, and fixed all five lows.\n\n`forge build` passed. `forge test`: **113 passed, 0 failed**, including gas limits and stateful invariants.\n\nREADME and launch manifest updated; changes documented in [ADAPTATION.md](ADAPTATION.md). Protected configuration and dependencies remain unchanged.","treeHash":"e28e2027dc533c828d69c64375e31405b3487db1","usage":{"cachedInputTokens":3320960,"inputTokens":141117,"model":"gpt-6-astra","outputTokens":28020,"runtime":"codex","turns":9,"wallClockMs":904901}}],"verification":[{"checks":[{"durationMs":62144,"exitCode":0,"name":"build","output":"Compiling 59 files with Solc 0.8.26\nSolc 0.8.26 finished in 61.99s\nCompiler run successful!\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:12:21\n   │\n12 │         int16 lat = int16(uint16(cell >> 16));\n   │                     ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:12:27\n   │\n12 │         int16 lat = int16(uint16(cell >> 16));\n   │                           ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:13:21\n   │\n13 │         int16 lon = int16(uint16(cell));\n   │                     ━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:13:27\n   │\n13 │         int16 lon = int16(uint16(cell));\n   │                           ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:19:29\n   │\n19 │         uint256 magnitude = uint256(milli < 0 ? -milli : milli);\n   │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:26:29\n   │\n26 │             b[--i] = bytes1(uint8(48 + n % 10));\n   │                             ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:39:27\n   │\n39 │         uint256 y = yoe + era * 400;\n   │                           ━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:40:30\n   │\n40 │         uint256 doy = doe - (365 * yoe + yoe / 4 - yoe / 100);\n   │                              ━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:42:28\n   │\n42 │         uint256 d = doy - (153 * mp + 2) / 5 + 1;\n   │                            ━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:50:40\n   │\n50 │         string memory lat = coordinate(int16(uint16(cell >> 16)));\n   │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:50:46\n   │\n50 │         string memory lat = coordinate(int16(uint16(cell >> 16)));\n   │                                              ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:51:40\n   │\n51 │         string memory lon = coordinate(int16(uint16(cell)));\n   │                                        ━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:51:46\n   │\n51 │         string memory lon = coordinate(int16(uint16(cell)));\n   │                                              ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:170:16\n    │\n170 │         return uint32(block.timestamp / 1 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/PlantOrganism.sol:173:19\n    │\n173 │     function bind(address hook_) external nonReentrant {\n    │                   ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:209:25\n    │\n209 │         require(held <= uint256(type(int256).max) && reserved <= uint256(type(int256).max));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:209:66\n    │\n209 │         require(held <= uint256(type(int256).max) && reserved <= uint256(type(int256).max));\n    │                                                                  ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:210:16\n    │\n210 │         return int256(held) - int256(reserved);\n    │                ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:210:31\n    │\n210 │         return int256(held) - int256(reserved);\n    │                               ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:215:24\n    │\n215 │         return p > 0 ? uint256(p) : 0;\n    │                        ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:556:13\n    │\n556 │             emit Checkpointed(holder, cell, credit);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:294:13\n    │\n294 │             emit Challenged(cell);\n    │             ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:255:9\n    │\n255 │         emit Parked(msg.sender, cell, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:280:9\n    │\n280 │         emit Unparked(msg.sender, cell, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `pending` is updated\n    ╭▸ src/PlantOrganism.sol:321:14\n    │\n321 │           id = intake.request(\n    │ ┏━━━━━━━━━━━━━━┛\n322 │ ┃             action,\n323 │ ┃             requestBody(location, day),\n324 │ ┃             IIntake.Callback(address(this), this.onOracleResult.selector),\n325 │ ┃             address(IMD),\n326 │ ┃             price\n327 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:304:13\n    │\n304 │         if (block.timestamp < retryAt) revert RetryLater();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:317:13\n    │\n317 │             emit Advanced(msg.sender, advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:332:9\n    │\n332 │         emit Asked(id, day, location, challenger, msg.sender, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/PlantOrganism.sol:329:13\n    │\n329 │         if (IMD.balanceOf(address(this)) != beforeBalance - price) revert NonExactTransfer();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:331:54\n    │\n331 │             Pending(id, day, challenger, msg.sender, uint64(block.timestamp), address(intake), true, false, bytes32(0));\n    │                                                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:360:9\n    │\n360 │         emit Received(requestId, a.requestId, word);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:350:13\n    │\n350 │         if (uint32(w >> 96) != p.day) revert WrongDay();\n    │             ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:369:17\n    │\n369 │             if (block.timestamp < uint256(pending.askedAt) + ORACLE_TIMEOUT) revert NotTimedOut();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:380:9\n    │\n380 │         emit Cleared(id, day, retryAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:404:13\n    │\n404 │             emit EmptyCatchUp(day, end);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:418:13\n    │\n418 │             emit Incomplete(day, count);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:527:9\n    │\n527 │         emit Rewarded(cell, pool, reserved);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:490:13\n    │\n490 │             emit Moved(current, candidate);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:435:13\n    │\n435 │             emit Bounty(caller, bounty);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:598:13\n    │\n598 │             emit Paid(holder, credit, advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:604:13\n    │\n604 │             emit PaymentDeferred(holder, credit + advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:438:9\n    │\n438 │         emit Settled(day, word, sips, backing, water, location);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:426:30\n    │\n426 │         _distribute(oldCell, pool);\n    │                              ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:438:33\n    │\n438 │         emit Settled(day, word, sips, backing, water, location);\n    │                                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:401:61\n    │\n401 │             uint32 end = hook == address(0) ? today() - 1 : uint32(Math.min(today() - 1, bindDay));\n    │                                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:455:17\n    │\n455 │         water = uint8(wet);\n    │                 ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:466:21\n    │\n466 │         uint32 to = uint32(Math.min(c.lastQueuedDay, _matureThrough()));\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:501:21\n    │\n501 │         uint32 to = uint32(Math.min(c.lastQueuedDay, through));\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:537:25\n    │\n537 │             uint32 to = uint32(Math.min(p.lastQueuedDay, through));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:592:22\n    │\n592 │         if (credit + advance == 0) return;\n    │                      ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:623:9\n    │\n623 │         emit Redeemed(msg.sender, amount, payout, dead);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:638:13\n    │\n638 │             emit Died(today(), merged);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:640:13\n    │\n640 │             emit PotMerged(merged);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:670:13\n    │\n670 │         if (block.timestamp > deadline) revert RotationExpired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/OracleAttestation.sol:192:9\n    │\n192 │         emit OracleSignerSet(signer);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:680:9\n    │\n680 │         emit Rotated(oldSigner, newSigner, newIntake, newAction, nonce);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:694:16\n    │\n694 │         return block.timestamp < signerAcceptedUntil[signer]\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/PlantOrganism.sol:701:13\n    │\n701 │         if (token.balanceOf(address(this)) != beforeBalance + amount) revert NonExactTransfer();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\n","passed":true},{"durationMs":9569,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 3 tests for test/WeatherQuestion.t.sol:WeatherQuestionTest\n[PASS] test_coordinatesAtEdgesAndNegativeZeroFraction() (gas: 40309)\n[PASS] test_exactLisbonBodyAndKnownDate() (gas: 15004)\n[PASS] test_exactNegativeLatitudeAndLongitudeBody() (gas: 15401)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 235.82µs (158.08µs CPU time)\n\nRan 4 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsOriginalProtocolSignatureInCanonicalVerifier() (gas: 117620)\n[PASS] test_bytes32WeatherFixtureAcceptedUnderStipend() (gas: 2404320)\n[PASS] test_callbackSelectorIsCanonical() (gas: 3543)\n[PASS] test_digestMatchesTheProtocol() (gas: 13207)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 2.00ms (1.05ms CPU time)\n\nRan 9 tests for test/PlantOrganism.t.sol:PlantLifecycleTest\n[PASS] test_bindIsOnceAndOnlyDeployerWithMatchingHook() (gas: 325845)\n[PASS] test_cellBoundsAndZeroRejected() (gas: 700646)\n[PASS] test_challengerOnlyStrictlyLargerAndCanBeRepaired() (gas: 3116585)\n[PASS] test_deathIsFinalAtThirtyDaysAndKeepsExits() (gas: 3251288)\n[PASS] test_deathUsesBindDayAfterLongUnboundPeriod() (gas: 285519)\n[PASS] test_moveUsesPendingCandidateAndRemainingCommittedBalances() (gas: 3804303)\n[PASS] test_noEarlyOrOutOfOrderSettleAndHeartbeat() (gas: 1001485)\n[PASS] test_preBindDaysSkipInOneCallWithoutRead() (gas: 636550)\n[PASS] test_unboundCatchUpIsBoundedAtOrigin() (gas: 149663)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 10.38ms (5.59ms CPU time)\n\nRan 4 tests for test/PlantOrganism.t.sol:PlantRotationTest\n[PASS] test_oldSignerExpiresAtThirtyDaysWhileNewSignerKeepsPlantAlive() (gas: 19983069)\n[PASS] test_onlyCurrentSignerCanRotateNonceCannotReplay() (gas: 1143696)\n[PASS] test_pendingIntakeAndOldSignerWorkAfterRotation() (gas: 4441349)\n[PASS] test_rotationDomainBindsAllFieldsAndContract() (gas: 972660)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 18.03ms (22.44ms CPU time)\n\nRan 7 tests for test/PlantAssumptions.t.sol:PlantAssumptionsTest\n[PASS] test_explicitZeroCellQuestionRemainsInvalid() (gas: 19594)\n[PASS] test_oldRotationSignatureExpires() (gas: 835017)\n[PASS] test_oldSourceWindowBacklogIsAlreadyDead() (gas: 1663671)\n[PASS] test_preBindDonationsHaveNoExit() (gas: 184091)\n[PASS] test_redeemedSupplyIsExcludedFromThreshold() (gas: 4409115)\n[PASS] test_rotatedIntakeCannotPullAboveKeeperCap() (gas: 2214924)\n[PASS] test_threeSilentRequestsSettleEmptyAndMoveWithRetainedStake() (gas: 3489418)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 20.62ms (8.89ms CPU time)\n\nRan 8 tests for test/PlantVotingCommitment.t.sol:PlantVotingCommitmentTest\n[PASS] testFuzz_withdrawalAndRedepositCannotIncreasePower(uint96,uint96) (runs: 256, μ: 3238151, ~: 3239138)\nLogs:\n  Bound result 19496\n  Bound result 23183\n\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotCaptureGardenersPool() (gas: 5216110)\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotMove() (gas: 4250883)\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotVeto() (gas: 3234065)\n[PASS] test_loanAcrossPreviousSettleLosesPowerOnWithdrawal() (gas: 3823076)\n[PASS] test_rearmedDecoyCannotHideHoldersCandidate() (gas: 3421856)\n[PASS] test_thresholdUsesCommittedStakeAndNewDepositsMatureAtSettle() (gas: 4211353)\n[PASS] test_timeoutAndReaskCannotRestoreWithdrawnPower() (gas: 4083292)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 323.08ms (334.16ms CPU time)\n\nRan 8 tests for test/PlantLaunchRevision.t.sol:PlantLaunchRevisionTest\n[PASS] test_firstEpochFlashCannotEarnGardenersAtOrigin() (gas: 3160338)\n[PASS] test_firstEpochFlashCannotMoveOrEarnGardenersAtDestination() (gas: 3249744)\n[PASS] test_lateBindSkipsThroughBindDayAndRequestsOnlyFirstFullDay() (gas: 1627184)\n[PASS] test_originFromRealCoordinatesRoundTripsThroughCentre() (gas: 69705)\n[PASS] test_repricingCannotExceedAdvanceCapAndZeroCapUsesPot() (gas: 1109319)\n[PASS] test_rotationDeadlineIsSignedAndAcceptedAtExactBoundary() (gas: 171457)\n[PASS] test_timeoutAfterDeathCannotAdvanceDayOrRevive() (gas: 1095165)\n[PASS] test_timeoutsAndIncompleteShareCounterAndReadRepairedCandidate() (gas: 4244168)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 407.79ms (7.90ms CPU time)\n\nRan 6 tests for test/GasAndDeployment.t.sol:GasAndDeploymentTest\n[PASS] test_coldCallbackAndMaxHoursMoveSettleGas() (gas: 3871680)\nLogs:\n  cold callback gas: 87736\n\n[PASS] test_coldMaxHoursWithRepairedCandidateSettleGas() (gas: 3891461)\n[PASS] test_requestedStaticConstructorAndForbiddenOpcodes() (gas: 9588169)\n[PASS] test_settlementFitsStipendWithManyEligibleHolders() (gas: 38901338)\n[PASS] test_thirdIncompleteMoveAndAdvancePaymentGas() (gas: 4803800)\n[PASS] test_thirdTimeoutMoveAndAdvancePaymentFitsColdStipend() (gas: 4294896)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 409.86ms (57.48ms CPU time)\n\nRan 8 tests for test/PlantSettleLag.t.sol:PlantSettleLagTest\n[PASS] test_bindDayDepositsWaitForFirstFullDaySettle() (gas: 844349)\n[PASS] test_lagDepositsMatureDayByDayWithExactShares() (gas: 5317839)\n[PASS] test_longLagWithDailyDepositsSettlesColdWithinStipend() (gas: 19728109)\n[PASS] test_parkAfterDayEndedCannotEarnThatDaysPool() (gas: 3596064)\n[PASS] test_parkAfterDayEndedCannotVoteOnThatDay() (gas: 4509076)\n[PASS] test_settleNamedDayRefusesCatchUpBeyondIt() (gas: 2341449)\n[PASS] test_unlockedAdvanceIsNotRelockedByNextHeartbeat() (gas: 3043811)\n[PASS] test_withdrawalDuringLagLeavesNewestDayFirst() (gas: 3514010)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 419.86ms (20.48ms CPU time)\n\nRan 13 tests for test/PlantOrganism.t.sol:PlantRewardsTest\n[PASS] testFuzz_floorConservationAndBurnCustody(uint96,uint96,uint24) (runs: 1000, μ: 2962526, ~: 2978675)\nLogs:\n  Bound result 19926\n\n[PASS] testFuzz_hourlyAccountingMatchesIndependentModel(uint24,uint24) (runs: 1000, μ: 2453017, ~: 2455347)\n[PASS] test_departuresDropOutAndReparkingCannotCaptureDay() (gas: 4705056)\n[PASS] test_finalRedemptionDoesNotDivideByZeroOrReleaseBurnedPlant() (gas: 3085270)\n[PASS] test_gardenerDustRoundsToBackingAndAccountsCloseExactly() (gas: 5820020)\n[PASS] test_hourZeroFirstRainCapAndSunRequiresWater() (gas: 5409625)\n[PASS] test_noGardenersSendsEntireSipToBacking() (gas: 1292079)\n[PASS] test_nonExactTokenTransfersRejected() (gas: 2619479)\n[PASS] test_oldCellKeepsItsRewardsAfterMoveAndLazyActivation() (gas: 6361054)\n[PASS] test_parkSettleClaimProRataAndMidDayJoinsWaitOneSettle() (gas: 3807527)\n[PASS] test_redeemRetainsPlantAndTenPercentAndFloorMonotonic() (gas: 2835731)\n[PASS] test_redeemThatPaysNothingIsRefusedAndKeepsPlant() (gas: 2700736)\n[PASS] test_reentrancyFromTokensAndIntakeBlocked() (gas: 2925416)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 425.03ms (768.00ms CPU time)\n\nRan 21 tests for test/PlantAdversarial.t.sol:PlantAdversarialTest\n[PASS] testFuzz_parkUnparkRoundTripCannotEarnWithoutSettlement(uint96,uint8) (runs: 1000, μ: 2647647, ~: 2371464)\nLogs:\n  Bound result 159141\n  Bound result 1\n\n[PASS] testFuzz_reservedWeatherBitsRejectedWithoutMutatingPending(uint8) (runs: 1000, μ: 2106688, ~: 2106679)\n[PASS] testFuzz_signedMalformedPanelsAreRejected(uint8) (runs: 1000, μ: 2103347, ~: 2103224)\n[PASS] test_answerMustBeExactlyOneWordIncludingTrailingData() (gas: 2244830)\n[PASS] test_bindRejectsNonContractWrongAndEmptyTokens() (gas: 1569386)\n[PASS] test_callbackAndSettlementEventsDescribeTheAppliedResult() (gas: 2330726)\n[PASS] test_consumedOracleUuidCannotBeReusedForSameDayRetry() (gas: 2901606)\n[PASS] test_deathClearsPendingAndPreservesGardenersAndFeeDebt() (gas: 3511001)\n[PASS] test_deferredAdvanceAndBountyRemainClaimableExactlyOnce() (gas: 2873914)\n[PASS] test_depositAfterAskMustMatureBeforeItCanChallenge() (gas: 3881994)\n[PASS] test_exactClockDriftToleranceAccepted() (gas: 2100004)\n[PASS] test_moveRewardsDepartingCellAndNeverIncomingCellForSameDay() (gas: 4052697)\n[PASS] test_moveThresholdRoundsUpWhenSupplyNotDivisibleByTwenty() (gas: 3802544)\n[PASS] test_rejectedResultCanBeCorrectedWithoutBurningRequest() (gas: 2397203)\n[PASS] test_rotatedIntakeCannotAnswerPreviousIntakesRequest() (gas: 4104324)\n[PASS] test_thirdIncompleteReadsCandidateFromLatestRequest() (gas: 4423609)\n[PASS] test_timeoutExactSecondAndOldResultCannotPoisonReask() (gas: 2592219)\n[PASS] test_twoKeepersAdvancesSurviveTimeoutAndOnlyUnlockOnSettlement() (gas: 3355706)\n[PASS] test_unparkAfterCallbackDropsOutBeforeHoursAndKeepsPreviousReward() (gas: 3240961)\n[PASS] test_validityWindowBoundariesAndAskedAt() (gas: 2498149)\n[PASS] test_zeroAmountsAndOverdrawCannotChangeCustody() (gas: 1861713)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 426.50ms (1.29s CPU time)\n\nRan 12 tests for test/PlantOrganism.t.sol:PlantOracleTest\n[PASS] test_blockedKeeperDoesNotBlockSettleAndCanClaimLater() (gas: 2725002)\n[PASS] test_callbackSenderIdAndReplay() (gas: 2859699)\n[PASS] test_callbackStoresOnlyAndFitsStipend() (gas: 2444266)\nLogs:\n  callback gas including mock encoding: 87736\n\n[PASS] test_clearIncompleteUsesSameCounterAndCannotDiscardComplete() (gas: 2837817)\n[PASS] test_exactApprovalAndIntakeBody() (gas: 2126429)\n[PASS] test_feeAdvanceTracksDeficitThenRepaidAtSettle() (gas: 2853496)\n[PASS] test_incompleteHasNoBiologicalChangesThenThirdReads() (gas: 4120217)\n[PASS] test_intakeMustPullExactPrice() (gas: 1963545)\n[PASS] test_rejectsExpiredWrongDomainSignerTypeDayChainAndPanel() (gas: 3147665)\n[PASS] test_rejectsPreAskFutureTamperedAndMalformedAttestations() (gas: 2896318)\n[PASS] test_timeoutClearsAndWaitsSixHoursToReaskSameDay() (gas: 2898620)\n[PASS] test_unfundedAdvanceDoesNotSpendBackingOrBlockSettle() (gas: 3401965)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 425.70ms (29.16ms CPU time)\n\nRan 4 tests for test/PlantContractSigner.t.sol:PlantContractSignerTest\n[PASS] test_canRotateToContractAndRejectInvalidOrRevokedSignatures() (gas: 2069805)\n[PASS] test_constructorContractAttestationAndRotationFitCallbackStipend() (gas: 2510578)\nLogs:\n  cold ERC-1271 callback gas: 91111\n\n[PASS] test_multiplePriorContractSignersKeepGraceWithoutRotationAuthority() (gas: 3401495)\n[PASS] test_previousContractGraceExpiresAtThirtyDays() (gas: 18335046)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 426.66ms (23.65ms CPU time)\n\nRan 13 tests for test/PlantVotingRevision.t.sol:PlantVotingRevisionTest\n[PASS] testFuzz_repeatedTopUpsCannotIncreaseCommittedStake(uint96) (runs: 1000, μ: 4355447, ~: 4355317)\nLogs:\n  Bound result 2416767182\n\n[PASS] testFuzz_withdrawalUsesOwnQueuedStakeBeforeCommitment(uint96) (runs: 1000, μ: 3767943, ~: 3768384)\nLogs:\n  Bound result 107130785685202118667\n\n[PASS] test_atomicCurrentCellTopUpCannotVetoCommittedCandidate() (gas: 3081537)\n[PASS] test_atomicDestinationTopUpCannotMoveOrCaptureRewards() (gas: 4476764)\n[PASS] test_currentCellWithdrawalBreaksTieForCommittedCandidate() (gas: 2937035)\n[PASS] test_emptyCapturedCandidateFallsBackToRepairedLiveCandidate() (gas: 3322350)\n[PASS] test_fallbackCannotUseNewPostHeartbeatStake() (gas: 4459179)\n[PASS] test_questionUsesOriginFromDeployment() (gas: 1729979)\n[PASS] test_replacementHolderCannotInheritWithdrawnVotingPower() (gas: 4585254)\n[PASS] test_thirdIncompleteAlsoUsesRepairedCandidate() (gas: 4886018)\n[PASS] test_thirdIncompleteReadsBeforePromotingFreshDeposits() (gas: 4801499)\n[PASS] test_timeoutRetryCannotMatureRequestOrCooldownDeposits() (gas: 4910890)\n[PASS] test_withdrawalRemovesPowerAndReaskCannotRestoreIt() (gas: 4949153)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 425.75ms (863.51ms CPU time)\n\nRan 1 test for test/PlantInvariant.t.sol:PlantInvariantTest\n[PASS] invariant_conservationAndPermanentBurnCustody() (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+---------------+-------+---------+----------╮\n| Contract     | Selector      | Calls | Reverts | Discards |\n+===========================================================+\n| PlantHandler | challenge     | 1050  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | checkpointAll | 988   | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | claim         | 1019  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | fund          | 1073  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | park          | 992   | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | redeem        | 1029  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | unpark        | 1026  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | weather       | 1015  | 0       | 0        |\n╰--------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 5473\n  Bound result 2379\n  Bound result 1852\n  Bound result 114\n  Bound result 803547396580323414577\n  Bound result 10818\n  Bound result 2\n  Bound result 7504000797407163592\n  Bound result 759\n  Bound result 2088\n  Bound result 125795110000000002477\n  Bound result 15618\n  Bound result 22786\n  Bound result 6449\n  Bound result 13818645566776476\n  Bound result 684\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.81s (1.81s CPU time)\n\nRan 1 test for test/PlantStateMachine.t.sol:PlantStateMachineInvariantTest\n[PASS] invariant_independentCustodyAndSolvency() (runs: 256, calls: 24576, reverts: 0)\n\n╭--------------------------+---------------+-------+---------+----------╮\n| Contract                 | Selector      | Calls | Reverts | Discards |\n+=======================================================================+\n| PlantStateMachineHandler | answer        | 2040  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | challenge     | 2060  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | claim         | 2031  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | clear         | 2012  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | donate        | 2082  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | elapse        | 2033  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | park          | 1991  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | redeem        | 2031  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | request       | 2044  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | settle        | 2186  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | transferPlant | 2027  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | unpark        | 2039  | 0       | 0        |\n╰--------------------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 3000000000000000000\n  Bound result 200000000000000000000\n  Bound result 3710896727\n  Bound result 22201\n  Bound result 2988\n  Bound result 12017\n  Bound result 3667637462\n  Bound result 10926\n  Bound result 2261676662\n  Bound result 22225\n  Bound result 39\n  Bound result 12793\n  Bound result 10232\n  Bound result 3930\n  Bound result 9972\n  Bound result 8086\n  Bound result 15\n  Bound result 42\n  Bound result 11095\n  Bound result 4211\n  Bound result 14255\n  Bound result 15606\n  Bound result 9182\n  Bound result 93\n  Bound result 17180\n  Bound result 22505\n  Bound result 8396\n  Bound result 2302\n  Bound result 21334\n  Bound result 2310\n  Bound result 10161\n  Bound result 7296\n  Bound result 12231\n  Bound result 319938126650649\n  Bound result 818489707393640526136\n  Bound result 17777\n  Bound result 366\n  Bound result 2870\n  Bound result 856283834714809569\n  Bound result 17810\n  Bound result 19010\n  Bound result 3653000059889891258\n  Bound result 3500\n  Bound result 49796170866680135679\n  Bound result 199143716165285190431\n  Bound result 1653\n  Bound result 2302\n  Bound result 43276445\n  Bound result 9084\n  Bound result 20765\n  Bound result 818489707393640526136\n  Bound result 996347319875975074643\n  Bound result 999999999999999986752\n  Bound result 999999680061873370685\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 9.48s (9.48s CPU time)\n\nRan 16 test suites in 9.48s (15.03s CPU time): 122 tests passed, 0 failed, 0 skipped (122 total tests)\n","passed":true},{"durationMs":54,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"PlantOrganism.bind(address)\",\"PlantOrganism.challenge(uint32)\",\"PlantOrganism.checkpoint(uint32,address)\",\"PlantOrganism.claim()\",\"PlantOrganism.claim(uint32[])\",\"PlantOrganism.clearPending()\",\"PlantOrganism.die()\",\"PlantOrganism.heartbeat(uint256)\",\"PlantOrganism.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"PlantOrganism.park(uint32,uint256)\",\"PlantOrganism.redeem(uint256)\",\"PlantOrganism.rotate(address,address,bytes32,uint256,uint256,bytes)\",\"PlantOrganism.settle()\",\"PlantOrganism.settle(uint32)\",\"PlantOrganism.unpark(uint32,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":44,\"DEPENDENCIES.md\":7,\"README.md\":17,\"foundry.toml\":19,\"launch.json\":17,\"src/OracleAttestation.sol\":231,\"src/PlantOrganism.sol\":703,\"src/WeatherQuestion.sol\":83,\"src/interfaces/IIntake.sol\":14,\"test/GasAndDeployment.t.sol\":156,\"test/OracleConsumerConformance.t.sol\":125,\"test/PlantAdversarial.t.sol\":428,\"test/PlantAssumptions.t.sol\":110,\"test/PlantContractSigner.t.sol\":169,\"test/PlantInvariant.t.sol\":170,\"test/PlantLaunchRevision.t.sol\":174,\"test/PlantOrganism.t.sol\":928,\"test/PlantSettleLag.t.sol\":226,\"test/PlantStateMachine.t.sol\":451,\"test/PlantVotingCommitment.t.sol\":199,\"test/PlantVotingRevision.t.sol\":249,\"test/README.md\":62,\"test/WeatherQuestion.t.sol\":36,\"test/fixtures/weather.json\":11,\"test/mocks/Mocks.sol\":139},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":4564,"exitCode":0,"name":"slither","output":"[high/medium] reentrancy-balance at src/PlantOrganism.sol:298: Reentrancy in PlantOrganism.heartbeat(uint256) (src/PlantOrganism.sol#298-333):\n[medium/medium] divide-before-multiply at src/WeatherQuestion.sol:33: WeatherQuestion.date(uint32) (src/WeatherQuestion.sol#33-46) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/WeatherQuestion.sol:33: WeatherQuestion.date(uint32) (src/WeatherQuestion.sol#33-46) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/WeatherQuestion.sol:33: WeatherQuestion.date(uint32) (src/WeatherQuestion.sol#33-46) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/PlantOrganism.sol:397: PlantOrganism._settle(bool,uint32) (src/PlantOrganism.sol#397-439) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PlantOrganism.sol:608: PlantOrganism.redeem(uint256) (src/PlantOrganism.sol#608-624) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PlantOrganism.sol:581: PlantOrganism._pay(address) (src/PlantOrganism.sol#581-606) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/PlantOrganism.sol:298: Reentrancy in PlantOrganism.heartbeat(uint256) (src/PlantOrganism.sol#298-333):\n[medium/medium] uninitialized-local at src/PlantOrganism.sol:583: PlantOrganism._pay(address).advance (src/PlantOrganism.sol#583) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PlantOrganism.sol:414: PlantOrganism._settle(bool,uint32).pool (src/PlantOrganism.sol#414) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PlantOrganism.sol:415: PlantOrganism._settle(bool,uint32).sips (src/PlantOrganism.sol#415) is a local variable never initialized\n[medium/medium] unused-return at src/PlantOrganism.sol:685: PlantOrganism._isValidAttestationSignature(bytes32,bytes) (src/PlantOrganism.sol#685-691) ignores return value by (recovered,err,None) = ECDSA.tryRecoverCalldata(digest,sig) (src/PlantOrganism.sol#687)\n[low/medium] timestamp at src/PlantOrganism.sol:475: PlantOrganism._matureThrough() (src/PlantOrganism.sol#475-479) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:698: PlantOrganism._pullExact(IERC20,address,uint256) (src/PlantOrganism.sol#698-702) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:441: PlantOrganism._hours(uint256) (src/PlantOrganism.sol#441-456) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:363: PlantOrganism.clearPending() (src/PlantOrganism.sol#363-373) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:685: PlantOrganism._isValidAttestationSignature(bytes32,bytes) (src/PlantOrganism.sol#685-691) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:206: PlantOrganism.pot() (src/PlantOrganism.sol#206-211) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:658: PlantOrganism.rotate(address,address,bytes32,uint256,uint256,bytes) (src/PlantOrganism.sol#658-681) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:298: PlantOrganism.heartbeat(uint256) (src/PlantOrganism.sol#298-333) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:397: PlantOrganism._settle(bool,uint32) (src/PlantOrganism.sol#397-439) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:631: PlantOrganism._syncDeath() (src/PlantOrganism.sol#631-642) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:188: PlantOrganism.isDead() (src/PlantOrganism.sol#188-190) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:213: PlantOrganism.spendablePot() (src/PlantOrganism.sol#213-216) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:693: PlantOrganism._graceSignature(address,bytes32,bytes) (src/PlantOrganism.sol#693-696) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:581: PlantOrganism._pay(address) (src/PlantOrganism.sol#581-606) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:497: PlantOrganism._rollCell(uint32) (src/PlantOrganism.sol#497-511) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:462: PlantOrganism.votingStake(uint32) (src/PlantOrganism.sol#462-471) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:530: PlantOrganism._checkpoint(uint32,address) (src/PlantOrganism.sol#530-558) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:608: PlantOrganism.redeem(uint256) (src/PlantOrganism.sol#608-624) uses timestamp for comparisons\n[low/medium] timestamp at src/OracleAttestation.sol:157: OracleAttestationConsumer._verifyAttestation(OracleAttestation.Attestation,bytes) (src/OracleAttestation.sol#157-165) uses timestamp for comparisons","passed":true},{"durationMs":561,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/PlantOrganism.sol:176: Reentrancy: State change after external call (8 places)\n[low] costly-loop at src/PlantOrganism.sol:266: Costly operations inside loop (4 places)\n[low] empty-require-revert at src/PlantOrganism.sol:209: Empty `require()` / `revert()` Statement\n[low] internal-function-used-once at src/OracleAttestation.sol:205: Internal Function Used Only Once (4 places)\n[low] literal-instead-of-constant at src/PlantOrganism.sol:345: Literal Instead of Constant (43 places)\n[low] local-variable-shadowing at src/PlantOrganism.sol:63: Local Variable Shadows State Variable (2 places)\n[low] uninitialized-local-variable at src/PlantOrganism.sol:444: Uninitialized Local Variable (2 places)","passed":true},{"durationMs":7628,"exitCode":0,"name":"proof db21a06befb6","output":"Compiling 47 files with Solc 0.8.26\nSolc 0.8.26 finished in 7.12s\nCompiler run successful!\n\nRan 1 test for test/imd-proof-5ccd87bd/Proof_db21a06befb6.t.sol:LateSettleForeknowledgeProof\n[PASS] test_parkAfterDayEndedMustNotEarnThatDaysPool() (gas: 2418245)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.98ms (1.22ms CPU time)\n\nRan 1 test suite in 2.95ms (1.98ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"0f759d34bc7364e1d40f51e6446f19397e1abf07af5173f5f9746639393d3383","verifiedTreeHash":"a04044f61feb66f5f46e170b9518ba1c531f8b54","verifierVersion":"0.1.0+8af37dff"},{"checks":[{"durationMs":69815,"exitCode":0,"name":"build","output":"Compiling 59 files with Solc 0.8.26\nSolc 0.8.26 finished in 69.62s\nCompiler run successful!\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:12:21\n   │\n12 │         int16 lat = int16(uint16(cell >> 16));\n   │                     ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:12:27\n   │\n12 │         int16 lat = int16(uint16(cell >> 16));\n   │                           ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:13:21\n   │\n13 │         int16 lon = int16(uint16(cell));\n   │                     ━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:13:27\n   │\n13 │         int16 lon = int16(uint16(cell));\n   │                           ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:19:29\n   │\n19 │         uint256 magnitude = uint256(milli < 0 ? -milli : milli);\n   │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:26:29\n   │\n26 │             b[--i] = bytes1(uint8(48 + n % 10));\n   │                             ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:39:27\n   │\n39 │         uint256 y = yoe + era * 400;\n   │                           ━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:40:30\n   │\n40 │         uint256 doy = doe - (365 * yoe + yoe / 4 - yoe / 100);\n   │                              ━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:42:28\n   │\n42 │         uint256 d = doy - (153 * mp + 2) / 5 + 1;\n   │                            ━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:50:40\n   │\n50 │         string memory lat = coordinate(int16(uint16(cell >> 16)));\n   │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:50:46\n   │\n50 │         string memory lat = coordinate(int16(uint16(cell >> 16)));\n   │                                              ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:51:40\n   │\n51 │         string memory lon = coordinate(int16(uint16(cell)));\n   │                                        ━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:51:46\n   │\n51 │         string memory lon = coordinate(int16(uint16(cell)));\n   │                                              ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:170:16\n    │\n170 │         return uint32(block.timestamp / 1 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/PlantOrganism.sol:173:19\n    │\n173 │     function bind(address hook_) external nonReentrant {\n    │                   ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:209:25\n    │\n209 │         require(held <= uint256(type(int256).max) && reserved <= uint256(type(int256).max));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:209:66\n    │\n209 │         require(held <= uint256(type(int256).max) && reserved <= uint256(type(int256).max));\n    │                                                                  ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:210:16\n    │\n210 │         return int256(held) - int256(reserved);\n    │                ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:210:31\n    │\n210 │         return int256(held) - int256(reserved);\n    │                               ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:215:24\n    │\n215 │         return p > 0 ? uint256(p) : 0;\n    │                        ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:556:13\n    │\n556 │             emit Checkpointed(holder, cell, credit);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:294:13\n    │\n294 │             emit Challenged(cell);\n    │             ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:255:9\n    │\n255 │         emit Parked(msg.sender, cell, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:280:9\n    │\n280 │         emit Unparked(msg.sender, cell, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `pending` is updated\n    ╭▸ src/PlantOrganism.sol:321:14\n    │\n321 │           id = intake.request(\n    │ ┏━━━━━━━━━━━━━━┛\n322 │ ┃             action,\n323 │ ┃             requestBody(location, day),\n324 │ ┃             IIntake.Callback(address(this), this.onOracleResult.selector),\n325 │ ┃             address(IMD),\n326 │ ┃             price\n327 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:304:13\n    │\n304 │         if (block.timestamp < retryAt) revert RetryLater();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:317:13\n    │\n317 │             emit Advanced(msg.sender, advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:332:9\n    │\n332 │         emit Asked(id, day, location, challenger, msg.sender, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/PlantOrganism.sol:329:13\n    │\n329 │         if (IMD.balanceOf(address(this)) != beforeBalance - price) revert NonExactTransfer();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:331:54\n    │\n331 │             Pending(id, day, challenger, msg.sender, uint64(block.timestamp), address(intake), true, false, bytes32(0));\n    │                                                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:360:9\n    │\n360 │         emit Received(requestId, a.requestId, word);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:350:13\n    │\n350 │         if (uint32(w >> 96) != p.day) revert WrongDay();\n    │             ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:369:17\n    │\n369 │             if (block.timestamp < uint256(pending.askedAt) + ORACLE_TIMEOUT) revert NotTimedOut();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:380:9\n    │\n380 │         emit Cleared(id, day, retryAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:404:13\n    │\n404 │             emit EmptyCatchUp(day, end);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:418:13\n    │\n418 │             emit Incomplete(day, count);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:527:9\n    │\n527 │         emit Rewarded(cell, pool, reserved);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:490:13\n    │\n490 │             emit Moved(current, candidate);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:435:13\n    │\n435 │             emit Bounty(caller, bounty);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:598:13\n    │\n598 │             emit Paid(holder, credit, advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:604:13\n    │\n604 │             emit PaymentDeferred(holder, credit + advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:438:9\n    │\n438 │         emit Settled(day, word, sips, backing, water, location);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:426:30\n    │\n426 │         _distribute(oldCell, pool);\n    │                              ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:438:33\n    │\n438 │         emit Settled(day, word, sips, backing, water, location);\n    │                                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:401:61\n    │\n401 │             uint32 end = hook == address(0) ? today() - 1 : uint32(Math.min(today() - 1, bindDay));\n    │                                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:455:17\n    │\n455 │         water = uint8(wet);\n    │                 ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:466:21\n    │\n466 │         uint32 to = uint32(Math.min(c.lastQueuedDay, _matureThrough()));\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:501:21\n    │\n501 │         uint32 to = uint32(Math.min(c.lastQueuedDay, through));\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:537:25\n    │\n537 │             uint32 to = uint32(Math.min(p.lastQueuedDay, through));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:592:22\n    │\n592 │         if (credit + advance == 0) return;\n    │                      ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:623:9\n    │\n623 │         emit Redeemed(msg.sender, amount, payout, dead);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:638:13\n    │\n638 │             emit Died(today(), merged);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:640:13\n    │\n640 │             emit PotMerged(merged);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:670:13\n    │\n670 │         if (block.timestamp > deadline) revert RotationExpired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/OracleAttestation.sol:192:9\n    │\n192 │         emit OracleSignerSet(signer);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:680:9\n    │\n680 │         emit Rotated(oldSigner, newSigner, newIntake, newAction, nonce);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:694:16\n    │\n694 │         return block.timestamp < signerAcceptedUntil[signer]\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/PlantOrganism.sol:701:13\n    │\n701 │         if (token.balanceOf(address(this)) != beforeBalance + amount) revert NonExactTransfer();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\n","passed":true},{"durationMs":10593,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 3 tests for test/WeatherQuestion.t.sol:WeatherQuestionTest\n[PASS] test_coordinatesAtEdgesAndNegativeZeroFraction() (gas: 40309)\n[PASS] test_exactLisbonBodyAndKnownDate() (gas: 15004)\n[PASS] test_exactNegativeLatitudeAndLongitudeBody() (gas: 15401)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 525.40µs (330.76µs CPU time)\n\nRan 4 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsOriginalProtocolSignatureInCanonicalVerifier() (gas: 117620)\n[PASS] test_bytes32WeatherFixtureAcceptedUnderStipend() (gas: 2404320)\n[PASS] test_callbackSelectorIsCanonical() (gas: 3543)\n[PASS] test_digestMatchesTheProtocol() (gas: 13207)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 4.27ms (2.81ms CPU time)\n\nRan 9 tests for test/PlantOrganism.t.sol:PlantLifecycleTest\n[PASS] test_bindIsOnceAndOnlyDeployerWithMatchingHook() (gas: 325845)\n[PASS] test_cellBoundsAndZeroRejected() (gas: 700646)\n[PASS] test_challengerOnlyStrictlyLargerAndCanBeRepaired() (gas: 3116585)\n[PASS] test_deathIsFinalAtThirtyDaysAndKeepsExits() (gas: 3251288)\n[PASS] test_deathUsesBindDayAfterLongUnboundPeriod() (gas: 285519)\n[PASS] test_moveUsesPendingCandidateAndRemainingCommittedBalances() (gas: 3804303)\n[PASS] test_noEarlyOrOutOfOrderSettleAndHeartbeat() (gas: 1001485)\n[PASS] test_preBindDaysSkipInOneCallWithoutRead() (gas: 636550)\n[PASS] test_unboundCatchUpIsBoundedAtOrigin() (gas: 149663)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 6.05ms (4.95ms CPU time)\n\nRan 7 tests for test/PlantAssumptions.t.sol:PlantAssumptionsTest\n[PASS] test_explicitZeroCellQuestionRemainsInvalid() (gas: 19594)\n[PASS] test_oldRotationSignatureExpires() (gas: 835017)\n[PASS] test_oldSourceWindowBacklogIsAlreadyDead() (gas: 1663671)\n[PASS] test_preBindDonationsHaveNoExit() (gas: 184091)\n[PASS] test_redeemedSupplyIsExcludedFromThreshold() (gas: 4409115)\n[PASS] test_rotatedIntakeCannotPullAboveKeeperCap() (gas: 2214924)\n[PASS] test_threeSilentRequestsSettleEmptyAndMoveWithRetainedStake() (gas: 3489418)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 10.97ms (7.54ms CPU time)\n\nRan 8 tests for test/PlantLaunchRevision.t.sol:PlantLaunchRevisionTest\n[PASS] test_firstEpochFlashCannotEarnGardenersAtOrigin() (gas: 3160338)\n[PASS] test_firstEpochFlashCannotMoveOrEarnGardenersAtDestination() (gas: 3249744)\n[PASS] test_lateBindSkipsThroughBindDayAndRequestsOnlyFirstFullDay() (gas: 1627184)\n[PASS] test_originFromRealCoordinatesRoundTripsThroughCentre() (gas: 69705)\n[PASS] test_repricingCannotExceedAdvanceCapAndZeroCapUsesPot() (gas: 1109319)\n[PASS] test_rotationDeadlineIsSignedAndAcceptedAtExactBoundary() (gas: 171457)\n[PASS] test_timeoutAfterDeathCannotAdvanceDayOrRevive() (gas: 1095165)\n[PASS] test_timeoutsAndIncompleteShareCounterAndReadRepairedCandidate() (gas: 4244168)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 11.81ms (10.18ms CPU time)\n\nRan 4 tests for test/PlantOrganism.t.sol:PlantRotationTest\n[PASS] test_oldSignerExpiresAtThirtyDaysWhileNewSignerKeepsPlantAlive() (gas: 19983069)\n[PASS] test_onlyCurrentSignerCanRotateNonceCannotReplay() (gas: 1143696)\n[PASS] test_pendingIntakeAndOldSignerWorkAfterRotation() (gas: 4441349)\n[PASS] test_rotationDomainBindsAllFieldsAndContract() (gas: 972660)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 23.44ms (31.13ms CPU time)\n\nRan 12 tests for test/PlantOrganism.t.sol:PlantOracleTest\n[PASS] test_blockedKeeperDoesNotBlockSettleAndCanClaimLater() (gas: 2725002)\n[PASS] test_callbackSenderIdAndReplay() (gas: 2859699)\n[PASS] test_callbackStoresOnlyAndFitsStipend() (gas: 2444266)\nLogs:\n  callback gas including mock encoding: 87736\n\n[PASS] test_clearIncompleteUsesSameCounterAndCannotDiscardComplete() (gas: 2837817)\n[PASS] test_exactApprovalAndIntakeBody() (gas: 2126429)\n[PASS] test_feeAdvanceTracksDeficitThenRepaidAtSettle() (gas: 2853496)\n[PASS] test_incompleteHasNoBiologicalChangesThenThirdReads() (gas: 4120217)\n[PASS] test_intakeMustPullExactPrice() (gas: 1963545)\n[PASS] test_rejectsExpiredWrongDomainSignerTypeDayChainAndPanel() (gas: 3147665)\n[PASS] test_rejectsPreAskFutureTamperedAndMalformedAttestations() (gas: 2896318)\n[PASS] test_timeoutClearsAndWaitsSixHoursToReaskSameDay() (gas: 2898620)\n[PASS] test_unfundedAdvanceDoesNotSpendBackingOrBlockSettle() (gas: 3401965)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 431.08ms (25.16ms CPU time)\n\nRan 4 tests for test/PlantContractSigner.t.sol:PlantContractSignerTest\n[PASS] test_canRotateToContractAndRejectInvalidOrRevokedSignatures() (gas: 2069805)\n[PASS] test_constructorContractAttestationAndRotationFitCallbackStipend() (gas: 2510578)\nLogs:\n  cold ERC-1271 callback gas: 91111\n\n[PASS] test_multiplePriorContractSignersKeepGraceWithoutRotationAuthority() (gas: 3401495)\n[PASS] test_previousContractGraceExpiresAtThirtyDays() (gas: 18335046)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 477.42ms (18.54ms CPU time)\n\nRan 6 tests for test/GasAndDeployment.t.sol:GasAndDeploymentTest\n[PASS] test_coldCallbackAndMaxHoursMoveSettleGas() (gas: 3871680)\nLogs:\n  cold callback gas: 87736\n\n[PASS] test_coldMaxHoursWithRepairedCandidateSettleGas() (gas: 3891461)\n[PASS] test_requestedStaticConstructorAndForbiddenOpcodes() (gas: 9588169)\n[PASS] test_settlementFitsStipendWithManyEligibleHolders() (gas: 38901338)\n[PASS] test_thirdIncompleteMoveAndAdvancePaymentGas() (gas: 4803800)\n[PASS] test_thirdTimeoutMoveAndAdvancePaymentFitsColdStipend() (gas: 4294896)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 497.97ms (58.62ms CPU time)\n\nRan 8 tests for test/PlantVotingCommitment.t.sol:PlantVotingCommitmentTest\n[PASS] testFuzz_withdrawalAndRedepositCannotIncreasePower(uint96,uint96) (runs: 256, μ: 3238311, ~: 3239162)\nLogs:\n  Bound result 11469\n  Bound result 4911\n\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotCaptureGardenersPool() (gas: 5216110)\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotMove() (gas: 4250883)\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotVeto() (gas: 3234065)\n[PASS] test_loanAcrossPreviousSettleLosesPowerOnWithdrawal() (gas: 3823076)\n[PASS] test_rearmedDecoyCannotHideHoldersCandidate() (gas: 3421856)\n[PASS] test_thresholdUsesCommittedStakeAndNewDepositsMatureAtSettle() (gas: 4211353)\n[PASS] test_timeoutAndReaskCannotRestoreWithdrawnPower() (gas: 4083292)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 498.04ms (491.53ms CPU time)\n\nRan 8 tests for test/PlantSettleLag.t.sol:PlantSettleLagTest\n[PASS] test_bindDayDepositsWaitForFirstFullDaySettle() (gas: 844349)\n[PASS] test_lagDepositsMatureDayByDayWithExactShares() (gas: 5317839)\n[PASS] test_longLagWithDailyDepositsSettlesColdWithinStipend() (gas: 19728109)\n[PASS] test_parkAfterDayEndedCannotEarnThatDaysPool() (gas: 3596064)\n[PASS] test_parkAfterDayEndedCannotVoteOnThatDay() (gas: 4509076)\n[PASS] test_settleNamedDayRefusesCatchUpBeyondIt() (gas: 2341449)\n[PASS] test_unlockedAdvanceIsNotRelockedByNextHeartbeat() (gas: 3043811)\n[PASS] test_withdrawalDuringLagLeavesNewestDayFirst() (gas: 3514010)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 498.08ms (30.14ms CPU time)\n\nRan 13 tests for test/PlantVotingRevision.t.sol:PlantVotingRevisionTest\n[PASS] testFuzz_repeatedTopUpsCannotIncreaseCommittedStake(uint96) (runs: 1000, μ: 4355461, ~: 4355341)\nLogs:\n  Bound result 65119203710315873\n\n[PASS] testFuzz_withdrawalUsesOwnQueuedStakeBeforeCommitment(uint96) (runs: 1000, μ: 3768011, ~: 3768384)\nLogs:\n  Bound result 558\n\n[PASS] test_atomicCurrentCellTopUpCannotVetoCommittedCandidate() (gas: 3081537)\n[PASS] test_atomicDestinationTopUpCannotMoveOrCaptureRewards() (gas: 4476764)\n[PASS] test_currentCellWithdrawalBreaksTieForCommittedCandidate() (gas: 2937035)\n[PASS] test_emptyCapturedCandidateFallsBackToRepairedLiveCandidate() (gas: 3322350)\n[PASS] test_fallbackCannotUseNewPostHeartbeatStake() (gas: 4459179)\n[PASS] test_questionUsesOriginFromDeployment() (gas: 1729979)\n[PASS] test_replacementHolderCannotInheritWithdrawnVotingPower() (gas: 4585254)\n[PASS] test_thirdIncompleteAlsoUsesRepairedCandidate() (gas: 4886018)\n[PASS] test_thirdIncompleteReadsBeforePromotingFreshDeposits() (gas: 4801499)\n[PASS] test_timeoutRetryCannotMatureRequestOrCooldownDeposits() (gas: 4910890)\n[PASS] test_withdrawalRemovesPowerAndReaskCannotRestoreIt() (gas: 4949153)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 498.08ms (1.03s CPU time)\n\nRan 13 tests for test/PlantOrganism.t.sol:PlantRewardsTest\n[PASS] testFuzz_floorConservationAndBurnCustody(uint96,uint96,uint24) (runs: 1000, μ: 2960060, ~: 2978675)\nLogs:\n  Bound result 4880\n\n[PASS] testFuzz_hourlyAccountingMatchesIndependentModel(uint24,uint24) (runs: 1000, μ: 2452023, ~: 2455205)\n[PASS] test_departuresDropOutAndReparkingCannotCaptureDay() (gas: 4705056)\n[PASS] test_finalRedemptionDoesNotDivideByZeroOrReleaseBurnedPlant() (gas: 3085270)\n[PASS] test_gardenerDustRoundsToBackingAndAccountsCloseExactly() (gas: 5820020)\n[PASS] test_hourZeroFirstRainCapAndSunRequiresWater() (gas: 5409625)\n[PASS] test_noGardenersSendsEntireSipToBacking() (gas: 1292079)\n[PASS] test_nonExactTokenTransfersRejected() (gas: 2619479)\n[PASS] test_oldCellKeepsItsRewardsAfterMoveAndLazyActivation() (gas: 6361054)\n[PASS] test_parkSettleClaimProRataAndMidDayJoinsWaitOneSettle() (gas: 3807527)\n[PASS] test_redeemRetainsPlantAndTenPercentAndFloorMonotonic() (gas: 2835731)\n[PASS] test_redeemThatPaysNothingIsRefusedAndKeepsPlant() (gas: 2700736)\n[PASS] test_reentrancyFromTokensAndIntakeBlocked() (gas: 2925416)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 498.14ms (1.01s CPU time)\n\nRan 21 tests for test/PlantAdversarial.t.sol:PlantAdversarialTest\n[PASS] testFuzz_parkUnparkRoundTripCannotEarnWithoutSettlement(uint96,uint8) (runs: 1000, μ: 2697023, ~: 2371464)\nLogs:\n  Bound result 98567\n  Bound result 15\n\n[PASS] testFuzz_reservedWeatherBitsRejectedWithoutMutatingPending(uint8) (runs: 1000, μ: 2106688, ~: 2106679)\n[PASS] testFuzz_signedMalformedPanelsAreRejected(uint8) (runs: 1000, μ: 2103359, ~: 2103390)\n[PASS] test_answerMustBeExactlyOneWordIncludingTrailingData() (gas: 2244830)\n[PASS] test_bindRejectsNonContractWrongAndEmptyTokens() (gas: 1569386)\n[PASS] test_callbackAndSettlementEventsDescribeTheAppliedResult() (gas: 2330726)\n[PASS] test_consumedOracleUuidCannotBeReusedForSameDayRetry() (gas: 2901606)\n[PASS] test_deathClearsPendingAndPreservesGardenersAndFeeDebt() (gas: 3511001)\n[PASS] test_deferredAdvanceAndBountyRemainClaimableExactlyOnce() (gas: 2873914)\n[PASS] test_depositAfterAskMustMatureBeforeItCanChallenge() (gas: 3881994)\n[PASS] test_exactClockDriftToleranceAccepted() (gas: 2100004)\n[PASS] test_moveRewardsDepartingCellAndNeverIncomingCellForSameDay() (gas: 4052697)\n[PASS] test_moveThresholdRoundsUpWhenSupplyNotDivisibleByTwenty() (gas: 3802544)\n[PASS] test_rejectedResultCanBeCorrectedWithoutBurningRequest() (gas: 2397203)\n[PASS] test_rotatedIntakeCannotAnswerPreviousIntakesRequest() (gas: 4104324)\n[PASS] test_thirdIncompleteReadsCandidateFromLatestRequest() (gas: 4423609)\n[PASS] test_timeoutExactSecondAndOldResultCannotPoisonReask() (gas: 2592219)\n[PASS] test_twoKeepersAdvancesSurviveTimeoutAndOnlyUnlockOnSettlement() (gas: 3355706)\n[PASS] test_unparkAfterCallbackDropsOutBeforeHoursAndKeepsPreviousReward() (gas: 3240961)\n[PASS] test_validityWindowBoundariesAndAskedAt() (gas: 2498149)\n[PASS] test_zeroAmountsAndOverdrawCannotChangeCustody() (gas: 1861713)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 498.35ms (924.64ms CPU time)\n\nRan 1 test for test/PlantInvariant.t.sol:PlantInvariantTest\n[PASS] invariant_conservationAndPermanentBurnCustody() (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+---------------+-------+---------+----------╮\n| Contract     | Selector      | Calls | Reverts | Discards |\n+===========================================================+\n| PlantHandler | challenge     | 960   | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | checkpointAll | 1056  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | claim         | 1038  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | fund          | 1009  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | park          | 1021  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | redeem        | 1040  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | unpark        | 989   | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | weather       | 1079  | 0       | 0        |\n╰--------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 10671537\n  Bound result 330\n  Bound result 526\n  Bound result 1862231151\n  Bound result 5469\n  Bound result 1164245952\n  Bound result 1980\n  Bound result 240\n  Bound result 21646\n  Bound result 3878\n  Bound result 2825\n  Bound result 331827732\n  Bound result 5390\n  Bound result 112880\n  Bound result 14476\n  Bound result 31598\n  Bound result 8460\n  Bound result 2064663460\n  Bound result 2058\n  Bound result 8980\n  Bound result 11492\n  Bound result 769656625\n  Bound result 5500\n  Bound result 10039\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.21s (2.21s CPU time)\n\nRan 1 test for test/PlantStateMachine.t.sol:PlantStateMachineInvariantTest\n[PASS] invariant_independentCustodyAndSolvency() (runs: 256, calls: 24576, reverts: 0)\n\n╭--------------------------+---------------+-------+---------+----------╮\n| Contract                 | Selector      | Calls | Reverts | Discards |\n+=======================================================================+\n| PlantStateMachineHandler | answer        | 2095  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | challenge     | 1973  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | claim         | 2038  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | clear         | 2041  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | donate        | 2056  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | elapse        | 2052  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | park          | 2081  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | redeem        | 2059  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | request       | 2035  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | settle        | 1989  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | transferPlant | 2073  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | unpark        | 2084  | 0       | 0        |\n╰--------------------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 3000000000000000000\n  Bound result 200000000000000000000\n  Bound result 3\n  Bound result 3589510279\n  Bound result 3511544184496\n  Bound result 200\n  Bound result 1671150390\n  Bound result 19578\n  Bound result 11200\n  Bound result 3416\n  Bound result 799999996486537455614\n  Bound result 6141\n  Bound result 22678\n  Bound result 699297196053228462\n  Bound result 668\n  Bound result 7182\n  Bound result 2705626677\n  Bound result 280307823497421933287\n  Bound result 54\n  Bound result 1\n  Bound result 157\n  Bound result 13776\n  Bound result 4863\n  Bound result 4351\n  Bound result 1043\n  Bound result 1\n  Bound result 16825\n  Bound result 381798440\n  Bound result 49\n  Bound result 10568\n  Bound result 18027\n  Bound result 2677459390\n  Bound result 17274\n  Bound result 28364\n  Bound result 7526\n  Bound result 10491\n  Bound result 4963\n  Bound result 876280959292239058248\n  Bound result 7870\n  Bound result 379\n  Bound result 27407206310771551395\n  Bound result 1852\n  Bound result 12553\n  Bound result 200000003509873016832\n  Bound result 876280959292239065432\n  Bound result 4351\n  Bound result 280307823500127572307\n  Bound result 27407206310771551395\n  Bound result 999999999996028683755\n  Bound result 1000000000002677459390\n  Bound result 1000000000000912058415\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 10.48s (10.47s CPU time)\n\nRan 16 test suites in 10.48s (16.64s CPU time): 122 tests passed, 0 failed, 0 skipped (122 total tests)\n","passed":true},{"durationMs":58,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"PlantOrganism.bind(address)\",\"PlantOrganism.challenge(uint32)\",\"PlantOrganism.checkpoint(uint32,address)\",\"PlantOrganism.claim()\",\"PlantOrganism.claim(uint32[])\",\"PlantOrganism.clearPending()\",\"PlantOrganism.die()\",\"PlantOrganism.heartbeat(uint256)\",\"PlantOrganism.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"PlantOrganism.park(uint32,uint256)\",\"PlantOrganism.redeem(uint256)\",\"PlantOrganism.rotate(address,address,bytes32,uint256,uint256,bytes)\",\"PlantOrganism.settle()\",\"PlantOrganism.settle(uint32)\",\"PlantOrganism.unpark(uint32,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":44,\"DEPENDENCIES.md\":7,\"README.md\":17,\"foundry.toml\":19,\"launch.json\":17,\"src/OracleAttestation.sol\":231,\"src/PlantOrganism.sol\":703,\"src/WeatherQuestion.sol\":83,\"src/interfaces/IIntake.sol\":14,\"test/GasAndDeployment.t.sol\":156,\"test/OracleConsumerConformance.t.sol\":125,\"test/PlantAdversarial.t.sol\":428,\"test/PlantAssumptions.t.sol\":110,\"test/PlantContractSigner.t.sol\":169,\"test/PlantInvariant.t.sol\":170,\"test/PlantLaunchRevision.t.sol\":174,\"test/PlantOrganism.t.sol\":928,\"test/PlantSettleLag.t.sol\":226,\"test/PlantStateMachine.t.sol\":451,\"test/PlantVotingCommitment.t.sol\":199,\"test/PlantVotingRevision.t.sol\":249,\"test/README.md\":62,\"test/WeatherQuestion.t.sol\":36,\"test/fixtures/weather.json\":11,\"test/mocks/Mocks.sol\":139},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"4295fc3a1958787b7c1eeda5494bec376f30f5a346c2516860142c12b6b433d2","verifiedTreeHash":"dd3702dc825a21ed604e53988c13aa60b1b4bcc0","verifierVersion":"0.1.0+8af37dff"},{"checks":[{"durationMs":74999,"exitCode":0,"name":"build","output":"Compiling 63 files with Solc 0.8.26\nSolc 0.8.26 finished in 74.83s\nCompiler run successful!\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:12:21\n   │\n12 │         int16 lat = int16(uint16(cell >> 16));\n   │                     ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:12:27\n   │\n12 │         int16 lat = int16(uint16(cell >> 16));\n   │                           ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:13:21\n   │\n13 │         int16 lon = int16(uint16(cell));\n   │                     ━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:13:27\n   │\n13 │         int16 lon = int16(uint16(cell));\n   │                           ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:19:29\n   │\n19 │         uint256 magnitude = uint256(milli < 0 ? -milli : milli);\n   │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:26:29\n   │\n26 │             b[--i] = bytes1(uint8(48 + n % 10));\n   │                             ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:39:27\n   │\n39 │         uint256 y = yoe + era * 400;\n   │                           ━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:40:30\n   │\n40 │         uint256 doy = doe - (365 * yoe + yoe / 4 - yoe / 100);\n   │                              ━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:42:28\n   │\n42 │         uint256 d = doy - (153 * mp + 2) / 5 + 1;\n   │                            ━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:50:40\n   │\n50 │         string memory lat = coordinate(int16(uint16(cell >> 16)));\n   │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:50:46\n   │\n50 │         string memory lat = coordinate(int16(uint16(cell >> 16)));\n   │                                              ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:51:40\n   │\n51 │         string memory lon = coordinate(int16(uint16(cell)));\n   │                                        ━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:51:46\n   │\n51 │         string memory lon = coordinate(int16(uint16(cell)));\n   │                                              ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:170:16\n    │\n170 │         return uint32(block.timestamp / 1 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/PlantOrganism.sol:173:19\n    │\n173 │     function bind(address hook_) external nonReentrant {\n    │                   ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:209:25\n    │\n209 │         require(held <= uint256(type(int256).max) && reserved <= uint256(type(int256).max));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:209:66\n    │\n209 │         require(held <= uint256(type(int256).max) && reserved <= uint256(type(int256).max));\n    │                                                                  ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:210:16\n    │\n210 │         return int256(held) - int256(reserved);\n    │                ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:210:31\n    │\n210 │         return int256(held) - int256(reserved);\n    │                               ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:215:24\n    │\n215 │         return p > 0 ? uint256(p) : 0;\n    │                        ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:556:13\n    │\n556 │             emit Checkpointed(holder, cell, credit);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:294:13\n    │\n294 │             emit Challenged(cell);\n    │             ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:255:9\n    │\n255 │         emit Parked(msg.sender, cell, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:280:9\n    │\n280 │         emit Unparked(msg.sender, cell, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `pending` is updated\n    ╭▸ src/PlantOrganism.sol:321:14\n    │\n321 │           id = intake.request(\n    │ ┏━━━━━━━━━━━━━━┛\n322 │ ┃             action,\n323 │ ┃             requestBody(location, day),\n324 │ ┃             IIntake.Callback(address(this), this.onOracleResult.selector),\n325 │ ┃             address(IMD),\n326 │ ┃             price\n327 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:304:13\n    │\n304 │         if (block.timestamp < retryAt) revert RetryLater();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:317:13\n    │\n317 │             emit Advanced(msg.sender, advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:332:9\n    │\n332 │         emit Asked(id, day, location, challenger, msg.sender, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/PlantOrganism.sol:329:13\n    │\n329 │         if (IMD.balanceOf(address(this)) != beforeBalance - price) revert NonExactTransfer();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:331:54\n    │\n331 │             Pending(id, day, challenger, msg.sender, uint64(block.timestamp), address(intake), true, false, bytes32(0));\n    │                                                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:360:9\n    │\n360 │         emit Received(requestId, a.requestId, word);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:350:13\n    │\n350 │         if (uint32(w >> 96) != p.day) revert WrongDay();\n    │             ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:369:17\n    │\n369 │             if (block.timestamp < uint256(pending.askedAt) + ORACLE_TIMEOUT) revert NotTimedOut();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:380:9\n    │\n380 │         emit Cleared(id, day, retryAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:404:13\n    │\n404 │             emit EmptyCatchUp(day, end);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:418:13\n    │\n418 │             emit Incomplete(day, count);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:527:9\n    │\n527 │         emit Rewarded(cell, pool, reserved);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:490:13\n    │\n490 │             emit Moved(current, candidate);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:435:13\n    │\n435 │             emit Bounty(caller, bounty);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:598:13\n    │\n598 │             emit Paid(holder, credit, advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:604:13\n    │\n604 │             emit PaymentDeferred(holder, credit + advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:438:9\n    │\n438 │         emit Settled(day, word, sips, backing, water, location);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:426:30\n    │\n426 │         _distribute(oldCell, pool);\n    │                              ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:438:33\n    │\n438 │         emit Settled(day, word, sips, backing, water, location);\n    │                                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:401:61\n    │\n401 │             uint32 end = hook == address(0) ? today() - 1 : uint32(Math.min(today() - 1, bindDay));\n    │                                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:455:17\n    │\n455 │         water = uint8(wet);\n    │                 ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:466:21\n    │\n466 │         uint32 to = uint32(Math.min(c.lastQueuedDay, _matureThrough()));\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:501:21\n    │\n501 │         uint32 to = uint32(Math.min(c.lastQueuedDay, through));\n    │                     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:537:25\n    │\n537 │             uint32 to = uint32(Math.min(p.lastQueuedDay, through));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:592:22\n    │\n592 │         if (credit + advance == 0) return;\n    │                      ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:623:9\n    │\n623 │         emit Redeemed(msg.sender, amount, payout, dead);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:638:13\n    │\n638 │             emit Died(today(), merged);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:640:13\n    │\n640 │             emit PotMerged(merged);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:670:13\n    │\n670 │         if (block.timestamp > deadline) revert RotationExpired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/OracleAttestation.sol:192:9\n    │\n192 │         emit OracleSignerSet(signer);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:680:9\n    │\n680 │         emit Rotated(oldSigner, newSigner, newIntake, newAction, nonce);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:694:16\n    │\n694 │         return block.timestamp < signerAcceptedUntil[signer]\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/PlantOrganism.sol:701:13\n    │\n701 │         if (token.balanceOf(address(this)) != beforeBalance + amount) revert NonExactTransfer();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\n","passed":true},{"durationMs":9493,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 3 tests for test/WeatherQuestion.t.sol:WeatherQuestionTest\n[PASS] test_coordinatesAtEdgesAndNegativeZeroFraction() (gas: 40309)\n[PASS] test_exactLisbonBodyAndKnownDate() (gas: 15004)\n[PASS] test_exactNegativeLatitudeAndLongitudeBody() (gas: 15401)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 387.45µs (240.38µs CPU time)\n\nRan 4 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsOriginalProtocolSignatureInCanonicalVerifier() (gas: 117620)\n[PASS] test_bytes32WeatherFixtureAcceptedUnderStipend() (gas: 2404320)\n[PASS] test_callbackSelectorIsCanonical() (gas: 3543)\n[PASS] test_digestMatchesTheProtocol() (gas: 13207)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 2.30ms (994.13µs CPU time)\n\nRan 8 tests for test/PlantLaunchRevision.t.sol:PlantLaunchRevisionTest\n[PASS] test_firstEpochFlashCannotEarnGardenersAtOrigin() (gas: 3160338)\n[PASS] test_firstEpochFlashCannotMoveOrEarnGardenersAtDestination() (gas: 3249744)\n[PASS] test_lateBindSkipsThroughBindDayAndRequestsOnlyFirstFullDay() (gas: 1627184)\n[PASS] test_originFromRealCoordinatesRoundTripsThroughCentre() (gas: 69705)\n[PASS] test_repricingCannotExceedAdvanceCapAndZeroCapUsesPot() (gas: 1109319)\n[PASS] test_rotationDeadlineIsSignedAndAcceptedAtExactBoundary() (gas: 171457)\n[PASS] test_timeoutAfterDeathCannotAdvanceDayOrRevive() (gas: 1095165)\n[PASS] test_timeoutsAndIncompleteShareCounterAndReadRepairedCandidate() (gas: 4244168)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 4.42ms (6.58ms CPU time)\n\nRan 9 tests for test/PlantOrganism.t.sol:PlantLifecycleTest\n[PASS] test_bindIsOnceAndOnlyDeployerWithMatchingHook() (gas: 325845)\n[PASS] test_cellBoundsAndZeroRejected() (gas: 700646)\n[PASS] test_challengerOnlyStrictlyLargerAndCanBeRepaired() (gas: 3116585)\n[PASS] test_deathIsFinalAtThirtyDaysAndKeepsExits() (gas: 3251288)\n[PASS] test_deathUsesBindDayAfterLongUnboundPeriod() (gas: 285519)\n[PASS] test_moveUsesPendingCandidateAndRemainingCommittedBalances() (gas: 3804303)\n[PASS] test_noEarlyOrOutOfOrderSettleAndHeartbeat() (gas: 1001485)\n[PASS] test_preBindDaysSkipInOneCallWithoutRead() (gas: 636550)\n[PASS] test_unboundCatchUpIsBoundedAtOrigin() (gas: 149663)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 7.66ms (7.64ms CPU time)\n\nRan 7 tests for test/PlantAssumptions.t.sol:PlantAssumptionsTest\n[PASS] test_explicitZeroCellQuestionRemainsInvalid() (gas: 19594)\n[PASS] test_oldRotationSignatureExpires() (gas: 835017)\n[PASS] test_oldSourceWindowBacklogIsAlreadyDead() (gas: 1663671)\n[PASS] test_preBindDonationsHaveNoExit() (gas: 184091)\n[PASS] test_redeemedSupplyIsExcludedFromThreshold() (gas: 4409115)\n[PASS] test_rotatedIntakeCannotPullAboveKeeperCap() (gas: 2214924)\n[PASS] test_threeSilentRequestsSettleEmptyAndMoveWithRetainedStake() (gas: 3489418)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 9.54ms (8.79ms CPU time)\n\nRan 8 tests for test/PlantSettleLag.t.sol:PlantSettleLagTest\n[PASS] test_bindDayDepositsWaitForFirstFullDaySettle() (gas: 844349)\n[PASS] test_lagDepositsMatureDayByDayWithExactShares() (gas: 5317839)\n[PASS] test_longLagWithDailyDepositsSettlesColdWithinStipend() (gas: 19728109)\n[PASS] test_parkAfterDayEndedCannotEarnThatDaysPool() (gas: 3596064)\n[PASS] test_parkAfterDayEndedCannotVoteOnThatDay() (gas: 4509076)\n[PASS] test_settleNamedDayRefusesCatchUpBeyondIt() (gas: 2341449)\n[PASS] test_unlockedAdvanceIsNotRelockedByNextHeartbeat() (gas: 3043811)\n[PASS] test_withdrawalDuringLagLeavesNewestDayFirst() (gas: 3514010)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 12.93ms (23.54ms CPU time)\n\nRan 4 tests for test/PlantOrganism.t.sol:PlantRotationTest\n[PASS] test_oldSignerExpiresAtThirtyDaysWhileNewSignerKeepsPlantAlive() (gas: 19983069)\n[PASS] test_onlyCurrentSignerCanRotateNonceCannotReplay() (gas: 1143696)\n[PASS] test_pendingIntakeAndOldSignerWorkAfterRotation() (gas: 4441349)\n[PASS] test_rotationDomainBindsAllFieldsAndContract() (gas: 972660)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 13.54ms (19.17ms CPU time)\n\nRan 12 tests for test/PlantOrganism.t.sol:PlantOracleTest\n[PASS] test_blockedKeeperDoesNotBlockSettleAndCanClaimLater() (gas: 2725002)\n[PASS] test_callbackSenderIdAndReplay() (gas: 2859699)\n[PASS] test_callbackStoresOnlyAndFitsStipend() (gas: 2444266)\nLogs:\n  callback gas including mock encoding: 87736\n\n[PASS] test_clearIncompleteUsesSameCounterAndCannotDiscardComplete() (gas: 2837817)\n[PASS] test_exactApprovalAndIntakeBody() (gas: 2126429)\n[PASS] test_feeAdvanceTracksDeficitThenRepaidAtSettle() (gas: 2853496)\n[PASS] test_incompleteHasNoBiologicalChangesThenThirdReads() (gas: 4120217)\n[PASS] test_intakeMustPullExactPrice() (gas: 1963545)\n[PASS] test_rejectsExpiredWrongDomainSignerTypeDayChainAndPanel() (gas: 3147665)\n[PASS] test_rejectsPreAskFutureTamperedAndMalformedAttestations() (gas: 2896318)\n[PASS] test_timeoutClearsAndWaitsSixHoursToReaskSameDay() (gas: 2898620)\n[PASS] test_unfundedAdvanceDoesNotSpendBackingOrBlockSettle() (gas: 3401965)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 21.95ms (24.09ms CPU time)\n\nRan 8 tests for test/PlantVotingCommitment.t.sol:PlantVotingCommitmentTest\n[PASS] testFuzz_withdrawalAndRedepositCannotIncreasePower(uint96,uint96) (runs: 256, μ: 3238010, ~: 3239138)\nLogs:\n  Bound result 22042\n  Bound result 16801\n\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotCaptureGardenersPool() (gas: 5216110)\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotMove() (gas: 4250883)\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotVeto() (gas: 3234065)\n[PASS] test_loanAcrossPreviousSettleLosesPowerOnWithdrawal() (gas: 3823076)\n[PASS] test_rearmedDecoyCannotHideHoldersCandidate() (gas: 3421856)\n[PASS] test_thresholdUsesCommittedStakeAndNewDepositsMatureAtSettle() (gas: 4211353)\n[PASS] test_timeoutAndReaskCannotRestoreWithdrawnPower() (gas: 4083292)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 236.71ms (248.38ms CPU time)\n\nRan 6 tests for test/GasAndDeployment.t.sol:GasAndDeploymentTest\n[PASS] test_coldCallbackAndMaxHoursMoveSettleGas() (gas: 3871680)\nLogs:\n  cold callback gas: 87736\n\n[PASS] test_coldMaxHoursWithRepairedCandidateSettleGas() (gas: 3891461)\n[PASS] test_requestedStaticConstructorAndForbiddenOpcodes() (gas: 9588169)\n[PASS] test_settlementFitsStipendWithManyEligibleHolders() (gas: 38901338)\n[PASS] test_thirdIncompleteMoveAndAdvancePaymentGas() (gas: 4803800)\n[PASS] test_thirdTimeoutMoveAndAdvancePaymentFitsColdStipend() (gas: 4294896)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 446.51ms (64.72ms CPU time)\n\nRan 9 tests for test/PlantOriginRegression.t.sol:PlantOriginRegressionTest\n[PASS] testFuzz_constructorAcceptsEveryLandOrSeaCellAndRejectsTheRest(int16,int16) (runs: 1000, μ: 47479, ~: 9637)\n[PASS] testFuzz_everyValidCellRoundTripsThroughItsPrintedCentre(int16,int16) (runs: 1000, μ: 37908, ~: 37877)\nLogs:\n  Bound result -21\n  Bound result -361\n\n[PASS] test_constructorRejectsEveryZeroDependency() (gas: 7447)\n[PASS] test_flashParkWithinOneTransactionNeverMovesOrEarns() (gas: 5536327)\n[PASS] test_heartbeatCapIsExactAndPendingNeverFormsOnRefusal() (gas: 1300217)\n[PASS] test_livePlantBalancesNeverCountAsStakeAnywhere() (gas: 3341127)\n[PASS] test_noBirthOrAdminSelectorsExist() (gas: 497179)\n[PASS] test_originSentenceNamesThePlaceAndItsReasonOnce() (gas: 126302)\n[PASS] test_rotateRequiresDeadlineFromSignedStructNotCalldataAlone() (gas: 1090447)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 457.65ms (462.82ms CPU time)\n\nRan 13 tests for test/PlantOrganism.t.sol:PlantRewardsTest\n[PASS] testFuzz_floorConservationAndBurnCustody(uint96,uint96,uint24) (runs: 1000, μ: 2962525, ~: 2978687)\nLogs:\n  Bound result 264532621739663\n\n[PASS] testFuzz_hourlyAccountingMatchesIndependentModel(uint24,uint24) (runs: 1000, μ: 2452710, ~: 2455347)\n[PASS] test_departuresDropOutAndReparkingCannotCaptureDay() (gas: 4705056)\n[PASS] test_finalRedemptionDoesNotDivideByZeroOrReleaseBurnedPlant() (gas: 3085270)\n[PASS] test_gardenerDustRoundsToBackingAndAccountsCloseExactly() (gas: 5820020)\n[PASS] test_hourZeroFirstRainCapAndSunRequiresWater() (gas: 5409625)\n[PASS] test_noGardenersSendsEntireSipToBacking() (gas: 1292079)\n[PASS] test_nonExactTokenTransfersRejected() (gas: 2619479)\n[PASS] test_oldCellKeepsItsRewardsAfterMoveAndLazyActivation() (gas: 6361054)\n[PASS] test_parkSettleClaimProRataAndMidDayJoinsWaitOneSettle() (gas: 3807527)\n[PASS] test_redeemRetainsPlantAndTenPercentAndFloorMonotonic() (gas: 2835731)\n[PASS] test_redeemThatPaysNothingIsRefusedAndKeepsPlant() (gas: 2700736)\n[PASS] test_reentrancyFromTokensAndIntakeBlocked() (gas: 2925416)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 473.24ms (751.67ms CPU time)\n\nRan 4 tests for test/PlantContractSigner.t.sol:PlantContractSignerTest\n[PASS] test_canRotateToContractAndRejectInvalidOrRevokedSignatures() (gas: 2069805)\n[PASS] test_constructorContractAttestationAndRotationFitCallbackStipend() (gas: 2510578)\nLogs:\n  cold ERC-1271 callback gas: 91111\n\n[PASS] test_multiplePriorContractSignersKeepGraceWithoutRotationAuthority() (gas: 3401495)\n[PASS] test_previousContractGraceExpiresAtThirtyDays() (gas: 18335046)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 474.94ms (19.09ms CPU time)\n\nRan 6 tests for test/PlantFailureAtomicity.t.sol:PlantFailureAtomicityTest\n[PASS] testFuzz_advanceCapUsesOnlySpendablePotAndFailedCapIsAtomic(uint96) (runs: 1000, μ: 3054419, ~: 3054345)\nLogs:\n  Bound result 1\n\n[PASS] test_failedParkCannotCheckpointOrConsumeAllowance() (gas: 3194577)\n[PASS] test_failedRedemptionCannotSurrenderPlantOrReduceBacking() (gas: 3016436)\n[PASS] test_failedUnparkRestoresCheckpointAndVotingPowerThenCanRetry() (gas: 3159255)\n[PASS] test_falseReturnOnClaimPreservesCreditWithoutBlockingOtherGardeners() (gas: 3269396)\n[PASS] test_underchargingIntakeRollsBackCallerAdvanceAndAllNestedTransfers() (gas: 2282589)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 475.13ms (478.89ms CPU time)\n\nRan 13 tests for test/PlantVotingRevision.t.sol:PlantVotingRevisionTest\n[PASS] testFuzz_repeatedTopUpsCannotIncreaseCommittedStake(uint96) (runs: 1000, μ: 4355427, ~: 4355317)\nLogs:\n  Bound result 1\n\n[PASS] testFuzz_withdrawalUsesOwnQueuedStakeBeforeCommitment(uint96) (runs: 1000, μ: 3768039, ~: 3768384)\nLogs:\n  Bound result 100000000000000000001\n\n[PASS] test_atomicCurrentCellTopUpCannotVetoCommittedCandidate() (gas: 3081537)\n[PASS] test_atomicDestinationTopUpCannotMoveOrCaptureRewards() (gas: 4476764)\n[PASS] test_currentCellWithdrawalBreaksTieForCommittedCandidate() (gas: 2937035)\n[PASS] test_emptyCapturedCandidateFallsBackToRepairedLiveCandidate() (gas: 3322350)\n[PASS] test_fallbackCannotUseNewPostHeartbeatStake() (gas: 4459179)\n[PASS] test_questionUsesOriginFromDeployment() (gas: 1729979)\n[PASS] test_replacementHolderCannotInheritWithdrawnVotingPower() (gas: 4585254)\n[PASS] test_thirdIncompleteAlsoUsesRepairedCandidate() (gas: 4886018)\n[PASS] test_thirdIncompleteReadsBeforePromotingFreshDeposits() (gas: 4801499)\n[PASS] test_timeoutRetryCannotMatureRequestOrCooldownDeposits() (gas: 4910890)\n[PASS] test_withdrawalRemovesPowerAndReaskCannotRestoreIt() (gas: 4949153)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 475.11ms (966.35ms CPU time)\n\nRan 21 tests for test/PlantAdversarial.t.sol:PlantAdversarialTest\n[PASS] testFuzz_parkUnparkRoundTripCannotEarnWithoutSettlement(uint96,uint8) (runs: 1000, μ: 2717299, ~: 2371464)\nLogs:\n  Bound result 3792566917963334\n  Bound result 9\n\n[PASS] testFuzz_reservedWeatherBitsRejectedWithoutMutatingPending(uint8) (runs: 1000, μ: 2106688, ~: 2106679)\n[PASS] testFuzz_signedMalformedPanelsAreRejected(uint8) (runs: 1000, μ: 2103342, ~: 2103224)\n[PASS] test_answerMustBeExactlyOneWordIncludingTrailingData() (gas: 2244830)\n[PASS] test_bindRejectsNonContractWrongAndEmptyTokens() (gas: 1569386)\n[PASS] test_callbackAndSettlementEventsDescribeTheAppliedResult() (gas: 2330726)\n[PASS] test_consumedOracleUuidCannotBeReusedForSameDayRetry() (gas: 2901606)\n[PASS] test_deathClearsPendingAndPreservesGardenersAndFeeDebt() (gas: 3511001)\n[PASS] test_deferredAdvanceAndBountyRemainClaimableExactlyOnce() (gas: 2873914)\n[PASS] test_depositAfterAskMustMatureBeforeItCanChallenge() (gas: 3881994)\n[PASS] test_exactClockDriftToleranceAccepted() (gas: 2100004)\n[PASS] test_moveRewardsDepartingCellAndNeverIncomingCellForSameDay() (gas: 4052697)\n[PASS] test_moveThresholdRoundsUpWhenSupplyNotDivisibleByTwenty() (gas: 3802544)\n[PASS] test_rejectedResultCanBeCorrectedWithoutBurningRequest() (gas: 2397203)\n[PASS] test_rotatedIntakeCannotAnswerPreviousIntakesRequest() (gas: 4104324)\n[PASS] test_thirdIncompleteReadsCandidateFromLatestRequest() (gas: 4423609)\n[PASS] test_timeoutExactSecondAndOldResultCannotPoisonReask() (gas: 2592219)\n[PASS] test_twoKeepersAdvancesSurviveTimeoutAndOnlyUnlockOnSettlement() (gas: 3355706)\n[PASS] test_unparkAfterCallbackDropsOutBeforeHoursAndKeepsPreviousReward() (gas: 3240961)\n[PASS] test_validityWindowBoundariesAndAskedAt() (gas: 2498149)\n[PASS] test_zeroAmountsAndOverdrawCannotChangeCustody() (gas: 1861713)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 475.21ms (1.18s CPU time)\n\nRan 1 test for test/PlantInvariant.t.sol:PlantInvariantTest\n[PASS] invariant_conservationAndPermanentBurnCustody() (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+---------------+-------+---------+----------╮\n| Contract     | Selector      | Calls | Reverts | Discards |\n+===========================================================+\n| PlantHandler | challenge     | 1010  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | checkpointAll | 1003  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | claim         | 1001  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | fund          | 1041  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | park          | 1047  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | redeem        | 1023  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | unpark        | 1030  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | weather       | 1037  | 0       | 0        |\n╰--------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 423166295081889109405\n  Bound result 5831\n  Bound result 23673376297767202460\n  Bound result 18812\n  Bound result 19891\n  Bound result 7659\n  Bound result 517440283\n  Bound result 50\n  Bound result 10\n  Bound result 11162\n  Bound result 233573859658130501406\n  Bound result 3441\n  Bound result 2521367690350\n  Bound result 870\n  Bound result 790597813218181823617\n  Bound result 11064\n  Bound result 6897\n  Bound result 3584\n  Bound result 304611135211116803937\n  Bound result 138717876574960140297\n  Bound result 23673376297767222352\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.88s (1.88s CPU time)\n\nRan 1 test for test/PlantRewardOwnershipInvariant.t.sol:PlantRewardOwnershipInvariantTest\n[PASS] invariant_eachGardenerOwnsExactlyTheirEarnedRewards() (runs: 256, calls: 24576, reverts: 0)\n\n╭-----------------------------+--------------+-------+---------+----------╮\n| Contract                    | Selector     | Calls | Reverts | Discards |\n+=========================================================================+\n| PlantRewardOwnershipHandler | blockPayment | 3044  | 0       | 0        |\n|-----------------------------+--------------+-------+---------+----------|\n| PlantRewardOwnershipHandler | challenge    | 2976  | 0       | 0        |\n|-----------------------------+--------------+-------+---------+----------|\n| PlantRewardOwnershipHandler | checkpoint   | 3112  | 0       | 0        |\n|-----------------------------+--------------+-------+---------+----------|\n| PlantRewardOwnershipHandler | claimDefault | 3186  | 0       | 0        |\n|-----------------------------+--------------+-------+---------+----------|\n| PlantRewardOwnershipHandler | claimSome    | 3154  | 0       | 0        |\n|-----------------------------+--------------+-------+---------+----------|\n| PlantRewardOwnershipHandler | grow         | 3089  | 0       | 0        |\n|-----------------------------+--------------+-------+---------+----------|\n| PlantRewardOwnershipHandler | park         | 2936  | 0       | 0        |\n|-----------------------------+--------------+-------+---------+----------|\n| PlantRewardOwnershipHandler | unpark       | 3079  | 0       | 0        |\n╰-----------------------------+--------------+-------+---------+----------╯\n\nLogs:\n  Bound result 100000000000000000000\n  Bound result 200000000000000000000\n  Bound result 300000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 19850\n  Bound result 13507\n  Bound result 7699606288\n  Bound result 3151\n  Bound result 31896715679727\n  Bound result 87229742144652779341\n  Bound result 2596\n  Bound result 32207057232424943547\n  Bound result 857\n  Bound result 115259028782913483554\n  Bound result 13963\n  Bound result 348\n  Bound result 2156\n  Bound result 24436798638719124859\n  Bound result 883831838\n  Bound result 71933386685567597734\n  Bound result 1487\n  Bound result 1071\n  Bound result 15674852585999510\n  Bound result 85850838224196\n  Bound result 5481\n  Bound result 10915\n  Bound result 69930611482754620690\n  Bound result 9733\n  Bound result 14264337593543950332\n  Bound result 2973\n  Bound result 8724326324260602710\n  Bound result 1225141\n  Bound result 43757891691162923976\n  Bound result 568633573079\n  Bound result 15438\n  Bound result 19351\n  Bound result 11731\n  Bound result 14666\n  Bound result 108724326324260602710\n  Bound result 1215956\n  Bound result 85850838221408\n  Bound result 167792943336208626559\n  Bound result 115259028783797322893\n  Bound result 7699604132\n  Bound result 19351\n  Bound result 299999968103284320273\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 6.34s (6.34s CPU time)\n\nRan 1 test for test/PlantStakeRuleInvariant.t.sol:PlantStakeRuleInvariantTest\n[PASS] invariant_votingStakeIsSettledParkedStakeAndNeverALiveBalance() (runs: 200, calls: 12800, reverts: 0)\n\n╭-----------------------+-------------+-------+---------+----------╮\n| Contract              | Selector    | Calls | Reverts | Discards |\n+==================================================================+\n| PlantStakeRuleHandler | challenge   | 1775  | 0       | 0        |\n|-----------------------+-------------+-------+---------+----------|\n| PlantStakeRuleHandler | claim       | 1876  | 0       | 0        |\n|-----------------------+-------------+-------+---------+----------|\n| PlantStakeRuleHandler | flashSettle | 1827  | 0       | 0        |\n|-----------------------+-------------+-------+---------+----------|\n| PlantStakeRuleHandler | park        | 1824  | 0       | 0        |\n|-----------------------+-------------+-------+---------+----------|\n| PlantStakeRuleHandler | silentDay   | 1809  | 0       | 0        |\n|-----------------------+-------------+-------+---------+----------|\n| PlantStakeRuleHandler | unpark      | 1837  | 0       | 0        |\n|-----------------------+-------------+-------+---------+----------|\n| PlantStakeRuleHandler | weather     | 1852  | 0       | 0        |\n╰-----------------------+-------------+-------+---------+----------╯\n\nLogs:\n  Bound result 9990354\n  Bound result 11243\n  Bound result 719\n  Bound result 8011\n  Bound result 2840\n  Bound result 362\n  Bound result 29054\n  Bound result 2\n  Bound result 11411470074835160269\n  Bound result 21899\n  Bound result 65500\n  Bound result 16015\n  Bound result 11881\n  Bound result 20645\n  Bound result 1325\n  Bound result 12337\n  Bound result 51800\n  Bound result 198\n  Bound result 58064823\n  Bound result 4096\n  Bound result 21253\n  Bound result 50\n  Bound result 35497\n  Bound result 1\n  Bound result 14858\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.17s (7.17s CPU time)\n\nRan 1 test for test/PlantStateMachine.t.sol:PlantStateMachineInvariantTest\n[PASS] invariant_independentCustodyAndSolvency() (runs: 256, calls: 24576, reverts: 0)\n\n╭--------------------------+---------------+-------+---------+----------╮\n| Contract                 | Selector      | Calls | Reverts | Discards |\n+=======================================================================+\n| PlantStateMachineHandler | answer        | 2074  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | challenge     | 2087  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | claim         | 2024  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | clear         | 2067  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | donate        | 2050  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | elapse        | 2072  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | park          | 1992  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | redeem        | 2019  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | request       | 2096  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | settle        | 1989  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | transferPlant | 2073  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | unpark        | 2033  | 0       | 0        |\n╰--------------------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 3000000000000000000\n  Bound result 200000000000000000000\n  Bound result 11552972960610128\n  Bound result 709001999313124832244\n  Bound result 15926\n  Bound result 8648\n  Bound result 19529\n  Bound result 41818260062031018800\n  Bound result 11954\n  Bound result 23294\n  Bound result 4699\n  Bound result 7235\n  Bound result 13477\n  Bound result 120400\n  Bound result 27666\n  Bound result 397532\n  Bound result 10778\n  Bound result 899929258565001754774\n  Bound result 13181\n  Bound result 9596\n  Bound result 10368\n  Bound result 4\n  Bound result 12049\n  Bound result 6047\n  Bound result 6474\n  Bound result 114264340121516542110\n  Bound result 34468\n  Bound result 6451\n  Bound result 6135663697331558634\n  Bound result 21585\n  Bound result 5528\n  Bound result 33229\n  Bound result 20454\n  Bound result 85944\n  Bound result 930612653300863705756\n  Bound result 32657110292285137189\n  Bound result 6202\n  Bound result 22676\n  Bound result 13276\n  Bound result 76543\n  Bound result 18842\n  Bound result 175\n  Bound result 18666\n  Bound result 2912\n  Bound result 72621935294431914113\n  Bound result 4823\n  Bound result 90590\n  Bound result 2831\n  Bound result 1\n  Bound result 18889\n  Bound result 241675970961349419671\n  Bound result 4226\n  Bound result 199999999999999997169\n  Bound result 6135663697331565085\n  Bound result 1\n  Bound result 4226\n  Bound result 963269763593148865621\n  Bound result 11552972960629657\n  Bound result 644059688917133999417\n  Bound result 341746712396347704831\n  Bound result 999999999999999601336\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 9.40s (9.40s CPU time)\n\nRan 20 test suites in 9.41s (28.38s CPU time): 139 tests passed, 0 failed, 0 skipped (139 total tests)\n","passed":true},{"durationMs":51,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"PlantOrganism.bind(address)\",\"PlantOrganism.challenge(uint32)\",\"PlantOrganism.checkpoint(uint32,address)\",\"PlantOrganism.claim()\",\"PlantOrganism.claim(uint32[])\",\"PlantOrganism.clearPending()\",\"PlantOrganism.die()\",\"PlantOrganism.heartbeat(uint256)\",\"PlantOrganism.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"PlantOrganism.park(uint32,uint256)\",\"PlantOrganism.redeem(uint256)\",\"PlantOrganism.rotate(address,address,bytes32,uint256,uint256,bytes)\",\"PlantOrganism.settle()\",\"PlantOrganism.settle(uint32)\",\"PlantOrganism.unpark(uint32,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":44,\"DEPENDENCIES.md\":7,\"README.md\":17,\"foundry.toml\":19,\"launch.json\":17,\"src/OracleAttestation.sol\":231,\"src/PlantOrganism.sol\":703,\"src/WeatherQuestion.sol\":83,\"src/interfaces/IIntake.sol\":14,\"test/GasAndDeployment.t.sol\":156,\"test/OracleConsumerConformance.t.sol\":125,\"test/PlantAdversarial.t.sol\":428,\"test/PlantAssumptions.t.sol\":110,\"test/PlantContractSigner.t.sol\":169,\"test/PlantFailureAtomicity.t.sol\":175,\"test/PlantInvariant.t.sol\":170,\"test/PlantLaunchRevision.t.sol\":174,\"test/PlantOrganism.t.sol\":928,\"test/PlantOriginRegression.t.sol\":321,\"test/PlantRewardOwnershipInvariant.t.sol\":265,\"test/PlantSettleLag.t.sol\":226,\"test/PlantStakeRuleInvariant.t.sol\":328,\"test/PlantStateMachine.t.sol\":451,\"test/PlantVotingCommitment.t.sol\":199,\"test/PlantVotingRevision.t.sol\":249,\"test/README.md\":104,\"test/WeatherQuestion.t.sol\":36,\"test/fixtures/weather.json\":11,\"test/mocks/Mocks.sol\":139},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"48620cf1e48e4460f90714f2a094ed4817403765a3a16f7d5e0ec8c98daf71b0","verifiedTreeHash":"6361e6f3a7bb32ca834f19af4060467c2e2099f1","verifierVersion":"0.1.0+8af37dff"},{"checks":[{"durationMs":49994,"exitCode":0,"name":"build","output":"Compiling 58 files with Solc 0.8.26\nSolc 0.8.26 finished in 49.85s\nCompiler run successful!\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:12:21\n   │\n12 │         int16 lat = int16(uint16(cell >> 16));\n   │                     ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:12:27\n   │\n12 │         int16 lat = int16(uint16(cell >> 16));\n   │                           ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:13:21\n   │\n13 │         int16 lon = int16(uint16(cell));\n   │                     ━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:13:27\n   │\n13 │         int16 lon = int16(uint16(cell));\n   │                           ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:19:29\n   │\n19 │         uint256 magnitude = uint256(milli < 0 ? -milli : milli);\n   │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:26:29\n   │\n26 │             b[--i] = bytes1(uint8(48 + n % 10));\n   │                             ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:39:27\n   │\n39 │         uint256 y = yoe + era * 400;\n   │                           ━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:40:30\n   │\n40 │         uint256 doy = doe - (365 * yoe + yoe / 4 - yoe / 100);\n   │                              ━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:42:28\n   │\n42 │         uint256 d = doy - (153 * mp + 2) / 5 + 1;\n   │                            ━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:50:40\n   │\n50 │         string memory lat = coordinate(int16(uint16(cell >> 16)));\n   │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:50:46\n   │\n50 │         string memory lat = coordinate(int16(uint16(cell >> 16)));\n   │                                              ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:51:40\n   │\n51 │         string memory lon = coordinate(int16(uint16(cell)));\n   │                                        ━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:51:46\n   │\n51 │         string memory lon = coordinate(int16(uint16(cell)));\n   │                                              ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:165:16\n    │\n165 │         return uint32(block.timestamp / 1 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/PlantOrganism.sol:168:19\n    │\n168 │     function bind(address hook_) external nonReentrant {\n    │                   ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:204:25\n    │\n204 │         require(held <= uint256(type(int256).max) && reserved <= uint256(type(int256).max));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:204:66\n    │\n204 │         require(held <= uint256(type(int256).max) && reserved <= uint256(type(int256).max));\n    │                                                                  ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:205:16\n    │\n205 │         return int256(held) - int256(reserved);\n    │                ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:205:31\n    │\n205 │         return int256(held) - int256(reserved);\n    │                               ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:210:24\n    │\n210 │         return p > 0 ? uint256(p) : 0;\n    │                        ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:506:13\n    │\n506 │             emit Checkpointed(holder, cell, credit);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:277:13\n    │\n277 │             emit Challenged(cell);\n    │             ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:247:9\n    │\n247 │         emit Parked(msg.sender, cell, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:265:9\n    │\n265 │         emit Unparked(msg.sender, cell, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `pending` is updated\n    ╭▸ src/PlantOrganism.sol:301:14\n    │\n301 │           id = intake.request(\n    │ ┏━━━━━━━━━━━━━━┛\n302 │ ┃             action,\n303 │ ┃             requestBody(location, day),\n304 │ ┃             IIntake.Callback(address(this), this.onOracleResult.selector),\n305 │ ┃             address(IMD),\n306 │ ┃             price\n307 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:287:13\n    │\n287 │         if (block.timestamp < retryAt) revert RetryLater();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:297:13\n    │\n297 │             emit Advanced(msg.sender, advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:312:9\n    │\n312 │         emit Asked(id, day, location, challenger, msg.sender, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/PlantOrganism.sol:309:13\n    │\n309 │         if (IMD.balanceOf(address(this)) != beforeBalance - price) revert NonExactTransfer();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:311:54\n    │\n311 │             Pending(id, day, challenger, msg.sender, uint64(block.timestamp), address(intake), true, false, bytes32(0));\n    │                                                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:340:9\n    │\n340 │         emit Received(requestId, a.requestId, word);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:330:13\n    │\n330 │         if (uint32(w >> 96) != p.day) revert WrongDay();\n    │             ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:349:17\n    │\n349 │             if (block.timestamp < uint256(pending.askedAt) + ORACLE_TIMEOUT) revert NotTimedOut();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:360:9\n    │\n360 │         emit Cleared(id, day, retryAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:378:13\n    │\n378 │             emit EmptyCatchUp(day, end);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:392:13\n    │\n392 │             emit Incomplete(day, count);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:484:9\n    │\n484 │         emit Rewarded(cell, pool, reserved);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:453:13\n    │\n453 │             emit Moved(current, candidate);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:409:13\n    │\n409 │             emit Bounty(caller, bounty);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:546:13\n    │\n546 │             emit Paid(holder, credit, advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:552:13\n    │\n552 │             emit PaymentDeferred(holder, credit + advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:412:9\n    │\n412 │         emit Settled(day, word, sips, backing, water, location);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:400:30\n    │\n400 │         _distribute(oldCell, pool);\n    │                              ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:412:33\n    │\n412 │         emit Settled(day, word, sips, backing, water, location);\n    │                                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:376:61\n    │\n376 │             uint32 end = hook == address(0) ? today() - 1 : uint32(Math.min(today() - 1, bindDay));\n    │                                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:429:17\n    │\n429 │         water = uint8(wet);\n    │                 ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:540:22\n    │\n540 │         if (credit + advance == 0) return;\n    │                      ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:569:9\n    │\n569 │         emit Redeemed(msg.sender, amount, payout, dead);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:584:13\n    │\n584 │             emit Died(today(), merged);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:586:13\n    │\n586 │             emit PotMerged(merged);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:616:13\n    │\n616 │         if (block.timestamp > deadline) revert RotationExpired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/OracleAttestation.sol:192:9\n    │\n192 │         emit OracleSignerSet(signer);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:626:9\n    │\n626 │         emit Rotated(oldSigner, newSigner, newIntake, newAction, nonce);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:640:16\n    │\n640 │         return block.timestamp < signerAcceptedUntil[signer]\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/PlantOrganism.sol:647:13\n    │\n647 │         if (token.balanceOf(address(this)) != beforeBalance + amount) revert NonExactTransfer();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\n","passed":true},{"durationMs":8084,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 3 tests for test/WeatherQuestion.t.sol:WeatherQuestionTest\n[PASS] test_coordinatesAtEdgesAndNegativeZeroFraction() (gas: 40309)\n[PASS] test_exactLisbonBodyAndKnownDate() (gas: 15004)\n[PASS] test_exactNegativeLatitudeAndLongitudeBody() (gas: 15401)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 341.62µs (219.83µs CPU time)\n\nRan 4 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsOriginalProtocolSignatureInCanonicalVerifier() (gas: 117620)\n[PASS] test_bytes32WeatherFixtureAcceptedUnderStipend() (gas: 2374304)\n[PASS] test_callbackSelectorIsCanonical() (gas: 3543)\n[PASS] test_digestMatchesTheProtocol() (gas: 13193)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 1.89ms (974.67µs CPU time)\n\nRan 7 tests for test/PlantAssumptions.t.sol:PlantAssumptionsTest\n[PASS] test_explicitZeroCellQuestionRemainsInvalid() (gas: 19566)\n[PASS] test_oldRotationSignatureExpires() (gas: 834939)\n[PASS] test_oldSourceWindowBacklogIsAlreadyDead() (gas: 1633703)\n[PASS] test_preBindDonationsHaveNoExit() (gas: 196044)\n[PASS] test_redeemedSupplyIsExcludedFromThreshold() (gas: 4409701)\n[PASS] test_rotatedIntakeCannotPullAboveKeeperCap() (gas: 2192042)\n[PASS] test_threeSilentRequestsSettleEmptyAndMoveWithRetainedStake() (gas: 3430671)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 4.87ms (3.96ms CPU time)\n\nRan 9 tests for test/PlantOrganism.t.sol:PlantLifecycleTest\n[PASS] test_bindIsOnceAndOnlyDeployerWithMatchingHook() (gas: 325761)\n[PASS] test_cellBoundsAndZeroRejected() (gas: 619172)\n[PASS] test_challengerOnlyStrictlyLargerAndCanBeRepaired() (gas: 3100639)\n[PASS] test_deathIsFinalAtThirtyDaysAndKeepsExits() (gas: 3253705)\n[PASS] test_deathUsesBindDayAfterLongUnboundPeriod() (gas: 285441)\n[PASS] test_moveUsesPendingCandidateAndRemainingCommittedBalances() (gas: 3834625)\n[PASS] test_noEarlyOrOutOfOrderSettleAndHeartbeat() (gas: 1001410)\n[PASS] test_preBindDaysSkipInOneCallWithoutRead() (gas: 594150)\n[PASS] test_unboundCatchUpIsBoundedAtOrigin() (gas: 149389)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 7.32ms (7.85ms CPU time)\n\nRan 4 tests for test/PlantOrganism.t.sol:PlantRotationTest\n[PASS] test_oldSignerExpiresAtThirtyDaysWhileNewSignerKeepsPlantAlive() (gas: 20361389)\n[PASS] test_onlyCurrentSignerCanRotateNonceCannotReplay() (gas: 1143484)\n[PASS] test_pendingIntakeAndOldSignerWorkAfterRotation() (gas: 4442836)\n[PASS] test_rotationDomainBindsAllFieldsAndContract() (gas: 972590)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 24.84ms (28.52ms CPU time)\n\nRan 8 tests for test/PlantLaunchRevision.t.sol:PlantLaunchRevisionTest\n[PASS] test_firstEpochFlashCannotEarnGardenersAtOrigin() (gas: 3205912)\n[PASS] test_firstEpochFlashCannotMoveOrEarnGardenersAtDestination() (gas: 3296976)\n[PASS] test_lateBindSkipsThroughBindDayAndRequestsOnlyFirstFullDay() (gas: 1583927)\n[PASS] test_originFromRealCoordinatesRoundTripsThroughCentre() (gas: 69533)\n[PASS] test_repricingCannotExceedAdvanceCapAndZeroCapUsesPot() (gas: 1109177)\n[PASS] test_rotationDeadlineIsSignedAndAcceptedAtExactBoundary() (gas: 171401)\n[PASS] test_timeoutAfterDeathCannotAdvanceDayOrRevive() (gas: 1094998)\n[PASS] test_timeoutsAndIncompleteShareCounterAndReadRepairedCandidate() (gas: 4167787)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 121.52ms (7.21ms CPU time)\n\nRan 12 tests for test/PlantOrganism.t.sol:PlantOracleTest\n[PASS] test_blockedKeeperDoesNotBlockSettleAndCanClaimLater() (gas: 2728727)\n[PASS] test_callbackSenderIdAndReplay() (gas: 2851277)\n[PASS] test_callbackStoresOnlyAndFitsStipend() (gas: 2435581)\nLogs:\n  callback gas including mock encoding: 87722\n\n[PASS] test_clearIncompleteUsesSameCounterAndCannotDiscardComplete() (gas: 2831155)\n[PASS] test_exactApprovalAndIntakeBody() (gas: 2096455)\n[PASS] test_feeAdvanceTracksDeficitThenRepaidAtSettle() (gas: 2826449)\n[PASS] test_incompleteHasNoBiologicalChangesThenThirdReads() (gas: 4060624)\n[PASS] test_intakeMustPullExactPrice() (gas: 1933599)\n[PASS] test_rejectsExpiredWrongDomainSignerTypeDayChainAndPanel() (gas: 3117187)\n[PASS] test_rejectsPreAskFutureTamperedAndMalformedAttestations() (gas: 2865952)\n[PASS] test_timeoutClearsAndWaitsSixHoursToReaskSameDay() (gas: 2890085)\n[PASS] test_unfundedAdvanceDoesNotSpendBackingOrBlockSettle() (gas: 3389963)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 143.14ms (31.63ms CPU time)\n\nRan 21 tests for test/PlantAdversarial.t.sol:PlantAdversarialTest\n[PASS] testFuzz_parkUnparkRoundTripCannotEarnWithoutSettlement(uint96,uint8) (runs: 1000, μ: 2656484, ~: 2305095)\nLogs:\n  Bound result 182750695342673\n  Bound result 3\n\n[PASS] testFuzz_reservedWeatherBitsRejectedWithoutMutatingPending(uint8) (runs: 1000, μ: 2076525, ~: 2076517)\n[PASS] testFuzz_signedMalformedPanelsAreRejected(uint8) (runs: 1000, μ: 2073187, ~: 2073062)\n[PASS] test_answerMustBeExactlyOneWordIncludingTrailingData() (gas: 2214466)\n[PASS] test_bindRejectsNonContractWrongAndEmptyTokens() (gas: 1569232)\n[PASS] test_callbackAndSettlementEventsDescribeTheAppliedResult() (gas: 2322430)\n[PASS] test_consumedOracleUuidCannotBeReusedForSameDayRetry() (gas: 2894895)\n[PASS] test_deathClearsPendingAndPreservesGardenersAndFeeDebt() (gas: 3492243)\n[PASS] test_deferredAdvanceAndBountyRemainClaimableExactlyOnce() (gas: 2861807)\n[PASS] test_depositAfterAskMustMatureBeforeItCanChallenge() (gas: 3218117)\n[PASS] test_exactClockDriftToleranceAccepted() (gas: 2070016)\n[PASS] test_moveRewardsDepartingCellAndNeverIncomingCellForSameDay() (gas: 4097478)\n[PASS] test_moveThresholdRoundsUpWhenSupplyNotDivisibleByTwenty() (gas: 3760778)\n[PASS] test_rejectedResultCanBeCorrectedWithoutBurningRequest() (gas: 2366731)\n[PASS] test_rotatedIntakeCannotAnswerPreviousIntakesRequest() (gas: 4097733)\n[PASS] test_thirdIncompleteReadsCandidateFromLatestRequest() (gas: 4360276)\n[PASS] test_timeoutExactSecondAndOldResultCannotPoisonReask() (gas: 2561998)\n[PASS] test_twoKeepersAdvancesSurviveTimeoutAndOnlyUnlockOnSettlement() (gas: 3313848)\n[PASS] test_unparkAfterCallbackDropsOutBeforeHoursAndKeepsPreviousReward() (gas: 3265833)\n[PASS] test_validityWindowBoundariesAndAskedAt() (gas: 2467555)\n[PASS] test_zeroAmountsAndOverdrawCannotChangeCustody() (gas: 1831479)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 368.19ms (948.89ms CPU time)\n\nRan 8 tests for test/PlantVotingCommitment.t.sol:PlantVotingCommitmentTest\n[PASS] testFuzz_withdrawalAndRedepositCannotIncreasePower(uint96,uint96) (runs: 256, μ: 3217999, ~: 3218643)\nLogs:\n  Bound result 114264337593543950333\n  Bound result 880266\n\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotCaptureGardenersPool() (gas: 5232170)\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotMove() (gas: 4237584)\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotVeto() (gas: 3186257)\n[PASS] test_loanAcrossPreviousSettleLosesPowerOnWithdrawal() (gas: 3769733)\n[PASS] test_rearmedDecoyCannotHideHoldersCandidate() (gas: 3393181)\n[PASS] test_thresholdUsesCommittedStakeAndNewDepositsMatureAtSettle() (gas: 4167601)\n[PASS] test_timeoutAndReaskCannotRestoreWithdrawnPower() (gas: 3455480)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 368.95ms (385.21ms CPU time)\n\nRan 6 tests for test/GasAndDeployment.t.sol:GasAndDeploymentTest\n[PASS] test_coldCallbackAndMaxHoursMoveSettleGas() (gas: 3761853)\nLogs:\n  cold callback gas: 87722\n\n[PASS] test_coldMaxHoursWithRepairedCandidateSettleGas() (gas: 3788592)\n[PASS] test_requestedStaticConstructorAndForbiddenOpcodes() (gas: 8419315)\n[PASS] test_settlementFitsStipendWithManyEligibleHolders() (gas: 38964884)\n[PASS] test_thirdIncompleteMoveAndAdvancePaymentGas() (gas: 4681569)\n[PASS] test_thirdTimeoutMoveAndAdvancePaymentFitsColdStipend() (gas: 4172834)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 369.15ms (77.65ms CPU time)\n\nRan 4 tests for test/PlantContractSigner.t.sol:PlantContractSignerTest\n[PASS] test_canRotateToContractAndRejectInvalidOrRevokedSignatures() (gas: 2069553)\n[PASS] test_constructorContractAttestationAndRotationFitCallbackStipend() (gas: 2468829)\nLogs:\n  cold ERC-1271 callback gas: 91097\n\n[PASS] test_multiplePriorContractSignersKeepGraceWithoutRotationAuthority() (gas: 3391483)\n[PASS] test_previousContractGraceExpiresAtThirtyDays() (gas: 18714785)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 369.10ms (20.87ms CPU time)\n\nRan 12 tests for test/PlantOrganism.t.sol:PlantRewardsTest\n[PASS] testFuzz_floorConservationAndBurnCustody(uint96,uint96,uint24) (runs: 1000, μ: 2978027, ~: 2991154)\nLogs:\n  Bound result 188133658834132802192\n\n[PASS] testFuzz_hourlyAccountingMatchesIndependentModel(uint24,uint24) (runs: 1000, μ: 2444016, ~: 2446674)\n[PASS] test_departuresDropOutAndReparkingCannotCaptureDay() (gas: 4736914)\n[PASS] test_finalRedemptionDoesNotDivideByZeroOrReleaseBurnedPlant() (gas: 3092689)\n[PASS] test_gardenerDustRoundsToBackingAndAccountsCloseExactly() (gas: 5878819)\n[PASS] test_hourZeroFirstRainCapAndSunRequiresWater() (gas: 5456711)\n[PASS] test_noGardenersSendsEntireSipToBacking() (gas: 1282225)\n[PASS] test_nonExactTokenTransfersRejected() (gas: 274408)\n[PASS] test_oldCellKeepsItsRewardsAfterMoveAndLazyActivation() (gas: 6423632)\n[PASS] test_parkSettleClaimProRataAndMidDayJoinsWaitOneSettle() (gas: 3822066)\n[PASS] test_redeemRetainsPlantAndTenPercentAndFloorMonotonic() (gas: 2843146)\n[PASS] test_reentrancyFromTokensAndIntakeBlocked() (gas: 2932391)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 369.23ms (746.81ms CPU time)\n\nRan 13 tests for test/PlantVotingRevision.t.sol:PlantVotingRevisionTest\n[PASS] testFuzz_repeatedTopUpsCannotIncreaseCommittedStake(uint96) (runs: 1000, μ: 3706317, ~: 3706223)\nLogs:\n  Bound result 9299\n\n[PASS] testFuzz_withdrawalUsesOwnQueuedStakeBeforeCommitment(uint96) (runs: 1000, μ: 3118452, ~: 3119287)\nLogs:\n  Bound result 24179656842\n\n[PASS] test_atomicCurrentCellTopUpCannotVetoCommittedCandidate() (gas: 3018336)\n[PASS] test_atomicDestinationTopUpCannotMoveOrCaptureRewards() (gas: 4477080)\n[PASS] test_currentCellWithdrawalBreaksTieForCommittedCandidate() (gas: 2885101)\n[PASS] test_emptyCapturedCandidateFallsBackToRepairedLiveCandidate() (gas: 3251245)\n[PASS] test_fallbackCannotUseNewPostHeartbeatStake() (gas: 3737380)\n[PASS] test_questionUsesOriginFromDeployment() (gas: 1699977)\n[PASS] test_replacementHolderCannotInheritWithdrawnVotingPower() (gas: 3943756)\n[PASS] test_thirdIncompleteAlsoUsesRepairedCandidate() (gas: 4822108)\n[PASS] test_thirdIncompleteReadsBeforePromotingFreshDeposits() (gas: 4742317)\n[PASS] test_timeoutRetryCannotMatureRequestOrCooldownDeposits() (gas: 4176489)\n[PASS] test_withdrawalRemovesPowerAndReaskCannotRestoreIt() (gas: 4308944)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 384.06ms (779.68ms CPU time)\n\nRan 1 test for test/PlantInvariant.t.sol:PlantInvariantTest\n[PASS] invariant_conservationAndPermanentBurnCustody() (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+---------------+-------+---------+----------╮\n| Contract     | Selector      | Calls | Reverts | Discards |\n+===========================================================+\n| PlantHandler | challenge     | 1044  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | checkpointAll | 991   | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | claim         | 977   | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | fund          | 1053  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | park          | 974   | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | redeem        | 1034  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | unpark        | 1032  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | weather       | 1087  | 0       | 0        |\n╰--------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1218\n  Bound result 13107\n  Bound result 15271\n  Bound result 867071172092131899701\n  Bound result 20597\n  Bound result 1164245951\n  Bound result 7998321706313019777\n  Bound result 39162851889974326248\n  Bound result 6234\n  Bound result 3240701122\n  Bound result 2466\n  Bound result 16264166028250\n  Bound result 2\n  Bound result 39718916127860267730\n  Bound result 2394\n  Bound result 2280\n  Bound result 2056\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.75s (1.75s CPU time)\n\nRan 1 test for test/PlantStateMachine.t.sol:PlantStateMachineInvariantTest\n[PASS] invariant_independentCustodyAndSolvency() (runs: 256, calls: 24576, reverts: 0)\n\n╭--------------------------+---------------+-------+---------+----------╮\n| Contract                 | Selector      | Calls | Reverts | Discards |\n+=======================================================================+\n| PlantStateMachineHandler | answer        | 2118  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | challenge     | 1988  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | claim         | 2068  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | clear         | 2045  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | donate        | 2065  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | elapse        | 2094  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | park          | 1955  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | redeem        | 2072  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | request       | 2063  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | settle        | 1996  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | transferPlant | 2050  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | unpark        | 2062  | 0       | 0        |\n╰--------------------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 3000000000000000000\n  Bound result 200000000000000000000\n  Bound result 2445\n  Bound result 2295\n  Bound result 504386924125232037852\n  Bound result 416\n  Bound result 1\n  Bound result 22639972303210\n  Bound result 3231\n  Bound result 18330\n  Bound result 106240516513069584451\n  Bound result 521\n  Bound result 454018146333155013769\n  Bound result 12683\n  Bound result 4820\n  Bound result 18621\n  Bound result 20044\n  Bound result 102953\n  Bound result 2219\n  Bound result 26646\n  Bound result 10490\n  Bound result 175\n  Bound result 263033503213\n  Bound result 65301\n  Bound result 9840\n  Bound result 250\n  Bound result 15472\n  Bound result 2505\n  Bound result 1605\n  Bound result 325\n  Bound result 16866\n  Bound result 255\n  Bound result 795\n  Bound result 57894\n  Bound result 365\n  Bound result 114754996\n  Bound result 86400\n  Bound result 9478\n  Bound result 9564\n  Bound result 18807\n  Bound result 654018146333269811813\n  Bound result 1\n  Bound result 11201\n  Bound result 50083131795838874679\n  Bound result 2949\n  Bound result 2896\n  Bound result 2739854339\n  Bound result 801787757\n  Bound result 11885\n  Bound result 7774\n  Bound result 4981\n  Bound result 6992\n  Bound result 6524\n  Bound result 18430\n  Bound result 5\n  Bound result 18637\n  Bound result 183276774371962491636\n  Bound result 123\n  Bound result 16884\n  Bound result 2236\n  Bound result 21567\n  Bound result 1494\n  Bound result 200000000000000002949\n  Bound result 4740\n  Bound result 1\n  Bound result 454018146333269816409\n  Bound result 36197\n  Bound result 850368755415023421182\n  Bound result 893759483223896895532\n  Bound result 495613075874767932140\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.01s (8.00s CPU time)\n\nRan 15 test suites in 8.01s (12.29s CPU time): 113 tests passed, 0 failed, 0 skipped (113 total tests)\n","passed":true},{"durationMs":51,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"PlantOrganism.bind(address)\",\"PlantOrganism.challenge(uint32)\",\"PlantOrganism.checkpoint(uint32,address)\",\"PlantOrganism.claim()\",\"PlantOrganism.claim(uint32[])\",\"PlantOrganism.clearPending()\",\"PlantOrganism.die()\",\"PlantOrganism.heartbeat(uint256)\",\"PlantOrganism.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"PlantOrganism.park(uint32,uint256)\",\"PlantOrganism.redeem(uint256)\",\"PlantOrganism.rotate(address,address,bytes32,uint256,uint256,bytes)\",\"PlantOrganism.settle()\",\"PlantOrganism.settle(uint32)\",\"PlantOrganism.unpark(uint32,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":31,\"DEPENDENCIES.md\":7,\"README.md\":17,\"foundry.toml\":19,\"launch.json\":17,\"src/OracleAttestation.sol\":231,\"src/PlantOrganism.sol\":649,\"src/WeatherQuestion.sol\":83,\"src/interfaces/IIntake.sol\":14,\"test/GasAndDeployment.t.sol\":156,\"test/OracleConsumerConformance.t.sol\":125,\"test/PlantAdversarial.t.sol\":423,\"test/PlantAssumptions.t.sol\":110,\"test/PlantContractSigner.t.sol\":169,\"test/PlantInvariant.t.sol\":166,\"test/PlantLaunchRevision.t.sol\":174,\"test/PlantOrganism.t.sol\":905,\"test/PlantStateMachine.t.sol\":403,\"test/PlantVotingCommitment.t.sol\":196,\"test/PlantVotingRevision.t.sol\":226,\"test/README.md\":57,\"test/WeatherQuestion.t.sol\":36,\"test/fixtures/weather.json\":11,\"test/mocks/Mocks.sol\":139},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"69d0bd24554a734d9eb1ed8f6bb23e236ff4b70232f08a96bb92ee54f4a8198d","verifiedTreeHash":"cce20f15125a0616e027435d9776be3b3b1b53f6","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":63054,"exitCode":0,"name":"build","output":"Compiling 60 files with Solc 0.8.26\nSolc 0.8.26 finished in 62.89s\nCompiler run successful!\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:12:21\n   │\n12 │         int16 lat = int16(uint16(cell >> 16));\n   │                     ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:12:27\n   │\n12 │         int16 lat = int16(uint16(cell >> 16));\n   │                           ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:13:21\n   │\n13 │         int16 lon = int16(uint16(cell));\n   │                     ━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:13:27\n   │\n13 │         int16 lon = int16(uint16(cell));\n   │                           ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:19:29\n   │\n19 │         uint256 magnitude = uint256(milli < 0 ? -milli : milli);\n   │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:26:29\n   │\n26 │             b[--i] = bytes1(uint8(48 + n % 10));\n   │                             ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:39:27\n   │\n39 │         uint256 y = yoe + era * 400;\n   │                           ━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:40:30\n   │\n40 │         uint256 doy = doe - (365 * yoe + yoe / 4 - yoe / 100);\n   │                              ━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:42:28\n   │\n42 │         uint256 d = doy - (153 * mp + 2) / 5 + 1;\n   │                            ━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:50:40\n   │\n50 │         string memory lat = coordinate(int16(uint16(cell >> 16)));\n   │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:50:46\n   │\n50 │         string memory lat = coordinate(int16(uint16(cell >> 16)));\n   │                                              ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:51:40\n   │\n51 │         string memory lon = coordinate(int16(uint16(cell)));\n   │                                        ━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:51:46\n   │\n51 │         string memory lon = coordinate(int16(uint16(cell)));\n   │                                              ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:165:16\n    │\n165 │         return uint32(block.timestamp / 1 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/PlantOrganism.sol:168:19\n    │\n168 │     function bind(address hook_) external nonReentrant {\n    │                   ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:204:25\n    │\n204 │         require(held <= uint256(type(int256).max) && reserved <= uint256(type(int256).max));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:204:66\n    │\n204 │         require(held <= uint256(type(int256).max) && reserved <= uint256(type(int256).max));\n    │                                                                  ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:205:16\n    │\n205 │         return int256(held) - int256(reserved);\n    │                ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:205:31\n    │\n205 │         return int256(held) - int256(reserved);\n    │                               ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:210:24\n    │\n210 │         return p > 0 ? uint256(p) : 0;\n    │                        ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:506:13\n    │\n506 │             emit Checkpointed(holder, cell, credit);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:277:13\n    │\n277 │             emit Challenged(cell);\n    │             ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:247:9\n    │\n247 │         emit Parked(msg.sender, cell, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:265:9\n    │\n265 │         emit Unparked(msg.sender, cell, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `pending` is updated\n    ╭▸ src/PlantOrganism.sol:301:14\n    │\n301 │           id = intake.request(\n    │ ┏━━━━━━━━━━━━━━┛\n302 │ ┃             action,\n303 │ ┃             requestBody(location, day),\n304 │ ┃             IIntake.Callback(address(this), this.onOracleResult.selector),\n305 │ ┃             address(IMD),\n306 │ ┃             price\n307 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:287:13\n    │\n287 │         if (block.timestamp < retryAt) revert RetryLater();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:297:13\n    │\n297 │             emit Advanced(msg.sender, advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:312:9\n    │\n312 │         emit Asked(id, day, location, challenger, msg.sender, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/PlantOrganism.sol:309:13\n    │\n309 │         if (IMD.balanceOf(address(this)) != beforeBalance - price) revert NonExactTransfer();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:311:54\n    │\n311 │             Pending(id, day, challenger, msg.sender, uint64(block.timestamp), address(intake), true, false, bytes32(0));\n    │                                                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:340:9\n    │\n340 │         emit Received(requestId, a.requestId, word);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:330:13\n    │\n330 │         if (uint32(w >> 96) != p.day) revert WrongDay();\n    │             ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:349:17\n    │\n349 │             if (block.timestamp < uint256(pending.askedAt) + ORACLE_TIMEOUT) revert NotTimedOut();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:360:9\n    │\n360 │         emit Cleared(id, day, retryAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:378:13\n    │\n378 │             emit EmptyCatchUp(day, end);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:392:13\n    │\n392 │             emit Incomplete(day, count);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:484:9\n    │\n484 │         emit Rewarded(cell, pool, reserved);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:453:13\n    │\n453 │             emit Moved(current, candidate);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:409:13\n    │\n409 │             emit Bounty(caller, bounty);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:546:13\n    │\n546 │             emit Paid(holder, credit, advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:552:13\n    │\n552 │             emit PaymentDeferred(holder, credit + advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:412:9\n    │\n412 │         emit Settled(day, word, sips, backing, water, location);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:412:33\n    │\n412 │         emit Settled(day, word, sips, backing, water, location);\n    │                                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:400:30\n    │\n400 │         _distribute(oldCell, pool);\n    │                              ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:376:61\n    │\n376 │             uint32 end = hook == address(0) ? today() - 1 : uint32(Math.min(today() - 1, bindDay));\n    │                                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:429:17\n    │\n429 │         water = uint8(wet);\n    │                 ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:540:22\n    │\n540 │         if (credit + advance == 0) return;\n    │                      ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:569:9\n    │\n569 │         emit Redeemed(msg.sender, amount, payout, dead);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:584:13\n    │\n584 │             emit Died(today(), merged);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:586:13\n    │\n586 │             emit PotMerged(merged);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:616:13\n    │\n616 │         if (block.timestamp > deadline) revert RotationExpired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/OracleAttestation.sol:192:9\n    │\n192 │         emit OracleSignerSet(signer);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:626:9\n    │\n626 │         emit Rotated(oldSigner, newSigner, newIntake, newAction, nonce);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:640:16\n    │\n640 │         return block.timestamp < signerAcceptedUntil[signer]\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/PlantOrganism.sol:647:13\n    │\n647 │         if (token.balanceOf(address(this)) != beforeBalance + amount) revert NonExactTransfer();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\n","passed":true},{"durationMs":8851,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 4 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsOriginalProtocolSignatureInCanonicalVerifier() (gas: 117620)\n[PASS] test_bytes32WeatherFixtureAcceptedUnderStipend() (gas: 2374304)\n[PASS] test_callbackSelectorIsCanonical() (gas: 3543)\n[PASS] test_digestMatchesTheProtocol() (gas: 13193)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 2.72ms (1.58ms CPU time)\n\nRan 4 tests for test/PlantOrganism.t.sol:PlantRotationTest\n[PASS] test_oldSignerExpiresAtThirtyDaysWhileNewSignerKeepsPlantAlive() (gas: 20361389)\n[PASS] test_onlyCurrentSignerCanRotateNonceCannotReplay() (gas: 1143484)\n[PASS] test_pendingIntakeAndOldSignerWorkAfterRotation() (gas: 4442836)\n[PASS] test_rotationDomainBindsAllFieldsAndContract() (gas: 972590)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 43.05ms (47.64ms CPU time)\n\nRan 8 tests for test/PlantVotingCommitment.t.sol:PlantVotingCommitmentTest\n[PASS] testFuzz_withdrawalAndRedepositCannotIncreasePower(uint96,uint96) (runs: 256, μ: 3217715, ~: 3218643)\nLogs:\n  Bound result 1541412288103\n  Bound result 26315844310\n\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotCaptureGardenersPool() (gas: 5232170)\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotMove() (gas: 4237584)\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotVeto() (gas: 3186257)\n[PASS] test_loanAcrossPreviousSettleLosesPowerOnWithdrawal() (gas: 3769733)\n[PASS] test_rearmedDecoyCannotHideHoldersCandidate() (gas: 3393181)\n[PASS] test_thresholdUsesCommittedStakeAndNewDepositsMatureAtSettle() (gas: 4167601)\n[PASS] test_timeoutAndReaskCannotRestoreWithdrawnPower() (gas: 3455480)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 264.34ms (278.38ms CPU time)\n\nRan 8 tests for test/PlantLaunchRevision.t.sol:PlantLaunchRevisionTest\n[PASS] test_firstEpochFlashCannotEarnGardenersAtOrigin() (gas: 3205912)\n[PASS] test_firstEpochFlashCannotMoveOrEarnGardenersAtDestination() (gas: 3296976)\n[PASS] test_lateBindSkipsThroughBindDayAndRequestsOnlyFirstFullDay() (gas: 1583927)\n[PASS] test_originFromRealCoordinatesRoundTripsThroughCentre() (gas: 69533)\n[PASS] test_repricingCannotExceedAdvanceCapAndZeroCapUsesPot() (gas: 1109177)\n[PASS] test_rotationDeadlineIsSignedAndAcceptedAtExactBoundary() (gas: 171401)\n[PASS] test_timeoutAfterDeathCannotAdvanceDayOrRevive() (gas: 1094998)\n[PASS] test_timeoutsAndIncompleteShareCounterAndReadRepairedCandidate() (gas: 4167787)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 428.64ms (7.26ms CPU time)\n\nRan 12 tests for test/PlantOrganism.t.sol:PlantRewardsTest\n[PASS] testFuzz_floorConservationAndBurnCustody(uint96,uint96,uint24) (runs: 1000, μ: 2980280, ~: 2991154)\nLogs:\n  Bound result 626430675151\n\n[PASS] testFuzz_hourlyAccountingMatchesIndependentModel(uint24,uint24) (runs: 1000, μ: 2443592, ~: 2446662)\n[PASS] test_departuresDropOutAndReparkingCannotCaptureDay() (gas: 4736914)\n[PASS] test_finalRedemptionDoesNotDivideByZeroOrReleaseBurnedPlant() (gas: 3092689)\n[PASS] test_gardenerDustRoundsToBackingAndAccountsCloseExactly() (gas: 5878819)\n[PASS] test_hourZeroFirstRainCapAndSunRequiresWater() (gas: 5456711)\n[PASS] test_noGardenersSendsEntireSipToBacking() (gas: 1282225)\n[PASS] test_nonExactTokenTransfersRejected() (gas: 274408)\n[PASS] test_oldCellKeepsItsRewardsAfterMoveAndLazyActivation() (gas: 6423632)\n[PASS] test_parkSettleClaimProRataAndMidDayJoinsWaitOneSettle() (gas: 3822066)\n[PASS] test_redeemRetainsPlantAndTenPercentAndFloorMonotonic() (gas: 2843146)\n[PASS] test_reentrancyFromTokensAndIntakeBlocked() (gas: 2932391)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 431.67ms (848.34ms CPU time)\n\nRan 7 tests for test/PlantAssumptions.t.sol:PlantAssumptionsTest\n[PASS] test_explicitZeroCellQuestionRemainsInvalid() (gas: 19566)\n[PASS] test_oldRotationSignatureExpires() (gas: 834939)\n[PASS] test_oldSourceWindowBacklogIsAlreadyDead() (gas: 1633703)\n[PASS] test_preBindDonationsHaveNoExit() (gas: 196044)\n[PASS] test_redeemedSupplyIsExcludedFromThreshold() (gas: 4409701)\n[PASS] test_rotatedIntakeCannotPullAboveKeeperCap() (gas: 2192042)\n[PASS] test_threeSilentRequestsSettleEmptyAndMoveWithRetainedStake() (gas: 3430671)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 442.40ms (9.63ms CPU time)\n\nRan 3 tests for test/WeatherQuestion.t.sol:WeatherQuestionTest\n[PASS] test_coordinatesAtEdgesAndNegativeZeroFraction() (gas: 40309)\n[PASS] test_exactLisbonBodyAndKnownDate() (gas: 15004)\n[PASS] test_exactNegativeLatitudeAndLongitudeBody() (gas: 15401)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 441.86ms (3.02ms CPU time)\n\nRan 21 tests for test/PlantAdversarial.t.sol:PlantAdversarialTest\n[PASS] testFuzz_parkUnparkRoundTripCannotEarnWithoutSettlement(uint96,uint8) (runs: 1000, μ: 2493059, ~: 2002365)\nLogs:\n  Bound result 2193\n  Bound result 15\n\n[PASS] testFuzz_reservedWeatherBitsRejectedWithoutMutatingPending(uint8) (runs: 1000, μ: 2076526, ~: 2076517)\n[PASS] testFuzz_signedMalformedPanelsAreRejected(uint8) (runs: 1000, μ: 2073178, ~: 2073062)\n[PASS] test_answerMustBeExactlyOneWordIncludingTrailingData() (gas: 2214466)\n[PASS] test_bindRejectsNonContractWrongAndEmptyTokens() (gas: 1569232)\n[PASS] test_callbackAndSettlementEventsDescribeTheAppliedResult() (gas: 2322430)\n[PASS] test_consumedOracleUuidCannotBeReusedForSameDayRetry() (gas: 2894895)\n[PASS] test_deathClearsPendingAndPreservesGardenersAndFeeDebt() (gas: 3492243)\n[PASS] test_deferredAdvanceAndBountyRemainClaimableExactlyOnce() (gas: 2861807)\n[PASS] test_depositAfterAskMustMatureBeforeItCanChallenge() (gas: 3218117)\n[PASS] test_exactClockDriftToleranceAccepted() (gas: 2070016)\n[PASS] test_moveRewardsDepartingCellAndNeverIncomingCellForSameDay() (gas: 4097478)\n[PASS] test_moveThresholdRoundsUpWhenSupplyNotDivisibleByTwenty() (gas: 3760778)\n[PASS] test_rejectedResultCanBeCorrectedWithoutBurningRequest() (gas: 2366731)\n[PASS] test_rotatedIntakeCannotAnswerPreviousIntakesRequest() (gas: 4097733)\n[PASS] test_thirdIncompleteReadsCandidateFromLatestRequest() (gas: 4360276)\n[PASS] test_timeoutExactSecondAndOldResultCannotPoisonReask() (gas: 2561998)\n[PASS] test_twoKeepersAdvancesSurviveTimeoutAndOnlyUnlockOnSettlement() (gas: 3313848)\n[PASS] test_unparkAfterCallbackDropsOutBeforeHoursAndKeepsPreviousReward() (gas: 3265833)\n[PASS] test_validityWindowBoundariesAndAskedAt() (gas: 2467555)\n[PASS] test_zeroAmountsAndOverdrawCannotChangeCustody() (gas: 1831479)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 442.53ms (1.28s CPU time)\n\nRan 6 tests for test/PlantFailureAtomicity.t.sol:PlantFailureAtomicityTest\n[PASS] testFuzz_advanceCapUsesOnlySpendablePotAndFailedCapIsAtomic(uint96) (runs: 1000, μ: 3023183, ~: 3023095)\nLogs:\n  Bound result 3646327707788577150\n\n[PASS] test_failedParkCannotCheckpointOrConsumeAllowance() (gas: 3206087)\n[PASS] test_failedRedemptionCannotSurrenderPlantOrReduceBacking() (gas: 3010428)\n[PASS] test_failedUnparkRestoresCheckpointAndVotingPowerThenCanRetry() (gas: 3187400)\n[PASS] test_falseReturnOnClaimPreservesCreditWithoutBlockingOtherGardeners() (gas: 3300231)\n[PASS] test_underchargingIntakeRollsBackCallerAdvanceAndAllNestedTransfers() (gas: 2237161)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 442.53ms (448.14ms CPU time)\n\nRan 9 tests for test/PlantOrganism.t.sol:PlantLifecycleTest\n[PASS] test_bindIsOnceAndOnlyDeployerWithMatchingHook() (gas: 325761)\n[PASS] test_cellBoundsAndZeroRejected() (gas: 619172)\n[PASS] test_challengerOnlyStrictlyLargerAndCanBeRepaired() (gas: 3100639)\n[PASS] test_deathIsFinalAtThirtyDaysAndKeepsExits() (gas: 3253705)\n[PASS] test_deathUsesBindDayAfterLongUnboundPeriod() (gas: 285441)\n[PASS] test_moveUsesPendingCandidateAndRemainingCommittedBalances() (gas: 3834625)\n[PASS] test_noEarlyOrOutOfOrderSettleAndHeartbeat() (gas: 1001410)\n[PASS] test_preBindDaysSkipInOneCallWithoutRead() (gas: 594150)\n[PASS] test_unboundCatchUpIsBoundedAtOrigin() (gas: 149389)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 443.25ms (9.69ms CPU time)\n\nRan 4 tests for test/PlantContractSigner.t.sol:PlantContractSignerTest\n[PASS] test_canRotateToContractAndRejectInvalidOrRevokedSignatures() (gas: 2069553)\n[PASS] test_constructorContractAttestationAndRotationFitCallbackStipend() (gas: 2468829)\nLogs:\n  cold ERC-1271 callback gas: 91097\n\n[PASS] test_multiplePriorContractSignersKeepGraceWithoutRotationAuthority() (gas: 3391483)\n[PASS] test_previousContractGraceExpiresAtThirtyDays() (gas: 18714785)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 443.26ms (21.76ms CPU time)\n\nRan 12 tests for test/PlantOrganism.t.sol:PlantOracleTest\n[PASS] test_blockedKeeperDoesNotBlockSettleAndCanClaimLater() (gas: 2728727)\n[PASS] test_callbackSenderIdAndReplay() (gas: 2851277)\n[PASS] test_callbackStoresOnlyAndFitsStipend() (gas: 2435581)\nLogs:\n  callback gas including mock encoding: 87722\n\n[PASS] test_clearIncompleteUsesSameCounterAndCannotDiscardComplete() (gas: 2831155)\n[PASS] test_exactApprovalAndIntakeBody() (gas: 2096455)\n[PASS] test_feeAdvanceTracksDeficitThenRepaidAtSettle() (gas: 2826449)\n[PASS] test_incompleteHasNoBiologicalChangesThenThirdReads() (gas: 4060624)\n[PASS] test_intakeMustPullExactPrice() (gas: 1933599)\n[PASS] test_rejectsExpiredWrongDomainSignerTypeDayChainAndPanel() (gas: 3117187)\n[PASS] test_rejectsPreAskFutureTamperedAndMalformedAttestations() (gas: 2865952)\n[PASS] test_timeoutClearsAndWaitsSixHoursToReaskSameDay() (gas: 2890085)\n[PASS] test_unfundedAdvanceDoesNotSpendBackingOrBlockSettle() (gas: 3389963)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 443.22ms (29.26ms CPU time)\n\nRan 6 tests for test/GasAndDeployment.t.sol:GasAndDeploymentTest\n[PASS] test_coldCallbackAndMaxHoursMoveSettleGas() (gas: 3761853)\nLogs:\n  cold callback gas: 87722\n\n[PASS] test_coldMaxHoursWithRepairedCandidateSettleGas() (gas: 3788592)\n[PASS] test_requestedStaticConstructorAndForbiddenOpcodes() (gas: 8419315)\n[PASS] test_settlementFitsStipendWithManyEligibleHolders() (gas: 38964884)\n[PASS] test_thirdIncompleteMoveAndAdvancePaymentGas() (gas: 4681569)\n[PASS] test_thirdTimeoutMoveAndAdvancePaymentFitsColdStipend() (gas: 4172834)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 443.35ms (75.40ms CPU time)\n\nRan 13 tests for test/PlantVotingRevision.t.sol:PlantVotingRevisionTest\n[PASS] testFuzz_repeatedTopUpsCannotIncreaseCommittedStake(uint96) (runs: 1000, μ: 3706338, ~: 3706223)\nLogs:\n  Bound result 96276548882276750110\n\n[PASS] testFuzz_withdrawalUsesOwnQueuedStakeBeforeCommitment(uint96) (runs: 1000, μ: 3118078, ~: 3119287)\nLogs:\n  Bound result 2185\n\n[PASS] test_atomicCurrentCellTopUpCannotVetoCommittedCandidate() (gas: 3018336)\n[PASS] test_atomicDestinationTopUpCannotMoveOrCaptureRewards() (gas: 4477080)\n[PASS] test_currentCellWithdrawalBreaksTieForCommittedCandidate() (gas: 2885101)\n[PASS] test_emptyCapturedCandidateFallsBackToRepairedLiveCandidate() (gas: 3251245)\n[PASS] test_fallbackCannotUseNewPostHeartbeatStake() (gas: 3737380)\n[PASS] test_questionUsesOriginFromDeployment() (gas: 1699977)\n[PASS] test_replacementHolderCannotInheritWithdrawnVotingPower() (gas: 3943756)\n[PASS] test_thirdIncompleteAlsoUsesRepairedCandidate() (gas: 4822108)\n[PASS] test_thirdIncompleteReadsBeforePromotingFreshDeposits() (gas: 4742317)\n[PASS] test_timeoutRetryCannotMatureRequestOrCooldownDeposits() (gas: 4176489)\n[PASS] test_withdrawalRemovesPowerAndReaskCannotRestoreIt() (gas: 4308944)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 442.68ms (903.26ms CPU time)\n\nRan 1 test for test/PlantInvariant.t.sol:PlantInvariantTest\n[PASS] invariant_conservationAndPermanentBurnCustody() (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+---------------+-------+---------+----------╮\n| Contract     | Selector      | Calls | Reverts | Discards |\n+===========================================================+\n| PlantHandler | challenge     | 1085  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | checkpointAll | 1014  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | claim         | 997   | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | fund          | 1065  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | park          | 958   | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | redeem        | 1008  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | unpark        | 1042  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | weather       | 1023  | 0       | 0        |\n╰--------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 12891\n  Bound result 23194\n  Bound result 2396\n  Bound result 5990\n  Bound result 739690568824677205004\n  Bound result 18363\n  Bound result 946368152364130\n  Bound result 2581\n  Bound result 34376665891864\n  Bound result 31229061\n  Bound result 17986\n  Bound result 9805\n  Bound result 11217\n  Bound result 1\n  Bound result 22575214231655539\n  Bound result 3\n  Bound result 10872183324999553\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.90s (1.90s CPU time)\n\nRan 1 test for test/PlantRewardOwnershipInvariant.t.sol:PlantRewardOwnershipInvariantTest\n[PASS] invariant_eachGardenerOwnsExactlyTheirEarnedRewards() (runs: 256, calls: 24576, reverts: 0)\n\n╭-----------------------------+--------------+-------+---------+----------╮\n| Contract                    | Selector     | Calls | Reverts | Discards |\n+=========================================================================+\n| PlantRewardOwnershipHandler | blockPayment | 3070  | 0       | 0        |\n|-----------------------------+--------------+-------+---------+----------|\n| PlantRewardOwnershipHandler | challenge    | 3086  | 0       | 0        |\n|-----------------------------+--------------+-------+---------+----------|\n| PlantRewardOwnershipHandler | checkpoint   | 3037  | 0       | 0        |\n|-----------------------------+--------------+-------+---------+----------|\n| PlantRewardOwnershipHandler | claimDefault | 3042  | 0       | 0        |\n|-----------------------------+--------------+-------+---------+----------|\n| PlantRewardOwnershipHandler | claimSome    | 3041  | 0       | 0        |\n|-----------------------------+--------------+-------+---------+----------|\n| PlantRewardOwnershipHandler | grow         | 3072  | 0       | 0        |\n|-----------------------------+--------------+-------+---------+----------|\n| PlantRewardOwnershipHandler | park         | 3143  | 0       | 0        |\n|-----------------------------+--------------+-------+---------+----------|\n| PlantRewardOwnershipHandler | unpark       | 3085  | 0       | 0        |\n╰-----------------------------+--------------+-------+---------+----------╯\n\nLogs:\n  Bound result 100000000000000000000\n  Bound result 200000000000000000000\n  Bound result 300000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 100000000000000000000\n  Bound result 8863\n  Bound result 5145\n  Bound result 10218\n  Bound result 12247\n  Bound result 10374\n  Bound result 2\n  Bound result 123143577\n  Bound result 6007\n  Bound result 4878\n  Bound result 16130\n  Bound result 3332\n  Bound result 13409\n  Bound result 50\n  Bound result 7358178136\n  Bound result 5317\n  Bound result 10138\n  Bound result 3075360042\n  Bound result 946413023514780496\n  Bound result 20129\n  Bound result 900\n  Bound result 4498\n  Bound result 98\n  Bound result 934125\n  Bound result 192\n  Bound result 383\n  Bound result 2624374698\n  Bound result 10539800062636624182\n  Bound result 14829\n  Bound result 7631\n  Bound result 6809\n  Bound result 1688\n  Bound result 488678688660382162206\n  Bound result 5705\n  Bound result 100000000000123143764\n  Bound result 11632\n  Bound result 488678688660382172580\n  Bound result 199999999999999989779\n  Bound result 300000000000000003738\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 6.52s (6.51s CPU time)\n\nRan 1 test for test/PlantStateMachine.t.sol:PlantStateMachineInvariantTest\n[PASS] invariant_independentCustodyAndSolvency() (runs: 256, calls: 24576, reverts: 0)\n\n╭--------------------------+---------------+-------+---------+----------╮\n| Contract                 | Selector      | Calls | Reverts | Discards |\n+=======================================================================+\n| PlantStateMachineHandler | answer        | 1996  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | challenge     | 2028  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | claim         | 2021  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | clear         | 2048  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | donate        | 2103  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | elapse        | 2041  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | park          | 2088  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | redeem        | 2051  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | request       | 1999  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | settle        | 2055  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | transferPlant | 2095  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | unpark        | 2051  | 0       | 0        |\n╰--------------------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 3000000000000000000\n  Bound result 200000000000000000000\n  Bound result 1543\n  Bound result 175\n  Bound result 9636\n  Bound result 5015\n  Bound result 5650\n  Bound result 921971935597075365889\n  Bound result 386912898977421564351\n  Bound result 9765\n  Bound result 11045\n  Bound result 121\n  Bound result 528879452601233027556\n  Bound result 64815\n  Bound result 323435050506130157\n  Bound result 2314673492\n  Bound result 724599213530681152\n  Bound result 678\n  Bound result 17777\n  Bound result 7766\n  Bound result 3943\n  Bound result 19712\n  Bound result 16761\n  Bound result 340023153681436\n  Bound result 699702388\n  Bound result 71828772520876749\n  Bound result 13891\n  Bound result 21730\n  Bound result 3340668342\n  Bound result 1459\n  Bound result 6424452771742860520\n  Bound result 81696\n  Bound result 2796492547\n  Bound result 8186\n  Bound result 1917\n  Bound result 2168\n  Bound result 18383\n  Bound result 2919\n  Bound result 10413\n  Bound result 1891705\n  Bound result 1395704055\n  Bound result 14\n  Bound result 7060\n  Bound result 6339\n  Bound result 32038\n  Bound result 3448068114\n  Bound result 993018925998\n  Bound result 199928171227479123251\n  Bound result 1918450\n  Bound result 7183\n  Bound result 1543\n  Bound result 386912898977421556381\n  Bound result 993018925998\n  Bound result 1944964287\n  Bound result 999999999999999995590\n  Bound result 999999999996985564472\n  Bound result 71280176580675663146\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.76s (8.75s CPU time)\n\nRan 17 test suites in 8.76s (22.33s CPU time): 120 tests passed, 0 failed, 0 skipped (120 total tests)\n","passed":true},{"durationMs":50,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"PlantOrganism.bind(address)\",\"PlantOrganism.challenge(uint32)\",\"PlantOrganism.checkpoint(uint32,address)\",\"PlantOrganism.claim()\",\"PlantOrganism.claim(uint32[])\",\"PlantOrganism.clearPending()\",\"PlantOrganism.die()\",\"PlantOrganism.heartbeat(uint256)\",\"PlantOrganism.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"PlantOrganism.park(uint32,uint256)\",\"PlantOrganism.redeem(uint256)\",\"PlantOrganism.rotate(address,address,bytes32,uint256,uint256,bytes)\",\"PlantOrganism.settle()\",\"PlantOrganism.settle(uint32)\",\"PlantOrganism.unpark(uint32,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":31,\"DEPENDENCIES.md\":7,\"README.md\":17,\"foundry.toml\":19,\"launch.json\":17,\"src/OracleAttestation.sol\":231,\"src/PlantOrganism.sol\":649,\"src/WeatherQuestion.sol\":83,\"src/interfaces/IIntake.sol\":14,\"test/GasAndDeployment.t.sol\":156,\"test/OracleConsumerConformance.t.sol\":125,\"test/PlantAdversarial.t.sol\":423,\"test/PlantAssumptions.t.sol\":110,\"test/PlantContractSigner.t.sol\":169,\"test/PlantFailureAtomicity.t.sol\":175,\"test/PlantInvariant.t.sol\":166,\"test/PlantLaunchRevision.t.sol\":174,\"test/PlantOrganism.t.sol\":905,\"test/PlantRewardOwnershipInvariant.t.sol\":265,\"test/PlantStateMachine.t.sol\":403,\"test/PlantVotingCommitment.t.sol\":196,\"test/PlantVotingRevision.t.sol\":226,\"test/README.md\":76,\"test/WeatherQuestion.t.sol\":36,\"test/fixtures/weather.json\":11,\"test/mocks/Mocks.sol\":139},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"c2e807ae0ca5f16d119cd33c7833e5ee8fe7a0defaf4b53f4d8de9e7113425ec","verifiedTreeHash":"a1dae5960358e652ac3788c82ed2690766345756","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":63043,"exitCode":0,"name":"build","output":"Compiling 58 files with Solc 0.8.26\nSolc 0.8.26 finished in 62.84s\nCompiler run successful!\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:12:21\n   │\n12 │         int16 lat = int16(uint16(cell >> 16));\n   │                     ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:12:27\n   │\n12 │         int16 lat = int16(uint16(cell >> 16));\n   │                           ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:13:21\n   │\n13 │         int16 lon = int16(uint16(cell));\n   │                     ━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:13:27\n   │\n13 │         int16 lon = int16(uint16(cell));\n   │                           ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:19:29\n   │\n19 │         uint256 magnitude = uint256(milli < 0 ? -milli : milli);\n   │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:26:29\n   │\n26 │             b[--i] = bytes1(uint8(48 + n % 10));\n   │                             ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:39:27\n   │\n39 │         uint256 y = yoe + era * 400;\n   │                           ━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:40:30\n   │\n40 │         uint256 doy = doe - (365 * yoe + yoe / 4 - yoe / 100);\n   │                              ━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/WeatherQuestion.sol:42:28\n   │\n42 │         uint256 d = doy - (153 * mp + 2) / 5 + 1;\n   │                            ━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:50:40\n   │\n50 │         string memory lat = coordinate(int16(uint16(cell >> 16)));\n   │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:50:46\n   │\n50 │         string memory lat = coordinate(int16(uint16(cell >> 16)));\n   │                                              ━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:51:40\n   │\n51 │         string memory lon = coordinate(int16(uint16(cell)));\n   │                                        ━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/WeatherQuestion.sol:51:46\n   │\n51 │         string memory lon = coordinate(int16(uint16(cell)));\n   │                                              ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:165:16\n    │\n165 │         return uint32(block.timestamp / 1 days);\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/PlantOrganism.sol:168:19\n    │\n168 │     function bind(address hook_) external nonReentrant {\n    │                   ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:204:25\n    │\n204 │         require(held <= uint256(type(int256).max) && reserved <= uint256(type(int256).max));\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:204:66\n    │\n204 │         require(held <= uint256(type(int256).max) && reserved <= uint256(type(int256).max));\n    │                                                                  ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:205:16\n    │\n205 │         return int256(held) - int256(reserved);\n    │                ━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:205:31\n    │\n205 │         return int256(held) - int256(reserved);\n    │                               ━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:210:24\n    │\n210 │         return p > 0 ? uint256(p) : 0;\n    │                        ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:506:13\n    │\n506 │             emit Checkpointed(holder, cell, credit);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:277:13\n    │\n277 │             emit Challenged(cell);\n    │             ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:247:9\n    │\n247 │         emit Parked(msg.sender, cell, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:265:9\n    │\n265 │         emit Unparked(msg.sender, cell, amount);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `pending` is updated\n    ╭▸ src/PlantOrganism.sol:301:14\n    │\n301 │           id = intake.request(\n    │ ┏━━━━━━━━━━━━━━┛\n302 │ ┃             action,\n303 │ ┃             requestBody(location, day),\n304 │ ┃             IIntake.Callback(address(this), this.onOracleResult.selector),\n305 │ ┃             address(IMD),\n306 │ ┃             price\n307 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:287:13\n    │\n287 │         if (block.timestamp < retryAt) revert RetryLater();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:297:13\n    │\n297 │             emit Advanced(msg.sender, advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:312:9\n    │\n312 │         emit Asked(id, day, location, challenger, msg.sender, price);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/PlantOrganism.sol:309:13\n    │\n309 │         if (IMD.balanceOf(address(this)) != beforeBalance - price) revert NonExactTransfer();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:311:54\n    │\n311 │             Pending(id, day, challenger, msg.sender, uint64(block.timestamp), address(intake), true, false, bytes32(0));\n    │                                                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:340:9\n    │\n340 │         emit Received(requestId, a.requestId, word);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:330:13\n    │\n330 │         if (uint32(w >> 96) != p.day) revert WrongDay();\n    │             ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:349:17\n    │\n349 │             if (block.timestamp < uint256(pending.askedAt) + ORACLE_TIMEOUT) revert NotTimedOut();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:360:9\n    │\n360 │         emit Cleared(id, day, retryAt);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:378:13\n    │\n378 │             emit EmptyCatchUp(day, end);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:392:13\n    │\n392 │             emit Incomplete(day, count);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:484:9\n    │\n484 │         emit Rewarded(cell, pool, reserved);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:453:13\n    │\n453 │             emit Moved(current, candidate);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:409:13\n    │\n409 │             emit Bounty(caller, bounty);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:546:13\n    │\n546 │             emit Paid(holder, credit, advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:552:13\n    │\n552 │             emit PaymentDeferred(holder, credit + advance);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:412:9\n    │\n412 │         emit Settled(day, word, sips, backing, water, location);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:400:30\n    │\n400 │         _distribute(oldCell, pool);\n    │                              ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:412:33\n    │\n412 │         emit Settled(day, word, sips, backing, water, location);\n    │                                 ━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:376:61\n    │\n376 │             uint32 end = hook == address(0) ? today() - 1 : uint32(Math.min(today() - 1, bindDay));\n    │                                                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint32' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/PlantOrganism.sol:429:17\n    │\n429 │         water = uint8(wet);\n    │                 ━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/PlantOrganism.sol:540:22\n    │\n540 │         if (credit + advance == 0) return;\n    │                      ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:569:9\n    │\n569 │         emit Redeemed(msg.sender, amount, payout, dead);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:584:13\n    │\n584 │             emit Died(today(), merged);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:586:13\n    │\n586 │             emit PotMerged(merged);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:616:13\n    │\n616 │         if (block.timestamp > deadline) revert RotationExpired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/OracleAttestation.sol:192:9\n    │\n192 │         emit OracleSignerSet(signer);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/PlantOrganism.sol:626:9\n    │\n626 │         emit Rotated(oldSigner, newSigner, newIntake, newAction, nonce);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/PlantOrganism.sol:640:16\n    │\n640 │         return block.timestamp < signerAcceptedUntil[signer]\n    │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/PlantOrganism.sol:647:13\n    │\n647 │         if (token.balanceOf(address(this)) != beforeBalance + amount) revert NonExactTransfer();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\n","passed":true},{"durationMs":9688,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 3 tests for test/WeatherQuestion.t.sol:WeatherQuestionTest\n[PASS] test_coordinatesAtEdgesAndNegativeZeroFraction() (gas: 40309)\n[PASS] test_exactLisbonBodyAndKnownDate() (gas: 15004)\n[PASS] test_exactNegativeLatitudeAndLongitudeBody() (gas: 15401)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 524.98µs (333.17µs CPU time)\n\nRan 4 tests for test/OracleConsumerConformance.t.sol:OracleConsumerConformanceTest\n[PASS] test_acceptsOriginalProtocolSignatureInCanonicalVerifier() (gas: 117620)\n[PASS] test_bytes32WeatherFixtureAcceptedUnderStipend() (gas: 2374304)\n[PASS] test_callbackSelectorIsCanonical() (gas: 3543)\n[PASS] test_digestMatchesTheProtocol() (gas: 13193)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 2.51ms (1.24ms CPU time)\n\nRan 8 tests for test/PlantLaunchRevision.t.sol:PlantLaunchRevisionTest\n[PASS] test_firstEpochFlashCannotEarnGardenersAtOrigin() (gas: 3205912)\n[PASS] test_firstEpochFlashCannotMoveOrEarnGardenersAtDestination() (gas: 3296976)\n[PASS] test_lateBindSkipsThroughBindDayAndRequestsOnlyFirstFullDay() (gas: 1583927)\n[PASS] test_originFromRealCoordinatesRoundTripsThroughCentre() (gas: 69533)\n[PASS] test_repricingCannotExceedAdvanceCapAndZeroCapUsesPot() (gas: 1109177)\n[PASS] test_rotationDeadlineIsSignedAndAcceptedAtExactBoundary() (gas: 171401)\n[PASS] test_timeoutAfterDeathCannotAdvanceDayOrRevive() (gas: 1094998)\n[PASS] test_timeoutsAndIncompleteShareCounterAndReadRepairedCandidate() (gas: 4167787)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 6.49ms (6.59ms CPU time)\n\nRan 4 tests for test/PlantOrganism.t.sol:PlantRotationTest\n[PASS] test_oldSignerExpiresAtThirtyDaysWhileNewSignerKeepsPlantAlive() (gas: 20361389)\n[PASS] test_onlyCurrentSignerCanRotateNonceCannotReplay() (gas: 1143484)\n[PASS] test_pendingIntakeAndOldSignerWorkAfterRotation() (gas: 4442836)\n[PASS] test_rotationDomainBindsAllFieldsAndContract() (gas: 972590)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 20.25ms (23.20ms CPU time)\n\nRan 8 tests for test/PlantVotingCommitment.t.sol:PlantVotingCommitmentTest\n[PASS] testFuzz_withdrawalAndRedepositCannotIncreasePower(uint96,uint96) (runs: 256, μ: 3217660, ~: 3218643)\nLogs:\n  Bound result 3\n  Bound result 3348710204410901\n\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotCaptureGardenersPool() (gas: 5232170)\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotMove() (gas: 4237584)\n[PASS] test_borrowingAtBothHeartbeatAndSettleCannotVeto() (gas: 3186257)\n[PASS] test_loanAcrossPreviousSettleLosesPowerOnWithdrawal() (gas: 3769733)\n[PASS] test_rearmedDecoyCannotHideHoldersCandidate() (gas: 3393181)\n[PASS] test_thresholdUsesCommittedStakeAndNewDepositsMatureAtSettle() (gas: 4167601)\n[PASS] test_timeoutAndReaskCannotRestoreWithdrawnPower() (gas: 3455480)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 333.36ms (260.03ms CPU time)\n\nRan 12 tests for test/PlantOrganism.t.sol:PlantOracleTest\n[PASS] test_blockedKeeperDoesNotBlockSettleAndCanClaimLater() (gas: 2728727)\n[PASS] test_callbackSenderIdAndReplay() (gas: 2851277)\n[PASS] test_callbackStoresOnlyAndFitsStipend() (gas: 2435581)\nLogs:\n  callback gas including mock encoding: 87722\n\n[PASS] test_clearIncompleteUsesSameCounterAndCannotDiscardComplete() (gas: 2831155)\n[PASS] test_exactApprovalAndIntakeBody() (gas: 2096455)\n[PASS] test_feeAdvanceTracksDeficitThenRepaidAtSettle() (gas: 2826449)\n[PASS] test_incompleteHasNoBiologicalChangesThenThirdReads() (gas: 4060624)\n[PASS] test_intakeMustPullExactPrice() (gas: 1933599)\n[PASS] test_rejectsExpiredWrongDomainSignerTypeDayChainAndPanel() (gas: 3117187)\n[PASS] test_rejectsPreAskFutureTamperedAndMalformedAttestations() (gas: 2865952)\n[PASS] test_timeoutClearsAndWaitsSixHoursToReaskSameDay() (gas: 2890085)\n[PASS] test_unfundedAdvanceDoesNotSpendBackingOrBlockSettle() (gas: 3389963)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 419.98ms (19.65ms CPU time)\n\nRan 6 tests for test/GasAndDeployment.t.sol:GasAndDeploymentTest\n[PASS] test_coldCallbackAndMaxHoursMoveSettleGas() (gas: 3761853)\nLogs:\n  cold callback gas: 87722\n\n[PASS] test_coldMaxHoursWithRepairedCandidateSettleGas() (gas: 3788592)\n[PASS] test_requestedStaticConstructorAndForbiddenOpcodes() (gas: 8419315)\n[PASS] test_settlementFitsStipendWithManyEligibleHolders() (gas: 38964884)\n[PASS] test_thirdIncompleteMoveAndAdvancePaymentGas() (gas: 4681569)\n[PASS] test_thirdTimeoutMoveAndAdvancePaymentFitsColdStipend() (gas: 4172834)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 423.03ms (71.60ms CPU time)\n\nRan 4 tests for test/PlantContractSigner.t.sol:PlantContractSignerTest\n[PASS] test_canRotateToContractAndRejectInvalidOrRevokedSignatures() (gas: 2069553)\n[PASS] test_constructorContractAttestationAndRotationFitCallbackStipend() (gas: 2468829)\nLogs:\n  cold ERC-1271 callback gas: 91097\n\n[PASS] test_multiplePriorContractSignersKeepGraceWithoutRotationAuthority() (gas: 3391483)\n[PASS] test_previousContractGraceExpiresAtThirtyDays() (gas: 18714785)\nSuite result: ok. 4 passed; 0 failed; 0 skipped; finished in 423.01ms (20.91ms CPU time)\n\nRan 9 tests for test/PlantOrganism.t.sol:PlantLifecycleTest\n[PASS] test_bindIsOnceAndOnlyDeployerWithMatchingHook() (gas: 325761)\n[PASS] test_cellBoundsAndZeroRejected() (gas: 619172)\n[PASS] test_challengerOnlyStrictlyLargerAndCanBeRepaired() (gas: 3100639)\n[PASS] test_deathIsFinalAtThirtyDaysAndKeepsExits() (gas: 3253705)\n[PASS] test_deathUsesBindDayAfterLongUnboundPeriod() (gas: 285441)\n[PASS] test_moveUsesPendingCandidateAndRemainingCommittedBalances() (gas: 3834625)\n[PASS] test_noEarlyOrOutOfOrderSettleAndHeartbeat() (gas: 1001410)\n[PASS] test_preBindDaysSkipInOneCallWithoutRead() (gas: 594150)\n[PASS] test_unboundCatchUpIsBoundedAtOrigin() (gas: 149389)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 423.07ms (8.59ms CPU time)\n\nRan 7 tests for test/PlantAssumptions.t.sol:PlantAssumptionsTest\n[PASS] test_explicitZeroCellQuestionRemainsInvalid() (gas: 19566)\n[PASS] test_oldRotationSignatureExpires() (gas: 834939)\n[PASS] test_oldSourceWindowBacklogIsAlreadyDead() (gas: 1633703)\n[PASS] test_preBindDonationsHaveNoExit() (gas: 196044)\n[PASS] test_redeemedSupplyIsExcludedFromThreshold() (gas: 4409701)\n[PASS] test_rotatedIntakeCannotPullAboveKeeperCap() (gas: 2192042)\n[PASS] test_threeSilentRequestsSettleEmptyAndMoveWithRetainedStake() (gas: 3430671)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 425.53ms (7.33ms CPU time)\n\nRan 12 tests for test/PlantOrganism.t.sol:PlantRewardsTest\n[PASS] testFuzz_floorConservationAndBurnCustody(uint96,uint96,uint24) (runs: 1000, μ: 2977898, ~: 2991154)\nLogs:\n  Bound result 23698\n\n[PASS] testFuzz_hourlyAccountingMatchesIndependentModel(uint24,uint24) (runs: 1000, μ: 2444297, ~: 2446523)\n[PASS] test_departuresDropOutAndReparkingCannotCaptureDay() (gas: 4736914)\n[PASS] test_finalRedemptionDoesNotDivideByZeroOrReleaseBurnedPlant() (gas: 3092689)\n[PASS] test_gardenerDustRoundsToBackingAndAccountsCloseExactly() (gas: 5878819)\n[PASS] test_hourZeroFirstRainCapAndSunRequiresWater() (gas: 5456711)\n[PASS] test_noGardenersSendsEntireSipToBacking() (gas: 1282225)\n[PASS] test_nonExactTokenTransfersRejected() (gas: 274408)\n[PASS] test_oldCellKeepsItsRewardsAfterMoveAndLazyActivation() (gas: 6423632)\n[PASS] test_parkSettleClaimProRataAndMidDayJoinsWaitOneSettle() (gas: 3822066)\n[PASS] test_redeemRetainsPlantAndTenPercentAndFloorMonotonic() (gas: 2843146)\n[PASS] test_reentrancyFromTokensAndIntakeBlocked() (gas: 2932391)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 425.57ms (636.04ms CPU time)\n\nRan 21 tests for test/PlantAdversarial.t.sol:PlantAdversarialTest\n[PASS] testFuzz_parkUnparkRoundTripCannotEarnWithoutSettlement(uint96,uint8) (runs: 1000, μ: 2583166, ~: 2304873)\nLogs:\n  Bound result 14264337593543950335\n  Bound result 13\n\n[PASS] testFuzz_reservedWeatherBitsRejectedWithoutMutatingPending(uint8) (runs: 1000, μ: 2076526, ~: 2076517)\n[PASS] testFuzz_signedMalformedPanelsAreRejected(uint8) (runs: 1000, μ: 2073187, ~: 2073062)\n[PASS] test_answerMustBeExactlyOneWordIncludingTrailingData() (gas: 2214466)\n[PASS] test_bindRejectsNonContractWrongAndEmptyTokens() (gas: 1569232)\n[PASS] test_callbackAndSettlementEventsDescribeTheAppliedResult() (gas: 2322430)\n[PASS] test_consumedOracleUuidCannotBeReusedForSameDayRetry() (gas: 2894895)\n[PASS] test_deathClearsPendingAndPreservesGardenersAndFeeDebt() (gas: 3492243)\n[PASS] test_deferredAdvanceAndBountyRemainClaimableExactlyOnce() (gas: 2861807)\n[PASS] test_depositAfterAskMustMatureBeforeItCanChallenge() (gas: 3218117)\n[PASS] test_exactClockDriftToleranceAccepted() (gas: 2070016)\n[PASS] test_moveRewardsDepartingCellAndNeverIncomingCellForSameDay() (gas: 4097478)\n[PASS] test_moveThresholdRoundsUpWhenSupplyNotDivisibleByTwenty() (gas: 3760778)\n[PASS] test_rejectedResultCanBeCorrectedWithoutBurningRequest() (gas: 2366731)\n[PASS] test_rotatedIntakeCannotAnswerPreviousIntakesRequest() (gas: 4097733)\n[PASS] test_thirdIncompleteReadsCandidateFromLatestRequest() (gas: 4360276)\n[PASS] test_timeoutExactSecondAndOldResultCannotPoisonReask() (gas: 2561998)\n[PASS] test_twoKeepersAdvancesSurviveTimeoutAndOnlyUnlockOnSettlement() (gas: 3313848)\n[PASS] test_unparkAfterCallbackDropsOutBeforeHoursAndKeepsPreviousReward() (gas: 3265833)\n[PASS] test_validityWindowBoundariesAndAskedAt() (gas: 2467555)\n[PASS] test_zeroAmountsAndOverdrawCannotChangeCustody() (gas: 1831479)\nSuite result: ok. 21 passed; 0 failed; 0 skipped; finished in 425.50ms (1.29s CPU time)\n\nRan 13 tests for test/PlantVotingRevision.t.sol:PlantVotingRevisionTest\n[PASS] testFuzz_repeatedTopUpsCannotIncreaseCommittedStake(uint96) (runs: 1000, μ: 3706343, ~: 3706223)\nLogs:\n  Bound result 20879\n\n[PASS] testFuzz_withdrawalUsesOwnQueuedStakeBeforeCommitment(uint96) (runs: 1000, μ: 3118071, ~: 3119287)\nLogs:\n  Bound result 14124\n\n[PASS] test_atomicCurrentCellTopUpCannotVetoCommittedCandidate() (gas: 3018336)\n[PASS] test_atomicDestinationTopUpCannotMoveOrCaptureRewards() (gas: 4477080)\n[PASS] test_currentCellWithdrawalBreaksTieForCommittedCandidate() (gas: 2885101)\n[PASS] test_emptyCapturedCandidateFallsBackToRepairedLiveCandidate() (gas: 3251245)\n[PASS] test_fallbackCannotUseNewPostHeartbeatStake() (gas: 3737380)\n[PASS] test_questionUsesOriginFromDeployment() (gas: 1699977)\n[PASS] test_replacementHolderCannotInheritWithdrawnVotingPower() (gas: 3943756)\n[PASS] test_thirdIncompleteAlsoUsesRepairedCandidate() (gas: 4822108)\n[PASS] test_thirdIncompleteReadsBeforePromotingFreshDeposits() (gas: 4742317)\n[PASS] test_timeoutRetryCannotMatureRequestOrCooldownDeposits() (gas: 4176489)\n[PASS] test_withdrawalRemovesPowerAndReaskCannotRestoreIt() (gas: 4308944)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 425.56ms (867.34ms CPU time)\n\nRan 1 test for test/PlantInvariant.t.sol:PlantInvariantTest\n[PASS] invariant_conservationAndPermanentBurnCustody() (runs: 128, calls: 8192, reverts: 0)\n\n╭--------------+---------------+-------+---------+----------╮\n| Contract     | Selector      | Calls | Reverts | Discards |\n+===========================================================+\n| PlantHandler | challenge     | 1070  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | checkpointAll | 970   | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | claim         | 1005  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | fund          | 1026  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | park          | 980   | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | redeem        | 1067  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | unpark        | 1021  | 0       | 0        |\n|--------------+---------------+-------+---------+----------|\n| PlantHandler | weather       | 1053  | 0       | 0        |\n╰--------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 6305\n  Bound result 5417\n  Bound result 4302\n  Bound result 514264337593543944029\n  Bound result 3030\n  Bound result 1373\n  Bound result 15368\n  Bound result 9092\n  Bound result 244920209213592906543\n  Bound result 1582\n  Bound result 12280\n  Bound result 2844\n  Bound result 695\n  Bound result 3938172395\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.12s (2.12s CPU time)\n\nRan 1 test for test/PlantStateMachine.t.sol:PlantStateMachineInvariantTest\n[PASS] invariant_independentCustodyAndSolvency() (runs: 256, calls: 24576, reverts: 0)\n\n╭--------------------------+---------------+-------+---------+----------╮\n| Contract                 | Selector      | Calls | Reverts | Discards |\n+=======================================================================+\n| PlantStateMachineHandler | answer        | 2143  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | challenge     | 2123  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | claim         | 2026  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | clear         | 2030  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | donate        | 1958  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | elapse        | 2083  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | park          | 2050  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | redeem        | 2025  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | request       | 2085  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | settle        | 2012  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | transferPlant | 2024  | 0       | 0        |\n|--------------------------+---------------+-------+---------+----------|\n| PlantStateMachineHandler | unpark        | 2017  | 0       | 0        |\n╰--------------------------+---------------+-------+---------+----------╯\n\nLogs:\n  Bound result 3000000000000000000\n  Bound result 200000000000000000000\n  Bound result 36602848819195607904\n  Bound result 4800\n  Bound result 21102\n  Bound result 20945\n  Bound result 1080644451\n  Bound result 13744152130770255309\n  Bound result 59751324585180392452\n  Bound result 11131\n  Bound result 13230\n  Bound result 16711680\n  Bound result 5275\n  Bound result 681321222936012177508\n  Bound result 12429\n  Bound result 404098526\n  Bound result 104639\n  Bound result 686\n  Bound result 13105\n  Bound result 24111\n  Bound result 180862945276902410476\n  Bound result 10324\n  Bound result 17947\n  Bound result 1\n  Bound result 1550\n  Bound result 30\n  Bound result 2\n  Bound result 1015914139986\n  Bound result 2324\n  Bound result 23292\n  Bound result 58375885185064659310\n  Bound result 11576\n  Bound result 6\n  Bound result 273\n  Bound result 15\n  Bound result 19638\n  Bound result 2416767184\n  Bound result 59381545440416094529\n  Bound result 1734516070\n  Bound result 547\n  Bound result 12038\n  Bound result 921587032743752237996\n  Bound result 2167\n  Bound result 21587\n  Bound result 6786\n  Bound result 110379595858208664027\n  Bound result 200000000000000000000\n  Bound result 12429\n  Bound result 59381545440820224107\n  Bound result 1015914139986\n  Bound result 610\n  Bound result 6786\n  Bound result 180862945276902410476\n  Bound result 723131341373064298889\n  Bound result 999999999999999978508\n  Bound result 208299181205779190491\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 9.58s (9.58s CPU time)\n\nRan 15 test suites in 9.58s (15.46s CPU time): 113 tests passed, 0 failed, 0 skipped (113 total tests)\n","passed":true},{"durationMs":71,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"PlantOrganism.bind(address)\",\"PlantOrganism.challenge(uint32)\",\"PlantOrganism.checkpoint(uint32,address)\",\"PlantOrganism.claim()\",\"PlantOrganism.claim(uint32[])\",\"PlantOrganism.clearPending()\",\"PlantOrganism.die()\",\"PlantOrganism.heartbeat(uint256)\",\"PlantOrganism.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"PlantOrganism.park(uint32,uint256)\",\"PlantOrganism.redeem(uint256)\",\"PlantOrganism.rotate(address,address,bytes32,uint256,uint256,bytes)\",\"PlantOrganism.settle()\",\"PlantOrganism.settle(uint32)\",\"PlantOrganism.unpark(uint32,uint256)\"],\"files\":{\".gitignore\":3,\"ADAPTATION.md\":31,\"DEPENDENCIES.md\":7,\"README.md\":17,\"foundry.toml\":19,\"launch.json\":17,\"src/OracleAttestation.sol\":231,\"src/PlantOrganism.sol\":649,\"src/WeatherQuestion.sol\":83,\"src/interfaces/IIntake.sol\":14,\"test/GasAndDeployment.t.sol\":156,\"test/OracleConsumerConformance.t.sol\":125,\"test/PlantAdversarial.t.sol\":423,\"test/PlantAssumptions.t.sol\":110,\"test/PlantContractSigner.t.sol\":169,\"test/PlantInvariant.t.sol\":166,\"test/PlantLaunchRevision.t.sol\":174,\"test/PlantOrganism.t.sol\":905,\"test/PlantStateMachine.t.sol\":403,\"test/PlantVotingCommitment.t.sol\":196,\"test/PlantVotingRevision.t.sol\":226,\"test/README.md\":57,\"test/WeatherQuestion.t.sol\":36,\"test/fixtures/weather.json\":11,\"test/mocks/Mocks.sol\":139},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":4813,"exitCode":0,"name":"slither","output":"[high/medium] reentrancy-balance at src/PlantOrganism.sol:281: Reentrancy in PlantOrganism.heartbeat(uint256) (src/PlantOrganism.sol#281-313):\n[medium/medium] divide-before-multiply at src/WeatherQuestion.sol:33: WeatherQuestion.date(uint32) (src/WeatherQuestion.sol#33-46) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/WeatherQuestion.sol:33: WeatherQuestion.date(uint32) (src/WeatherQuestion.sol#33-46) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/WeatherQuestion.sol:33: WeatherQuestion.date(uint32) (src/WeatherQuestion.sol#33-46) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/PlantOrganism.sol:372: PlantOrganism._settle(bool) (src/PlantOrganism.sol#372-413) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/PlantOrganism.sol:531: PlantOrganism._pay(address) (src/PlantOrganism.sol#531-554) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/PlantOrganism.sol:281: Reentrancy in PlantOrganism.heartbeat(uint256) (src/PlantOrganism.sol#281-313):\n[medium/medium] uninitialized-local at src/PlantOrganism.sol:389: PlantOrganism._settle(bool).sips (src/PlantOrganism.sol#389) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PlantOrganism.sol:533: PlantOrganism._pay(address).advance (src/PlantOrganism.sol#533) is a local variable never initialized\n[medium/medium] uninitialized-local at src/PlantOrganism.sol:388: PlantOrganism._settle(bool).pool (src/PlantOrganism.sol#388) is a local variable never initialized\n[medium/medium] unused-return at src/PlantOrganism.sol:631: PlantOrganism._isValidAttestationSignature(bytes32,bytes) (src/PlantOrganism.sol#631-637) ignores return value by (recovered,err,None) = ECDSA.tryRecoverCalldata(digest,sig) (src/PlantOrganism.sol#633)\n[low/medium] timestamp at src/PlantOrganism.sol:639: PlantOrganism._graceSignature(address,bytes32,bytes) (src/PlantOrganism.sol#639-642) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:415: PlantOrganism._hours(uint256) (src/PlantOrganism.sol#415-430) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:183: PlantOrganism.isDead() (src/PlantOrganism.sol#183-185) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:631: PlantOrganism._isValidAttestationSignature(bytes32,bytes) (src/PlantOrganism.sol#631-637) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:604: PlantOrganism.rotate(address,address,bytes32,uint256,uint256,bytes) (src/PlantOrganism.sol#604-627) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:343: PlantOrganism.clearPending() (src/PlantOrganism.sol#343-353) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:372: PlantOrganism._settle(bool) (src/PlantOrganism.sol#372-413) uses timestamp for comparisons\n[low/medium] timestamp at src/OracleAttestation.sol:157: OracleAttestationConsumer._verifyAttestation(OracleAttestation.Attestation,bytes) (src/OracleAttestation.sol#157-165) uses timestamp for comparisons\n[low/medium] timestamp at src/PlantOrganism.sol:281: PlantOrganism.heartbeat(uint256) (src/PlantOrganism.sol#281-313) uses timestamp for comparisons","passed":true},{"durationMs":679,"exitCode":0,"name":"aderyn","output":"[high] reentrancy-state-change at src/PlantOrganism.sol:171: Reentrancy: State change after external call (8 places)\n[low] costly-loop at src/PlantOrganism.sol:525: Costly operations inside loop\n[low] empty-require-revert at src/PlantOrganism.sol:204: Empty `require()` / `revert()` Statement\n[low] internal-function-used-once at src/OracleAttestation.sol:205: Internal Function Used Only Once (4 places)\n[low] literal-instead-of-constant at src/PlantOrganism.sol:325: Literal Instead of Constant (43 places)\n[low] local-variable-shadowing at src/PlantOrganism.sol:63: Local Variable Shadows State Variable (4 places)\n[low] uninitialized-local-variable at src/PlantOrganism.sol:418: Uninitialized Local Variable (2 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"f49120bc135b3e9c592dc485cdc9218015e256816acc1b0ccbf2752176e9e14b","verifiedTreeHash":"e28e2027dc533c828d69c64375e31405b3487db1","verifierVersion":"0.1.0+ad90ce4c"}]}