{"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":"e3e9b712-4a74-44d7-83e6-58bdf61bde0c","kind":"audit","nodes":[{"acceptedSubmissionHash":"246b0b16b258d0c7815800e05abeed2b2d0c564dd6aade8a6e402a4196cb14cc","dependsOn":[],"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":"44a0ed79eff9f81f1904f54e621419cdaa3d551864a751d05664e9d4ebcddb4c","dependsOn":[],"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":"39340cc459ea762d6d12cae73f7b647704c6ca2225ef59dc180317eef7f790be","dependsOn":["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":"02842db621c57f7aa646f5f77fcd1a923667ce4e2ad5e8ab99cfc061d76ed140","dependsOn":[],"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":"e227d43d5161f9408a7c7671b10057f45fc115349b533eab6316e1ff58de0d4e","dependsOn":[],"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"}],"objective":"Review Submission20/ only (read Submission20/AUDIT_REQUEST.md first; Submission19/AUDIT_REQUEST.md is the reference for the GOLD ledger design). World source 0727200, NOT deployed, production registry empty. It fixes Swarm audit 8febfeed and makes the paid Genesis order name its payment token (the Genesis contract's matching change is public at github.com/tungweb3/ember-evo-genesis-review, Submission7). Files: server/genesis-gold.ts, genesis-gold-reader.ts, genesis-gold-service.ts, genesis-deployments.ts, world-gold-result.ts, tests/genesis-gold.test.mjs.\n\n1. Token binding: can a hold be made for a token the registry entry does not list, at another token's GOLD price, or with a wallet consent that names a different token than the order?\n2. The stored-order retry path (parseOrder with prices=false): can a caller use it to hold or change anything the first hold would have refused (another wallet, order, price, deployment, or no valid consent)?\n3. orderWindow deploy branch (lo = deploy, then binary search): any off-by-one or case where the consumption block is left out? It must only ever keep a hold, never release one.\n4. Cron page per deployment (query filtered by chain_instance, chain_id, contract; one reconcileHeldMintGold call per id): can it skip or repeat a held order across cursor wraps, or exceed the cron's CPU and subrequest limits?\n5. Rate-limit keys (genesis:rpc for the cron, genesis:rpc:service for the service binding): does any chain read use the wrong key?\n\nReport severity, reproduction and fix. Not in scope: 3D/rendering, media, Celestao, AIMarket.","parentJobId":null,"planHash":"6d9d1e7d74bc592a58417b97c34b7ddfaa78063213c8d9c126c1f5985fa65506","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"e3e9b712-4a74-44d7-83e6-58bdf61bde0c","publication":{"commit":null,"deliveredAt":null,"repoUrl":null},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52604","feedbackHash":"c2f2c71e6cf37a9feeefcea4d64f32472a28fb693e7f0e26bc24925c6736ee37","nodeKey":"audit_economics","submissionHash":"246b0b16b258d0c7815800e05abeed2b2d0c564dd6aade8a6e402a4196cb14cc","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51035","feedbackHash":"4e86a5e37b0e7e26fb8997c89ca8883ee3ab906e088a922ce24581c39a2c859c","nodeKey":"audit_flow","submissionHash":"44a0ed79eff9f81f1904f54e621419cdaa3d551864a751d05664e9d4ebcddb4c","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52164","feedbackHash":"2f806aa7dbbdfd4afe74eebc95c2383719ed835b221aee0b7efc1cefff8d263e","nodeKey":"audit_judge","submissionHash":"39340cc459ea762d6d12cae73f7b647704c6ca2225ef59dc180317eef7f790be","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52606","feedbackHash":"4b9ed91ae389c953af87c5377b7a5795ba27040bde0cfd52e98df69d81441fb4","nodeKey":"audit_math","submissionHash":"02842db621c57f7aa646f5f77fcd1a923667ce4e2ad5e8ab99cfc061d76ed140","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52608","feedbackHash":"7d8d57813ecda6f5fd7a48bcad91d9e89d31e15da79c4021e353394235ed53f0","nodeKey":"audit_permissions","submissionHash":"e227d43d5161f9408a7c7671b10057f45fc115349b533eab6316e1ff58de0d4e","tag1":"review:submission","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"51289724712fa7d6c131e61299add784f11d938a381a8b2a1d5a102b4f42225d","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"829d84438fb3fdc8","findings":[{"citation":"resolved","description":"The filter on MINT_SCOPE_MISMATCH was correct in 7939c37, where reconcileHeldMintGold paged across every held mint and other deployments' rows produced that code as noise. In 0727200 the page is already restricted to this deployment (query on chain_instance, chain_id, contract, line 175) and reconcileHeldMintGold is called per id, so the book-side scope check in world-gold.ts line 206 and the reader's own check (genesis-gold-reader.ts line 93) can never fire. The only remaining sources of MINT_SCOPE_MISMATCH are real failures of the deployment itself: eth_chainId not equal to the registry chainId (reader line 97, e.g. GENESIS_RPC_URL pointing at the wrong network, or the Alchemy transport answering for another chain) and keccak256(eth_getCode) not equal to the registry codeHash (reader line 102, e.g. a wrong codeHash in a new entry). Both are filtered out of the deployment's outcomes, so maintainGenesisGold (genesis-gold-service.ts line 57) returns an empty list, worker/app.ts logs nothing (it logs only when settled.length is non-zero), the cursor is written as usual, and every held order of the deployment stays held for ever with no operator signal. No GOLD is released or spent wrongly (hold kept), but the condition that stops all settlement is invisible, while the same failure through the service binding is reported (reconcileGenesisGold returns code MINT_SCOPE_MISMATCH, as the test 'wrong chain, code, events or an RPC failure keep the hold' asserts). Boundary x invariant seam: the filter encoded the old paging invariant ('a scope mismatch is another deployment's row'); the new per-deployment page changed the invariant and the filter was not revisited.","line":181,"path":"Submission20/source/server/genesis-gold.ts","reproduction":"State: one held order for DEP (tests/genesis-gold.test.mjs fixtures: reserve(f, await request())). Input: run the cron step with a chain whose eth_chainId answers 0x1 while DEP.chainId is 11155111, i.e. reconcileGenesisDeployments(f.db, LIST, 'sepolia', (d,hint)=>createGenesisR5Reader(d, chain({chainId:1}).rpc, hint), NOW), or with chain({code:'0x60aa'}) so the code hash differs from DEP.codeHash. Expected: out[0].outcomes equals [{id: order().orderId, status:'MINT_SCOPE_MISMATCH'}] and maintainGenesisGold returns that entry so the cron logs it (the service path already returns this code for the same chain: settle(f, chain({chainId:1})) gives code 'MINT_SCOPE_MISMATCH'). Actual: out[0].outcomes is [] (the filter at line 181 removes the only outcome), maintainGenesisGold returns [], no 'genesis_gold' log line is written, the cursor is written as '' and the order stays held on every later run with the same silence. Fix: drop the filter (report outcomes unchanged), or, if a scope mismatch is still to be hidden for some reason, hide it only when it came from the book's own scope check, which the per-deployment query makes unreachable anyway. One line: out.push({deployment:d.id,outcomes});","severity":"low","snippet":"   out.push({deployment:d.id,outcomes:outcomes.filter(o=>o.status!=='MINT_SCOPE_MISMATCH')});","title":"Cron swallows MINT_SCOPE_MISMATCH: a wrong-chain RPC answer or a code-hash mismatch keeps every hold of a deployment without any log line"},{"citation":"resolved","description":"The cursor is advanced to the last id whenever the page is full (ids.length === limit) and reset to '' only when a page comes back short. The query reads exactly `limit` rows, so a full page cannot tell whether any row follows it. When the number of held orders of a deployment (with id above the cursor) is an exact multiple of GENESIS_CRON_PAGE (8, 16, 24 ...), the run after the last full page selects nothing, does no chain read, and only resets the cursor; the orders are visited again one run later. With the production cron at */15 (R6/PRODUCTION_DEPLOYMENT.json) and GENESIS_MAX_TTL_S = 900 s, a typical abandoned order is seen as 'pending' on the first visit (deadline not yet past in chain time) and released on the second; the empty run inserts a third 15-minute interval between the two visits, so the wallet's GOLD stays reserved 30 minutes instead of 15 after the deadline, and a consumed order the signer did not reconcile with a hint is settled 15 minutes later than necessary. The existing test uses n = GENESIS_CRON_PAGE + 2 and so never meets the exact-multiple case. Boundary x invariant: the cursor invariant 'a full page means more rows may follow' is true, but the implementation treats it as 'more rows do follow'.","line":180,"path":"Submission20/source/server/genesis-gold.ts","reproduction":"State: exactly 8 held orders of DEP (as in the test 'cron pages through held orders ...' but with n = GENESIS_CRON_PAGE instead of GENESIS_CRON_PAGE + 2), chain at finalTime DEADLINE (every order pending). Run 1: reconcileGenesisDeployments(...) returns 8 'pending' outcomes and the cursor is ids[7]. Run 2 with chain finalTime DEADLINE + 1 (all releasable): expected 8 'released' outcomes (or at least a non-empty page); actual: the page query returns zero rows (no id > ids[7]), outcomes is [], no RPC is made, the cursor is reset to ''. Run 3 finally releases the 8 orders; (await f.snapshot()).reserved only becomes '0' after the third run instead of the second. Fix: read limit + 1 rows (LIMIT ?+1 or bind limit+1), reconcile only the first `limit`, and set the cursor to the last reconciled id only when a (limit+1)th row exists, else ''. Alternatively, when the page is empty and the cursor was non-empty, immediately re-run the query from '' in the same invocation (bounded to one extra query).","severity":"low","snippet":"    .bind(d.id,ids.length===limit?ids.at(-1)!:'',nowMs).run();","title":"Cron cursor: a page that is exactly full ends the cycle one run late (an empty run before the wrap), delaying release or settlement of that page by one cron interval"},{"citation":"resolved","description":"The page size is sized for the worst case per order (a consumed order without a transaction hint: ~1 eth_chainId + 1 finalized block + 1 eth_getCode (once per block) + 2 eth_call + 2 timeOf + up to ~20 binary-search timeOf + ~11 eth_getLogs of 10 blocks + receipt + 2 block checks, about 35-40 RPC subrequests, so 8 orders are about 300 subrequests of the Paid plan's 1,000 per invocation). But the common cron case is the cheap one: an order that was never paid (pending, then released) costs 5-6 RPC calls and no log search. The page counts orders, not cost, so the cron releases at most 8 orders per run, and since an abandoned order is usually seen once as 'pending' before its deadline passes in chain time and once more as 'released', the sustained rate is 4-8 releases per 15-minute run, 384-768 per day per deployment. Numbers for the 1,688-piece sale: 200 orders abandoned within one hour (consent given, GOLD held, mintPaid never sent, which the user can do at no cost) take 25-50 cron runs, 6-12 hours, before the last one is released; each such wallet's 1,200 or 1,600 GOLD stays reserved for that time and, unless its book balance is at least twice the price, every new order of that wallet is refused with GOLD_INSUFFICIENT (world_gold_holds SUM(amount) counts the stale hold) until the cron gets to it. The signer can release such an order sooner through the service binding (reconcile without a hint reads the chain and releases after the deadline), but nothing in 0727200 requires it to, and the Submission19 request names the cron as the path that settles orders the signer did not reconcile. Boundary x precision: the page bound was derived from the most expensive order and applied to every order.","line":163,"path":"Submission20/source/server/genesis-gold.ts","reproduction":"State: 24 held orders of DEP with the same deadline (reserve 24 orders with orderIds H(0x500+i), a wallet with enough GOLD or 24 wallets), chain at finalTime DEADLINE + 1 so every order is releasable. Input: reconcileGenesisDeployments(f.db, LIST, 'sepolia', reader, NOW) once. Expected (what the RPC budget allows): the 24 cheap reads, 6 RPC each, about 150 subrequests, all released in one run. Actual: 8 released, 16 still held; two more runs (30 minutes in production) are needed, and (await f.snapshot()).reserved stays non-zero until then; a new reserve for one of those wallets with book balance below 2x the price fails GOLD_INSUFFICIENT meanwhile. Fix that keeps the worst-case bound: page by RPC budget instead of by order count, e.g. keep GENESIS_CRON_PAGE as the cap on orders that needed a log search (the reader can report whether it searched), and let the loop continue over further ids while the outcome was 'pending' or 'released' up to reconcileHeldMintGold's own cap of 32 per deployment; or read two pages, one of orders whose deadline (world_gold_mints.deadline) is already past in wall-clock time (cheap, released or consumed, larger page) and one of the rest. Document whichever bound is chosen next to GENESIS_CRON_PAGE with the per-order subrequest counts above.","severity":"low","snippet":"export const GENESIS_CRON_PAGE=8;","title":"Cron page of 8 bounds release throughput to roughly 4-8 abandoned orders per 15 minutes per deployment; a wallet with one abandoned hold cannot place a second order until the cron reaches it"}],"hash":"02842db621c57f7aa646f5f77fcd1a923667ce4e2ad5e8ab99cfc061d76ed140","nodeId":"860b693f-d47e-42ec-b785-7d2a4a048058","outcome":"completed","summary":"The review is complete. Three Low findings are written to `.imd-findings.json`, validated against the tree (path, line and snippet all match). No critical or high finding, so no Foundry proof was needed, and no repository file was changed.\n\n**Outcome of the five questions in the audit request**\n\n1. **Token binding: no defect.** The order's token is normalized, looked up by exact match against the registry's payment token or added tokens, and the price must equal that token's listed price. The wallet's consent and the stored document both carry the token. The public Submission7 contract was fetched and checked: its event signatures, indexed fields, deadline comparison and `GenesisMinted.cost` all match what the reader expects, so 8febfeed finding 1 is correctly closed as not applicable.\n2. **Retry path: no defect.** With prices skipped, the rebuilt document must still equal the stored one byte for byte, the scope must match, and the wallet's consent is verified. The path writes nothing, so nothing can be held or changed.\n3. **orderWindow deploy branch: correct.** The clamped start block always has a timestamp below the window start or triggers the early return, the binary-search invariant holds for both branches, and the inclusive upper bound follows from one block per slot. No case leaves the consumption block out.\n4. **Cron page: three Low findings, listed below.** No order can be skipped permanently, and repeats are idempotent.\n5. **Rate-limit keys: correct.** The cron reader defaults to the cron key and the service binding passes the service key through every chain read.\n\n**Findings**\n\n- **Low: MINT_SCOPE_MISMATCH is filtered out of the cron's report.** The filter was right when the page spanned all deployments. Now the page is per deployment, so the only remaining sources are a wrong-chain RPC answer or a code-hash mismatch, and both are silenced with no log line while every hold of that deployment stays held. Fix is to drop the filter.\n- **Low: an exactly full page costs an empty cron run.** With a held count that is a multiple of eight, the next run selects nothing and only resets the cursor, delaying release or settlement by one 15-minute interval. Fix is to read one extra row to decide whether to advance the cursor.\n- **Low: the page of 8 bounds throughput by order count, not by RPC cost.** Abandoned orders cost about six RPC calls each but still consume a slot, giving roughly 4 to 8 releases per run. A wallet with one abandoned hold cannot place a new order without twice the GOLD until the cron reaches it. Fix is to page by RPC budget.\n\n**Coverage limits.** The TypeScript project is not runnable from this snapshot, since economy-config.ts and the test fixture are not public, so reproductions are given against the project's own test harness rather than executed here. CPU and subrequest limits of the Worker could not be measured; the subrequest arithmetic in the third finding is derived from the reader's call pattern.","treeHash":null,"usage":{"cachedInputTokens":2805274,"inputTokens":674,"model":"claude-fable-5-1","outputTokens":43149,"runtime":"claude","turns":39,"wallClockMs":992124}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"9e17b97b8ac7c97a","findings":[{"citation":"resolved","description":"reconcileGenesisDeployments stores the last id of the page as the cursor whenever the page is full (ids.length===limit), without knowing whether any held order sorts after it. When the number of a deployment's held orders is an exact multiple of GENESIS_CRON_PAGE (8), the run after a full page selects `id>cursor`, finds nothing, reconciles nothing, and only resets the cursor to ''. The deployment's holds are then reconciled on every second cron run instead of every run, so the time to settle or release a hold doubles (with N held orders, a full cycle takes ceil(N/8)+1 runs whenever N mod 8 == 0, instead of ceil(N/8)). No order is skipped or double-settled (the probe shows every id reached after the wrap, and settlement is idempotent), and no GOLD is affected, but the cron's budget is wasted and the per-deployment settlement latency is twice what the audit request states (one page per run). This is the code path the submission introduced for audit 8febfeed finding 3; the earlier version had the same wrap behaviour through reconcileHeldMintGold's `next`, now owned here. Fix: select limit+1 rows and treat the page as full only when the extra row exists (store ids[limit-1] as the cursor and process only the first `limit`), or, simpler, when the page is full and no later row exists (a second cheap `SELECT 1 ... AND id>? LIMIT 1`), store '' so the next run starts from the beginning. Either keeps the one-page-per-run bound and the no-starvation property.","line":180,"path":"Submission20/source/server/genesis-gold.ts","reproduction":"State: one registry entry (environment 'sepolia', id 'sepolia-r5-test-1'), a wallet with 1000 GOLD, exactly 8 held Genesis orders of that entry (ids 0x..500 to 0x..507), and a chain reader whose finalized block timestamp equals the order deadline (every order stays pending; tokenId 0, not revoked, not past deadline). Call reconcileGenesisDeployments(db,[DEP],'sepolia',reader,NOW) three times. Expected: each run reconciles the 8 held orders (one page per run, as AUDIT_REQUEST.md section 3 item 4 states). Actual (measured with the submission's genesis-gold.ts over the locked world-gold.ts and a node:sqlite D1 stand-in): run 1 reconciles 8 orders and stores cursor 0x..507; run 2 reconciles 0 orders (the page query `id>0x..507` returns no row) and stores cursor ''; run 3 reconciles 8 again. Adding a ninth hold with a lower id (0x..100) between runs reproduces the same idle run after each full page (run 4: 0 orders; run 5: 8 orders ending at 0x..506; run 6: 1 order). The pattern repeats indefinitely while the count stays a multiple of 8, e.g. eight orders stuck in MINT_PROOF_CONFLICT (which the request says stay held) make every other cron run a no-op for that deployment.","severity":"low","snippet":"    .bind(d.id,ids.length===limit?ids.at(-1)!:'',nowMs).run();","title":"Cron cursor: when a deployment's held orders fill the page exactly, every second cron run reconciles nothing for it"},{"citation":"resolved","description":"Submission20 makes the order, the wallet's consent and the stored document name the payment token, and the contract's PaidAuthorization binds it. The World's settlement, however, still compares only PaidOrderConsumed(orderId, wallet, tokenId; goldCost) and GenesisMinted(wallet, tokenId, lookKey; choice, skin, paid, cost): neither event carries the token, so the stored order.token is never checked against the chain. For two listed tokens with the same GOLD price (imdUSD v1 and v2, both 1,200 GOLD, the case the audit request names) the proof is identical whichever one paid. This is only reachable through the trusted Genesis signer (it must sign a PaidAuthorization naming a different token than the hold it reserved), so it is a documented trust assumption, not a bypass: GOLD held and GOLD charged are equal, and the wallet consented to that amount. The consequence is a World record (world_gold_mints.auth_json order.token, and the review record built from it) that names a token other than the one actually paid, which a later reconciliation of the treasury Safe's receipts against the book would not explain. The receipt the reader already fetches contains the payment: an ERC-20 Transfer(wallet -> order.recipient) emitted by order.token. Minimal fix that preserves the design: in the consumed branch require exactly one Transfer log emitted by `order.token` with topics[1]==wallet and topics[2]==order.recipient in the receipt (MINT_PROOF_CONFLICT otherwise, which keeps the hold as every other mismatch does). Alternatively, have the Genesis contract include the token in PaidOrderConsumed and compare it here.","line":141,"path":"Submission20/source/server/genesis-gold-reader.ts","reproduction":"State: registry entry listing paymentToken IMD (8 GOLD) and addedTokens [USDC 9, V2 8]; a held order with token IMD, goldCost 8, consent signed over token IMD. Chain reader input: paidOrderTokenId(orderId)=7, a finalized receipt with status 1 containing (a) a Transfer log emitted by V2 (not IMD) from the wallet to the recipient, (b) GenesisMinted for the wallet and token 7 with the order's lookKey, choice, paid=1 and embeoCost, (c) PaidOrderConsumed(orderId, wallet, 7; goldCost 8). Expected (if the token binding were enforced end to end): the hold stays held with MINT_PROOF_CONFLICT because the payment came from a token other than the one the order and consent name. Actual (measured with the submission's reader): reconcileGenesisGold returns state 'consumed'; world_gold_mints.auth_json still records order.token = IMD (0xa1a1...a1a1) while the token that emitted the payment Transfer is V2 (0xd3d3...d3d3).","severity":"info","snippet":"   if(addrTopic(c[2])!==m.wallet||BigInt(c[3])!==tokenId||wordAt(cData,0)!==BigInt(m.gold)\n    ||addrTopic(g[1])!==m.wallet||BigInt(g[2])!==tokenId||g[3]!==order.lookKey||wordAt(gData,0)!==BigInt(order.choice as number)\n    ||wordAt(gData,2)!==1n||wordAt(gData,3)!==BigInt(order.embeoCost as string))fail('MINT_PROOF_CONFLICT');","title":"Trust assumption: the reader cannot verify which listed token paid; a hold recorded for imdUSD v1 settles on a receipt paid in imdUSD v2 (same GOLD price)"}],"hash":"246b0b16b258d0c7815800e05abeed2b2d0c564dd6aade8a6e402a4196cb14cc","nodeId":"d3a6d392-1f80-4977-ba56-2e0082a634e3","outcome":"completed","summary":"Review of Submission20 (World source 0727200) is complete. The findings file holds one Low and one Info finding; no repository file was changed.\n\n**How I checked.** The six scope files are TypeScript, and the private modules they import are not in the tree, so the submission's own test file cannot run here. I built a harness outside the repository with the submission's six files, the locked `world-gold.ts` from Submission19, stubs for the missing private modules, and a node:sqlite stand-in for D1. Every claim below was exercised against that harness with concrete inputs.\n\n**Findings written to `.imd-findings.json`:**\n\n- **Low, cron cursor idle run** (`genesis-gold.ts:180`). When a deployment's held orders are an exact multiple of the page size, the cursor is set to the last id, the next run finds nothing above it and only resets the cursor. Measured: with 8 held pending orders, run 1 reconciles 8, run 2 reconciles 0, run 3 reconciles 8. Settlement latency for that deployment doubles. No order is skipped or double-settled. Fix: fetch one extra row and only advance the cursor when a later row exists.\n- **Info, trust assumption** (`genesis-gold-reader.ts:141`). The order and consent now name the token, but `PaidOrderConsumed` and `GenesisMinted` carry no token, so the reader never checks it. A hold recorded for imdUSD v1 settles as consumed on a receipt whose payment Transfer came from imdUSD v2 at the same GOLD price. Only the trusted signer can cause this and no GOLD is lost, so it is documented, not a bypass. The receipt already contains the payment Transfer, so the reader could require one emitted by the order's token to the recipient.\n\n**Questions with no defect found:**\n\n1. **Token binding.** Unlisted token, cross-price, the recipient as token, and consents naming another token, chain or contract were all refused with the expected codes. Nothing was held.\n2. **Retry path.** Thirteen variants (other wallet's consent, garbage consent, other token at the same price, other wallet, edited registry token, recipient, deployBlock, embeoCost, codeHash, domain version, retry an hour after the deadline, longer deadline, EIP-55 casing) either returned the stored view or were refused. The hold count never changed. A changed codeHash or domain version conflicts, which matches the append-only registry rule.\n3. **orderWindow.** Fuzzed through the reader on 3008 random chains with missed slots and random deploy blocks, plus the deploy-block edges (deploy timestamp exactly at the window start, consumption in the deploy block, deadline exactly on a block). Every consumption inside the window was found. At most 27 RPC calls and 98 searched blocks per read.\n4. **Cron page.** No skip and no repeat within a cycle; a low id inserted between runs is reached after the wrap. Per deployment a full page costs at most about 216 RPC calls, inside the 600 per minute limiter budget seen in the Worker config.\n5. **Rate-limit keys.** The service reader is built with the service key, the cron with the cron key, and neither the mainnet transport in `ownership.ts` nor `upstreamFetch` applies a limiter of its own. No read uses the wrong key.\n\n**Limits.** The private `economyAddress`, schema and test fixture were replaced by stubs whose behavior I inferred from the submission's passing tests. The genesis contract's event shapes were taken from the reader's own topic definitions, not the Solidity source.","treeHash":null,"usage":{"cachedInputTokens":2393495,"inputTokens":546,"model":"claude-fable-5-1","outputTokens":48247,"runtime":"claude","turns":44,"wallClockMs":644148}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"63458a1bd2b2d376","findings":[{"citation":"resolved","description":"In 7939c37 the cron page came from the global reconcileHeldMintGold, which returned MINT_SCOPE_MISMATCH for every other deployment's held order, so filtering that code out was noise removal. In 0727200 the page is already scoped (chain_instance, chain_id, contract are bound in the SELECT at line 175, and reconcileHeldMintGold is called once per id with the deployment's own reader), so the book-side scope check in the locked world-gold.ts (line 206) and the reader's binding check (genesis-gold-reader.ts line 93) can no longer fire. The only MINT_SCOPE_MISMATCH that can reach line 181 now comes from the reader itself: eth_chainId not equal to the registry chainId (reader line 97: GENESIS_RPC_URL or the Alchemy app on another network) or keccak256(eth_getCode) not equal to the registry codeHash, or empty code (reader line 102: a metadata-hash difference between artifact and deployed bytecode, a typo in a new entry). Both mean every hold of that deployment stays held for ever (the reader fails before any settle). The filter removes those outcomes, maintainGenesisGold (genesis-gold-service.ts line 57) returns an empty list, worker/app.ts logs genesis_gold only when the list is non-empty, and the cursor is written normally, so the run leaves no trace. The service path reports the same chain state correctly (reconcileGenesisGold returns code MINT_SCOPE_MISMATCH, asserted by the test 'wrong chain, code, events or an RPC failure keep the hold'), so the two paths disagree about one chain state. No GOLD is spent or released wrongly (the hold is kept); the operator path meant to notice a stuck deployment is blind. Merged from three specialist reports of the same line (math, flow); reproduced in a harness of the submission's files over the locked world-gold.ts with a node:sqlite D1 stand-in. Fix: push outcomes unchanged (one line: out.push({deployment:d.id,outcomes})) and let maintainGenesisGold's status!=='pending' filter surface MINT_SCOPE_MISMATCH per id like MINT_PROOF_CONFLICT and MINT_CHAIN_UNAVAILABLE; or collapse repeated scope mismatches of one page into one deployment-level status, but never drop them. Add a cron-path case to the existing wrong-chain test.","line":181,"path":"Submission20/source/server/genesis-gold.ts","reproduction":"State: registry entry DEP (tests/genesis-gold.test.mjs fixtures), one held order (reserveGenesisGold with a valid consent, reserved 8). Chain stand-in: chain({chainId:1}) (eth_chainId answers 0x1 for the 11155111 entry) or chain({code:'0x60aa'}) (code hash differs from DEP.codeHash). Input: reconcileGenesisDeployments(db,LIST,'sepolia',(d,hint)=>createGenesisR5Reader(d,c.rpc,hint),NOW), and maintainGenesisGold(env,{deployments:LIST,environment:'sepolia'},fetchStub,NOW) with the same answers. Expected: out[0].outcomes equals [{id:order().orderId,status:'MINT_SCOPE_MISMATCH'}] and maintainGenesisGold returns that entry, as the service path does for the same chain (reconcileGenesisGold(...) returns code 'MINT_SCOPE_MISMATCH'). Actual (measured): service code MINT_SCOPE_MISMATCH; cron outcomes []; maintainGenesisGold []; cursor written as ''; order still held (reserved 8) on every later run with the same silence. Both chain variants behave identically.","severity":"low","snippet":"   out.push({deployment:d.id,outcomes:outcomes.filter(o=>o.status!=='MINT_SCOPE_MISMATCH')});","title":"Cron page drops every MINT_SCOPE_MISMATCH outcome, so a wrong-chain RPC or a wrong registry codeHash leaves all of a deployment's holds stuck with nothing logged"},{"citation":"resolved","description":"The cursor is advanced to the last id whenever ids.length===limit and reset to '' only when a page comes back short. The SELECT reads exactly limit rows, so a full page cannot tell whether a row follows it. When a deployment's held orders above the cursor number an exact multiple of GENESIS_CRON_PAGE (8, 16, 24, ...), the run after the last full page selects nothing (no id > cursor), makes no chain read, and only resets the cursor; the orders are visited one run later. No order is skipped or reconciled twice per wrap (id>cursor ORDER BY id; an order inserted below the cursor is reached after the wrap), and settlement is idempotent, so correctness holds; the cost is one wasted scheduled invocation per cycle and doubled per-deployment latency for the last page. The scheduled handler runs maintainGold on the '* * * * *' trigger (worker/app.ts line 262; Submission13 wrangler.jsonc lists both '*/15 * * * *' and '* * * * *'), so the delay is one minute per wrap, not the 15 minutes some specialist reports assumed; a page of 8 orders stuck in MINT_PROOF_CONFLICT (which the request says stay held) makes every other run a no-op for that deployment indefinitely. The existing test uses n = GENESIS_CRON_PAGE + 2 and never meets the exact-multiple case. Merged from three specialist reports of the same line (math, flow, economics). Fix: select limit+1 rows, reconcile only the first limit, and store ids[limit-1] as the cursor only when the extra row exists, else ''; or, after a full page, run one cheap 'SELECT 1 ... AND id>? LIMIT 1' and store '' when it is empty. Either keeps the one-page-per-run bound and the no-starvation property. Add a test with n = GENESIS_CRON_PAGE.","line":180,"path":"Submission20/source/server/genesis-gold.ts","reproduction":"State: exactly 8 held orders of DEP (orderIds H(0x500..0x507), a wallet with enough GOLD), cursor row absent. Run 1: reconcileGenesisDeployments(db,[DEP],'sepolia',reader,NOW) with chain({finalTime:DEADLINE}) (every order pending). Run 2 with chain({finalTime:DEADLINE+1}) (every order releasable). Expected for run 2: 8 'released' outcomes, reserved 0 (one page per run, AUDIT_REQUEST section 3 item 4). Actual (measured): run 1 returns 8 outcomes and stores cursor 0x...0507; run 2 returns 0 outcomes, makes no RPC call, stores cursor '' and reserved stays 64; run 3 returns 8 'released' and reserved becomes 0. The pattern repeats on every wrap while the count stays a multiple of 8.","severity":"low","snippet":"    .bind(d.id,ids.length===limit?ids.at(-1)!:'',nowMs).run();","title":"Cron cursor treats an exactly full page as \"more rows follow\": with k*GENESIS_CRON_PAGE held orders every cycle costs one empty run, delaying release or settlement of that page by one cron interval"},{"citation":"resolved","description":"0727200 adds token to the order, to the wallet's GenesisGoldHold consent and to the stored document, and the registry comment (genesis-gold.ts lines 30-32) says an order 'is payable only in' its token. On the World side that binding ends at the hold. createGenesisR5Reader.read() settles from PaidOrderConsumed(orderId, wallet, tokenId; goldCost) and GenesisMinted(wallet, tokenId, lookKey; choice, skin, paid, cost): neither event carries the payment token, the `own` filter at line 130 keeps only logs the Genesis contract emitted, so the ERC-20 Transfer that shows which token actually paid is never read, and order.token is never compared with anything on chain (lines 95-96 and 141-143 compare orderId, wallet, goldCost, deadline, lookKey, choice, embeoCost, schema, deploymentId and codeHash only). For two listed tokens with the same GOLD price (imdUSD v1 and v2, both 1,200 GOLD, the case the audit request names) the proof is identical whichever token paid. Reachability: the contract's PaidAuthorization binds the token the Genesis signer signs, so this needs the signer to sign a different token than the hold it reserved (a signer defect, a later signer change, or a compromise); Submission19 section 2 records the signer as trusted. Impact today: GOLD held and GOLD charged are equal and the wallet consented to that amount, but world_gold_mints.auth_json (and the review record built from it) names a token other than the one that paid, which a reconciliation of the treasury Safe's receipts against the book cannot explain; if the other token has a different price, the hold stays MINT_PROOF_CONFLICT (safe). Reported so the 'payable only in it' claim is read as a signer property, and because a later addPaymentToken at another price makes the equal-price assumption load-bearing. Merged from three specialist reports of the same line (permissions, flow, economics). Minimal fix that preserves the design: in the consumed branch require, in the same receipt, exactly one Transfer(address,address,uint256) log emitted by order.token with topics[1]==wallet and topics[2]==order.recipient (the contract pulls the payment with transferFrom to paymentRecipient; a Safe or 4337 wallet is the order wallet itself), MINT_PROOF_CONFLICT otherwise; optionally compare the amount with a per-token amount in the registry. Alternatively have the Genesis contract include the token in PaidOrderConsumed and compare it here. Add a test where an IMD hold meets a receipt whose Transfer comes from V2, expecting MINT_PROOF_CONFLICT.","line":141,"path":"Submission20/source/server/genesis-gold-reader.ts","reproduction":"State: registry entry listing paymentToken IMD (goldCost '8') and addedTokens [{USDC,'9'},{V2,'8'}]; a held order with token IMD, goldCost '8', consent signed over token IMD. Chain reader input: paidOrderTokenId(orderId)=7, a finalized receipt with status 1 whose logs are (a) Transfer(wallet -> recipient, 20e18) emitted by V2 (0xd3d3...d3d3) and none by IMD, (b) GenesisMinted for the wallet and token 7 with the order's lookKey, choice, paid=1, embeoCost, (c) PaidOrderConsumed(orderId, wallet, 7; goldCost 8). Call reconcileGenesisGold(db,LIST,'sepolia',reader,{deploymentId,orderId},NOW). Expected if the token binding were enforced end to end: state held, code MINT_PROOF_CONFLICT. Actual (measured): state 'consumed', reserved 0, auth_json order.token still 0xa1a1...a1a1 (IMD). Same with the existing harness: settle(f,chain({tokenId:7n})) settles an IMD hold although the receipt contains no ERC-20 Transfer log at all.","severity":"low","snippet":"   if(addrTopic(c[2])!==m.wallet||BigInt(c[3])!==tokenId||wordAt(cData,0)!==BigInt(m.gold)","title":"Settlement never checks which token paid: a hold that names imdUSD v1 is consumed by a mint paid in v2 or any token with the same GOLD price (a Genesis-signer trust assumption, not a World check)"},{"citation":"resolved","description":"The page size is sized for the worst case per order (a consumed order without a transaction hint: about 35-41 RPC subrequests including the binary search and up to 11 eth_getLogs of 10 blocks), but the common cron case is cheap: an order that was never paid costs eth_chainId, finalized block, eth_getCode (once per block), two eth_call and the final block check, about 5-6 calls and no log search. Because the page counts orders, a run releases at most 8 abandoned orders per deployment, and each such wallet's held GOLD counts against its available balance (world_gold_holds SUM(amount)) until the cron reaches it; a wallet whose book is below twice the price cannot place a second order meanwhile (GOLD_INSUFFICIENT). The scheduled handler runs the GOLD step on the '* * * * *' trigger (worker/app.ts line 262, Submission13 wrangler.jsonc), so the bound is about 8 releases per minute per deployment, roughly 480 per hour; 200 holds abandoned in one hour of a sale clear within about 25-50 minutes of the last deadline, not the 6-12 hours one specialist computed from a 15-minute interval. With ECONOMY_CHAIN_LIMITER at 600 per minute per location (Submission13 wrangler.jsonc) and the Paid plan's 1,000 subrequests, a worst-case page of 8 (about 330 calls) fits; the limits are not exceeded. This is a documented design bound (Submission19 section 1 item 4) rather than a defect, listed so the throughput is known. If it matters for the sale: page by cost instead of count (let the loop continue past 8 while outcomes are 'pending' or 'released', up to reconcileHeldMintGold's cap of 32, or read a larger page of orders whose deadline is already past), and document the per-order call counts next to GENESIS_CRON_PAGE.","line":163,"path":"Submission20/source/server/genesis-gold.ts","reproduction":"State: 24 held orders of DEP (orderIds H(0x500..0x517)) with the same deadline, chain({finalTime:DEADLINE+1}) so every order is releasable. Input: reconcileGenesisDeployments(db,LIST,'sepolia',reader,NOW) once. Expected (what the RPC budget allows): 24 released in one run. Actual (measured): 8 released, 41 RPC calls in total, reserved stays 128 (16 holds of 8 GOLD); two more runs are needed. A new order of the same wallet succeeds only because the fixture book (1000) exceeds reserved + price; with a book below 2x the price it fails GOLD_INSUFFICIENT until the cron reaches the stale hold.","severity":"info","snippet":"export const GENESIS_CRON_PAGE=8;","title":"GENESIS_CRON_PAGE=8 counts orders, not RPC cost: the cron releases at most 8 abandoned holds per deployment per minute while a cheap release costs about 5 RPC calls"},{"citation":"resolved","description":"The stored-order branch of reserveGenesisGold (genesis-gold.ts lines 114-124) requires the same deployment scope, a byte-identical document (order including token and goldCost, domain, codeHash, recipient), and then verifies the wallet's consent over the stored order at line 122, so it cannot hold or change anything the first hold would refuse; measured: a retry with another key's consent or a garbage signature returns INVALID_GOLD_CONSENT, and a retry with changed token, goldCost, recipient or wallet returns MINT_ORDER_CONFLICT, reserved unchanged. The suite does not cover those guards: 'the same orderId with any other content conflicts' (line 47) changes only choice, lookKey, uriHash, deadline and signerEpoch; 'World audit 8febfeed finding 4' (line 392) retries only the identical request; 'consent must be the wallet's own signature' (line 55) uses orders that were never held, so it takes the first-hold branch. Mutation check: with line 122 (await verifyConsent(d,o,sig as string)) deleted, a retry of a held order with a consent signed by any other key returns the held view (state 'held', the wallet's book/reserved/available), and no test in tests/genesis-gold.test.mjs would fail, because every retry test sends the original valid consent or expects MINT_ORDER_CONFLICT before line 122 runs. The same holds for dropping token or goldCost from the byte comparison: no retry test patches them. Fix: add retry cases after a successful hold: (a) identical order, consent by another account -> INVALID_GOLD_CONSENT; (b) consentSignature '0x'+'1'.repeat(130) -> INVALID_GOLD_CONSENT; (c) same orderId with {token:USDC,goldCost:'9'}, {token:V2}, {goldCost:'9'}, another wallet with its own valid consent, another recipient, each under a registry that lists that price or recipient -> MINT_ORDER_CONFLICT; reserved unchanged in all cases. (The private fixture world-gold-audit5-fixture.mjs is not in the public tree; the checks above ran on a stand-in over the submission's files and the locked world-gold.ts.)","line":392,"path":"Submission20/source/tests/genesis-gold.test.mjs","reproduction":"Copy Submission20/source/server/genesis-gold.ts and delete line 122 (the verifyConsent call on the stored-order path). Hold order() with the wallet's consent, then call reserveGenesisGold with the same order and consentSignature signed by privateKeyToAccount('0x'+'22'.repeat(32)). Expected: INVALID_GOLD_CONSENT (as the unmutated code returns, measured). Actual on the mutant (measured): returns {state:'held',...} with the wallet's balances. Every test in tests/genesis-gold.test.mjs that reaches the stored-order branch (lines 39, 349, 398) sends the original consent, so none fails on the mutant.","severity":"info","snippet":"test('World audit 8febfeed finding 4: an identical retry is answered from the stored order after the registry changes; another order still conflicts',async()=>{","title":"Stored-order retry path (prices=false) is correct but untested for another account's or an invalid consent and for a changed token, goldCost, wallet or recipient"}],"hash":"39340cc459ea762d6d12cae73f7b647704c6ca2225ef59dc180317eef7f790be","nodeId":"d9e9bbca-b569-443d-b9e0-e0c24ceb01ed","outcome":"completed","summary":"Review complete. The findings file `.imd-findings.json` holds 5 merged findings (3 low, 2 info), each reproduced against the Submission20 code.\n\n**How I checked.** The private test fixture and several imported modules are not in the public tree, so I built a harness outside the repository: the six Submission20 files over the locked `world-gold.ts` from Submission19, stubs for the private helpers, and a node:sqlite D1 stand-in. Every claim below was run there, and every snippet was verified against the tree.\n\n**Kept, merged across specialists:**\n\n- **Low, cron drops MINT_SCOPE_MISMATCH** (genesis-gold.ts line 181). The filter was correct when the page spanned all deployments. Now the page is scoped, so the only remaining source of that code is the reader itself: an RPC answering for another chain, or a code hash that does not match the registry. Measured: the service path returns the code, the cron returns an empty page, maintainGenesisGold returns nothing, no log line, holds stay held silently. Three specialists reported this, merged into one.\n- **Low, cursor on an exactly full page** (line 180). With 8 held orders, run two selects nothing and only resets the cursor. Measured: run one 8 pending, run two 0 outcomes with all orders releasable, run three releases. No skip and no repeat, so correctness holds. Three reports merged.\n- **Low, settlement never checks the paying token** (genesis-gold-reader.ts line 141). Neither event carries the token and the reader ignores ERC-20 Transfer logs. Measured: an imdUSD hold settles as consumed on a receipt whose only Transfer comes from the v2 token, and the stored record still names imdUSD. Reachable only through the trusted signer, so this is a documented trust assumption with a World-side fix offered. Three reports merged.\n- **Info, page bound of 8 counts orders not cost** (line 163). Measured 8 of 24 releasable holds per run at 41 RPC calls. I corrected the specialists' arithmetic: the GOLD step runs on the `* * * * *` trigger, so this is about 8 releases per minute, not per 15 minutes. Limits are not exceeded.\n- **Info, retry path untested** (tests line 392). The code is correct on every probe I ran. A mutant with the consent check deleted accepts another key's consent on retry, and no existing test would catch it.\n\n**Checked and clean:** the token binding at hold time, the stored-order retry guards, the orderWindow deploy branch (bounds and binary-search invariant hold, it only ever keeps a hold), and the rate-limit keys (service reads use the service key, cron reads use the cron key, no other chain read exists).\n\n**Limits:** the production wrangler config and the signer Worker are not public, so the cron trigger and limiter figures come from Submission13's wrangler.jsonc. The private fixture could not be run, so the suite's 29 tests were not re-executed, only read.","treeHash":null,"usage":{"cachedInputTokens":1389199,"inputTokens":322,"model":"claude-fable-5-1","outputTokens":37136,"runtime":"claude","turns":27,"wallClockMs":568151}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"8472a2af9a9cf974","findings":[{"citation":"resolved","description":"In Submission19 the cron page came from the global reconcileHeldMintGold, which returned MINT_SCOPE_MISMATCH for every other deployment's held order, so filtering that code out of the page was correct noise removal. In 0727200 the page is already scoped (chain_instance, chain_id and contract are bound in the SELECT at line 175, and reconcileHeldMintGold is called once per id with the deployment's own reader), so the locked function's own scope check can no longer fire. The only MINT_SCOPE_MISMATCH that can now reach line 181 comes from the reader itself: genesis-gold-reader.ts line 97 (eth_chainId of the endpoint is not the registry chain) and line 102 (keccak256 of the runtime code at the finalized block is not the registry codeHash, or the code is empty). Both mean every hold of that deployment will stay held forever (the reader fails before any settle), and both are exactly the mis-registration mistakes the registry comment at genesis-deployments.ts says are guarded by reading values back before an entry is added (a metadata-hash difference between the compiled artifact and the deployed bytecode, or a GENESIS_RPC_URL / Alchemy app on the wrong network). The filter removes those outcomes, maintainGenesisGold (genesis-gold-service.ts line 57) then returns an empty list for the deployment, and worker/app.ts logs 'genesis_gold' only when the list is non-empty, so the cron run leaves no trace at all. The service path reports the same condition correctly (reconcileGenesisGold returns code MINT_SCOPE_MISMATCH; the test 'wrong chain, code, events or an RPC failure keep the hold' asserts it), so the two paths disagree about the same chain state. No GOLD is spent or released wrongly (the hold is kept), but the operator path that is meant to notice a stuck deployment is blind to it. Fix: remove the filter (push outcomes unchanged) and let maintainGenesisGold's existing status!=='pending' filter surface MINT_SCOPE_MISMATCH per id like MINT_PROOF_CONFLICT and MINT_CHAIN_UNAVAILABLE; alternatively collapse repeated scope mismatches of one page into one deployment-level status, but never drop them.","line":181,"path":"Submission20/source/server/genesis-gold.ts","reproduction":"State: registry entry DEP (any environment) with codeHash = keccak256('0x6080604052'); one held order (reserveGenesisGold with a valid consent). Chain stand-in returns eth_getCode = '0x60aa' at the finalized block (as the existing test case chain({code:'0x60aa'}) does), or alternatively eth_chainId = 0x1 for a chainId 11155111 entry. Run maintainGenesisGold(env,{deployments:[DEP],environment},fetchStub,NOW) or reconcileGenesisDeployments(db,[DEP],environment,reader,NOW). Expected: [{id:<orderId>,status:'MINT_SCOPE_MISMATCH'}] (what reconcileGenesisGold returns as `code` for the same chain state). Actual: reconcileGenesisDeployments returns [{deployment:DEP.id,outcomes:[]}] and maintainGenesisGold returns [], so worker/app.ts writes no 'genesis_gold' log line; the order stays held on every subsequent run with the same empty output.","severity":"low","snippet":"   out.push({deployment:d.id,outcomes:outcomes.filter(o=>o.status!=='MINT_SCOPE_MISMATCH')});","title":"Cron page drops every MINT_SCOPE_MISMATCH outcome, so a wrong registry codeHash or an RPC answering for another chain leaves a deployment's holds stuck with nothing logged"},{"citation":"resolved","description":"The cursor is advanced to the last id whenever the page is exactly full, with no check that another held order exists after it. When the deployment has exactly k*GENESIS_CRON_PAGE held orders (8, 16, ...), the run after the last full page selects zero rows, only resets the cursor to '', and reconciles nothing; the orders are read again one run later. No order is skipped or reconciled twice per wrap (the query is id>cursor ORDER BY id, and an order inserted below the cursor is reached after the wrap), so correctness holds; the cost is one wasted scheduled invocation and, with a 15-minute cron, up to 30 minutes instead of 15 before a deadline-expired hold is released by the cron (the signer's own reconcile call with a transaction hint is unaffected). Fix: select limit+1 rows and set the cursor to ids[limit-1] only if a (limit+1)th row exists, else ''; or reset the cursor to '' when the page is full but the next SELECT would be empty.","line":180,"path":"Submission20/source/server/genesis-gold.ts","reproduction":"State: exactly 8 held orders of one deployment, all still before their deadline, cursor row absent. Run 1 of reconcileGenesisDeployments: outcomes for the 8 ids, cursor = 8th id. Run 2 (same chain state): page SELECT returns 0 rows, outcomes [], cursor = ''. Run 3: the same 8 ids again. Expected for run 2: the 8 orders are read again (or run 1 already left the cursor at '' because nothing follows the page). Actual: run 2 does no reconciliation; the existing test 'cron pages through held orders ... with a persisted cursor' uses 10 orders and so never observes the empty run.","severity":"info","snippet":"    .bind(d.id,ids.length===limit?ids.at(-1)!:'',nowMs).run();","title":"A held count that is a multiple of GENESIS_CRON_PAGE costs one empty cron run per wrap, doubling settlement latency for a full last page"},{"citation":"resolved","description":"0727200 adds `token` to the order, the wallet consent and the stored document, and the registry comment at genesis-gold.ts lines 30-32 says an order 'is payable only in' its token. On the World side that binding ends at the hold: the reader compares only PaidOrderConsumed.goldCost with the held amount (line 141) and GenesisMinted's wallet, tokenId, lookKey, choice, paid flag and cost (lines 142-143). Neither event carries the payment token, so a consumption paid in a different token at the same GOLD price (imdUSD v1 and v2 are both 1,200 GOLD by the owner decision) matches and settles. The contract's PaidAuthorization binds the token the signer signs, so this is reachable only if the Genesis signer signs a different token than the order it reserved with the World; Submission19 section 2 already records the signer as trusted, and the two tokens cost the same dollar amount and the same GOLD, so there is no loss today. It is listed so the 'payable only in it' claim is read as a signer property, not a World check, and because a later price change on chain (the owner can add a token at any GOLD price) would make the equal-price assumption load-bearing. Possible World-side check without a contract change: require, in the same receipt, exactly one ERC-20 Transfer log emitted by order.token with topics[1] == wallet and topics[2] == the registry recipient (the contract pulls the payment with transferFrom to paymentRecipient), and fail MINT_PROOF_CONFLICT otherwise.","line":141,"path":"Submission20/source/server/genesis-gold-reader.ts","reproduction":"State: registry lists paymentToken IMD (v1) at '8' and addedTokens [{token:V2,goldCost:'8'}]. Hold order O with token = IMD, goldCost '8' (valid consent). On chain the signer signs PaidAuthorization(O.orderId, token = V2, goldCost = 8) and the wallet mints paying V2; the receipt holds PaidOrderConsumed(O.orderId, wallet, tokenId, 8) and the matching GenesisMinted. reconcileGenesisGold(... {deploymentId, orderId:O.orderId, transactionHash}). Expected by the stored document and the registry comment: the hold named IMD, the payment was V2, so either a conflict or an explicit documented acceptance. Actual: state 'consumed', 8 GOLD spent; the stored order.token is never read by the reader (only orderId, wallet, goldCost, deadline, lookKey, choice, embeoCost, schema, deploymentId and codeHash are compared at lines 95-96 and 141-143).","severity":"info","snippet":"   if(addrTopic(c[2])!==m.wallet||BigInt(c[3])!==tokenId||wordAt(cData,0)!==BigInt(m.gold)","title":"Settlement never checks the token actually paid: a hold named for one token settles on a consumption paid in any other token with the same GOLD price (signer trust assumption, not enforced by the Worl"}],"hash":"44a0ed79eff9f81f1904f54e621419cdaa3d551864a751d05664e9d4ebcddb4c","nodeId":"a76a8d2a-67ea-4649-a4d8-3a4f39d17b7b","outcome":"completed","summary":"Review of Submission20 (World source 0727200) is complete. The findings file holds 3 findings, all snippet-verified against the tree. No critical or high defects.\n\n**Findings written to `.imd-findings.json`:**\n\n- **Low, cron silences real scope failures.** The per-deployment page at genesis-gold.ts:181 still filters out `MINT_SCOPE_MISMATCH`. In Submission19 that code was noise from other deployments' orders. Now the page is scoped, so the only source left is the reader itself: an endpoint answering for another chain, or a registry `codeHash` that does not match the deployed runtime code. Both leave every hold of that deployment stuck forever, and the cron logs nothing because the outcome list comes back empty. The service path reports the same state as `MINT_SCOPE_MISMATCH`. Fix: drop the filter.\n- **Info, one empty run per cursor wrap.** When held orders number exactly a multiple of 8, the run after a full page selects zero rows and only resets the cursor. No skip, no repeat, but settlement by the cron can take 30 minutes instead of 15.\n- **Info, token not checked at settlement.** The order, consent and document now name the token, but the reader never reads it. A consumption paid in a different token at the same GOLD price settles. Reachable only if the signer signs a different token than it reserved, so it is the documented signer trust assumption. A World-side check is possible via the ERC-20 Transfer log in the receipt.\n\n**Questions answered clean by trace:**\n\n- **Token binding.** An unlisted token or a wrong price fails `MINT_PRICE_MISMATCH` before any hold. The consent message includes the order's token, so a consent over another token recovers to a different signer.\n- **Retry path.** With `prices=false` the result is compared byte for byte against the stored document (minus consent), scope is checked, and the wallet's consent is still verified. It only returns the stored state and can hold or change nothing.\n- **orderWindow.** The deploy branch is inclusive at `lo = deploy`, the binary search keeps `timeOf(lo) < start <= timeOf(hi)`, and `to` is a floor bound under the one-block-per-slot rule. The window is only used when the order is already consumed, so a miss can only keep a hold.\n- **Rate-limit keys.** Every chain read goes through the one wrapper. The service passes `genesis:rpc:service`, the cron takes the default `genesis:rpc`.\n\n**Limits of this review.** The runtime tree needed to execute `tests/genesis-gold.test.mjs` (fixture, economy-config.ts, d1.ts, node_modules) is not in this repository, so all verification is by trace, not by run. The CPU and subrequest budget of the cron (8 orders per deployment, worst case roughly 44 RPC calls per consumed order) sits under the Paid-plan limit by arithmetic, but was not measured in workerd and whether D1 queries count toward that limit was not confirmed. No files outside `.imd-findings.json` were changed.","treeHash":null,"usage":{"cachedInputTokens":1089035,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":31439,"runtime":"claude","turns":26,"wallClockMs":447922}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"3c9b660ee1938912","findings":[{"citation":"resolved","description":"Since 0727200 the order names its payment token, and the wallet's GenesisGoldHold consent signs that token, so that v1 and v2 (both 1,200 GOLD) are no longer interchangeable for one order (AUDIT_REQUEST section 1). That binding is enforced only when the hold is made. createGenesisR5Reader.read() settles the hold from PaidOrderConsumed(orderId, wallet, tokenId, goldCost) and GenesisMinted(..., cost). Neither event carries the token. `own` (line 130) keeps only logs emitted by the Genesis contract, so the ERC-20 Transfer that shows which token actually paid is never read, and order.token is never compared with anything on chain. The only on-chain check tied to the token is wordAt(cData,0)===m.gold, which cannot tell apart two tokens with the same GOLD price. So the World book relies entirely on the Genesis signer to sign PaidAuthorization with the hold's own token (paid-approval.mjs approve() currently does). A signer defect or compromise, or a later signer change that re-signs an existing orderId for another token, debits the wallet's GOLD for a payment it never consented to, and the settlement record says it was paid in the consented token. If the other token has a different price, the hold instead stays 'held' forever with MINT_PROOF_CONFLICT, because tokenId!=0 never releases. The test fixture shows the gap: chain() in tests/genesis-gold.test.mjs returns a receipt with no ERC-20 Transfer log at all, and holds in both IMD and USDC still settle as consumed. Fix: In read(), after `own` is computed, also require exactly one log in receipt.logs with address===order.token, topics[0]===keccak256('Transfer(address,address,uint256)'), topics[1]==wallet and topics[2]==order.recipient, the same way `consumed` and `minted` are matched (optionally also check the amount: add the per-token amount to the registry, which addPaymentToken already emits). Add a test where a hold names IMD and the receipt's Transfer comes from V2, expecting MINT_PROOF_CONFLICT.","line":141,"path":"Submission20/source/server/genesis-gold-reader.ts","reproduction":"Registry entry (as in the tests, with the owner's 2026-10-29 price pairs): paymentToken IMD goldCost '8', addedTokens [{USDC,'9'},{V2,'8'}]. 1) reserveGenesisGold with order {token:IMD, goldCost:'8'} and the wallet's consent naming IMD -> held, reserved 8. 2) On chain the order is executed as mintPaid(..., orderId, ..., token=V2), which needs a PaidAuthorization signed with token=V2. The receipt then holds PaidOrderConsumed(orderId, W, 7, 8), GenesisMinted(W, 7, lookKey, choice, skin, true, EMBEO) and a Transfer(W -> SAFE) emitted by V2, with none emitted by IMD. 3) reconcileGenesisGold / the cron. Expected: MINT_PROOF_CONFLICT, the hold stays held (the consumption does not match the token the wallet consented to). Actual: read() returns a proof, reconcileHeldMintGold settles 'consumed' and books a -8 mint-payment entry. The same thing happens with the existing harness: settle(f, chain({tokenId:7n, consumed:{gold:8}})) settles an IMD hold although the receipt has no IMD Transfer log.","severity":"low","snippet":"   if(addrTopic(c[2])!==m.wallet||BigInt(c[3])!==tokenId||wordAt(cData,0)!==BigInt(m.gold)\n    ||addrTopic(g[1])!==m.wallet||BigInt(g[2])!==tokenId||g[3]!==order.lookKey||wordAt(gData,0)!==BigInt(order.choice as number)\n    ||wordAt(gData,2)!==1n||wordAt(gData,3)!==BigInt(order.embeoCost as string))fail('MINT_PROOF_CONFLICT');","title":"Settlement never checks which token paid: a hold naming imdUSD v1 is consumed by a mint paid in v2 (or any token with the same GOLD price)"},{"citation":"resolved","description":"The stored-order branch of reserveGenesisGold (lines 114-124) is correct on inspection. It requires the same deployment scope, byte-identical order, domain and code hash, then verifies the wallet's consent over the stored order, so it cannot hold or change anything the first hold would refuse. Its two guards for finding 4 are only partly tested, though. 'the same orderId with any other content conflicts' (test line 47) changes only choice, lookKey, uriHash, deadline and signerEpoch. 'World audit 8febfeed finding 4' (line 392) retries only with the identical request. 'consent must be the wallet's own signature' (line 55) uses only orders that were never held, so it goes down the first-hold branch. No test sends an already-held orderId with a consent from another account, a malformed consent, or a changed token, goldCost, wallet or recipient. That last group is the case prices=false stops checking against the registry. Fix: Add retry-path cases after a successful hold: (a) the identical order with a consent signed by another account -> INVALID_GOLD_CONSENT; (b) consentSignature '0x'+'1'.repeat(130) -> INVALID_GOLD_CONSENT; (c) the same orderId with {token:USDC,goldCost:'9'}, {token:V2}, {goldCost:'9'}, another wallet with its own valid consent, and another recipient, each under a registry where that price or recipient is listed -> MINT_ORDER_CONFLICT; reserved unchanged in all cases.","line":122,"path":"Submission20/source/server/genesis-gold.ts","reproduction":"Mutation check by reading the suite: delete line 122 (`await verifyConsent(d,o,sig as string);`). Every test in tests/genesis-gold.test.mjs that reaches the stored-order branch either sends the original valid consent or expects MINT_ORDER_CONFLICT before line 122 runs, so none of them would fail. After the mutation, a retry of a held order with consentSignature signed by any other key returns the held view (state 'held', the wallet's book/reserved/available) instead of INVALID_GOLD_CONSENT, and the Genesis signer's approve() would then sign the PaidAuthorization. The same applies to dropping the `withoutConsent` comparison's token or goldCost fields: no retry test patches them. (Not run: the fixture world-gold-audit5-fixture.mjs and server/economy-config.ts are not in the public tree.)","severity":"info","snippet":"  await verifyConsent(d,o,sig as string);","title":"Retry path (prices=false) is untested for another wallet's or an invalid consent and for changes to token, goldCost, wallet or recipient"}],"hash":"e227d43d5161f9408a7c7671b10057f45fc115349b533eab6316e1ff58de0d4e","nodeId":"dd1e033f-f1b3-47cd-aa12-705330229d9b","outcome":"completed","summary":"The review is finished: **one low finding and one info finding**, and no medium or higher. Both are written to `.imd-findings.json`, and their snippets match the files. I changed no repository files and didn't run the project's tests, because their fixture and `server/economy-config.ts` aren't in the public tree.\n\n## Findings\n\n**1. Low: settlement never checks which token paid** (`Submission20/source/server/genesis-gold-reader.ts:141`)\n- **The gap:** the token is enforced only when the hold is made. When the hold settles, `read()` matches the order to the chain using only the contract's two events, and neither names the token. The token's own Transfer log in the receipt is never read.\n- **Failing state:** a hold for `{token: IMD, goldCost: 8}`, where the order is actually paid on chain with V2 (same 8 GOLD price). The book should refuse with `MINT_PROOF_CONFLICT`. Instead it settles `consumed` and debits 8 GOLD.\n- **Why it's only low:** it needs the Genesis signer to sign the payment authorization for a token other than the hold's. Its current `approve()` doesn't do that. So imdUSD v1 and v2 stay \"not interchangeable\" only because the signer behaves correctly.\n- **Where it shows in the tests:** the test fixture's receipts contain no token Transfer log at all, and holds in both IMD and USDC still settle.\n- **Fix:** require exactly one Transfer log from `order.token`, from the wallet to `order.recipient`, in the receipt.\n\n**2. Info: the retry path is under-tested** (`Submission20/source/server/genesis-gold.ts:122`)\n- Deleting the consent check on line 122 would fail none of the 29 tests. No test retries an order that is already held using another account's consent, a malformed consent, or a changed token, `goldCost`, wallet or recipient.\n- The fix is to add those cases.\n\n## Your five questions\n\n1. **Token binding (hold side): clean.** An unlisted token, another token's price, or a consent naming a different token are all refused. The settlement-side gap is finding 1.\n2. **Retry with `prices=false`: clean.** It needs the same deployment, a byte-identical order and a valid consent from the same wallet, and it never creates a hold. It can't reach a different wallet, order, price or deployment.\n3. **`orderWindow` deploy branch: clean.** The bounds read correctly. I also copied the function out and fuzzed it over 20,000 random chains with missed slots and deploy blocks inside the window. The consumption block was never outside the window, and nothing errored. Releasing a hold doesn't depend on this function.\n4. **Cron page: clean.** The cursor resets after a short page, so nothing is skipped or processed twice. If a run is cut off before the cursor is saved, the same page is simply retried. Worst case is roughly 34 chain reads per order, so about 270 per deployment per run. That is under the 600-per-minute rate limit, and at least one check of a 24 KB bytecode costs about 2 ms of CPU against the 50 ms limit.\n5. **Rate-limit keys: clean.** The cron uses `genesis:rpc` and the service's reconcile uses `genesis:rpc:service`; reserve and order make no chain reads. I couldn't see whether the private mainnet transport adds its own limiter.\n\nThe Genesis-side check (`mintPaid`, the event layouts, the signer's `approve`) used the public Submission7 code.","treeHash":null,"usage":{"cachedInputTokens":2130085,"inputTokens":54,"model":"claude-opus-5-5","outputTokens":37041,"runtime":"claude","turns":28,"wallClockMs":439768}}],"verification":[]}