Repository navigation
refactor: group the client by feature and give the backend one source for its rules - #34
Merged
Merged
Conversation
… for its rules The client was split by layer (components/, pages/, lib/, data/), so one mode's code sat in four folders. It now has a folder per mode (daily/, dex/, bounties/, lab/, map/) plus home/, learn/ and players/, with neuron widgets in neuron/ and generic primitives in ui/. The 486-line daily page is split into the page, its result card, the guess list, the heat review and the archive, and the example game reuses the daily's guess row. Backend: - schema validators come from the rules (effects, rarities) instead of copies, and rarity is a union, not a string, so the casts to Rarity are gone - jobs are a union per kind, so the worker API reads typed args instead of casting from v.any() - daily.current nests the answer inside the result, and lab.mine returns a result only once one exists - shared checks live in lib.ts (checkPush, checkDate, profileOf) and lib.ts no longer re-exports rules.ts - dates, the search layer, the map square and the catch neuron are checked where they come in - dose, efficiency, bounty length and reply length live in rules.ts, so the client copy reads them instead of repeating the numbers, and the client no longer imports the server-only bounty pool - the stats row has its own module instead of living in jobs.ts
This comment has been minimized.
This comment has been minimized.
[Medium impact] The PR appears safe to merge; the reported search crash is fixed.
|
The backend now refuses it, and a refused query throws while the page renders.
ishaanko
added a commit
that referenced
this pull request
Oct 29, 2026
…on paper (#35) Stacked on #34. Merge that first, and GitHub will retarget this one to `main`. The UI was full of design slop: a double-ruled "field plate" with corner registration marks, a `Plate Nº 003` strip and a `daily / 2026-10-29 / easy` breadcrumb, ASCII textures inside bordered panels, dividers between every row and section, a translucent blurred nav and modal backdrop, five neutral shades plus opacities, italic lines, tight headline kerning, letter-spaced mono capitals over every section, rarity pills, a numbered how-to list, a heat chart with a ruler, legend and curve, and the behavior map repeated on four pages. Now the content is plain type on paper, grouped by space: - **Palette:** `bg`, `fg`, `dim` and one `line` color, used only for input edges (3.3:1 on paper, 3.8:1 at night). `card`, `raised`, `faint`, `line-strong` and the accent shades are gone, and so is every `/NN` opacity and the blur. Rarity and heat keep their colors because they carry meaning. - **Containers and dividers:** no bordered boxes, cards, panels, plates or row rules anywhere. Buttons are square and swap ink and paper on hover. Inputs keep one edge. - **Type:** no italics (the italic font file is dropped too), no `tracking-tight`, no letter-spaced capitals. Section headings are plain serif. Page titles lose the rust full stop, and the headline is one color. - **Numbering and breadcrumbs:** no "Plate Nº", "Daily Nº" or "Field guide" lines above headings, and no path strips. The how-to steps are paragraphs. The puzzle keeps its `#3`, since that's its name in the share text. - **Tags:** rarity is a colored word with no dot, and the specimen loses its glitch tag. - **Diagrams:** the heat chart is gone. The guess list already shows each heat, and the result card now shows the share grid. The behavior map stays only on the Map page; the Dex, neuron and daily copies are gone. The Map page loses its on-map labels (the legend beside it names the zones) and per-dot colors. - **Modal:** a plain full-page sheet with a Close button inside the dialog, instead of a framed box over a dimmed page. - `daily.current` no longer looks up map places for each guess, since nothing draws them. - `CONTRIBUTING.md`'s UI rule now lists these, so they don't creep back. The zone colors on the map were drawn at 32% opacity, but the legend swatches were full strength, so the two never matched (that's true on main too). Both now use the same solid mix of the zone color and the page color. This reverses the settled field-plate look (frame, corner marks, mono capitals, ASCII fields). Cream paper stays the default, and dark stays opt-in. **Verification** - `bunx tsc -p convex --noEmit`, `bun run build` (bundle 12 KB smaller), `bun run lint` (20 warnings, same as #34) and `bun run test` (81) pass. - Ran it against a copy of the local dev backend and walked every page in Chromium in both themes at 1360 px, and in paper at 390 px, with no page errors. Played practice puzzles to a solve as a guest: the result card, the solved panel and "Why each guess scored" all render. - `e2e/session/run.mjs` passes 15/15, with the `crypto.randomUUID` polyfill described in #34; the join dialog now uses the new modal. `e2e/game.mjs` wasn't run (it needs a second GPU worker), but I checked the selectors it uses still exist. - Before and after screenshots are local, not attached. Claude Opus 5.5 in Claude Code 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The codebase had a lot of slop: the client was split by layer (
components/,pages/,lib/,data/), so one mode lived in four folders;Daily.tsxandui.tsxwere god files; game numbers and validators were copied between the schema, the rules and the page copy; jobs carriedv.any()args that the worker API cast back; and some arguments were never checked at the API boundary.Now the client has a folder per mode (
daily/,dex/,bounties/,lab/,map/, plushome/,learn/,players/), with shared neuron widgets inneuron/and generic primitives inui/. The backend has one source for each rule, and bad states and bad input can't get in.src/is grouped by feature.worker/places.pynow writessrc/map/zones.json.Daily.tsx(486 lines) is split into the page, result card, guess list, heat review and archive.ui.tsxis split into genericui/primitives andneuron/parts.rules.ts. Profile and puzzle fields are declared once and reused by the worker API. Heat bands have one threshold table, used by the bar, chart, map and share grid. The example game reuses the daily's guess row. Lab'sMetricbecameStat.checkPushandprofileOfreplace repeated inline code.PageTitle,DoseInputandbuttonClassreplace copied markup.JoinDialogusesModal.rarityis a union, not a string (removes 6 casts). Jobs are a union per kind, sojob.kind === "judge"gives typedargs.daily.currentnestsanswerinsideresult, andlab.minereturnsresultonly once one exists, which removes the!assertions in Daily and Lab.lib.tsno longer re-exportsrules.ts. The client no longer importsconvex/bountyPool(where the hidden judge prompts live).lab.tsno longer importsDOSEfrombounties.ts. Stats moved out ofjobs.tsintostats.ts.lib/no longer imports components. The session/JoinDialog import cycle is gone.rules.ts, and the copy reads them. About and the field notes read the placed and quiet counts fromzones.json. Clerk and the theme-color meta read theme colors from the CSS instead of keeping copies. Nav and footer links sit together.catchNeuronchecks its neuron./daily/<garbage>shows "No such puzzle." Saved field notes are filtered to known ids.STORE.Deploy notes
rarityand the job rows. Convex checks existing rows when it deploys. If an old prod row doesn't match, the deploy fails and the current version stays live; no data is touched. The local dev data passed.daily.current,lab.mine). A tab left open across the deploy may break on a finished daily until it reloads.neuronaut-prod-worker. I didn't restart it.Verification
bunx tsc -p convex --noEmit,bun run build,bun run lint(20 warnings, down from 23) andbun run test(81) pass. Workerpytestpasses (29).result.answer.worker:fail. Not run on the GPU.e2e/session/run.mjsfails all 15 cases on main too: itsabout:blankpage has nocrypto.randomUUID. With a polyfill added to a local copy, it passes 15/15 on both main and this branch. The fulle2e/game.mjswasn't run, because it needs a second GPU worker next to the prod one.A follow-up design PR is stacked on this branch.
Claude Opus 5.5 in Claude Code
🤖 Generated with Claude Code