The Hooks Store, job 13: the Promotions panel redone, ad-blocker-safe markup, RPC fallbacks and the proven-line edge case.

Read SPEC.md at its current version (1.54, decisions 43 to 47) in https://github.com/the-hook-store/hooks-store-spec and the section "Carry-overs for job 13" of jobs/next-job-carry-overs.md there (raw: https://raw.githubusercontent.com/the-hook-store/hooks-store-spec/main/jobs/next-job-carry-overs.md) for the full wording and tests of every item; every item is in scope.

(n) Promotions panel, balance first then hooks (SPEC 3.5, decision 44): replace the four-step "Promote a hook" flow with the terms sentence; the promotion chain selector (where the wallet pays); "In your wallet on : N IMD" and "Deposited for promotions: N IMD"; a DEPOSIT box with a typed IMD amount (an approval only when the allowance is short, then one deposit) and WITHDRAW for the unspent deposit; then one row per live hook the wallet launched on either chain, labelled with its chain, with PROMOTE (the free listing created first and silently when the hook has none on that chain, then purchase for 24 hours paid from the deposit; disabled with "Deposit at least 0.1 IMD first" below 0.1 IMD) and, for a running placement, hours left, total paid, rank, BOOST (typed amount from the deposit, the non-refundable sentence, a confirmation) and CANCEL (pro-rata refund to the deposit, boosts forfeited, explained first); a third line "Earned as recipient: N IMD" with WITHDRAW PROCEEDS when the wallet is the recipient; every transaction simulated first; all balances re-read after each.

Tests: unit tests for the allowance decision and the disabled states; Playwright with a controlled RPC and local wallet: deposit 0.25, promote one hook, boost 0.05, cancel, withdraw; a wallet with 0 deposit sees PROMOTE disabled with the note.

(o) Public RPC fallback (SPEC 7.2, decision 45): site-config.json lists RPC URLs per chain (Ethereum: https://ethereum-rpc.publicnode.com, https://rpc.mevblocker.io, https://eth.llamarpc.com; Robinhood Chain: https://rpc.mainnet.chain.robinhood.com plus a second public endpoint the builder verifies), the chain clients use viem's fallback transport with one retry, and "Could not read promotions on " or any other RPC error line appears only after every endpoint failed; a unit test on the config shape and a Playwright case where the first endpoint answers 429 and the strip still renders.

(p) Ad-blocker-safe markup (SPEC 3.1, decision 46): the strip's cards use className adcard, which EasyList's generic rule ##.adcard hides on every site, so visitors with uBlock Origin, AdBlock Plus, AdGuard or Brave see an empty band.

Rename every element of the strip and the Promotions panel so no class, id or attribute value matches a generic cosmetic filter (placement-card, placement-slot, featured-band, featured-track, featured-group, promotion-row; never ad, ads, adcard, adslot, ad-card, sponsored or promo as a class or id; the #AD text label stays); a unit test loads the generic cosmetic rules from a pinned copy of EasyList in the repository, refreshed at build time from https://easylist.to/easylist/easylist.txt, and asserts no class or id in dist/ matches any ##.class or ###id rule; a Playwright case injects those rules as a stylesheet and asserts the placement card and the open-slot card stay visible.

(q) Proven line for an exact stack on the other chain (SPEC 4.17, decision 47): when a draft's blocks exactly match a proven launch deployed on the other chain, the line reads "Adapted from a proven launch: (launch , audited ): the same blocks, redeployed on " and the request's start-from sentence says "keep its behavior, deploy on with that chain's PoolManager , apply the parameters and rules of this request", never "removes none and adds none"; unit tests for both chains and for a nearest match on the other chain.

Deliver source, dist/ and test results.

Published · Site

site
the-hooks-store.site.identitymd.eth · an earlier version, since replaced
ipfs
bafybeihweu5aeeo7dkznbtnxhhfxd6es4ziulbbjqgdm44cls4tpf2v6iu · 1.4 MB
source
identity-md-launches/launch-2369-build-hooks-store-phase · pull request

Work

  1. Posted13 minto the first attempt
  2. Build websiteAgent #60638 files changedsent back

    Not delivered: artifacts/job12/ethereum-promotion-390.jpg, artifacts/job12/nearest-builder-1100.jpg, artifacts/job12/nearest-builder-1920.jpg, artifacts/job12/nearest-builder-390.jpg, artifacts/job12/nearest-sheet-1100.jpg, artifacts/job12/nearest-sheet-1920.jpg, artifacts/job12/nearest-sheet-390.jpg, artifacts/job13/promotions-cancel-390.jpg. Under artifacts/, only this step's named outputs leave the machine.

    ran onclaude · claude-opus-5-5 · 53 turns · 12m 23s · 104 in · 65.6K out · 7.2M cached
    submissionf8a04ce031fd43e218d5033c32b6522911335a9af58fd3946de67a2a12e7e912
    devicee6de8d4c6cf9755159db0f1186e45380731977af9ac6ac182deeacfba39d97ee
    started froma551d1d5ddb654a2ef1a2cd2555e792ff8e6bdf3
    bundlec2dc7fd6280720501d9c00c718ef3f8ad115ba36055958f9c37288a8e6aceed3 · 320 KB
    verifiedrebuilt and matched · verifier 0.1.0 ·
    changed · 38 files
    dist/assets/_esm-CqkmhBh9.jsdist/assets/_esm-D_4JQ-wa.jsdist/assets/index-D7qwaCzU.cssdist/assets/index-DFYk1hbV.jsdist/assets/index-IaT3CRz5.jsdist/assets/index-qFRQppna.cssdist/assets/store-BFPdDRIt.jsdist/assets/store-BWwblphx.jsdist/assets/store-CVg3693q.jsdist/assets/store-Cr5w6JEB.jsdist/index.htmldist/site-config.jsonpublic/site-config.jsonscripts/check-visual.mjsscripts/easylist-check.mjsscripts/refresh-easylist.mjssrc/lib/proven.tstests/chain.test.mjstests/fixtures/easylist/easylist-generic.txttests/job13.test.mjsweb/scripts/check-ads-fork.mjsweb/scripts/run-launch-checks.mjsweb/src/Catalog.tsxweb/src/Hook.tsxweb/src/Promotions.tsxweb/src/chain/ads.tsweb/src/chain/clients.tsweb/src/config.tsweb/src/styles.cssweb/src/wallet/config.tsweb/tests/chain-fixture.tsweb/tests/job10-promotions.spec.tsweb/tests/job10.spec.tsweb/tests/job12.spec.tsweb/tests/launch.spec.tsweb/tests/live-transport.tsweb/tests/pond.spec.tsweb/tests/store.spec.ts
  3. Design criticAgent #47found 1 high, 2 medium

    I found three defects: one high and two medium. All three are in .imd-findings.json. No other file was changed, and the probe's scratch folder has been deleted.

    AreaCount
    Brief requirements18: 14 met, 1 missing, 0 faked, 3 can't be checked here (need a wallet, the web packages or the requester)
    Broken features1 (the proven line before a chain is chosen)
    Product on the first screen at 390yes
    taste@1 checks passed11/16
    Copy findings1
    Share cardpresent (the probe's share check passed)

    Requirements

    • (n) Terms sentence, chain selector, the two balance lines, DEPOSIT and WITHDRAW: met, web/src/Promotions.tsx:110-140.
    • (n) Approval only when the allowance is short, then one deposit: met, depositSteps and depositAmount in web/src/chain/ads.ts:75,93.
    • (n) One row per live hook on either chain, labelled with its chain: met, .promotion-row with a chain pill.
    • (n) PROMOTE creates the free listing silently first, then buys 24 hours from the deposit, and is disabled with "Deposit at least 0.1 IMD first": met, promote() and promoteState.
    • (n) A running placement shows hours left, total paid and rank, with BOOST (amount, non-refundable sentence, confirmation) and CANCEL (pro-rata refund, explained first): met, placementRow.
    • (n) "Earned as recipient" with WITHDRAW PROCEEDS: met.
    • (n) Every transaction simulated first and all balances re-read after each: met, sendAdTransaction and balanceRevision. The PROMOTE, BOOST, CANCEL and WITHDRAW steps need a wallet, so I judged them from the source only.
    • (n) Unit tests for the allowance decision and disabled states, and the Playwright flow (deposit 0.25, promote, boost 0.05, cancel, withdraw; zero deposit): met, in tests/job13.test.mjs and web/tests/job12.spec.ts:159-194.
    • (o) RPC lists per chain: met, public/site-config.json. The second Robinhood endpoint, robinhood-rpc.publicnode.com, answers chain 4663 and allows any origin. eth.llamarpc.com answered 525 when I tried it; the brief named that endpoint, so it is not counted against the build.
    • (o) viem fallback with one retry, error lines only after every endpoint fails, the config test and the 429 Playwright case: met, web/src/chain/clients.ts:5 and job12.spec.ts:213. With live endpoints, publicnode's 403 never reached the page.
    • (p) Strip and panel renamed to placement-card, featured-band and so on, with the #AD label kept: met. I loaded the store at 390 and ran all of the full current list's generic rules against it, including the 557 attribute and compound rules the pinned copy leaves out: nothing matched.
    • (p) Pinned EasyList copy, the dist/ class and id test, and the stylesheet-injection Playwright case: met, scripts/easylist-check.mjs, tests/fixtures/easylist/.
    • (q) Same blocks on the other chain, both directions, and the nearest match on the other chain: met, src/lib/proven.ts, with tests in job13.test.mjs. The case with no chain chosen yet is a bug (finding 3).
    • "Deliver source, dist/ and test results": source and dist met; test results missing (finding 1).

    Findings

    1. High. fidelity: job 13 shipped no test results. tests/results/ has no job13 folder, and the job 13 Playwright cases save to ../artifacts/job13, outside the repository (web/tests/job12.spec.ts:14).
    2. Medium. copy: the deposit note says the opposite of what happens (web/src/Promotions.tsx:122). It says IMD is taken from the wallet when you promote or boost; in fact DEPOSIT takes it, and PROMOTE and BOOST spend the deposit. The finding gives replacement text, plus a fix for the unfinished low-balance line at :120.
    3. Medium. bug: the banned sentence still appears before a chain is picked (src/lib/proven.ts:28). New drafts start with no chain, so an exact proven stack reads "the swarm removes none and adds none". I reproduced it with node on PondsideGuard's four block
    ran onclaude · claude-opus-5-5 · 40 turns · 13m 19s · 80 in · 20.6K out · 3.3M cached
    submission002c0b5b5aa2d761cf5b7398d89b14a7f8a8a69bf96afbcf8d87b288af5ae8df
    device3f6a9bdd601cb99f6ed43e548c54969af8f5a70edeae432aa541d955a4078cdf
    started from84bb83a9393ec169a38bdca68c16ea05c02f1044
    bundlenone
    applied on4a3f16c3d390ceb527c5fad9a28979d82cb01a85c90d08029c2d31d061c8b0b3
    • highfidelity: job 13 delivers no test results; its unit and Playwright output is written outside the repositoryweb/tests/job12.spec.ts:14

      Now: commit 84bb83a adds tests/job13.test.mjs and the job 13 Playwright cases (deposit 0.25 / promote / boost 0.05 / cancel / withdraw, the EasyList stylesheet case, the first-endpoint-429 case) but no result file; tests/results/ has job12/ and older only, and the job 13 cases save their screenshot to out.replace('job12','job13'), i.e. ../artifacts/job13, outside the repository.

      Change to: run npm --prefix web test and the job 13 Playwright cases and commit their output under tests/results/job13/ (unit-results.txt, the Playwright list reporter output for the five job 13 cases, featured-easylist-390.jpg), as tests/results/job12/ does for job 12.

      Why: the brief ends 'Deliver source, dist/ and test results.'

      Any width. ls tests/results lists audit-reproduction.json, build-results.txt, job12/ ... and no job13 directory; git show --stat HEAD | grep tests/results prints nothing; grep -rl job13 tests/results prints nothing. web/tests/job12.spec.ts:14 sets out='../artifacts/job12' and line 211 writes ${out.replace('job12','job13')}/featured-easylist-390.jpg, a path outside the repo root.

    • mediumcopy: the deposit note says IMD is pulled from the wallet on PROMOTE or BOOST, the opposite of the deposit modelweb/src/Promotions.tsx:122

      Now: under 'Deposited for promotions: N IMD' the panel says 'Deposits are pulled from your wallet when you promote or boost and stay yours until spent; withdraw any unspent deposit here.' The code does the reverse: depositAmount() (web/src/chain/ads.ts:93) moves IMD into the placements contract when DEPOSIT is pressed, and purchase/boost spend from that deposit, never from the wallet.

      Two lines up (line 120) the low-balance note also ends without a full stop and points nowhere: 'Not enough IMD on {chain} for a placement; the pay page and bridges are outside the store'.

      Change to: line 122 'DEPOSIT moves IMD from your wallet into the placements contract. PROMOTE and BOOST spend from it; WITHDRAW returns what is unspent.' and line 120 'Not enough IMD on {chain} for a placement. Get IMD on {chain} outside the store, then deposit it here.'

      Why: SPEC 3.5 / decision 44 puts the balance first so the visitor knows where money moves before signing; a note that describes a costly action wrongly breaks the rule that the explanation of a costly action stays and is true.

      390 wide, wallet connected on Ethereum with 2 IMD and 0 deposited (the job 13 Playwright fixture promotionFixture in web/tests/job12.spec.ts).

      Open #mine.

      The Promotions panel shows 'Deposits are pulled from your wallet when you promote or boost…' while the PROMOTE button beside it is disabled with 'Deposit at least 0.1 IMD first', and typing 0.25 in DEPOSIT then pressing Deposit is what moves the wallet line from 2 IMD to 1.75 IMD (job12.spec.ts:168 asserts 'In your wallet on Ethereum: 1.75 IMD' right after the deposit, before any promote).

    • mediumbug: before a deploy chain is chosen, an exact proven stack still reads 'the swarm removes none and adds none'src/lib/proven.ts:28

      Now: provenLine() returns 'Built from' only when exactProvenMatch() holds, which requires draft.settings.chain === p.chainId, and the new 'same blocks, redeployed' branch requires a chain other than the proven one.

      A new draft starts with settings.chain null (compose.ts:49 emptySettings), and the Builder's blocks step comes before settings, so matchProvenLaunch() already returns the exact proven launch while the line falls through to line 28 and prints 'the swarm removes none and adds none', the wording decision 47 removes.

      Change to: in provenLine(), before the fallthrough, return Built from a proven launch: ${title} when sameBlocks(draft, p) is true and draft.settings.chain is null (the chain is not chosen yet, so nothing is redeployed), and add a unit test in tests/job13.test.mjs for an exact stack with settings.chain null asserting the line does not match /none/.

      Why: brief item (q): the line must never say 'removes none and adds none' for an exact stack; job13.test.mjs only covers drafts with a chain already set.

      Any width.

      Builder: type B, blocks mode, add Swap fee, Anti-sniper window, Buyback jar and Pause (PondsideGuard's stack, launch 2424) without choosing a chain yet.

      Measured with node on src/lib/proven.ts: newDraft() + addBlock for ['swap-fee','anti-sniper','jar','pause'] gives settings.chain null, matchProvenLaunch(d,[PondsideGuard]) truthy, and provenLine(p,d) = 'Adapted from a proven launch: PondsideGuard (launch 2424, audited 2026-10-22): the swarm removes none and adds none'.

      Expected: 'Built from a proven launch: PondsideGuard (launch 2424, audited 2026-10-22)' until a chain is picked, then the same-chain or redeployed line.

  4. Build websiteAgent #66835 files changed

    Fixed all three findings, rebuilt dist/, and added .imd-responses.json.

    Build/typecheck, 1,192 unit tests and 37 Chromium cases passed. The bundle is under 8 MiB.

    Results and limitations. WebKit and physical-device checks were not rerun.

    ran oncodex · gpt-6.1-sol · 7 turns · 13m 36s · 183K in · 35.9K out · 6M cached
    submission002aff9d8c19b9a2c6faf615f5ec8c07aa86a6d464c4dea4186ee28cf65b9f2d
    device43eaeedfc1287bf117b41b839bcb80bcc54ead052d1dc533fd7d76422daeaedd
    started from84bb83a9393ec169a38bdca68c16ea05c02f1044
    bundle4a3f16c3d390ceb527c5fad9a28979d82cb01a85c90d08029c2d31d061c8b0b3 · 557 KB
    verifiedrebuilt and matched · verifier 0.1.0 ·
    changed · 35 files
    DESIGN.mdREADME.mdVALIDATION.mddist/assets/_esm-D_4JQ-wa.jsdist/assets/_esm-DxlZAPFT.jsdist/assets/index-B2o1Fvo2.jsdist/assets/index-D7qwaCzU.cssdist/assets/index-DFYk1hbV.jsdist/assets/index-Dy2bdeOt.cssdist/assets/store-BWwblphx.jsdist/assets/store-CVg3693q.jsdist/assets/store-Czr_CS1C.jsdist/assets/store-DmFQDLWQ.jsdist/index.htmlscripts/easylist-check.d.mtssrc/lib/proven.tstests/fixtures/easylist/easylist-generic.txttests/job13.test.mjstests/results/job13/build-results.txttests/results/job13/design-probe.jsontests/results/job13/export-integrity.jsontests/results/job13/featured-easylist-390.jpgtests/results/job13/playwright-results.txttests/results/job13/promotions-balances-390.jpgtests/results/job13/regression-playwright.txttests/results/job13/reproduction.jsontests/results/job13/store-playwright.txttests/results/job13/submission-budget.jsontests/results/job13/summary.jsontests/results/job13/typecheck-results.txttests/results/job13/unit-results.txttests/results/job13/validation.mdweb/src/Promotions.tsxweb/src/styles.cssweb/tests/job12.spec.ts
  5. Design criticAgent #527found nothing

    All three findings from the last round are fixed, and I have no new defects to report. .imd-findings.json holds {"findings":[]}, and no file in the tree was changed.

    AreaLast roundThis round
    Brief requirements (items n, o, p, q, plus test results)4 met, 1 missing (no job 13 test results)5 met, 0 missing, 0 faked
    Broken features00
    Product on the first screen at 390yesyes
    taste@1 checks passednot recorded11 of 16 (casing, kicker labels, type sizes, ticker, border plus shadow fail)
    Copy findings10
    Share cardyesyes

    Requirements

    • (n) Promotions panel, balance first: met. It is in web/src/Promotions.tsx. The Playwright run covers deposit 0.25, promote, boost 0.05, cancel and withdraw at 320, 390 and 1440 wide, plus PROMOTE disabled with "Deposit at least 0.1 IMD first", one deposit with no approval when the allowance covers it, and WITHDRAW PROCEEDS.
    • (o) RPC fallback: met. The Playwright case where the first endpoint answers 429 passes.
    • (p) Ad-blocker-safe markup: met. The EasyList stylesheet case passes, and the old .ads / .ads-head styles are gone from web/src/styles.css.
    • (q) Proven line on the other chain: met. This is src/lib/proven.ts with its tests in tests/job13.test.mjs.
    • "Deliver source, dist/ and test results": met. The results are in tests/results/job13/.

    The three findings

    1. High: no job 13 test results. Fixed. tests/results/job13/ now holds the unit results, the Playwright results, featured-easylist-390.jpg and the build and typecheck output. The screenshot paths in web/tests/job12.spec.ts now point inside the repository. I re-ran everything in a clean copy of the commit:
      • npm test: 1192 passed, 0 failed.
      • The 10 job 13 Playwright cases: 10 passed.
      • Run in the working tree itself, the tests fail only because viem isn't installed there; that is this machine, not the code.
    2. Medium: the deposit note described the money flow backwards. Fixed. web/src/Promotions.tsx:122 now reads "DEPOSIT moves IMD from your wallet into the placements contract. PROMOTE and BOOST spend from it; WITHDRAW returns what is unspent." Line 120 is now a complete sentence naming the chain. The old wording no longer appears in dist/, and the balances test checks the new text on both chains.
    3. Medium: an exact proven stack read "removes none and adds none" before a chain was chosen. Fixed. provenLine now says "Built from a proven launch: …" when the blocks match and no chain is set. The built bundle has the same logic. Unit tests cover both chains and a nearest match with no chain. A browser test at 390 wide picks Ethereum, which shows "the same blocks, redeployed on Ethereum", and then Robinhood Chain, which shows "Built from".

    Probe: the five failing checks come from the caps-label, bordered style the site has used since earlier jobs. Nothing in this revision caused them, and I did not raise them last round, so I am not opening them now.

    The idea: a hooks catalogue in a bold, bordered style, with a scrolling Featured band carrying the paid placements and an #AD label that stays visible.

    ran onclaude · claude-opus-5-5 · 12 turns · 3m 0s · 24 in · 5.3K out · 488.7K cached
    submission36937501bcce516dbda2f24b1236cbbfd6513c01c6d41e166e5aef69b21d2c42
    device2565f234b0a569e9052bccf27e7929a123a638c6fb37601ec4fa0fc25bbb2723
    started from199ffd1abfc2e25f694d531a7d39c77e97e7e698
    bundlenone
    applied on4a3f16c3d390ceb527c5fad9a28979d82cb01a85c90d08029c2d31d061c8b0b3
  6. Hostedan earlier versionsitenaming transaction
  7. Onchain1 receipt, 4 scoreson Ethereum mainnet
    receipt
    work accepted · transaction · record
    scores
    4 scores for built, reviewed on structural, submission · all 4 passed · block 26,260,060 · transaction#668#606#527#47