{"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":"ab593214-f31a-41a3-a0e4-77dccebdd6bd","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"332bf9a5e98c947a9ba513fd40b1e9f577d50c910a1f6b4f7155d9bbb8763208","dependsOn":["audit_imported_code"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"ea5db8ea23a93d7611f9ab749d6255ad6596ee76a985c1261d43e63612dfc3cf","skillId":"adapt-contract-project","tools":[]},"key":"adapt_contract_project","kind":"code","role":"implement","skillHash":"ea5db8ea23a93d7611f9ab749d6255ad6596ee76a985c1261d43e63612dfc3cf","skillId":"adapt-contract-project","state":"accepted"},{"acceptedSubmissionHash":"81c78b2151d454cb800cbc7ddc51e1f70aebe8bdd050eb4a18c022eb17d1a840","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"db250a8a68fc80735efd456f2f350423916dc89e32cb4ba923c60fd78c28e3f1","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"ff7b8b127d7f182ce51a965836774e4129bd8f12a76075a342cfd0de929d27d8","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"b72293c3366fff3f0b93151bca72cc6cbd189dad31d1ccd1d34dd483f2165a36","skillId":"audit-imported-code","subagents":4,"tools":[]},"key":"audit_imported_code","kind":"code","role":"review","skillHash":"b72293c3366fff3f0b93151bca72cc6cbd189dad31d1ccd1d34dd483f2165a36","skillId":"audit-imported-code","state":"accepted"},{"acceptedSubmissionHash":"a8ea26cb28cd0483a9c3342564aabb1361d9ff28aa676a28b12b8d201d8158c2","dependsOn":["adapt_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"b89279670f5a00f5d26286edee00c97dd158b997031350a01cafe6e0329ad227","skillId":"audit-judge","subagents":4,"tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"b89279670f5a00f5d26286edee00c97dd158b997031350a01cafe6e0329ad227","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"3efbfa9a310de5a18b8e5bb07b4cfff80aba537b9d218ff810ee6ed597929894","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"7537d913d42f760989be3559e277d3f9639f6958e6f0b981284de47e685e1aad","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","subagents":3,"tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"bc5bfc8455464381f2db18badb2b55cf8bec1e535c019349a0378fa990741171","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"b43f3fdfd8a5068ac55899e50e3d22926aa3f32fa8e1c827863e1e634fd1a8df","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"697a14badd0f371bdda7a4e7bcaffb79e9f1f2149eb5b1fb1571b04c18e346a2","dependsOn":["adapt_contract_project"],"execution":{"forkChains":[1],"network":false,"profile":"foundry","requires":[],"skillHash":"606842ccca0e7c5d3017a54684625438eab9b351eb51dcf0cf88c43d1ea41464","skillId":"write-foundry-tests","subagents":4,"tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"606842ccca0e7c5d3017a54684625438eab9b351eb51dcf0cf88c43d1ea41464","skillId":"write-foundry-tests","state":"accepted"}],"objective":"Deploy the profiles contract of moneycanbuy.fun as it is: Profiles, an evm_contracts launch from this repository on Ethereum mainnet (no token), one contract. No core contract reads it and it reads no core contract; it calls two Ethereum mainnet contracts given to its constructor.\n\nContracts, in this order:\n1. Profiles, constructorArgs [\"0xAdfe6bd2C17dB514241e1A9B3342F88876073B7F\", \"0x00000000000000447e69651d841bD8D104Bed493\"]\n\nThe first argument is textRules: the TextRules helper of moneycanbuy.fun on Ethereum mainnet (its runtime code is src/helpers/TextRules.sol of this repository); Profiles calls only its pure checkScreenshotUrl(string). The second is delegateRegistry: the delegate.xyz v2 registry; Profiles calls only checkDelegateForERC721(address,address,address,uint256,bytes32).\n\nProfiles keeps one display name and one picture per wallet. set(name, pic, nft, tokenId, link) replaces the caller's whole record and emits ProfileSet; clear() erases it, frees its name at once and emits ProfileCleared. A name is 3..20 bytes of A-Z a-z 0-9 _, not starting with 0x or 0X, otherwise BadName. Names are unique by skeleton: lower case, _ dropped, 0 becomes o, 1 and i become l; the skeleton has at least 3 characters (BadName), a skeleton held by another wallet reverts NameTaken. These 17 skeletons are reserved for nobody and revert NameReserved, compared as whole skeletons only (a name that merely contains one is allowed): moneycanbuy, moneycanbuyfun, mcb, lmd, lmdfun, swarm, yolo, admln, offlclal, support, team, treasury, oracle, mod, moderator, system, deployer. The name may be empty when there is a picture; name and picture both empty reverts BadName. pic 0 none (nft, tokenId and link empty); pic 1 an ERC-721 and pic 2 an ERC-1155 token (link empty, nft must answer supportsInterface 0x80ac58cd or 0xd9b67a26, the caller must hold tokenId now, for ERC-721 also through a delegate.xyz v2 delegation, otherwise NotNftOwner); pic 3 an https link (nft and tokenId zero) accepted by textRules.checkScreenshotUrl, whose errors HostNotAllowed and BadEvidence pass through unchanged; anything else BadPicture. Every call to a token contract or the registry is a STATICCALL capped at CALL_GAS = 30000 gas that reads 32 bytes; a failure counts as not owned. profileOf(user) returns (name, pic, nft, tokenId, link, owned, since) with owned re-checked on every read (true for a link, false for none); profilesOf(users) returns one per address; ownerOfName(name) returns the wallet holding that skeleton, address(0) when free or invalid. Hiding a profile is not part of this contract: the site's hide list HiddenList takes (the Profiles address, 3, the wallet as uint160) like any other item.\n\nFixed parameters, fail, don't change: the two constructor arguments above, in this order; the name rules, the skeleton mapping and exactly the 17 reserved skeletons above, none added or removed and no substring match; PIC_NONE() = 0, PIC_ERC721() = 1, PIC_ERC1155() = 2, PIC_LINK() = 3, CALL_GAS() = 30000; the functions set(string,uint8,address,uint256,string), clear(), profileOf(address), profilesOf(address[]), ownerOfName(string), nameOwner(bytes20), textRules(), delegateRegistry(), with the return tuple of profileOf in the order above; the events ProfileSet(address indexed user, string name, uint8 pic, address nft, uint256 tokenId, string link) and ProfileCleared(address indexed user); the errors BadName(), NameTaken(), NameReserved(), BadPicture(), NotNftOwner(), ZeroAddress(), HostNotAllowed(), BadEvidence(). The site decodes exactly these; if a reproduced finding would need any of them changed, fail the job instead of changing it.\n\nProfiles has no owner, no admin, no role, no pause and no upgrade path; no payable function, no receive or fallback, no token transfer; it holds no money. The constructor only stores the two addresses (textRules must not be zero, ZeroAddress).\n\nKnown limitations (accepted rules, not findings): anyone may set a profile, gas is the only cost and a free name goes to the first wallet that takes it; a name stays with its wallet when the picture token is sold, only owned turns false; the picture token is any contract that answers the checks, a token contract that reverts, burns gas or returns a large payload only makes its own owned false; the link is checked by host and length only, not by content; names are not filtered beyond the charset, the skeleton and the reserved list.\n\nThe tests must keep passing: forge test (35 tests: 34 in test/Profiles.t.sol, the fork test is skipped without FORK_URL); test/fork/ProfilesFork.t.sol runs against the two constructor contracts on a mainnet fork (FORK_URL). This commit holds only Profiles, the TextRules helper and their tests.\n\nAudit it as it arrived. Adapt only what the launch rules or a reproduced audit finding require, and record each change in ADAPTATION.md. Do not change the fixed parameters above, and do not add an owner, a pause, an upgrade path, a fee, a payable function or a token transfer.\nKnown limitations listed in docs are accepted rules, not findings; do not change them.","parentJobId":null,"planHash":"ae1ff3090eb9db4f609a0ec2d7a1417a316886f025c45177fb8391d94dddb180","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"ab593214-f31a-41a3-a0e4-77dccebdd6bd","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-2726-deploy-profiles-contract-moneycanbuy-fun"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51407","feedbackHash":"f64491df94f7eb3ac1252884eb77aa2cee6a44f4df9cb2b02928a93c8a209fa8","nodeKey":"adapt_contract_project","submissionHash":"332bf9a5e98c947a9ba513fd40b1e9f577d50c910a1f6b4f7155d9bbb8763208","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52585","feedbackHash":"3d3dac0b56a3727416fbcb768b883cfc17b7b592e9e5ee701f3f9d3f7661b3ad","nodeKey":"audit_economics","submissionHash":"81c78b2151d454cb800cbc7ddc51e1f70aebe8bdd050eb4a18c022eb17d1a840","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52672","feedbackHash":"deedc5870c75d9208719fc2938dedf7e71c64aaa2010779f562c38c0a669812b","nodeKey":"audit_flow","submissionHash":"db250a8a68fc80735efd456f2f350423916dc89e32cb4ba923c60fd78c28e3f1","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52596","feedbackHash":"a1b3dc5f13baf6a035992ca9d5f5813ecc05ec36beb8dd447547e09609f18932","nodeKey":"audit_imported_code","submissionHash":"ff7b8b127d7f182ce51a965836774e4129bd8f12a76075a342cfd0de929d27d8","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52616","feedbackHash":"1402b2b781750a299332f9fa31cfedd64b53787a5b628bef723360a7c4e58cc7","nodeKey":"audit_judge","submissionHash":"a8ea26cb28cd0483a9c3342564aabb1361d9ff28aa676a28b12b8d201d8158c2","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51878","feedbackHash":"68f8fdda2253fe3e306fcfc8fa3ee80da288d12f67d8d9cabf4d2690a8dfca22","nodeKey":"audit_math","submissionHash":"3efbfa9a310de5a18b8e5bb07b4cfff80aba537b9d218ff810ee6ed597929894","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51879","feedbackHash":"227ac43cc1fffb836a35ba87a2eae35405861f4f4d813abd8ba073e7cec2e1d5","nodeKey":"audit_permissions","submissionHash":"7537d913d42f760989be3559e277d3f9639f6958e6f0b981284de47e685e1aad","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52233","feedbackHash":"a6276d6e27d29c7dfc2110772a479078117d963a02496c50e06e762d717c6f23","nodeKey":"manifest","submissionHash":"b43f3fdfd8a5068ac55899e50e3d22926aa3f32fa8e1c827863e1e634fd1a8df","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51155","feedbackHash":"14293be6952d0d20214f0559659abb009618040f8aa7a5ab29abe937072c5e9b","nodeKey":"write_foundry_tests","submissionHash":"697a14badd0f371bdda7a4e7bcaffb79e9f1f2149eb5b1fb1571b04c18e346a2","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"7926fbbb185a740481c63fa1478bfb9a6ef2f4ea7200c2c7863863e4c85b79b8","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"d92c7089b9c5618a166dfeba3a032a45970ad3b85ee44f9a3d58b180e9c845b0","device":"06cf148faa51546b","findings":[],"hash":"332bf9a5e98c947a9ba513fd40b1e9f577d50c910a1f6b4f7155d9bbb8763208","nodeId":"8150aa5f-a30c-4ecf-8a23-b8fe5a77b453","outcome":"completed","summary":"Profiles meets the launch requirements without production changes. Added 10 factory/audit tests and recorded the review in [ADAPTATION.md](/home/imd-worker/.identitymd/work/ab593214-f31a-41a3-a0e4-77dccebdd6bd/8150aa5f-a30c-4ecf-8a23-b8fe5a77b453/ADAPTATION.md).\n\nValidation with the required fuzz seed:\n\n- `forge build`: passed.\n- `forge test`: **44 passed, 0 failed, 1 skipped**.\n\nThe mainnet fork suite skipped because `FORK_URL` is unset. No transaction was broadcast.","treeHash":"58276e381647ca107cbd3147a2b930dbe39dcd78","usage":{"cachedInputTokens":1241856,"inputTokens":98210,"model":"gpt-6-astra","outputTokens":14797,"runtime":"codex","turns":7,"wallClockMs":502250}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"00920b27421b9a80","findings":[],"hash":"338706e4fb8e3b1d7d47f798cc01920c529a2a76258b749f9decb2450e6e7a6c","nodeId":"ef8324a0-c89b-4336-8e5f-b95bdbcfca73","outcome":"failed","summary":"Claude Code can't use your Claude subscription, usually because a payment is past due · Pay or renew at https://claude.ai/… (if you just paid, try again shortly), or use an Anthropic API key instead","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":null,"outputTokens":0,"runtime":"claude","turns":1,"wallClockMs":1610}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"2a6239e0c1b8c774","findings":[{"citation":"resolved","description":"Boundary (external-call gas corner case) x invariant seam. Every token read is a STATICCALL with exactly CALL_GAS = 30000 gas (src/Profiles.sol:29, :257) and any failure, including out-of-gas inside the token, counts as not owned (src/Profiles.sol:238, :251), which set() turns into NotNftOwner (src/Profiles.sol:224). The brief frames this cap as protection against a token contract that 'reverts, burns gas or returns a large payload'. It also fires on a very common, entirely honest ERC-721 implementation: ERC721A (chiru-labs) stores the owner only at the first token of a batch mint and its ownerOf(tokenId) walks backwards through _packedOwnerships[--tokenId] until it finds a non-zero slot, one cold SLOAD (2100 gas) per step. Arithmetic: the call starts with two cold SLOADs (the queried slot and _currentIndex, 4200) plus ~1000 of dispatch and loop overhead, then 2100 per step back; 30000 is exhausted at about 12 steps. Measured with a faithful model of that loop (test/scratch/ProfilesCallGas.t.sol): ownerOf of offsets 0..19 of a 20-token batch costs 5285, 9621, 11824, ... 29441 (offset 10), 31642 (offset 11), ... 49260 (offset 19) gas; under a 30000 cap offsets 0..11 succeed and offsets 12..19 run out of gas. Consequence: a wallet that minted a batch of 20 ERC721A tokens (or holds one that was never transferred token by token) cannot set tokens 12..19 of that batch as its picture: set() reverts NotNftOwner although ownerOf(tokenId) returns that wallet. Since ERC721A initializes a slot on every transfer and never clears it, a token that was once accepted stays readable, so the read side (profileOf.owned) is only affected in that the same capped read is what set() relies on; the user-visible defect is the rejected set(). The guarantee stated in the brief, 'the caller must hold tokenId now ... otherwise NotNftOwner', and the profileOf meaning of owned ('held now') are therefore not what the contract computes for this class of real tokens; the known-limitations list only covers token contracts that misbehave, not well-behaved ones whose read legitimately costs more than 30000 gas. Live checks for the two constructor dependencies are well inside the cap: identity.md ownerOf(827) ~3.1k gas and delegate.xyz v2 checkDelegateForERC721 ~8.8k gas (eth_estimateGas on mainnet, 2026-10-30); the ERC721A collections I sampled on mainnet (Beanz, goblintown, Invisible Friends, Checks) only had already-initialized tokens in the sampled ids, so the mainnet instance is not pinned to a specific tokenId here. CALL_GAS is a fixed parameter of this launch ('fail, don't change'), so the remedy is a decision, not a code edit: either accept and document that ERC721A tokens deep inside an untouched batch (offset >= ~12) cannot be a picture, or fail the job to raise the cap (a cap of ~60000 would admit untouched batches up to ~26 tokens; the delegated path costs two separately capped calls so the total stays bounded).","line":257,"path":"src/Profiles.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Profiles} from \"src/Profiles.sol\";\nimport {TextRules} from \"src/helpers/TextRules.sol\";\n\n/// @dev A faithful model of ERC721A's storage layout and `_packedOwnershipOf` walk (chiru-labs/ERC721A v4):\n///      a batch mint writes the owner only at the first token of the batch; `ownerOf` of a later token in the\n///      batch walks backwards one cold SLOAD (2100 gas) per token until it finds that slot. Nothing hostile.\ncontract ERC721ALike {\n    uint256 private _currentIndex;\n    mapping(uint256 => uint256) private _packedOwnerships;\n\n    function supportsInterface(bytes4 id) external pure returns (bool) {\n        return id == 0x80ac58cd || id == 0x01ffc9a7 || id == 0x5b5e139f;\n    }\n\n    function mint(address to, uint256 quantity) external {\n        uint256 start = _currentIndex;\n        _packedOwnerships[start] = uint256(uint160(to)) | (block.timestamp << 160);\n        _currentIndex = start + quantity;\n    }\n\n    function ownerOf(uint256 tokenId) external view returns (address) {\n        return address(uint160(_packedOwnershipOf(tokenId)));\n    }\n\n    function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) {\n        packed = _packedOwnerships[tokenId];\n        if (packed == 0) {\n            require(tokenId < _currentIndex, \"OwnerQueryForNonexistentToken\");\n            for (;;) {\n                unchecked {\n                    packed = _packedOwnerships[--tokenId];\n                }\n                if (packed != 0) break;\n            }\n        }\n    }\n}\n\n/// @dev Fails on the code as it is: Alice holds token 19 (ownerOf(19) == Alice, no revert, ~47k gas), yet\n///      Profiles.set reverts NotNftOwner because the 30,000-gas STATICCALL runs out inside ownerOf.\ncontract ProfilesCallGasProofTest is Test {\n    Profiles profiles;\n    ERC721ALike nft;\n    address constant ALICE = address(0xA11CE);\n\n    function setUp() public {\n        profiles = new Profiles(address(new TextRules()), address(0));\n        nft = new ERC721ALike();\n        nft.mint(ALICE, 20); // ids 0..19 in one transaction\n    }\n\n    function test_HolderOfLateBatchTokenCanSetIt() public {\n        assertEq(nft.ownerOf(19), ALICE); // she is the owner by the token's own account\n        vm.prank(ALICE);\n        profiles.set(\"alice\", 1, address(nft), 19, \"\"); // reverts NotNftOwner on the code as it is\n        assertTrue(profiles.profileOf(ALICE).owned);\n    }\n}","reproduction":"Setup: deploy Profiles(textRules, address(0)) and an ERC721A-style token (owner stored only at the batch start; ownerOf walks back one SLOAD per token, as in chiru-labs ERC721A v4 _packedOwnershipOf). Mint 20 tokens (ids 0..19) to Alice in one call. 1) nft.ownerOf(19) returns Alice and costs ~47-49k gas with unlimited gas. 2) vm.prank(Alice); profiles.set(\"alice\", 1, nft, 19, \"\"). Expected per the brief: succeeds, since Alice holds tokenId 19 now. Actual: reverts NotNftOwner() because the STATICCALL capped at 30000 gas runs out inside ownerOf, _call32 returns ok = false, _owned returns false. 3) Same call with tokenId 5 succeeds (ownerOf costs ~18k). 4) The threshold under the cap is offset 12 of the batch (offsets 0..11 fit, 12..19 do not), see test/scratch/ProfilesCallGas.t.sol test_Threshold.","severity":"low","snippet":"            ok := staticcall(CALL_GAS, target, add(data, 32), mload(data), 0, 32)","title":"CALL_GAS = 30000 rejects legitimate holders of ERC721A batch-minted tokens: ownerOf walks one cold SLOAD per token, runs out of gas, and set() reverts NotNftOwner for a token the caller holds"}],"hash":"3efbfa9a310de5a18b8e5bb07b4cfff80aba537b9d218ff810ee6ed597929894","nodeId":"3b386b1e-b729-489b-8126-a133d7edf0bf","outcome":"completed","summary":"Review complete. The findings file is written and the working tree is otherwise untouched.\n\n**Outcome.** One low-severity finding in the math and boundary area, with a proof test that fails on the current code. The rest of the arithmetic and boundary surface holds.\n\n**Finding 1 (low), `src/Profiles.sol:257`.** The 30000-gas STATICCALL cap on `ownerOf` rejects honest holders of ERC721A batch-minted tokens. ERC721A stores the owner only at the first token of a batch and walks back one cold SLOAD per token, so the read exhausts the cap at about the twelfth token of an untouched batch. A faithful model shows offsets 0 to 11 of a 20-token batch succeed and offsets 12 to 19 fail. For those tokens `set` reverts NotNftOwner even though the token contract says the caller owns it. The brief's known limitation only covers misbehaving token contracts, not well-behaved ones with an expensive read. CALL_GAS is a fixed parameter, so the remedy is a decision to accept and document it or to fail the job, not a code edit.\n\n**What holds, with evidence.**\n- Shifts and casts in the name parser and skeleton stay inside the top 20 bytes; the timestamp cast cannot truncate; there is no division or fixed point.\n- The two skeleton routines agree on every stored name, and the name-ownership mapping stays consistent through set, rename, picture-only and clear.\n- The 32-byte call decoder checks success and return size before any consumer reads the word.\n- The deployed TextRules matches the repository source and behaves as specified at the 300 and 512 byte boundaries. I ran the repository's fork test against a public mainnet RPC and it passed.\n- The live delegate.xyz check costs about 8.8k gas and the identity.md read about 3.1k, both well inside the cap.\n\n**Not pinned down.** The mainnet ERC721A collections I sampled had already-initialized slots for the sampled ids, so the finding rests on the model of ERC721A's loop rather than a specific live tokenId.\n\n**Coverage.** Both listed entry points have rows: `set` is marked finding, `clear` holds. Ten further rows cover the view functions, the constructor and the invariants checked. The proof and a threshold test sit under `test/scratch/`, which is not kept.","treeHash":null,"usage":{"cachedInputTokens":1271363,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":36263,"runtime":"claude","turns":37,"wallClockMs":621683}},{"artifacts":[],"attempt":1,"bundleHash":"285e2c86e6317034ffe92d64399b48880fd1d917f36207f7cbdf83771d8cddab","device":"a84da3707fa87187","findings":[],"hash":"697a14badd0f371bdda7a4e7bcaffb79e9f1f2149eb5b1fb1571b04c18e346a2","nodeId":"c3c66a91-b365-4052-aca4-a6628bbf9555","outcome":"completed","summary":"Added failure-path, fuzz, invariant, and fork coverage under `test/`.\n\n- Build passed.\n- Seeded suite: **84 passed**, including 10 mainnet fork tests at block **26305652**.\n- Invariants: **25,600 calls**, no unexpected reverts.\n- Offline: **74 passed**, fork suite skipped.\n\nNo contract defects reproduced. Changes documented in [test/ADAPTATION.md](/home/imd/.identitymd/work/ab593214-f31a-41a3-a0e4-77dccebdd6bd/c3c66a91-b365-4052-aca4-a6628bbf9555/test/ADAPTATION.md).","treeHash":"f080170bf78ca67ab152c978c0539139725837d7","usage":{"cachedInputTokens":2007552,"inputTokens":117122,"model":"gpt-6-astra","outputTokens":28982,"runtime":"codex","turns":7,"wallClockMs":967351}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"4faf975f1178e1f8","findings":[{"citation":"resolved","description":"set() rejects the empty record (name and picture both empty reverts BadName, src/Profiles.sol:93-95), but clear() has no counterpart check: a wallet that never set a profile, or already cleared it, can call clear() again and the contract emits ProfileCleared(user) although nothing was deleted. No storage is touched beyond deleting already-zero slots and no other wallet's record or name reservation is affected, so this is not a permission bypass. The only effect is on off-chain consumers: an indexer that counts ProfileCleared events, or treats one as evidence that a profile existed, sees events for wallets that never had a profile, and any wallet can emit them at gas cost only. The launch text states the fixed event set and functions; making clear() a no-op or revert on an empty record is a behaviour choice for the author, not a required fix.","line":125,"path":"src/Profiles.sol","reproduction":"State: fresh Profiles(textRules, 0x0). Call: vm.prank(0x1234); profiles.clear(). Expected (symmetry with set on an empty record): no event, or a revert. Actual: exactly one log with topic0 = ProfileCleared.selector and user = 0x1234; profileOf(0x1234) is byte-identical before and after (name \"\", pic 0, since 0). Verified with a scratch Foundry test using vm.recordLogs(); the existing suite only clears wallets that hold a profile (test_ClearFreesName, test_FirstCallerCanSetAndClearAfterFactoryDeployment).","severity":"info","snippet":"        emit ProfileCleared(msg.sender);","title":"clear() on a wallet with no profile emits ProfileCleared without any state change (set/clear asymmetry on the empty record)"}],"hash":"7537d913d42f760989be3559e277d3f9639f6958e6f0b981284de47e685e1aad","nodeId":"c046e3f1-efcd-42a0-b768-e594705d1bb7","outcome":"completed","summary":"The review is complete. The findings file is written, and the tree holds no other change.\n\n**Result: the permission model of Profiles holds.** One informational asymmetry is recorded, nothing of higher severity.\n\n**What I checked, in my area:**\n- **Access Control.** Both writers, `set` and `clear`, are unguarded by design and touch only the caller's own record. The name index can only be written to the caller after the holder check, and only the caller's own skeleton is ever deleted. The constructor hands no role to the factory. There is no initializer, proxy, delegatecall or payable path.\n- **Asymmetry.** The parser key and the stored-name skeleton agree for every charset byte, so rename and clear always release the right slot. The ownership check at write and at read is the same function. The only mismatch is that `set` rejects the empty record while `clear` accepts it.\n- **Trust Gap.** With no privileged actor, no fee and no value flow, no seam can form. The two constructor dependencies were verified live.\n\n**Live verification on a mainnet fork** through a public RPC, beyond what the shipped tests run:\n- The TextRules runtime at the constructor address is byte-identical to the local source.\n- Real delegate.xyz v2 wallet-level and token-level delegations grant the picture under the 30,000 gas cap, and revocation removes it. A rights-specific delegation is rejected, as documented.\n- `ownerOf` on identity.md stays under the cap for every existing token, ids 0 to 1999.\n\n**The one finding (info):** calling `clear()` from a wallet that never had a profile emits `ProfileCleared` with no state change. It affects only off-chain consumers that count or trust that event. It is a behaviour choice for the author, not a permission defect.\n\n**Coverage record:** nine rows, covering both listed entry points plus the constructor, the name-index invariant, the views, the live delegate path, both dependencies and the gas cap. Nothing was left unreached. Scratch tests were removed after running.","treeHash":null,"usage":{"cachedInputTokens":1102115,"inputTokens":386,"model":"claude-fable-5-1","outputTokens":26400,"runtime":"claude","turns":34,"wallClockMs":484107}},{"artifacts":[],"attempt":2,"bundleHash":null,"device":"3c1226d190150ef0","findings":[],"hash":"81c78b2151d454cb800cbc7ddc51e1f70aebe8bdd050eb4a18c022eb17d1a840","nodeId":"ef8324a0-c89b-4336-8e5f-b95bdbcfca73","outcome":"completed","summary":"**I found no defects in the economics audit of `Profiles`, so `.imd-findings.json` has an empty findings list and 14 coverage rows.** Both entry points, `set` and `clear`, are marked `holds`. No tracked file changed and my scratch tests are deleted. The default `forge test` still gives 44 passed, 0 failed, 1 skipped, and all 3 fork tests pass with `FORK_URL` set to a public RPC.\n\n**Economic Security**\n- **Value at risk:** the contract has no funds, fees, prices or payable functions, so there is nothing to extract.\n- **Mainnet dependencies:**\n  - The live `TextRules` runtime is byte-identical to the local build, and its errors pass through unchanged on a fork.\n  - On the real delegate.xyz registry, a whole-wallet delegation counts, a rights-limited one doesn't, and revoking turns `owned` false. A cold miss costs 11,002 gas, well under `CALL_GAS`.\n- **Hostile tokens:** reverts, gas burning, short or oversized returns and dirty address bits only produce `false`. A low-gas call can't produce a wrong `true`. It can't return a false `owned` to a reader either, because about 1/64 of the gas is left, too little to finish.\n- **Griefing:** no third party can block `clear`, or block `set` except by already holding the name, which is the accepted first-come rule.\n\n**Invariant**\n- **Name ownership:** a scratch invariant run of 15,000 handler calls on easily confused spellings found no stale or lost name, and neither did a fuzz of the full charset.\n- **Other state:** `since` matched a shadow model throughout that run. Separate checks showed views match what `set` stored and leftover links are cleared.\n- **Reserved names:** all 25 spelling variants I tried revert `NameReserved`, and names that merely contain a reserved word are allowed.\n\n**Flow Gap**\n- **Mid-transaction changes:** `set` only makes static calls, so nothing can re-enter or change state partway through.\n- **Flash-borrowed NFTs:** one can pass `set`, but `owned` is checked on every read, so it reads false once the token is returned.\n- **Events and storage:** each picture type forces `nft`, `tokenId` and `link` to fixed values, so events and stored records can't differ.\n\n**Rejected lead:** a hostile token costs up to 70,083 gas per wallet in `profilesOf`, so about 714 such wallets in one batch would break a 50M-gas read. I didn't report it because the reader chooses the batch size and can split it, the suite's reference batch is 100, and `CALL_GAS` is fixed. Keep site batches well below that size.\n\n**Not covered**\n- `TextRules.validText`, `checkCover` and `checkProof` weren't audited because `Profiles` never calls them; they have an `unreached` row.\n- There's no `launch.json` in this tree yet, so the manifest wasn't reviewed.\n- This was a single-reviewer pass of the three assigned guides, with no helpers. Slither and Mythril weren't run.","treeHash":null,"usage":{"cachedInputTokens":425714,"inputTokens":12,"model":"claude-opus-5-5","outputTokens":25976,"runtime":"claude","turns":19,"wallClockMs":284685}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"a7979f925df7a720","findings":[{"citation":"resolved","description":"The launch rules (docs/LAUNCH-PROFILES.md:8-9,30) and README.md:94-95 say test/fork/ProfilesFork.t.sol runs against the two constructor contracts on a mainnet fork when FORK_URL is set. The accepted test commit 3e0981d changed setUp from vm.envOr(\"FORK_URL\", ...) to vm.envOr(\"MAINNET_RPC_URL\", ...). Any check or person that sets FORK_URL as documented now gets 'skipped' and not a fork run. That includes the TextRules runtime-equality assertion, the delegate.xyz delegation tests and the identity.md #827 ownership tests. The skip looks the same as the accepted 'no RPC' case, so the only check of the two constructor dependencies against mainnet drops out without anyone noticing. Profiles.sol is not affected. The fix belongs in the test: read FORK_URL (falling back to MAINNET_RPC_URL if both are wanted) and correct the comment at line 28.","line":39,"path":"test/fork/ProfilesFork.t.sol","reproduction":"With an unreachable RPC so that any real fork attempt would fail: `FORK_URL=http://127.0.0.1:1 forge test --match-path test/fork/ProfilesFork.t.sol` gives `[SKIP: skipped] setUp()`, 0 failed, 1 skipped. So FORK_URL is ignored. `MAINNET_RPC_URL=http://127.0.0.1:1 forge test --match-path test/fork/ProfilesFork.t.sol` instead tries the fork and fails. Expected per the launch rules: FORK_URL drives the fork suite. Actual: only MAINNET_RPC_URL does, and the documented FORK_URL is ignored.","severity":"low","snippet":"        string memory url = vm.envOr(\"MAINNET_RPC_URL\", string(\"\"));","title":"Fork test now reads MAINNET_RPC_URL instead of FORK_URL, so the required mainnet-fork check silently skips when run as the launch rules and README specify"}],"hash":"a8ea26cb28cd0483a9c3342564aabb1361d9ff28aa676a28b12b8d201d8158c2","nodeId":"66a737d8-b7ee-4253-92bf-9634e56584ab","outcome":"completed","summary":"I found nothing wrong in `Profiles.sol` itself. The review keeps one low finding, which is in the test suite, and drops both specialist findings. The results are in `.imd-findings.json`, and no repository file was changed.\n\n**Kept (low): the fork test ignores `FORK_URL`.** `test/fork/ProfilesFork.t.sol:39` now reads `MAINNET_RPC_URL`. An earlier accepted test commit (3e0981d) made that change. The launch rules and the README both say the fork test runs when `FORK_URL` is set. I confirmed it locally: with `FORK_URL` set to an unreachable RPC, the fork suite just reports \"skipped\". With `MAINNET_RPC_URL` set to the same address, it tries the fork and fails. So anyone following the documented setup never runs the mainnet check of the two constructor contracts, and the skip looks the same as having no RPC. The fix is in the test only.\n\n**Dropped:**\n- **ERC721A tokens deep in a batch mint (math specialist, low).** The specialist's proof does fail as they describe: a 30,000-gas `ownerOf` call on token 12 or later of an untouched batch runs out of gas, and `set()` reverts `NotNftOwner`. But that is the behaviour the brief fixes: every token call is capped at 30,000 gas, a failure counts as not owned, and a token contract that burns gas only makes its own `owned` false. Fixing it would mean changing `CALL_GAS`, which is a fixed parameter, so it is an accepted rule rather than a finding. The holder can also work around it by sending the token to themselves, which records its owner directly.\n- **`clear()` emits an event on an empty record (permissions specialist, info).** It reproduces, but the brief only says `clear()` erases the record and emits `ProfileCleared`. Nothing breaks and no other wallet is affected, so it is not a defect.\n\nThe economics and flow specialists and the tester reported nothing.\n\n**Coverage:**\n- **`set` holds.** All the name rules check out: charset, the `0x` prefix, length, the skeleton mapping (the same when a name is checked and when it is stored), exactly the 17 reserved names as whole skeletons, and `NameTaken`. A rename or an empty name frees the old name. Each picture type is checked as specified; every token and registry call is capped and a failure counts as not owned. TextRules errors pass through unchanged, and every revert happens before anything is written.\n- **`clear` holds.** It frees only the caller's own name and erases only the caller's record.\n- **Name ownership stays consistent.** `nameOwner` always points to the wallet whose stored name has that skeleton.\n- **Deployment holds.** The constructor only stores the two addresses and makes no outside call. `launch.json` matches the brief, and the contract is far under the size limits.\n\nThe full suite gave 74 passed and 1 skipped (the fork suite, since no RPC was set), plus the specialist's proof failing as expected. I couldn't reach mainnet, so the fork tests themselves didn't run. I deleted the scratch copy of the proof afterwards.","treeHash":null,"usage":{"cachedInputTokens":445976,"inputTokens":20,"model":"claude-opus-5-5","outputTokens":9951,"runtime":"claude","turns":11,"wallClockMs":175601}},{"artifacts":[],"attempt":1,"bundleHash":"7fa1684ec7e0d0375837325c1c73487bcbf21a3817ed8b622dd5a4c15db61ebe","device":"0da932e4a0b9bd4a","findings":[],"hash":"b43f3fdfd8a5068ac55899e50e3d22926aa3f32fa8e1c827863e1e634fd1a8df","nodeId":"ce00259d-ea72-46f6-a611-ba49ae079708","outcome":"completed","summary":"Created [launch.json](/home/imd/.identitymd/work/ab593214-f31a-41a3-a0e4-77dccebdd6bd/ce00259d-ea72-46f6-a611-ba49ae079708/launch.json) for `Profiles` with the exact constructor addresses and order.\n\n- Manifest structure and compiled ABI checks passed.\n- `forge build` passed.\n- Seeded `forge test`: 44 passed, 0 failed, 1 skipped (`FORK_URL` unset).\n\nOnly `launch.json` changed.","treeHash":"3329e859983ed5a7c3548ab36246aafa7586c188","usage":{"cachedInputTokens":653696,"inputTokens":75340,"model":"gpt-6-astra","outputTokens":4735,"runtime":"codex","turns":5,"wallClockMs":176403}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"223fd994d1a35f81","findings":[],"hash":"db250a8a68fc80735efd456f2f350423916dc89e32cb4ba923c60fd78c28e3f1","nodeId":"1f0590a4-6c28-4ec2-8dca-c1b7a1750f67","outcome":"completed","summary":"I found no defects in Profiles that I could reproduce, so `.imd-findings.json` has an empty findings list. It also has a coverage row for each of the two entry points and three rows for invariants I checked. No repository files were changed. I deleted my temporary test file under `test/scratch/` afterwards.\n\n**Tests**\n- I reached a public mainnet RPC, so I ran the full suite against a mainnet fork: 47 passed, 0 failed, 0 skipped. That includes the 3 fork tests the earlier pass had to skip because `FORK_URL` was unset.\n- I added one temporary fork test that used the real delegate.xyz v2 registry. A token-level delegation and a whole-wallet delegation with all rights both let the hot wallet `set` an ERC-721 picture (an Azuki token) and read back as `owned`. A delegation with non-zero rights correctly reverted with `NotNftOwner`.\n\n**Coverage**\n- **`set(string,uint8,address,uint256,string)`: holds.** Every check (name rules, reserved list, `NameTaken`, picture rules) runs before anything is written. The only outside calls are read-only (STATICCALL), including the call to TextRules, so nothing can call back in and change state. The name reservation is swapped only when the old and new skeletons differ.\n- **`clear()`: holds.** It makes no outside call, frees the skeleton worked out from the stored name and deletes the whole record, including `since` and the link.\n- **Name skeletons.** Names are first checked when they come in, and later re-derived from the stored copy; both use the same mapping (upper case, `I`/`i`/`1` to `l`, `0` to `o`, `_` dropped). So each skeleton has at most one holder. The 17 reserved skeletons match the brief exactly and are compared as whole skeletons only.\n- **Gas cap on token and registry calls.** The 30,000 cap is far above what these calls need on mainnet. A registry check where no delegation exists, which runs all three lookups, uses about 8k gas beyond the transaction's base cost; Azuki `ownerOf` uses about 5k.\n- **Link pictures.** `HostNotAllowed` and `BadEvidence` from TextRules pass through unchanged. The existing fork test confirms the deployed TextRules accepts the same hosts.\n\n**Leads I ruled out**\n- **Gas-heavy NFT contracts.** I looked at whether some collections' `ownerOf` could exceed the 30,000 cap and lock real holders out. Azuki did not come close, and the brief accepts this case anyway, with `CALL_GAS` fixed.\n- **Wallets sending less gas.** A caller who sends too little gas only makes their own `set` fail with `NotNftOwner`; it can't affect anyone else.\n\nFrom the Execution Trace, Periphery and First Principles guides, the parts that don't apply here are reentrancy that writes state, money moving in or out, signatures and upgrades: the contract has none of these. A clean review is not proof that no defects exist.","treeHash":null,"usage":{"cachedInputTokens":427468,"inputTokens":19,"model":"claude-opus-5-5","outputTokens":11341,"runtime":"claude","turns":10,"wallClockMs":165399}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"629987aaf6c7aa88","findings":[],"hash":"ff7b8b127d7f182ce51a965836774e4129bd8f12a76075a342cfd0de929d27d8","nodeId":"f101efeb-3a96-45c2-8d52-3c13ca7de8e0","outcome":"completed","summary":"The review is complete. The findings file holds an empty list because no defect reproduced.\n\n**Verdict.** Profiles as it arrived matches its launch text and I found no reproducible defect of any severity. The file `.imd-findings.json` contains `{\"findings\":[]}`.\n\n**What was read.** All of it: Profiles, the TextRules helper and TextLib, the delegate registry interface, VaultTypes for the shared error declarations, both test files and both mocks, the launch text, and the two protected floor tests. Nothing in scope was out of reach.\n\n**What was verified beyond reading.**\n- **Shipped suite:** 34 tests pass, the fork test skips without FORK_URL, as the text says.\n- **Fork suite on mainnet:** run against a public RPC, 3 of 3 pass, including the real identity.md NFT and the real registry.\n- **Constructor contracts:** the TextRules runtime at the first address is byte-identical to the local build, and the registry at the second address has code and rejects ERC-721 interface id in its own supportsInterface.\n- **Gas cap:** the registry's worst path and the NFT's ownerOf both execute in well under the 30,000 cap. The deployed TextRules accepts an arweave link and rejects an evil host with the expected selector.\n- **Forbidden opcodes:** a scan of the compiled runtime, same rule as the protected floor, finds no reachable DELEGATECALL, CALLCODE or SELFDESTRUCT. Runtime is 5,489 bytes.\n- **Scratch tests (removed afterwards):** a fuzz invariant that the skeleton computed on set equals the one recomputed from storage on rename and clear, an ERC-721 that returns address zero from ownerOf while the registry answers true (correctly NotNftOwner), clear dropping a stored link, the literal 0x rule versus underscore and capital O prefixes, and six reserved variants through the mapping. All pass.\n\n**Review passes.** Access control (two public functions, each touching only the caller's record and the name slot it holds), reentrancy (every outside call is a STATICCALL), arithmetic (shifts bounded by index under 20, no unchecked blocks), the name invariant (a stored name implies its skeleton maps back to that wallet, and no path writes another wallet's slot), picture checks, error selector pass-through from VaultTypes, constructor behaviour on an empty chain, and launch-forbidden features. None turned up a failing input.\n\n**Notes for the adapter, not findings.**\n- `clear()` on a wallet with no record succeeds and emits ProfileCleared. Harmless to an indexer, and the text does not ask for a revert, so leave it.\n- ERC-721A collections minted in large batches can need more than 30,000 gas in ownerOf, so such tokens show NotNftOwner or owned false. This is the accepted gas-cap rule, and CALL_GAS is fixed.\n- The fork test exercises the registry only on the false path. The mainnet gas estimate shows the true path fits the cap as well.\n- The protected tests pin solc 0.8.26 while foundry.toml pins 0.8.28. Earlier launches from this repository passed with the same config, so the floor compiles them separately.","treeHash":null,"usage":{"cachedInputTokens":668509,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":28749,"runtime":"claude","turns":26,"wallClockMs":412624}}],"verification":[{"checks":[{"durationMs":11256,"exitCode":0,"name":"build","output":"Compiling 52 files with Solc 0.8.28\nSolc 0.8.28 finished in 11.16s\nCompiler run successful!\n","passed":true},{"durationMs":125,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/fork/ProfilesFork.t.sol:ProfilesForkTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 250.98µs (0.00ns CPU time)\n\nRan 2 tests for test/ProfilesLaunch.t.sol:ProfilesLaunchTest\n[PASS] test_FactoryDeploymentUsesExactArgumentsWithoutInitialization() (gas: 39084)\n[PASS] test_FirstCallerCanSetAndClearAfterFactoryDeployment() (gas: 176505)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 14.77ms (310.93µs CPU time)\n\nRan 5 tests for test/Profiles.t.sol:ProfilesGasTest\n[PASS] test_Gas_Clear() (gas: 42049)\n[PASS] test_Gas_NameLink() (gas: 194922)\n[PASS] test_Gas_NameNft() (gas: 139750)\n[PASS] test_Gas_NameOnlyFirst() (gas: 90900)\n[PASS] test_Gas_Rename() (gas: 78005)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 14.85ms (610.02µs CPU time)\n\nRan 8 tests for test/ProfilesAudit.t.sol:ProfilesAuditTest\n[PASS] testFuzz_NameOwnershipSurvivesRenameAndClear(uint256) (runs: 256, μ: 621682, ~: 625991)\n[PASS] testFuzz_RegistryOnlyAcceptsCanonicalTrue(uint256) (runs: 256, μ: 302081, ~: 302892)\n[PASS] test_DelegationUsesCurrentOwnerAndAllRights() (gas: 356745)\n[PASS] test_EmptyAndDuplicateBatchMatchesIndividualReads() (gas: 301629)\n[PASS] test_FailedUpdatesPreserveWholeRecord() (gas: 476682)\n[PASS] test_InterfaceFailuresRejectWithoutChangingRecord() (gas: 770590)\n[PASS] test_RegistryFailuresDoNotBreakBatchOrReleaseName() (gas: 2313479)\n[PASS] test_TokenCallsAreStaticAndGasCapped() (gas: 950591)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 31.40ms (50.87ms CPU time)\n\nRan 29 tests for test/Profiles.t.sol:ProfilesTest\n[PASS] test_BadPicture() (gas: 369828)\n[PASS] test_ClearFreesName() (gas: 258377)\n[PASS] test_ConstructorZeroTextRules() (gas: 6970)\n[PASS] test_Cyrillic_BadName() (gas: 58769)\n[PASS] test_Dots_BadName() (gas: 116191)\n[PASS] test_Emoji_BadName() (gas: 61664)\n[PASS] test_EvilNft1155_ReadNeverBreaks() (gas: 462943)\n[PASS] test_EvilNft_CannotSetWhileHostile() (gas: 148646)\n[PASS] test_EvilNft_ReadNeverBreaks() (gas: 997540)\nLogs:\n  evil mode 1 profilesOf(3) gas 47909\n  evil mode 2 profilesOf(3) gas 75442\n  evil mode 3 profilesOf(3) gas 75465\n  evil mode 4 profilesOf(3) gas 47953\n  evil mode 5 profilesOf(3) gas 48174\n\n[PASS] test_Link_ArweaveOk() (gas: 284798)\n[PASS] test_Link_EvilHost() (gas: 202692)\n[PASS] test_Link_OtherAllowlistedHosts() (gas: 274155)\n[PASS] test_Link_TooLongOrBadChars() (gas: 694010)\n[PASS] test_Nft1155_SetOwnedAndSold() (gas: 428222)\n[PASS] test_Nft721_Delegate() (gas: 408562)\n[PASS] test_Nft721_NoRegistry_NoDelegate() (gas: 95905)\n[PASS] test_Nft721_NotOwner() (gas: 91811)\n[PASS] test_Nft721_SetAndOwned() (gas: 163475)\n[PASS] test_Nft721_SoldThenOwnedFalse_NewOwnerSetsIt() (gas: 404468)\n[PASS] test_NoMoney() (gas: 67476)\n[PASS] test_OtherBadNames() (gas: 298949)\n[PASS] test_PictureOnly_ThenNameFreed() (gas: 210888)\n[PASS] test_ProfilesOf100() (gas: 21772190)\nLogs:\n  profilesOf(100 x name+NFT) gas 1585092\n\n[PASS] test_RenameFreesOldName() (gas: 275268)\n[PASS] test_Reserved() (gas: 949156)\n[PASS] test_SinceKeptOnUpdate() (gas: 185541)\n[PASS] test_SkeletonUnique() (gas: 628651)\n[PASS] test_Space_BadName() (gas: 88581)\n[PASS] test_ValidNames() (gas: 477450)\nSuite result: ok. 29 passed; 0 failed; 0 skipped; finished in 31.30ms (21.02ms CPU time)\n\nRan 5 test suites in 32.42ms (92.57ms CPU time): 44 tests passed, 0 failed, 1 skipped (45 total tests)\n","passed":true},{"durationMs":40,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Profiles.clear()\",\"Profiles.set(string,uint8,address,uint256,string)\"],\"files\":{\".gitignore\":5,\".gitmodules\":9,\"ADAPTATION.md\":39,\"README.md\":101,\"docs/LAUNCH-PROFILES.md\":44,\"foundry.lock\":11,\"foundry.toml\":33,\"src/Profiles.sol\":272,\"src/VaultTypes.sol\":450,\"src/helpers/TextRules.sol\":245,\"src/interfaces/IDelegateRegistry.sol\":12,\"test/Profiles.t.sol\":576,\"test/ProfilesAudit.t.sol\":289,\"test/ProfilesLaunch.t.sol\":62,\"test/fork/ProfilesFork.t.sol\":128,\"test/mocks/MockDelegateRegistry.sol\":26,\"test/mocks/MockNFT.sol\":17},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"332bf9a5e98c947a9ba513fd40b1e9f577d50c910a1f6b4f7155d9bbb8763208","verifiedTreeHash":"58276e381647ca107cbd3147a2b930dbe39dcd78","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":21470,"exitCode":0,"name":"build","output":"Compiling 56 files with Solc 0.8.28\nSolc 0.8.28 finished in 21.38s\nCompiler run successful!\n","passed":true},{"durationMs":15448,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/ProfilesLaunch.t.sol:ProfilesLaunchTest\n[PASS] test_FactoryDeploymentUsesExactArgumentsWithoutInitialization() (gas: 39084)\n[PASS] test_FirstCallerCanSetAndClearAfterFactoryDeployment() (gas: 176505)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 641.82µs (322.91µs CPU time)\n\nRan 29 tests for test/Profiles.t.sol:ProfilesTest\n[PASS] test_BadPicture() (gas: 369828)\n[PASS] test_ClearFreesName() (gas: 258377)\n[PASS] test_ConstructorZeroTextRules() (gas: 6970)\n[PASS] test_Cyrillic_BadName() (gas: 58769)\n[PASS] test_Dots_BadName() (gas: 116191)\n[PASS] test_Emoji_BadName() (gas: 61664)\n[PASS] test_EvilNft1155_ReadNeverBreaks() (gas: 462943)\n[PASS] test_EvilNft_CannotSetWhileHostile() (gas: 148646)\n[PASS] test_EvilNft_ReadNeverBreaks() (gas: 997540)\nLogs:\n  evil mode 1 profilesOf(3) gas 47909\n  evil mode 2 profilesOf(3) gas 75442\n  evil mode 3 profilesOf(3) gas 75465\n  evil mode 4 profilesOf(3) gas 47953\n  evil mode 5 profilesOf(3) gas 48174\n\n[PASS] test_Link_ArweaveOk() (gas: 284798)\n[PASS] test_Link_EvilHost() (gas: 202692)\n[PASS] test_Link_OtherAllowlistedHosts() (gas: 274155)\n[PASS] test_Link_TooLongOrBadChars() (gas: 694010)\n[PASS] test_Nft1155_SetOwnedAndSold() (gas: 428222)\n[PASS] test_Nft721_Delegate() (gas: 408562)\n[PASS] test_Nft721_NoRegistry_NoDelegate() (gas: 95905)\n[PASS] test_Nft721_NotOwner() (gas: 91811)\n[PASS] test_Nft721_SetAndOwned() (gas: 163475)\n[PASS] test_Nft721_SoldThenOwnedFalse_NewOwnerSetsIt() (gas: 404468)\n[PASS] test_NoMoney() (gas: 67476)\n[PASS] test_OtherBadNames() (gas: 298949)\n[PASS] test_PictureOnly_ThenNameFreed() (gas: 210888)\n[PASS] test_ProfilesOf100() (gas: 21772190)\nLogs:\n  profilesOf(100 x name+NFT) gas 1585092\n\n[PASS] test_RenameFreesOldName() (gas: 275268)\n[PASS] test_Reserved() (gas: 949156)\n[PASS] test_SinceKeptOnUpdate() (gas: 185541)\n[PASS] test_SkeletonUnique() (gas: 628651)\n[PASS] test_Space_BadName() (gas: 88581)\n[PASS] test_ValidNames() (gas: 477450)\nSuite result: ok. 29 passed; 0 failed; 0 skipped; finished in 21.11ms (19.73ms CPU time)\n\nRan 5 tests for test/Profiles.t.sol:ProfilesGasTest\n[PASS] test_Gas_Clear() (gas: 42049)\n[PASS] test_Gas_NameLink() (gas: 194922)\n[PASS] test_Gas_NameNft() (gas: 139750)\n[PASS] test_Gas_NameOnlyFirst() (gas: 90900)\n[PASS] test_Gas_Rename() (gas: 78005)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 46.11ms (968.95µs CPU time)\n\nRan 8 tests for test/ProfilesAudit.t.sol:ProfilesAuditTest\n[PASS] testFuzz_NameOwnershipSurvivesRenameAndClear(uint256) (runs: 256, μ: 621244, ~: 625991)\n[PASS] testFuzz_RegistryOnlyAcceptsCanonicalTrue(uint256) (runs: 256, μ: 302364, ~: 302898)\n[PASS] test_DelegationUsesCurrentOwnerAndAllRights() (gas: 356745)\n[PASS] test_EmptyAndDuplicateBatchMatchesIndividualReads() (gas: 301629)\n[PASS] test_FailedUpdatesPreserveWholeRecord() (gas: 476682)\n[PASS] test_InterfaceFailuresRejectWithoutChangingRecord() (gas: 770590)\n[PASS] test_RegistryFailuresDoNotBreakBatchOrReleaseName() (gas: 2313479)\n[PASS] test_TokenCallsAreStaticAndGasCapped() (gas: 950591)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 55.10ms (81.04ms CPU time)\n\nRan 8 tests for test/ProfilesBehavior.t.sol:ProfilesReturnDataTest\n[PASS] testFuzz_1155AcceptsAnyPositiveBalance(uint256) (runs: 1000, μ: 283337, ~: 283819)\n[PASS] testFuzz_InterfaceBooleanMustBeCanonical(uint256) (runs: 1000, μ: 88359, ~: 87481)\n[PASS] test_AllShortReturnLengthsFailAtEveryExternalBoundary() (gas: 27375958)\n[PASS] test_CompleteWordWithTrailingDataUsesOnlyTheFirstWord() (gas: 1849086)\n[PASS] test_FailedCallWithAnOtherwiseValidWordIsNotAccepted() (gas: 644409)\n[PASS] test_LosingTokenCodeDoesNotBreakBatchAndClear() (gas: 304780)\n[PASS] test_NoRegistryCodeFailsClosedButDirectOwnerStillWorks() (gas: 275589)\n[PASS] test_ZeroOrDirtyOwnerCannotBeRescuedByRegistry() (gas: 369334)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 61.37ms (129.28ms CPU time)\n\nRan 9 tests for test/ProfilesRules.t.sol:ProfilesRulesTest\n[PASS] testFuzz_FullWidthNamesRoundTripAndRelease(bytes32,uint8) (runs: 1000, μ: 403645, ~: 392331)\n[PASS] test_AllReservedSkeletonsAreWholeWordsOnly() (gas: 6017784)\n[PASS] test_ByteAndSkeletonLengthBoundaries() (gas: 1603391)\n[PASS] test_EveryByteClassInAName() (gas: 22664359)\n[PASS] test_EveryLinkTailByte() (gas: 25159627)\n[PASS] test_ForbiddenPrefixDependsOnRawSpelling() (gas: 349595)\n[PASS] test_LinkPrefixesAndSeparatorsAreAccepted() (gas: 1433294)\n[PASS] test_LinksRejectHostConfusionAndBubbleExactErrors() (gas: 1562311)\n[PASS] test_UrlLengthAndStorageBoundaries() (gas: 2263336)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 64.86ms (176.19ms CPU time)\n\nRan 11 tests for test/ProfilesBehavior.t.sol:ProfilesBehaviorTest\n[PASS] testFuzz_UndefinedPictureKindsNeverReleaseTheOldName(uint8) (runs: 1000, μ: 227783, ~: 227764)\n[PASS] test_ApprovalsAndOperatorsAreNotOwnership() (gas: 260525)\n[PASS] test_BurnRemintAndPartial1155TransfersAreReflectedWithoutSet() (gas: 779790)\n[PASS] test_ClearIsCallerScopedAndIdempotentAcrossAllPictures() (gas: 1210859)\n[PASS] test_EventWireFormatForEveryPictureAndRepeatedClear() (gas: 446867)\n[PASS] test_EveryPictureTransitionReplacesTheWholeRecord() (gas: 4941317)\n[PASS] test_InvalidPictureFieldsPreserveRecordAndReservations() (gas: 363725)\n[PASS] test_NoFallbackAndNoValueThroughAnyPublicSelector() (gas: 714075)\n[PASS] test_ProfileTupleWireOrderForEveryPicture() (gas: 438493)\n[PASS] test_RequiredErrorSelectorsRemainStable() (gas: 591)\n[PASS] test_ZeroAndMaximumTokenIdsAreNotSentinelsForNftPictures() (gas: 545951)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 64.94ms (81.87ms CPU time)\n\nRan 10 tests for test/fork/ProfilesFork.t.sol:ProfilesForkTest\n[PASS] test_Fork_ContractDelegationGrantAndRevoke() (gas: 762264)\n[PASS] test_Fork_DelegationBindsOwnerCollectionTokenAndRights() (gas: 1503444)\n[PASS] test_Fork_DeployedTextRulesSameHosts() (gas: 1264388)\nLogs:\n  deployed TextRules code bytes 5249\n  local    TextRules code bytes 5249\n  same runtime code true\n\n[PASS] test_Fork_Identity827() (gas: 468112)\nLogs:\n  identity.md #827 holder 0xa281a719C19486Aa6492Ba8C714272799f0df923\n  ownerOf(827) gas (warm) 5708\n\n[PASS] test_Fork_LinkErrorsPreservePreviousProfile() (gas: 888954)\n[PASS] test_Fork_LinkThroughDeployedTextRules() (gas: 255665)\n[PASS] test_Fork_NftApprovalsDoNotAuthorizePictures() (gas: 232420)\n[PASS] test_Fork_SaleRequiresDelegationFromTheNewOwner() (gas: 862554)\n[PASS] test_Fork_TokenDelegationGrantAndRevoke() (gas: 798346)\n[PASS] test_Fork_WalletDelegationGrantAndRevoke() (gas: 747450)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 1.71s (3.37s CPU time)\n\nRan 2 tests for test/ProfilesInvariant.t.sol:ProfilesInvariantTest\n[PASS] invariant_RecordsReservationsAndLiveOwnershipMatchUserActions() (runs: 256, calls: 25600, reverts: 0)\n\n╭-----------------+---------------+-------+---------+----------╮\n| Contract        | Selector      | Calls | Reverts | Discards |\n+==============================================================+\n| ProfilesHandler | advanceTime   | 3626  | 0       | 0        |\n|-----------------+---------------+-------+---------+----------|\n| ProfilesHandler | clearProfile  | 3708  | 0       | 0        |\n|-----------------+---------------+-------+---------+----------|\n| ProfilesHandler | delegate721   | 3662  | 0       | 0        |\n|-----------------+---------------+-------+---------+----------|\n| ProfilesHandler | invalidUpdate | 3667  | 0       | 0        |\n|-----------------+---------------+-------+---------+----------|\n| ProfilesHandler | setProfile    | 3665  | 0       | 0        |\n|-----------------+---------------+-------+---------+----------|\n| ProfilesHandler | transfer1155  | 3715  | 0       | 0        |\n|-----------------+---------------+-------+---------+----------|\n| ProfilesHandler | transfer721   | 3557  | 0       | 0        |\n╰-----------------+---------------+-------+---------+----------╯\n\n[PASS] test_HandlerExercisesSuccessFailureRevocationAndReclaim() (gas: 7780672)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 15.35s (15.36s CPU time)\n\nRan 9 test suites in 15.35s (17.38s CPU time): 84 tests passed, 0 failed, 0 skipped (84 total tests)\n","passed":true},{"durationMs":57,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Profiles.clear()\",\"Profiles.set(string,uint8,address,uint256,string)\"],\"files\":{\".gitignore\":5,\".gitmodules\":9,\"ADAPTATION.md\":39,\"README.md\":101,\"docs/LAUNCH-PROFILES.md\":44,\"foundry.lock\":11,\"foundry.toml\":33,\"src/Profiles.sol\":272,\"src/VaultTypes.sol\":450,\"src/helpers/TextRules.sol\":245,\"src/interfaces/IDelegateRegistry.sol\":12,\"test/ADAPTATION.md\":30,\"test/Profiles.t.sol\":576,\"test/ProfilesAudit.t.sol\":289,\"test/ProfilesBehavior.t.sol\":446,\"test/ProfilesInvariant.t.sol\":245,\"test/ProfilesLaunch.t.sol\":62,\"test/ProfilesRules.t.sol\":271,\"test/fork/ProfilesFork.t.sol\":302,\"test/mocks/MockDelegateRegistry.sol\":26,\"test/mocks/MockNFT.sol\":17,\"test/mocks/ProfilesTestTokens.sol\":49},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"697a14badd0f371bdda7a4e7bcaffb79e9f1f2149eb5b1fb1571b04c18e346a2","verifiedTreeHash":"f080170bf78ca67ab152c978c0539139725837d7","verifierVersion":"0.1.0+d372f99e"},{"checks":[{"durationMs":9970,"exitCode":0,"name":"build","output":"Compiling 52 files with Solc 0.8.28\nSolc 0.8.28 finished in 9.90s\nCompiler run successful!\n","passed":true},{"durationMs":123,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/fork/ProfilesFork.t.sol:ProfilesForkTest\n[SKIP: skipped] setUp() (gas: 0)\nSuite result: ok. 0 passed; 0 failed; 1 skipped; finished in 301.02µs (0.00ns CPU time)\n\nRan 2 tests for test/ProfilesLaunch.t.sol:ProfilesLaunchTest\n[PASS] test_FactoryDeploymentUsesExactArgumentsWithoutInitialization() (gas: 39084)\n[PASS] test_FirstCallerCanSetAndClearAfterFactoryDeployment() (gas: 176505)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.32ms (552.48µs CPU time)\n\nRan 5 tests for test/Profiles.t.sol:ProfilesGasTest\n[PASS] test_Gas_Clear() (gas: 42049)\n[PASS] test_Gas_NameLink() (gas: 194922)\n[PASS] test_Gas_NameNft() (gas: 139750)\n[PASS] test_Gas_NameOnlyFirst() (gas: 90900)\n[PASS] test_Gas_Rename() (gas: 78005)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 12.26ms (612.85µs CPU time)\n\nRan 8 tests for test/ProfilesAudit.t.sol:ProfilesAuditTest\n[PASS] testFuzz_NameOwnershipSurvivesRenameAndClear(uint256) (runs: 256, μ: 621682, ~: 625991)\n[PASS] testFuzz_RegistryOnlyAcceptsCanonicalTrue(uint256) (runs: 256, μ: 302081, ~: 302892)\n[PASS] test_DelegationUsesCurrentOwnerAndAllRights() (gas: 356745)\n[PASS] test_EmptyAndDuplicateBatchMatchesIndividualReads() (gas: 301629)\n[PASS] test_FailedUpdatesPreserveWholeRecord() (gas: 476682)\n[PASS] test_InterfaceFailuresRejectWithoutChangingRecord() (gas: 770590)\n[PASS] test_RegistryFailuresDoNotBreakBatchOrReleaseName() (gas: 2313479)\n[PASS] test_TokenCallsAreStaticAndGasCapped() (gas: 950591)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 29.15ms (46.09ms CPU time)\n\nRan 29 tests for test/Profiles.t.sol:ProfilesTest\n[PASS] test_BadPicture() (gas: 369828)\n[PASS] test_ClearFreesName() (gas: 258377)\n[PASS] test_ConstructorZeroTextRules() (gas: 6970)\n[PASS] test_Cyrillic_BadName() (gas: 58769)\n[PASS] test_Dots_BadName() (gas: 116191)\n[PASS] test_Emoji_BadName() (gas: 61664)\n[PASS] test_EvilNft1155_ReadNeverBreaks() (gas: 462943)\n[PASS] test_EvilNft_CannotSetWhileHostile() (gas: 148646)\n[PASS] test_EvilNft_ReadNeverBreaks() (gas: 997540)\nLogs:\n  evil mode 1 profilesOf(3) gas 47909\n  evil mode 2 profilesOf(3) gas 75442\n  evil mode 3 profilesOf(3) gas 75465\n  evil mode 4 profilesOf(3) gas 47953\n  evil mode 5 profilesOf(3) gas 48174\n\n[PASS] test_Link_ArweaveOk() (gas: 284798)\n[PASS] test_Link_EvilHost() (gas: 202692)\n[PASS] test_Link_OtherAllowlistedHosts() (gas: 274155)\n[PASS] test_Link_TooLongOrBadChars() (gas: 694010)\n[PASS] test_Nft1155_SetOwnedAndSold() (gas: 428222)\n[PASS] test_Nft721_Delegate() (gas: 408562)\n[PASS] test_Nft721_NoRegistry_NoDelegate() (gas: 95905)\n[PASS] test_Nft721_NotOwner() (gas: 91811)\n[PASS] test_Nft721_SetAndOwned() (gas: 163475)\n[PASS] test_Nft721_SoldThenOwnedFalse_NewOwnerSetsIt() (gas: 404468)\n[PASS] test_NoMoney() (gas: 67476)\n[PASS] test_OtherBadNames() (gas: 298949)\n[PASS] test_PictureOnly_ThenNameFreed() (gas: 210888)\n[PASS] test_ProfilesOf100() (gas: 21772190)\nLogs:\n  profilesOf(100 x name+NFT) gas 1585092\n\n[PASS] test_RenameFreesOldName() (gas: 275268)\n[PASS] test_Reserved() (gas: 949156)\n[PASS] test_SinceKeptOnUpdate() (gas: 185541)\n[PASS] test_SkeletonUnique() (gas: 628651)\n[PASS] test_Space_BadName() (gas: 88581)\n[PASS] test_ValidNames() (gas: 477450)\nSuite result: ok. 29 passed; 0 failed; 0 skipped; finished in 29.15ms (20.74ms CPU time)\n\nRan 5 test suites in 29.97ms (72.18ms CPU time): 44 tests passed, 0 failed, 1 skipped (45 total tests)\n","passed":true},{"durationMs":44,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"Profiles.clear()\",\"Profiles.set(string,uint8,address,uint256,string)\"],\"files\":{\".gitignore\":5,\".gitmodules\":9,\"ADAPTATION.md\":39,\"README.md\":101,\"docs/LAUNCH-PROFILES.md\":44,\"foundry.lock\":11,\"foundry.toml\":33,\"launch.json\":13,\"src/Profiles.sol\":272,\"src/VaultTypes.sol\":450,\"src/helpers/TextRules.sol\":245,\"src/interfaces/IDelegateRegistry.sol\":12,\"test/Profiles.t.sol\":576,\"test/ProfilesAudit.t.sol\":289,\"test/ProfilesLaunch.t.sol\":62,\"test/fork/ProfilesFork.t.sol\":128,\"test/mocks/MockDelegateRegistry.sol\":26,\"test/mocks/MockNFT.sol\":17},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"b43f3fdfd8a5068ac55899e50e3d22926aa3f32fa8e1c827863e1e634fd1a8df","verifiedTreeHash":"3329e859983ed5a7c3548ab36246aafa7586c188","verifierVersion":"0.1.0+d372f99e"}]}