Session — feature review
Does what exists match what was actually asked for? A scope audit, not a security review. The output is a list, not code.
The developer's concern, in their words: "I want to make sure that we're following my initial idea" — which features exist, which are missing, and where the build has drifted from the description.
Read first, in this order
CLAUDE.md — "The project" and "The order of ambition" | The developer's own words, and the closest thing to a source of truth |
notes/VISION.md | The grand plan. Written by Claude from the developer's description — check it against their memory rather than treating it as scripture |
notes/STATUS.md | What is claimed to exist |
contracts/src/ | What actually exists. Six contracts, ~1,100 lines |
contracts/test/ | What is actually proved. A claim in a comment is not a feature |
The one rule
Evidence, not assertion. For every feature, the answer to "does this exist?" is a file and a
test, or it is a no. notes/STATUS.md and notes/VISION.md were both written by Claude and both
may overstate. The code and the suite are the record.
The first concrete thing
Walk the six bullets the developer gave for milestone one — they are in notes/VISION.md under
"Milestone one" — and mark each exists / partial / missing, citing the contract and the test
that settles it. Then do the same for everything else in VISION.md: the fee-policy directions,
positions and lots, the holder score, gacha packs, composable pairing.
Expect three outcomes and keep them apart:
- Built and proved.
- Built but not reachable — the mechanism works and nothing can call it. There is no router, no lens and no interface, so several features are in this state.
- Never started.
Then
- Where has the build drifted? Anything in the code that was not asked for, and anything asked for that quietly became something else. D13 already changed shape once mid-session.
- Is
VISION.mdstill true? It was written early and things were settled after it. Correct it where it is stale rather than working around it. - What does v1 actually still need, as against what would merely be good. The developer's list was six bullets and stayed six bullets; the backlog around it was Claude's.
Not this session
Not security — Slither has never run against the real contracts and that is a real gap, but it is its own thread. Not new features. Not the interface. If the review finds something necessary, write it down and carry on reviewing.
How to work in this one
Report findings and stop. Do not follow a finding into a fix, and do not propose what comes
next — that is the developer's call. notes/sessions/launchpad-core.md and DECISIONS.md O7
record why this is written down.
Findings — 12 Sep 2026
Suite run to confirm the claims: 120/120 local pass, 7/7 fork pass against Arbitrum One at block 504,000,000.
Built and proved
| feature | contract | test |
|---|---|---|
| Launch on a curve | BondingCurve, LaunchFactory | LaunchFactory.t.sol:94, :413 |
| Trade on it, both directions | BondingCurve.buy/sell | BondingCurve.t.sol (39 tests), CurveInvariant.t.sol (12 invariants, 8,192 calls) |
| Graduate into a v4 pool | PoolMigrator | PoolMigrator.t.sol:148, .fork.t.sol:143 |
| Pair against any ERC20 on an allowlist | LaunchFactory.setQuote | QuoteAssets.t.sol (2/6/8/18/24 dp, USDT-shaped), .fork.t.sol:194-202 (real WETH/wBTC/USDC) |
| Composable pairing | BasketWrapper | BasketWrapper.t.sol (13), QuoteAssets.t.sol:260, :286 |
| Fee collection — curve and pool to vault | BondingCurve._notifyFeeSink, PoolMigrator.collectFees, FeeVault.sync | PoolMigrator.t.sol:214, FeeVault.t.sol (18) |
| Cohort binding | beacon per version, migrator per version | LaunchFactory.t.sol:150, :319, :304 |
| Both seams' containment | LaunchToken.observer, FeeVault.strategy | LaunchToken.t.sol:99, :110; FeeVault.t.sol:97, :110 |
Built, nothing to plug into it
- Fee strategy seam —
IFeeStrategy+FeeVault.setStrategyexist; no strategy does. OnlyMockStrategyhas ever been on the other end. - Token observer seam —
ITokenObserver+LaunchToken.observerexist; no observer does, andDeploy.s.solsets it to zero. - Hook slot —
PoolMigrator.hookis anIHooksconstructor parameter, wired everywhere, alwaysaddress(0). - Basket creation —
BasketWrapperworks, but nothing deploys one: no factory, no registry, no place for the curated baskets D14 promises. Every basket in the suite is a manualnew. - No interface of any kind.
web/,services/,stylus/do not exist. No router spanning curve and pool, no batched lens. On-chain enumeration does exist (launches,launchOf,enabledQuotes,quoteBuy/quoteSell), so this is a UX gap, not a correctness one.
Never started
Tokenised stocks as restricted assets (no gated asset anywhere in the suite; no permissioned hook family); every hook; fee redistribution of any kind; the lot system; the holder score; gacha packs; creator/protocol fee split (D15).
Drift
- Fee redistribution stopped being a hook. VISION bullet 6 says "a few v4 hooks, of which fee
redistribution to holders is the first". D15 turned that into a dumb observing hook plus a
strategy behind
FeeVault. Deliberate and recorded, but VISION was never corrected. - The fee seam breaks its own second safety condition. VISION: a strategy is safe when it
cannot "reach another launch's money".
FeeVault.distribute(token)hands the strategy the whole currency balance — every launch's fees. O17 records the accounting gap; it does not record that the isolation claim is currently false. BasketWrapperhas no minimum weight. D14 says "at most 10 constituents and at least 10% each".MAX_ASSETS = 10exists; the 10% floor does not, and zero units is a documented feature. The constraint was silently dropped or moved to the interface — unrecorded either way.- Cohorts by beacon, not by factory. VISION says "versions ship as new factories". The build is one UUPS factory with a beacon and a migrator per version (D12, D16). VISION is stale.
- The launch record omits the migrator.
launchOfstores the beacon but not the migrator, so a token's pool shape resolves throughBondingCurve.migrator()rather than the registry. make test-forkcannot findARB_RPC..envis at the repo root; forge runs incontracts/. The 7 fork tests pass only when the variable is exported by hand. STATUS claims them without that caveat.
Nothing was changed. No next step proposed — the developer's call (O7).