# Job 10 carry-overs (full text) The request for job 10 names each of these items in one line; this file holds the full wording, numbers and tests. Every item is in scope and comes before the ads work. Written 2026-10-22; the request points here by its raw URL. Carry-overs from job 11 (Builder v2, delivered 2026-10-22 at commit e1112f9b, checked on the live site), before everything else: (a) The hook card's scrolling details area (.hc-scroll, holding the tiles, the money line and the readiness list) is sized by a layout effect from the card's document position (getBoundingClientRect().top + scrollY), so once the sticky column is stuck and anything re-renders (a keystroke in a field, a poll) the area collapses to the 140 px floor and stays there until a re-render back at the top of the page: at 1440×900 it goes from 182 px to 140 px, at 2560×1300 from 582 px to 140 px, hiding most of the hook. Size it from the card's on-screen position instead (the top of its bounding rectangle in the viewport, which equals the sticky offset once stuck), recompute on scroll (through requestAnimationFrame) and on resize, and never let it shrink below its size at load while the column is stuck. A Playwright test at 1440×900 and at 2560×1300 scrolls down 1000 px, types in Owner address, and asserts .hc-scroll is at least as tall as at load and at least 300 px, and that the card still fits the viewport. (b) On phones (below 720 px) the same area is a 64 px window holding about 680 px of content, so a phone never shows the rules: give it a floor of 40 percent of the viewport height there (the card may then run past the first screen on short phones; the page scrolls). Tests at 390×844 and 320×900 assert .hc-scroll is at least 0.4 × innerHeight tall or as tall as its content. (c) web/playwright.config.ts lists the job 7, job 7-revision, job 8, job 8-revision, job 8-written-fees and job 9 browser specs under testIgnore instead of porting them; port every test in those six files to the v2 selectors (#stack .rule[data-block], .hookcard, the sheet's #composed, #findings, the step 2 controls) and remove testIgnore, so the launch, hook page, free-check, fixed-fact-conflict, written-fees and proven-launch screens they cover run again; no spec file may be ignored. (d) A finding's excerpt reads 'The request says "(choose a chain)" in the request.'; drop the trailing "in the request." so it reads 'The request says "(choose a chain)".' Then the carry-overs from the first live launches (2026-10-22, launches 2448, 2449 and 2450 on Robinhood Chain, checked on the live site at 14:50 UTC): (e) Type A goes live from the launch record. Launch 2448 (test, TEST, request 0xece8c70d612890553921a16cfbf19b2c674937735f78591743476d8b3ff3bd5c) is live on chain (TestHook 0x5a9e7a61c45d2c615162fa57931bcbc06d9b20cc, TestToken 0xe7244bfb99c7ad49c5a40eaeedb215cb47dde85b, MerkleDistributor 0x29760ee79ca59cec260da5e476ef03a137fc66b6, the TEST/IMD pool with fee 12500 and tick spacing 60 seeded in the launch transaction), yet the catalog card and the hook page say "In progress" and every address "unknown until live", because for type A the site trusts only the result file behind the Intake's Completed event, and IMD's result file names the launch id and status but no address. Apply the launch record for type A exactly as for B and C: artifacts by role (hook, token, distributor), status live when the record says live and the hook has code on chain, the pool id computed from the record's seeded pool key (keccak256 of the ABI-encoded PoolKey currency0, currency1, fee, tickSpacing, hooks; for 2448 that is 0xccab6575b5cdd5798731f62f9299c442f954366e91b9513386d83e249cb99843) and prefilled into the pool selector, the Live step reading "Launch record live; addresses from the record". Unit tests on 2448's record (evidence/launch-5-launch-live.json in the spec repository) and a Playwright case for a type A page that reaches Live. (f) Type C page: on launch 2450 (LilyGuard, request 0x17a9c37c4f71fec5d7927455d577237574edf6f6592eb8b07800ae0122fbd992) the owner row says "Owner could not be read" although owner() on the hook 0xb3373d1d202449c07fc6a51c5fc38483b409a0cc answers on the public RPC; find the cause (the hook address is resolved through the deployer after the first render; the owner read must run again once it is known) and fix it, and a type C page must not say "unknown until live" for Distributor and Pool id: there is no distributor for an existing token (drop the row) and the pool is opened later ("No pool yet; open one below", with the OPEN THE POOL panel of 6.4). (g) Contracts launches paid from the same wallet (2454 and 2456, the ad contracts) are not hooks: a #hook link to their request opens "Hook not found", and they must not appear in the catalog; My hooks lists them as one plain row "Contracts launch 2454, live" linking to the IMD explorer. Then the earlier carry-overs (2026-10-22, found on launch 7, the audits and job 9's review): (1) the notice shown on the hook page after payment links "Open IMD explorer" to the request's build page https://explorer.imd.fun/jobs/, the job id read from the intake fate's admission.result.jobId exactly as the Source job link already does; until the request is admitted the link is labelled "IMD explorer" and opens https://explorer.imd.fun/. (2) The notice drops its "Hook page" link, which pointed at the page it is shown on; it keeps the request id and the Copy link from job 9. (3) The hook page's "Launch page" link to explorer.imd.fun/launches/ answers 404 because the explorer has no per-launch page; replace it with the same build page link, one per job id, labelled "Build page". The Hook row keeps its block-explorer link to the hook contract. Add a unit test that the notice and the hook page never link explorer.imd.fun/launches and that the build link carries the job id. (4) SPEC 4.16 rule 31, range orders: the sentences of Allowlist opening, Open at, Trading hours and Anti-sniper add "While this rule is active, adding liquidity is allowed only to the factory and the owner" (type B and C: only to the owner), "removing liquidity is never restricted", and enable beforeAddLiquidity in the permission line; the sentences of Max buy, Max swap and Cooldown add "A one-sided liquidity position is not a swap: it is not limited by this rule and pays no hook fee." Unit tests assert each sentence and the permission bit; the 1,014 block-pair sweep stays clean. (5) SPEC 4.16 item 8, same trade, same fee: every fee sentence adds "the same pool execution pays the same fee whichever amount the swap specifies: when the swap specifies its pair-currency amount, exact input A pays A × rate ÷ (10000 + rate) and exact output A pays A × rate ÷ (10000 − rate), computed with mulDiv". (6) SPEC 4.16 item 24: every request without the Dynamic LP fee block adds "a pool initialized with the dynamic-fee flag (0x800000) is rejected at initialization". Unit tests assert both sentences. (7) importProvenSource in web/src/relay.ts compares the relay's returned repoUrl with the index entry after normalising both: strip a trailing .git and a trailing slash, compare case-insensitively; the unit and Playwright mocks for /import return IMD's real shape, with .git appended to repoUrl, so the test fails on the old code. (8) src/lib/writtenFees.ts: "1 pct", "1 pct.", "1/100", "one in every hundred", "1 in 100" and "one out of a hundred" near a trade word are a 1% rate; any amount the reader cannot turn into a rate raises the fee-rate finding instead of writing "Hook fee rate: 0%"; an unknown payee followed by receives, accrues, gets, earns, keeps or collects raises the recipient finding exactly as "is paid" does; regression tests for each phrasing. (9) web/src/LaunchNotifications.tsx watches only launches paid from this browser (the saved submitted drafts and the connected wallet's own requests), never a hook page the visitor merely opened; a test proves a browsed page adds no watch. (10) The wait line reads "Usually 30 to 90 minutes, sometimes up to 3 hours: the swarm writes, tests, audits with four auditors and a judge, then deploys. From a proven launch, usually less." (launches 5, 6 and 7 took 31, 65 and 36 minutes to admission). (11) From the ad contracts' audit (launch 2454): the strip and the Promotions panel never render a placement whose getPlacement status is cancelled or whose end time has passed, even when featured() lists its id, and paging continues past such ids; the BOOST step says "A boost is non-refundable, has no deadline and pays for whatever time remains on this placement" and asks for a confirmation before the transaction; rank and totals shown come from rankOf and the placement's live total, never from a cancelled placement's nominal base. (12) Hook page controls before a pool exists (SPEC decision 33): when a management row needs a pool id and none is set, it shows "No pool uses this hook yet. Open a pool with it, or enter its pool id above." with its Send button disabled and no reading attempted; the pool selector offers the pools initialized with this hook, read from the PoolManager's Initialize events filtered by the hook address through the chain client, plus a typed pool id; every Send simulates first and, on a revert, shows the plain reason from the catalog row (for example "Nothing to claim yet", "The jar is below its threshold", "Swaps are paused") instead of "The contract refused this call"; and the management rows are built from the contract's own ABI at the launch's source commit (out/.sol/.json read from raw.githubusercontent.com, falling back to the catalog signatures), matched to the catalog rows by function name, so launch 2424 (claimFees() without a pool id, a global pause()) keeps working controls. Playwright covers a hook-only page with no pool and the launch 2424 ABI.