Session — Bug fixing, one at a time, on master
What this session is for
The interface was rebuilt to the approved design on 21 Sep and pushed to master. It is now on
staging and being used, and use is turning up bugs. This thread takes them one at a time: the
developer names one, it gets fixed, proved and pushed, and then the next one.
The list below is what has been caught so far and it is incomplete on purpose — more will arrive during the session. Do not work ahead of it. Do not start a sweep.
How this thread works
- Directly on
master. No branch. Staging rebuilds from it, so a fix is live a minute after it is pushed and can be confirmed in the browser the developer already has open. - One bug per commit, in the house convention. A commit that fixes two is a commit that cannot be reverted when one of them turns out wrong.
- The gate is
make fmt-app,yarn lintandmake build-app-testnet— the app half ofmake check, about fifteen seconds. Run the fullmake checkbefore a push that touchescontracts/,services/orsupabase/, and not otherwise: the contract suite is minutes and this thread is not going to touch it. - Ask before redesigning anything. Several items below are "this looks bad". That is a brief for a conversation, not a licence to rewrite a screen.
The redeploy path
make fmt-app && (cd app && yarn lint) && make build-app-testnet # the gate
git commit ... && git push origin master # staging follows
Vercel, in stealthy-town: stadium-app builds app/ and stadium-docs builds docs/.
The branch picks the chain (D30) — master → 421614, Arbitrum Sepolia; prod → Arbitrum One,
and prod does not exist yet. Each project's ignoreCommand skips the build when its own
directory did not change, so an app/-only commit does not rebuild the docs.
Do not watch the deployment. Push and carry on; the developer will say if it did not land.
What must still work
Each of these was found the hard way and none of them is obvious from the code.
- The trade panel quotes by simulating the real call (
app/src/chain/trade.ts). It is not a formula and must not become one — a module runs inside the trade and the curve cannot report it from aview. - The gas floor.
sendRawhands over 3,000,000 becauseBondingCurve,LaunchHookandLaunchTokeneach checkgasleft()and revert when short, and the floors are sequential. Do not tidy it into an estimate. A limit is a ceiling, not a price. - Every write names
chain.id(app/src/chain/network.tsand the four call sites). Without it wagmi builds for whichever chain the wallet is pointed at, which is how a launch on Sepolia opened an Ethereum mainnet confirmation. Keep thechainIdon anything new that writes. - The wallet picker offers the EIP-6963-discovered wallets.
connectors[0]reaches whichever extension won the injection race, which is how MetaMask was unreachable. - The faucet appears only where the quote asset will actually mint, decided by simulating it.
- The ETH pay option appears only where a v3 route exists. On Sepolia it never does.
- The deadline comes from the chain's clock, not the browser's.
lightweight-chartsparses colours itself and knows nothing ofcolor-mix()— it throws from inside its own render loop, so the symptom is a 300x150 canvas in the corner of a correctly sized box.PriceChartresolves tokens torgba()first; keep that.
The list so far
The developer's words, with what is already known about each underneath. Unordered within a band — they will pick.
High
- Connect wallet flow, missing "profile" section. There is no profile anywhere today. A wallet
connects, and
/portfoliois the only thing that is "yours". Needs a conversation about what a profile is here before anything is built — a public page at/portfolio/:walletalready exists and is nearly one. - Seed data so it is easier to debug.
make devseeds 305 launches;make dev-curateadds the podium and endorsements. What is missing is a seeded wallet — positions, activity and a watchlist for the account the developer actually connects with. - Cannot launch a token, wrong network selected — replace with RainbowKit if possible. The
wrong-network half is fixed (f42c616): every write names its chain, and the frame carries a
banner with a switch button. Confirm that before doing anything else.
RainbowKit is a separate question and has a trap waiting: Yarn 1 hoists a workspace's
dependency to the root with its own copy of a peer, and RainbowKit landing beside a second
wagmigives two React contexts and a blank page.resolve.dedupein the Vite config is the fix, andnode_modules/.vitehas to be cleared after the install. Weigh it against what the current picker already does right (EIP-6963, no WalletConnect project id, no relay). - Watchlist: "The signature was not given, so the list stays closed." Sign-in is broken on staging by design — see issue #3 — and the watchlist depends on it. Establish whether this is that known breakage or a second thing on top of it before changing any code.
- Go over the FAQ text and verify it against the contracts.
app/src/pages/Faq.tsx. Some of it reads live from the factory; the prose around it does not. Check each claim againstcontracts/src, not againstnotes/. - Add a "Launch token" button as the first item in the sidebar. Today it is in the top bar and
hidden on the front page, where the hero carries it.
app/src/shell/Shell.tsx.
Mid
- Portfolio should always show something, not "Nothing held" — and a public username. A username is storage, a write path and a uniqueness rule; it is a feature, not a fix.
- The chart could be nicer.
app/src/charts/PriceChart.tsx. Read the trap above first. - Basic metadata and favicon.
app/index.htmlhas a title and nothing else: no description, no Open Graph, no icon. Cheapest item on the list. - The hero image is bad on the light theme. It is drained to
mix-blend-mode: luminosityat 30% because the photograph is a dark block on cream..hero-fieldinapp/src/pages/discover.css. - Sidebar issue. Not yet specific — get the developer to say what they are seeing.
- Content display issue. Same.
- The lab page looks bad, could use art. Known and expected: the mechanic cards have a slot
for an illustration and no illustrations exist. The approved pack builds its versions out of
fifty class names of divs under 3D transforms rather than shipping files, so ours have to be
drawn.
app/src/assets/mechanics/README.mdis the contract — drop an SVG in and it appears.
Hanging over all of it
- "New design overhaul, current one is bad." Said after the interface was matched to the approved pack, so this is about the pack rather than about the match. Do not act on it inside this thread. It is a design conversation and it wants its own.
Low
- Copy on the website. Text is bad in places; no list yet.
Deploy the docs to theDone, 21 Sep. Live atdocs.subdomain.docs.stadium.money: the domain is on thestadium-docsproject and Namecheap carries adocsCNAME tobb6b601a96915cb8.vercel-dns-016.com.plus a second_vercelTXT beside the existingstageone.docusaurus.config.tsnames the domain so canonical links and the sitemap are right. One loose end:/internal404s there, because the project builds with the framework default rather thandocs/scripts/vercel-build.sh— soDOCS_INTERNAL=1is never set and the branch split D30 describes is not wired up. It lands where it should by accident. Worth fixing the config so it is on purpose, andstage.stadium.moneyalready exists for the app.
What the last thread left behind
notes/sessions/redesign.md is the full record. The parts that matter here:
- Read the design by measuring it, never from its stylesheets. The pack is a dozen last-wins
layers and what they say a colour is and what the browser paints are different things. Serving a
copy of the compiled design same-origin and reading
getComputedStyleis how the palette, the type and the glass were finally got right, after a first attempt from the CSS got all three wrong. The values are inapp/src/theme/tokens.csswith that noted. - Five things were removed because the design has no slot for them: the front page's totals,
its trade ticker and its "Chosen by us" strip, the catalogue's
305 of 305 · indexedsource line, and the lab's essay. A sixth — the token page's mechanics disclosure — was removed and then put back, because the public documentation promises it in four places.data/discover.tsstill exportsuseCurationanduseRecentTradeswith no caller. - Responsive is measured, not eyeballed:
documentElement.scrollWidthagainstclientWidthper route in a same-origin iframe of a fixed width. Chrome will not resize below its minimum and page zoom decouplesinnerWidth, so the iframe is the only honest way. Every route was clean at 320px when the thread closed.
Done in this thread
da69a6c— the buy that could not be quoted. Not a contract fault and not the wrong network. Arbitrum's ownsepolia-rollup.arbitrum.io/rpcanswers-32603 method handler crashedtoeth_simulateV1for any non-empty call list, whileeth_callon the same call is fine. The quote is a simulation, so every quote failed: viem printed "An internal error was received" and the panel fell through to "This trade would fail". The CORS*,*and the 429s were downstream — a keystroke burst of doomed simulations trips the rate limiter, and its 429 duplicates the header. Proved by running the app's own approve-plus-buy bundle against three endpoints.publicnodeanddrpcboth answer it properly;arb-sepolia.g.alchemy.comdoes too. The endpoint is nowVITE_RPC_URL, falling back to publicnode, so a keyed one can be set in Vercel rather than committed. It still ships in the bundle — it is only out of git and rotatable.4f49427— the quote no longer runs per keystroke. 350ms of settling, applied at once when the field is emptied. The send takes the sametradeobject the quote was for, because aminOutmeasured for a different size is slippage protection for a trade nobody made.6f003d5,b66ab0c— the edge functions' preflight refused the header the client sends. Saving launch metadata, and signing in, both failed asnet::ERR_FAILED/ "Failed to fetch". The client sendsAuthorization: Bearer <publishable key>; that header is not simple, so the browser preflights, and both functions answeredAccess-Control-Allow-Headers: content-type. Chrome refuses a preflight that does not name every header asked for, so the POST was never sent. The functions were healthy throughout -- a curl POST past the browser, with no auth header at all, reached the metadata function's signature check. Both now answer Supabase's documented list, becausesupabase-jsaddsapikeyandx-client-infoof its own accord.verify_jwt = falsefor both: the header is not checked, it only has to be allowed.
Correction to issue #3
Sign-in completes. Driven end to end against staging with a throwaway wallet once the preflight
was fixed: /auth/nonce returns 200 and a message, /auth/verify returns 200 and an HS256 token.
So jwtSecret() did not throw, which means a symmetric secret is reachable from the function.
The likely reason the issue's premise does not bite: auth/index.ts reads SUPABASE_JWT_SECRET
first, and Supabase injects that into edge functions itself. The issue is right that the CLI will
not reveal the secret; it does not follow that the function cannot read it.
PostgREST accepts the token. Confirmed in the browser on 21 Sep from
0x334C16436e9F3e789cA35829CA012cF4849885B6: a star filled, stuck, and the launch appeared on the
watchlist -- a write and a read back through the RLS policies. So issue #3 does not bite today
and its premise is wrong: the CLI will not reveal the JWT secret, but Supabase injects it into edge
functions as SUPABASE_JWT_SECRET, which is the name auth/index.ts reads first.
What remains true is the direction: the legacy symmetric secret is being retired, so this works on
borrowed time. signInWithWeb3({ chain: "ethereum", message, signature }) exists in the
@supabase/supabase-js@2.116.0 already installed, takes a message and signature directly (so
wagmi keeps choosing the wallet, not window.ethereum), and has Supabase mint the session itself --
deleting our auth function, the JWT_SECRET and the custom wallet claim. Not urgent, now that
nothing is broken.
Why sign-in looked broken, and was not
Three separate faults stacked, in this order, each hiding the next:
- The preflight refused
Authorization, so no request left the browser (b66ab0c). useSessionwas a plain hook, so the session never reached the code that writes (c55c46f).- Issue #3 -- which turned out not to be a fault at all.
Still open in this thread
- The Alchemy key is not set anywhere yet. Until
VITE_RPC_URLis added tostadium-appin Vercel (all environments) staging runs on publicnode, which works. Redeploy after setting it — Vite reads it at build time, not at run time. - Quotes still run for amounts the wallet cannot afford.
shortis known locally from the balance, so those simulations are free waste. Two lines, not done: it is a different bug from the keystroke spam and wants its own commit.