npm run dev # Next.js dev server on http://localhost:3000
npm run build # Static export → ./out (no `start` needed for the deployed site)
npm run lint # ESLint (flat config extending eslint-config-next)
npm run format # Prettier write across the repoThere is no test runner. CI (.github/workflows/ci.yml) runs npm run lint and npm run build on every PR — both must pass. Pre-commit runs lint-staged (eslint --fix + prettier) via simple-git-hooks. Node 24.x is pinned in package.json#engines.
The deployed build sets PAGES_BASE_PATH (see next.config.ts and .github/workflows/deploy.yml); to mirror the deployed paths locally, set the same env var before npm run build.
CONTEXT.md defines the project's terminology (Tracker, Submission, Instance, Category, Runtime to solution) and lists forbidden synonyms for each. Read it before naming anything user-facing or writing prose — using "track", "entry", "problem", "status", "TTS", etc. is a documented mistake. Categories are not freeform strings; they're the three values in src/lib/categories.ts (Active candidates, Superseded candidates, Baseline benchmarks) and drive the primary tab filter on every tracker page.
Next.js 16 App Router, statically exported (output: 'export' in next.config.ts) and deployed to GitHub Pages. There is no server runtime — every page must work as static HTML + client JS.
Three parallel trackers, one shared shell. OE / VP / CVP each have:
- A route at
src/app/trackers/<tracker>/page.tsxthat imports itsdata/<tracker>/submissions.jsonand the relevant instance file (circuit-models.jsonfor OE/CVP,hamiltonians.jsonfor VP) via JSON import assertions, then renders a tracker-specificSubmissionsTable.tsxnext to it. - A thin tracker-specific
SubmissionsTable.tsx(in the same route folder) that adapts the tracker's submission shape to the generic shared<SubmissionsTable>insrc/components/SubmissionsTable.tsxby passinggetInstanceId,getInstanceUrl,getQubits,getGates, avalueColumnrenderer, and achartconfig.
When adding a feature that should appear in all three trackers, change the shared component in src/components/ and pass new props through each route's adapter — don't duplicate logic across the three app/trackers/<tracker>/SubmissionsTable.tsx files.
The shared table uses nuqs to mirror filter state (category, instance) into URL query params; keep that contract intact when adding filters so deep links continue to work. The submission types in src/types/submissions.ts (OESubmission, VPSubmission, CVPSubmission) all extend BaseSubmission — put cross-tracker fields there.
Submissions are never edited by hand. The pipeline is:
- Contributor opens a GitHub issue using one of the templates in
.github/ISSUE_TEMPLATE/(six templates: regular + "problem" variants for each of the three trackers). - A maintainer adds the
verifiedlabel. .github/workflows/verify-issue.ymlfires: it picks the matching template based on thepath: <tracker>andproblem submissionlabels, parses the issue body withissue-ops/parser, runs.github/workflows/parse-submission.jsto coerce numeric fields and prependcreatedAt/url, appends the result todata/<tracker>/submissions.jsonviajq, and opens a PR.
If you change a submission field, update all of: the relevant issue template(s), parse-submission.js (numeric field list), the *Submission type in src/types/submissions.ts, and the table/chart adapters that read it. The exponential-number marker hack in parse-submission.js exists because JSON.stringify would otherwise quote scientific notation as a string — preserve that pattern if extending the numeric list.
- Path alias
@/*→src/*(use it; relative../../../is reserved for importingdata/). - Prettier config is inside
package.json(singleQuote,printWidth: 100) plus three plugins:organize-imports,packagejson,tailwindcss— runningnpm run formatwill reorder imports and Tailwind classes. - Tailwind v4 (no
tailwind.config); design tokens live insrc/app/globals.css. UI primitives insrc/components/ui/follow the shadcn/Radix pattern (seecomponents.json). - Client components live where they're used; the shared
SubmissionsTableis'use client'because ofnuqsanduseState. Tracker page entry points stay server components and pass JSON data down.