{"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":"a7aaa9a4-82bb-45d6-b4b0-2bed8c34f12d","kind":"skill:build-website","nodes":[{"acceptedSubmissionHash":"ea7079195e215bdf480ffcdc85a34c47251d85e05c561e04c87f80aef6543ad4","dependsOn":[],"execution":{"mustProduce":["dist/index.html"],"network":true,"optionalTools":["browser"],"profile":"none","requires":["network"],"skillHash":"a60bc8b42446c13d993341179fe13c712a5addb118fc532fb2d15e71f912efc8","skillId":"build-website","tools":[]},"key":"build_website","kind":"code","role":"implement","skillHash":"a60bc8b42446c13d993341179fe13c712a5addb118fc532fb2d15e71f912efc8","skillId":"build-website","state":"accepted"},{"acceptedSubmissionHash":"9621d7f76918111c42795c35dc270d869694c14657ba6def4a5c9d6ff640b1eb","dependsOn":["build_website"],"execution":{"network":true,"optionalTools":["browser"],"profile":"none","requires":["network"],"skillHash":"fd33b6741366d364a55a4c0ba2bc4f5d329cec0b62f27a83289dc5b30ab03575","skillId":"design-critic","tools":[]},"key":"design_critic","kind":"code","role":"review","skillHash":"fd33b6741366d364a55a4c0ba2bc4f5d329cec0b62f27a83289dc5b30ab03575","skillId":"design-critic","state":"accepted"}],"objective":"Build an English-only DeFi web app called [PROJECT_NAME] (placeholder “VAULTLINE” if unnamed; one config field). No other language, no RTL, no token sale, NFTs, or extra fees. This spec overrides generic crypto templates.\n\nPRODUCT\nInstitutional lend/borrow for tokenized real-world assets on Ethereum mainnet (chainId 1) only. Wrong network: block the action and ask the user to switch. No other chains.\n\n- LEND: supply USDC, earn variable supply APY.\n- BORROW: lock an RWA token as collateral, borrow USDC (LTV, liquidation threshold, health factor).\n\nDemo markets (ERC-20, “demo issuer”): tT-BILL (short-term U.S. Treasury bills), tREAL (investment-grade real estate), tGOLD (allocated gold), tINVOICE (trade receivables). Each shows oracle, collateral factor, liquidation threshold and penalty, supply APY, borrow APR, utilization, supplied, borrowed, and liquidity.\n\nNo invented audits, partners, licenses, team photos, or guaranteed yield. Demo numbers are marked SIMULATED.\n\nPROTOCOL REVENUE — NOT LENDER YIELD\nBorrower interest is paid first to lenders. Lenders keep that APY. It never enters the funds.\nThe protocol then takes a displayed fee (demo: 10% of borrower interest) plus all origination fees and its share of liquidation penalties. 100% of that protocol revenue is atomically split and cannot be edited in the UI or by admin (a change needs a new contract):\n\n- Assurance Fund ..................... 30% (first-loss reserve for bad debt, oracle failure, RWA default — not insurance and not a principal guarantee)\n- Advertising & User Incentive Fund .. 30% (rewards, rebates, referrals, ads; demo policy 70% rewards / 30% ads, policy only)\n- Revenue Fund ....................... 30% (operations, development, treasury — not user yield)\n- Charity Fund ....................... 10% (USDC grants to named causes; demo recipients are fictional; never mixed back into Revenue)\n\nNever say risk-free, guaranteed, insured, or fixed APY. One config module holds basis points 3000/3000/3000/1000 (must sum to 10000). Everything imports it.\n\nDATA\nNEXT_PUBLIC_DATA_MODE=demo|live (default demo). Same interface either way: supply, withdraw, borrow, repay, collateral toggle, health, oracle price, and a revenue router (distribute + totals per fund) into four USDC vaults. Wallet via injected EIP-1193 or WalletConnect. No email custody, no seed phrase. Read-only pages work disconnected. Before signing, show action, amount, fee, health factor before → after, and liquidation price.\nDemo banner on every page: “Demo mode — simulated Ethereum data, no real funds.” Seeded data, stable on refresh. At least 12 ledger rows that match vault balances. Empty live addresses show “Contracts not deployed,” not fake balances. Health factor: <1.0 liquidatable, <1.2 at risk.\n\nPAGES\nHeader: Markets, Revenue Split, Funds, Charity, Portfolio, How it works, Security, network, Connect.\nFooter: “Digital-asset lending can result in partial or total loss. RWA tokens can default, be frozen by an issuer, or be mispriced by an oracle.”\n\n- Home: one-sentence explanation plus a flow diagram (borrower interest → lender yield → protocol fee → 30/30/30/10). Stats: supplied, borrowed, revenue routed, assurance coverage. Market strip. CTAs: Supply USDC, Borrow against RWA.\n- Markets: Lend | Borrow table; row opens detail with Supply, Withdraw, Borrow, Repay, risk parameters, utilization curve, and fee events. Warn if health would fall below 1.2.\n- Revenue Split: chart locked to 30/30/30/10 and this example on Home, here, and How it works: 100,000 borrower interest → 90,000 to lenders → 10,000 protocol revenue → 3,000 / 3,000 / 3,000 / 1,000. Ledger, cumulative totals, CSV. Live hashes go to etherscan.io; demo hashes do not.\n- One page per fund: mandate, balance, inflows, spend policy, transactions. Assurance includes a default example where losses above the reserve are not covered. Incentive Claim in demo is labeled “Simulated transaction.” Charity lists cause, recipient, amount, date, pledged or sent.\n- Portfolio (wallet for personal data): supplies, debt, health factor, collateral, liquidation price, claimable rewards. Note that supply APY is not reduced by the split.\n- How it works: five short steps covering RWA freeze/default, variable APY, collateral, liquidation into the router, and the same numeric example.\n- Security: contract bugs (no audit claimed), oracle, issuer default/freeze, illiquid withdrawals, reserve may be smaller than losses. Admin may pause a market or change an oracle. Admin cannot change the split or take lender deposits.\n\nLook: institutional, not meme-coin. No purple gradients, 3D coins, or fake audit badges. One accent. Four fixed fund colors. Tabular numbers. Usable at 360px. Disable invalid submits and say why. Rejected signatures keep the form.","parentJobId":null,"planHash":"5a25ba1d08bddfe7658ab36302076403c849c130d3e4fea78f30f62366c9e1b7","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"a7aaa9a4-82bb-45d6-b4b0-2bed8c34f12d","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-2849-build-english-only-defi-web"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51024","feedbackHash":"a4e2b818c6f2ea29b8925c798e6385e55d11ce3f95f489ee56aee8f43fc865f1","nodeKey":"build_website","submissionHash":"ea7079195e215bdf480ffcdc85a34c47251d85e05c561e04c87f80aef6543ad4","tag1":"verification:structural","tag2":"acceptance-v2","value":1},{"agentId":"51198","feedbackHash":"3bd6242ab733de4770e83742580e5beb9073efd4e213123c676f783590281d8b","nodeKey":"design_critic","submissionHash":"9621d7f76918111c42795c35dc270d869694c14657ba6def4a5c9d6ff640b1eb","tag1":"review:submission","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"b0742a6e97bac07710b7164dd74f2d28a239266e321f312dfc8471e7302583a4","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"29ea8835baa3dfe1","findings":[{"citation":"resolved","description":"Now: the charts, tables and worked example read SPLIT_BPS / PROTOCOL_FEE_BPS from src/config/split.ts, but six copy strings type the numbers by hand: src/pages/Revenue.tsx:24 and :32 (\"30/30/30/10\", \"10% fee\"), src/pages/Info.tsx:16 (\"lenders receive 90% of it\"), :24 (\"the 10% interest fee\"), :27 (\"The router splits revenue 30/30/30/10\"), :59 (\"Change the 30/30/30/10 revenue split\"), and src/components/Charts.tsx:21 (\"Protocol revenue (10% fee)\").\nChange to: build these strings from the config, e.g. `const SPLIT_LABEL = FUNDS.map((f) => f.bps / 100).join(\"/\")` exported from src/config/split.ts and `pct(PROTOCOL_FEE_BPS)` / `pct(BPS_DENOMINATOR - PROTOCOL_FEE_BPS)` for the 10% and 90%; replace each literal with the interpolated value.\nWhy: the brief says \"One config module holds basis points 3000/3000/3000/1000 (must sum to 10000). Everything imports it.\" Changing the config today leaves the headings and How it works stating the old split and fee while the chart shows the new one.","line":24,"path":"src/pages/Revenue.tsx","reproduction":"Any width. Run `grep -rn \"30/30/30/10\\|90%\\|10%\" src --include=*.tsx`: 7 hits in Revenue.tsx (24, 32), Info.tsx (16, 24, 27, 59) and Charts.tsx (21), none of which import SPLIT_BPS or PROTOCOL_FEE_BPS. Change PROTOCOL_FEE_BPS to 1500 in src/config/split.ts and rebuild: the How it works step 2 still reads \"lenders receive 90% of it\" and the flow card still reads \"Protocol revenue (10% fee)\", while supplyApy in src/lib/math.ts:15 uses 15%.","severity":"medium","snippet":"      <PageHead title=\"Revenue Split\" lead=\"Protocol revenue is split 30/30/30/10 in the same transaction that collects it. The split is fixed in the router contract; neither this interface nor an admin can change it.\" />","title":"fidelity: split and fee percentages are hard-coded in copy instead of imported from the split config"},{"citation":"resolved","description":"Now: MarketDetail renders the 7-card stats grid (MarketDetail.tsx:38, .stats in styles.css:191 with minmax(160px,1fr) = 2 columns at 390) before the grid-2 that holds <ActionPanel>. At 390x844 the \"Manage position\" heading sits at y=860 and the amount input at y=1120, so a visitor who tapped a market to act sees only numbers, and the 7th card (Liquidity) sits alone in its row.\nChange to: move the `<div className=\"grid-2\">…</div>` block (lines 49-83) above the `section-head` + stats block (lines 36-47), so the action panel opens right under the page head and the market stats follow it; no content is removed.\nWhy: the brief says a market \"row opens detail with Supply, Withdraw, Borrow, Repay\"; the action that row opens should be on its first screen at phone width (\"Usable at 360px\").","line":49,"path":"src/pages/MarketDetail.tsx","reproduction":"390x844, Chromium, dist served statically. Open #/markets, tap tINVOICE. Measured: h2 \"Manage position\" getBoundingClientRect().top = 860, `.amount input` top = 1120; viewport height 844. Screenshot shows banner, header, crumb, title, lead and 7 SIMULATED stat cards, with Liquidity alone in the last row and no action control.","severity":"medium","snippet":"      <div className=\"grid-2\">","title":"taste: on a market's page at 390 the Supply/Withdraw/Borrow/Repay panel starts below the first screen"},{"citation":"resolved","description":"Now: the four stats read \"96.1M USDC\", \"69.1M USDC\", \"133,030.00 USDC\", \"38,789.00 USDC\" (Home.tsx:56-59): two compact, two with cents, in one comparison row.\nChange to: use compact() for Revenue routed and Assurance coverage too (\"133K USDC\", \"38.8K USDC\"), keeping the exact cents on the Revenue Split and Funds pages where the ledger is read.\nWhy: one kind of comparison has one format; the brief asks for tabular numbers, and mixed precision makes the row harder to scan.","line":58,"path":"src/pages/Home.tsx","reproduction":"1440x900, Home, Protocol totals row: screenshot shows \"96.1M USDC | 69.1M USDC | 133,030.00 USDC | 38,789.00 USDC\". Same at 390.","severity":"low","snippet":"            <Stat label=\"Revenue routed\" value={`${fmtCents(st.routedCents)} USDC`} />","title":"taste: Home protocol totals mix compact and full-cents number formats in one row"},{"citation":"resolved","description":"Now: the crumb links on fund, charity and market pages (Funds.tsx:69, Charity.tsx:14, MarketDetail.tsx:33) render at small font with no padding: \"Funds\" is 34x17, \"Markets\" 46x17.\nChange to: in src/styles.css:170 add `.crumb a { display: inline-block; padding: 4px 0; min-height: 24px; }`.\nWhy: controls at least 24px (WCAG 2.5.8); the crumb is the only in-page way back to the list on phones where nav sits behind Menu.","line":69,"path":"src/pages/Funds.tsx","reproduction":"320 and 390 wide, open #/funds/assurance, #/charity or #/markets/tinvoice. Measured getBoundingClientRect of `.crumb a`: 34x17 (Funds), 46x17 (Markets).","severity":"low","snippet":"      <p className=\"crumb\"><a href=\"#/funds\">Funds</a> / {f.name}</p>","title":"accessibility: breadcrumb links are 17px tall, under the 24px target minimum"}],"hash":"9621d7f76918111c42795c35dc270d869694c14657ba6def4a5c9d6ff640b1eb","nodeId":"1285e382-71a1-4e6b-af08-3ebeaf3955ac","outcome":"completed","summary":"I found no high or broken-feature defects in this build, only 2 medium and 2 low findings, all in `.imd-findings.json`. The probe ran (I pointed it at the Chromium already on this machine because the Playwright browser download hung), and I measured the inner pages myself at 320 and 390. I didn't run a WebKit pass. No repository files were changed.\n\n| Area | Count |\n|---|---|\n| Brief requirements | 58 listed: 49 met, 1 missing, 0 faked, 3 after review, 5 needs the requester |\n| Broken features | 0 |\n| Product on first screen at 390 | yes (headline, Supply USDC / Borrow against RWA buttons, and the market strip) |\n| taste@1 checks passed | 15 / 16 (the only failure is the em dash in the banner, which the brief requires word for word) |\n| Copy findings | 1 (split and fee percentages typed into copy, logged as fidelity) |\n| Share card | present: title, og:title, og:image `./og.png`, twitter large image, favicon |\n\n**Findings**\n1. **medium, fidelity:** \"30/30/30/10\", \"10%\" and \"90%\" are typed into the copy in seven places: `src/pages/Revenue.tsx:24`, `src/pages/Revenue.tsx:32`, `src/pages/Info.tsx:16`, `:24`, `:27`, `:59` and `src/components/Charts.tsx:21`. The brief says \"Everything imports it.\" If the config changes, the headings and How it works keep the old numbers. Build these strings from `SPLIT_BPS` and `PROTOCOL_FEE_BPS` instead.\n2. **medium, taste:** on a market's page at 390×844, the Manage position panel starts at y=860 and the amount input at y=1120. Seven stat cards come first. Move the `grid-2` block (`src/pages/MarketDetail.tsx:49`) above the stats.\n3. **low, taste:** the Home totals mix formats in one row: \"96.1M USDC\" next to \"133,030.00 USDC\" (`src/pages/Home.tsx:58`).\n4. **low, accessibility:** breadcrumb links measure 34×17 and 46×17, under the 24px minimum (`src/pages/Funds.tsx:69`, `src/pages/Charity.tsx:14`, `src/pages/MarketDetail.tsx:33`).\n\n**Requirements**\n- **Met:**\n  - **Name:** a single `PROJECT_NAME` field (`src/config/site.ts:4`), English only, no token sale, NFTs or extra fees.\n  - **Chain:** Ethereum mainnet only (`CHAIN_ID = 1`). On the wrong network, actions are blocked with \"Wrong network. Switch…\" (`src/lib/tx.ts`) and there's a switch button in the header (`ConnectSheet.tsx:75`).\n  - **Markets:** the four demo markets, each with oracle, collateral factor, liquidation threshold and penalty, APY/APR, utilization, supplied, borrowed and liquidity (`Markets.tsx`, `MarketDetail.tsx`). Demo numbers are badged SIMULATED.\n  - **Split config:** 3000/3000/3000/1000 basis points, checked at runtime to sum to 10000 (`src/config/split.ts`). The router split puts rounding dust into Assurance.\n  - **Revenue sources:** the fee is shown (10% of interest) along with origination fees and the protocol's share of liquidation penalties.\n  - **Fund wording:** each fund's mandate wording is right; the Assurance Fund is \"not insurance\".\n  - **Banned words:** none of risk-free, guaranteed, insured or fixed APY appear.\n  - **Data mode:** `NEXT_PUBLIC_DATA_MODE` with demo as the default. In live mode with empty addresses, pages show \"Contracts not deployed\".\n  - **Demo data:** seeded and stable on refresh; it lives in this browser's localStorage, which the page says. The ledger has 14 rows, and fund balances are computed from them.\n  - **Wallet:** injected wallet; no email or seed phrase. Pages read without a wallet.\n  - **Before signing:** the review shows action, amount, fee, health factor before → after and liquidation price. It warns below 1.2 and blocks below 1.0. Invalid submits are disabled with a reason, and a rejected signature keeps the form.\n  - **Demo banner and footer:** both carry the exact text.\n  - **Header:** all nine items; the network indicator sits inside Menu below 480px.\n  - **Home:** one sentence, flow diagram, four stats, market strip and both buttons.\n  - **Revenue Split:** split bar, the 100,000 → 90,000 → 10,000 → 3,000/3,000/3,000/1,000 example (also on Home and How it works), cumulative total","treeHash":null,"usage":{"cachedInputTokens":1522159,"inputTokens":52,"model":"claude-opus-5-5","outputTokens":17078,"runtime":"claude","turns":28,"wallClockMs":624998}},{"artifacts":[],"attempt":1,"bundleHash":"84d5d664332adf83b0697a888493884339ae2d62744985c7cdefbfafb7aec708","device":"e6de8d4c6cf97551","findings":[],"hash":"ea7079195e215bdf480ffcdc85a34c47251d85e05c561e04c87f80aef6543ad4","nodeId":"5c4fccd5-2834-4c7b-b372-d1a93e1f3eb2","outcome":"completed","summary":"","treeHash":"167378687576753024dd2c2026390cae5955f2be","usage":{"cachedInputTokens":5719953,"inputTokens":105,"model":"claude-opus-5-5","outputTokens":96318,"runtime":"claude","turns":53,"wallClockMs":1292847}}],"verification":[{"checks":[],"detail":"paths and tree verified; no suite was run for this kind of work","evaluation":"structural","profile":"none","status":"accepted","submissionHash":"ea7079195e215bdf480ffcdc85a34c47251d85e05c561e04c87f80aef6543ad4","verifiedTreeHash":"167378687576753024dd2c2026390cae5955f2be","verifierVersion":"0.1.0+b10502ca"}]}