# Carry-overs for job 12 (the job after job 10) Found after job 10 was paid (2026-10-22, 15:37 UTC), so they ride at the top of job 12 (jobs/job-12-proven-lane.json, the proven lane of decision 39), before its own work. Anything found in job 10's review is added here too before job 12 is staged. Full wording here; the request names each in one line. (h) Phantom scroll gap: done in job 10 (the design critic found it independently and the builder positioned the scroll containers; verified on the live site 2026-10-22, decision 42). Nothing left for job 12 except keeping the test: the column's scrollHeight equals its last child's bottom plus the padding within 2 px at 1920×1080 and 1366×768. (i) The Builder goes fluid (SPEC 3.2 and decision 38, replacing the 1240 px cap). .builder-page.wrap takes max-width 1800px with padding-inline clamp(16px, 3vw, 48px) (keeping the safe-area max() on each side); the .b2 grid keeps steps minmax(0, 1fr) and the card becomes clamp(420px, 28vw, 520px) from 1100 px up; the sticky column, the shelf, the rule rows and the fields fill their column; paragraph text keeps its 65ch measure; type sizes stay fixed. The width sweep adds 1920×1080 and 2560×1440 and asserts that the content's left and right edges sit within the gutter of the window edges up to 1800 px (at 2560 the content is 1800 px wide and centred, the card 520 px), that nothing scrolls sideways, and that the card still fits the viewport. The rest of the site keeps its 1180 px reading width. (j) Readable text (SPEC section 14 "Type", decision 41). Keep Press Start 2P exactly where it is used today (bar, h1 to h3, buttons, pills, chips, labels, eyebrows). Replace Pixelify Sans with Atkinson Hyperlegible for all reading text (body, paragraphs, rule lines, findings, inputs, selects, notices, catalog cards, the Learn page) at the existing sizes (15 to 18 px), weight 400, bold 700; replace VT323 with JetBrains Mono for every number, address, hash, function signature, the exact request text and every reading in the hook page panels, weight 400 or 500, font-variant-numeric tabular-nums. Self-host both as latin woff2 subsets under /fonts beside the existing files (SIL Open Font License, licence texts added to LICENSES), declare fallbacks (Verdana; ui-monospace, Menlo), keep font-display swap, and remove the Pixelify Sans and VT323 files and @font-face rules. Do not change sizes, line heights or layout; the landing tile scene keeps its own drawing. Tests: a unit test that styles.css declares no Pixelify Sans or VT323 and that --body and --mono name the new faces; Playwright asserts the computed font-family of a paragraph, a rule line, an address and the cost number on the Builder and the hook page at 390 and 1440 px, and that no horizontal scroll appears at any width in the sweep. (k) A request id that is not a hook (decision 42). Opening #hook/1/ for the ad contracts launches (2454, 2456) without a connected wallet shows "Hook not found. This request was not found among launches made through this store." with a Browse hooks link; the plain "Contracts launch , live" page with its IMD explorer link appears only once the request is matched to the connected wallet's own launches. Resolve the request through the relay's intake fate (GET /intake// is not available by request id, so read the Intake's Requested event for that id from the chain, which the site already indexes for store bodies) so the contracts-launch page with its explorer link shows for any visitor, and say "Not a hook: a contracts launch for the store" rather than "not found". Playwright: the ads request id without a wallet reaches the contracts-launch page. (l) The Promotions panel shows the wallet's IMD (SPEC 3.5, decision 43). Today the panel shows only "Available balance: N IMD", the deposit held inside FeaturedPlacementsV2, which a new user reads as their IMD balance (the owner saw "0 IMD" while holding IMD). Show two lines, each read on load and after every transaction: "In your wallet on : N IMD" from the IMD token's balanceOf on that chain (and, when it is below 0.1 IMD, "Not enough IMD on for a placement; the pay page and bridges are outside the store"), and "Deposited for promotions: N IMD" from available(address) with the sentence "Deposits are pulled from your wallet when you promote or boost and stay yours until spent; withdraw any unspent deposit here." Unit test on the two readings; Playwright with a controlled RPC asserts both lines and the low-balance note. (m) Pay on any chain (SPEC 3.5 and 6.6, decision 43). The promotion chain selector means where the wallet pays; the hook dropdown lists every live hook the connected wallet launched through the store on either chain, each labelled with its chain ("ReedGuard · Robinhood Chain"); createListing is sent to the promotion chain's registry with the hook's own chain id and address (the contracts already accept this); purchase, boost, cancel and withdraw run on the promotion chain; the panel's own-placements rows show placements from both chains. The featured strip reads featured() on both chains, merges by hook (chain id plus address), sums the totals paid for the same hook and shows one card ranked by that total; the hook page's #ad state looks on both chains. Playwright with controlled RPC responses: a Robinhood Chain hook promoted with the wallet on Ethereum reaches Done, and the strip shows one card for a hook placed on both chains. # Carry-overs for job 13 (the job after job 12) Job 12 was paid on 2026-10-22 at 19:01 UTC, so what follows rides at the top of job 13. (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 that sends an approval only when the allowance is short and then one deposit(amount); WITHDRAW for the unspent deposit; then one row per live hook the wallet launched on either chain (labelled with its chain) with PROMOTE (creates the free listing first and silently if the hook has none on that chain, then purchase(listingId, revision, recipient, deadline) for 24 hours paid from the deposit; disabled with "Deposit at least 0.1 IMD first" when the deposit is 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 proceeds 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 gives each chain a list of RPC URLs instead of one (Ethereum: https://ethereum-rpc.publicnode.com, https://rpc.mevblocker.io, https://eth.llamarpc.com; Robinhood Chain: https://rpc.mainnet.chain.robinhood.com plus any second public endpoint the builder verifies); the chain clients use viem's fallback transport with one retry, so a 429 or a timeout on the first endpoint never surfaces; the "Could not read promotions on " line and every other RPC error line appear only after every endpoint failed. Unit test on the config shape; a Playwright case where the first endpoint answers 429 and the strip still renders. (p) Ad blockers hide the strip (SPEC 3.1, decision 46). The featured strip's cards use className adcard (and adcard slot), which EasyList's generic cosmetic rule ##.adcard hides on every site, so visitors with uBlock Origin, AdBlock Plus, AdGuard or Brave Shields see an empty band; the owner did. Rename every element of the strip and the Promotions panel so that no class, id or attribute value matches a generic cosmetic filter: placement-card, placement-slot, featured-band, featured-track, featured-group, promotion-row and so on; never ad, ads, adcard, adslot, ad-card, sponsored or promo as a class or id; keep the #AD text label. Add a unit test that loads the generic cosmetic rules from a pinned copy of EasyList in the repository (refreshed by the builder at build time from https://easylist.to/easylist/easylist.txt) and asserts that no class name or id in the built dist/ matches any ##.class or ###id rule; and a Playwright case that injects the EasyList generic rules as a stylesheet and asserts the placement card and the open-slot card are still visible. (q) Proven line for an exact stack on the other chain (SPEC 4.17, decision 47; the job 12 critic's finding). When a draft's blocks exactly match a proven launch deployed on the other chain, the Builder line and the request say "the swarm removes none and adds none". Instead: 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…"; unit tests for both chains and for a nearest match on the other chain ("remove X; add Y; deploy on "). # Carry-overs for a later job 14 Job 13 was paid on 2026-10-22 at 20:07 UTC and accepted at 21:10 UTC (decision 48). Job 14 was staged on 2026-10-23 (jobs/job-14-public-pond.json) with items (u) and (v) of the next section at the top, then these three in this order. (r) Live without IMD's record plane (decision 48). A fresh browser resolves Live through the relay's /intake and /jobs reads; when IMD answers 503 "busy" or 502, every hook reads "In progress" and the strip loses its placements, as happened on 2026-10-22 around 21:00 UTC on both the job 12 and job 13 builds. Fix: the spec repository's scheduled script (scripts/proven_index.py, every six hours) also writes evidence/launch-records.json, a snapshot per store launch of id, launch number, chain, status, request id, artifacts with addresses, and the seeded pool key; the site fetches it at load like the proven index and uses it to resolve addresses and Live whenever /intake or /jobs fail or time out, confirming the hook's code on chain as today; the chain scan keeps working for new requests. Playwright: with /jobs and /intake answering 503, the catalog shows the four live hooks as Live from the snapshot. (s) Log windows and backoff (SPEC 7.2, decision 48). The publicnode endpoints refuse the site's eth_getLogs windows with 403 (ranges above their cap) and eth.llamarpc.com answered 525, so the fallback never helps a scan and a rate-limited primary turns into a storm of failing calls (81 failed Robinhood reads in one page load). Fix: a per-endpoint maximum log range in site-config.json (publicnode: 10,000 blocks), windows split to fit the endpoint in use, a backoff of 2, 4, 8 seconds on 429 before any retry, at most two log scans in flight per chain, and the validation run includes a scan against the real endpoints with the counts of failed calls in the results (must be zero on a quiet network). (t) Findings grouped by cause (SPEC 6.7, low). On a hook-only draft with a name typed and no wallet connected, the Builder lists seven findings for two causes: no deploy chain and no owner or recipient address. The chain finding should suppress the PoolManager and deployer findings that follow from it, and the missing owner should raise one finding that also covers the recipient, the body address and the deployer constructor lines, with the others appearing only when the owner is set and still wrong. Unit tests on the grouping; Playwright asserts two findings on that draft. # Carry-overs for job 14 (staged 2026-10-23) The owner asked on 2026-10-23 for a fast way to get the failed test launches off the website (decision 49). These two items lead job 14; (r), (s) and (t) above follow them. Job 14 was delivered on 2026-10-23 at 13:44 UTC (commit 956e22dc) and accepted (decision 50): all five items shipped. (u) Stopped and failed launches leave the public pond (SPEC 3.1, 3.4, 3.5, 7.3, decision 49). Today the Store's grid lists seven hooks: four live and proven, and three REQUESTED cards that will never change, the test launches of 2026-10-21 that IMD's builders stopped with a question: WordsmithHook (intake chain 1, request 0x43921ed530010bc8effbfb4380e572d46b4bf4198579ad1fdb6a924973d1d9f6), ImdGuard (0x4208cbe00e43add660c7f53f8abba3a03791839731dd33fa905251df2e320939) and a second test $TEST (0x8c7a29725510defec7710b2e12328f349511cc5659719c09437289761e5e322d). The Intake writes no Completed event for a stopped launch, so the site keeps them as Requested. Define public: a launch is public while it is live, in progress (IMD's record, read through the relay or from the snapshot of item r, says its job is executing, or completed with the launch not yet live, or its launch is deploying), or requested for less than 24 hours since its Requested log's block time with no record saying it stopped. Not public: the Completed event has status 1 or 2 (Failed); the job record is blocked, cancelled, failed or superseded, or has a node whose failure reason says needs_input (the three above); the launch record is parked or failed; or the request is 24 hours old or older and no record says it is running. The age rule works with the relay unreachable, so the three stopped launches leave the grid even while IMD's record plane is busy. Public surfaces, which list public launches only: the catalog grid and its count, the search results, the status rail (All means every public launch; Live only; In progress means in progress, checking and young requested), the landing's launch list and its casts, and the featured strip's hook lookup. Not public launches stay in My hooks for the payer, newest first, with the status pill (Failed, or Requested with the Needs attention text and Fix in Builder), and at their direct link #hook// for anyone who has it, where the page shows one line under the header, "Not on the pond: IMD stopped this launch" or "Not on the pond: this launch failed", and is otherwise unchanged. The Failed pill no longer appears on catalog cards (none are public); nothing else about the cards changes. Tests: unit tests of the public rule on fixtures for every case (live; in progress; young requested with no record; old requested with no record; requested with a blocked job record built from the three stopped launches' real job records, which the relay serves; failed with status 1 and with status 2; parked; live awaiting hook verification); Playwright on a fixture set shaped like the live pond: the grid counts 4 hooks, the three stopped launches appear in neither the grid nor a search for their names, all three appear in My hooks for the paying wallet with the Needs attention text, their direct links open with the "Not on the pond" line, a request younger than 24 hours shows in the grid and disappears on the next refresh once its job record reads blocked, and the four live hooks still read LIVE and PROVEN. (v) Checking, not In progress (SPEC 7.3, low). A live type A launch whose hook code is not yet verified on chain today reads "In progress" for 10 to 30 seconds on a cold load (store.ts sets status in-progress until hookCodeVerified), which reads as a stalled launch. Instead it reads "Checking…" with the status class status-checking, is public, counts as In progress in the rail, and turns LIVE when the verification completes; it never reads In progress. Unit test on the status derivation; Playwright asserts "Checking…" on a live type A fixture before the code read answers and LIVE after. # Carry-overs for job 15 (found 2026-10-23 while accepting job 14) Job 14 was paid on 2026-10-23 at 04:58 UTC and accepted the same day (decision 50), verified from the delivery served locally because IMD's domain imd.fun was on client hold. These items lead the next job. (z) Repository launches start with the audit step (SPEC 4.17, 5.1, decision 51, high; first in job 15). IMD's free check refuses the Builder's default draft, which the proven lane adapts from launch 2448, and every own-code draft, with blocker `audit_required`: "a launch from your own repository starts with an audit of it as it arrived: add an audit-imported-code step before it is adapted". Cause: `compose()` (src/lib/compose.ts, the `shape: 'chain'` line) sends `steps: [build-contract-project, adversarial-review]` for every chain launch and only adds `repoUrl` and `baseCommit` for a proven match or own code; IMD's docs ("From your repository") say a repository launch runs through `audit-imported-code`, `adapt-contract-project` and the audit panel. Verified with IMD's checker on 2026-10-23: the same body with `steps: [audit-imported-code, adapt-contract-project, adversarial-review]` passes with no blockers and a plan of audit, adapt, tests, four audit specialists, judge, review; `[audit-imported-code, adapt-contract-project]` alone is refused (`launch_requires_review`); evidence/check-proven-lane-steps-*.json. Fix, part one: whenever the body carries `repoUrl` and `baseCommit` (proven lane or own code), the steps are `audit-imported-code`, `adapt-contract-project`, `adversarial-review`; from-scratch launches keep `build-contract-project`, `adversarial-review`. The wait estimate for a proven launch stays as it is unless IMD's plan says otherwise. Fix, part two (recommended; the owner confirms when job 15 is staged): on the launch page, Approve stays locked until a free check with no blockers has run on the exact body being paid (same bytes), and a body change after the check locks it again; the Builder's Continue already locks on a blocker once the check has run. Tests: unit tests of `body()` for proven, own-code and from-scratch drafts on both chains and all three types; a Playwright case that runs the free check on the default proven draft against a fixture relay and expects no blocker and the audit-first plan; a case that the launch page's Approve is locked before a clean check and unlocked after it; a real free check of the default draft recorded in tests/results. (w) The store's contracts launches without IMD's record plane (SPEC 3.5, 7.3, low). With api.imd.fun and the relay unreachable, My hooks lists the two ad-placement contracts launches (launch numbers 2454 and 2456) as "Contracts launch , in-progress": no name, no launch number, no link, and a stray space before the comma. With IMD reachable (checked 2026-10-23 16:20 UTC) the rows read "Contracts launch 2456, live" and "Contracts launch 2454, live", still without a link to their pages. Cause: scripts/launch_records.py keeps only launches whose job objective ends with the composer line, and the store's contracts requests do not end with it, so the snapshot has no record for them and the site falls back to "in-progress". Fix: the snapshot script also keeps evm_contracts launches whose job is paid by the request's payer and whose objective SHA-256 matches a contracts request the store sent (the request bodies are in the spec repository's jobs/ folder); the site names such a row from the snapshot (kind, launch number, chain), links it to its page and reads Live from the record; the comma spacing goes. Test: with the record plane answering 503, the two rows read "Contracts launch 2454 · Robinhood Chain · LIVE" (and 2456 likewise) and link to their pages; with the record plane up, nothing changes. (x) No notification offer on a stopped or failed launch (SPEC 3.4, low). The page of a stopped launch still shows "Let this browser notify you when your launch goes live? Keep the site open to receive it." under the "Not on the pond" line. The offer appears only while the launch is public and not yet live. Test: the three stopped launches' pages show no offer; a young requested launch's page does; a live hook's page does not. (y) The pond is never empty while the history scan runs (SPEC 3.1, 7.2, medium). On a cold load the count reads "0 hooks" with "Reading Robinhood Chain and Ethereum launch history. Results appear as they are found." until the Ethereum Intake history has been read, and the four live hooks appear only then: 35 seconds in a headless browser and about a minute and a half in the owner's Chrome on 2026-10-23, with IMD's services unreachable (the site waits on the relay and ipfs.imd.fun before falling back) and the older Ethereum history (anything beyond publicnode's last 9,000 blocks) served only by rpc.mevblocker.io, which took 7 seconds per 10,000-block window that afternoon, while eth.llamarpc.com answered nothing. The owner asked why the site says there are 0 hooks. Fix, two parts. First, the cards of the launch-records snapshot (r) and the proven index are drawn as soon as those files load, before any log window answers; the scan then confirms, adds or replaces them (a snapshot entry carries the launch's chain, kind, name, launch number, addresses, job state and Live status, so it draws the same card, with the request id from the snapshot's objective match or the record). Second, while the first scan runs the count reads "Reading…" (or "4 hooks · reading more") instead of "0 hooks", and a number stands alone only once every window has answered or failed. Endpoints: drop eth.llamarpc.com (dead on 2026-10-23, 525 on 2026-10-22); do not add rpc.flashbots.net (it answered 0 logs for a window where mevblocker returned 24); eth.drpc.org serves windows under 10,000 blocks without a key and could take the older Ethereum history ahead of mevblocker; cloudflare-eth.com caps at 800 blocks and blastapi at 10, so neither helps. Test: with every RPC request held, the grid shows the snapshot's four hooks as LIVE and PROVEN within 2 seconds of load and the count never reads "0 hooks"; with the RPCs answering, the result is unchanged from today's; a launch missing from the snapshot still appears from the scan.