From 9f9b930971c3fc0b0f2e474e4a768c07b0cb7f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Caruelle?= Date: Mon, 14 Sep 2026 00:58:44 +0200 Subject: [PATCH] =?UTF-8?q?ci(cron):=20typechecker=20ce=20que=20le=20cron?= =?UTF-8?q?=20ex=C3=A9cute?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le tsconfig racine exclut `src/solver`, donc le `tsc --noEmit` de `bun run build` ne lit jamais generate-daily.ts — l'entrypoint du cron. Et le service cron construit avec `bun install`, sans typecheck du tout. Le solveur partait donc en production sans qu'aucun compilateur ne l'ait lu. `src/solver/tsconfig.json` existait déjà mais aucun script ne l'invoquait. `typecheck:solver` lui donne un appelant, en un seul endroit : la CI l'exécute sur chaque PR, le build Railway du cron sur chaque déploiement. Deux trous restent ouverts, consignés dans AGENTS.md : un run qui casse à 05:00 sur du code qui compile est toujours muet — l'IaC Railway n'a aucune primitive de notification, `webhook` et `notification` n'apparaissent nulle part dans les types du SDK — et le domaine public du service cron n'est pas supprimable depuis le fichier. --- .github/workflows/ci.yml | 6 ++++++ .railway/railway.ts | 11 ++++++++++- AGENTS.md | 24 ++++++++++++++++-------- package.json | 1 + 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9df477..fdb64cb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,12 @@ jobs: # route modules, a thirteenth is a regression. - run: bun run lint + # The root tsconfig EXCLUDES src/solver, so `bun run build`'s tsc never + # reads the cron's entrypoint (generate-daily.ts). Its own project does. + # Railway's cron build runs the same check — this one fails the PR + # instead of the deploy. + - run: bun run typecheck:solver + # `test` and `build` each compile paraglide first; src/paraglide is # gitignored, so no separate generation step is needed. - run: bun run test diff --git a/.railway/railway.ts b/.railway/railway.ts index 3265fb5..936ae46 100644 --- a/.railway/railway.ts +++ b/.railway/railway.ts @@ -40,12 +40,21 @@ export default defineRailway(() => { // schedule, then exits (restart NEVER — it's a one-shot per run). const cron = service("cron", { source: github(REPO), - build: "bun install", + // Skips the vite build (this service serves nothing), but still typechecks + // what it actually runs: the root tsconfig EXCLUDES src/solver, so the web + // build's `tsc --noEmit` never sees generate-daily.ts. Without this line the + // cron ships code no compiler has read. + build: "bun install && bun run typecheck:solver", start: "bun run gen:daily", deploy: { cronSchedule: "0 5 * * *", restartPolicyType: "NEVER", }, + // NOTE: this service has a generated public domain + // (cron-production-ad37.up.railway.app) that serves nothing — a process + // which exits has no port to expose. It is NOT removable from here: both + // `serviceDomains: { "": null }` and `serviceDomains: null` plan as + // no-ops in railway 3.5.7. Delete it from the dashboard. env: { DATABASE_URL: Postgres.env.DATABASE_URL, }, diff --git a/AGENTS.md b/AGENTS.md index f5ef38a..f044071 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -104,12 +104,15 @@ routing, and build were migrated. overwrites `src/db/schema.ts` — re-append our tables from git after: `dailyPuzzle`, `dailyScore`, `dailyView`, `levelScore`) - `bun run lint` — oxlint, capped at `--max-warnings=12` (see "Key decisions") +- `bun run typecheck:solver` — `tsc` over `src/solver`, which the root tsconfig + excludes. `bun run build` does NOT cover it, and it is what the cron runs. - `bun run generate-routes` — regenerate the route tree (`tsr generate`) -CI (`.github/workflows/ci.yml`) runs `lint` → `test` → `verify` → `build` on -every push to `main` and every pull request, on the bun version pinned by -`packageManager`. No Postgres service: no test imports `src/db/index.ts` or -reads `DATABASE_URL`, and the suite stays stateless on purpose. +CI (`.github/workflows/ci.yml`) runs `lint` → `typecheck:solver` → `test` → +`verify` → `build` on every push to `main` and every pull request, on the bun +version pinned by `packageManager`. No Postgres service: no test imports +`src/db/index.ts` or reads `DATABASE_URL`, and the suite stays stateless on +purpose. ### Environment variables @@ -233,10 +236,15 @@ Topology in `.railway/railway.ts`: (secrets, `preserve()`d in IaC). - **Postgres** — `postgres("Postgres")`; other services reference its `DATABASE_URL`. -- **cron** — `source: github(...)`, build `bun install` (skips the vite build), - start `bun run gen:daily`, `deploy.cronSchedule = "0 5 * * *"` (UTC), - `restartPolicyType: "NEVER"`. The generator closes the pool and `exit(0)` or - the next run is skipped. +- **cron** — `source: github(...)`, build `bun install && bun run +typecheck:solver` (skips the vite build, but still typechecks what it runs — + the root tsconfig excludes `src/solver`, so the web build never reads + `generate-daily.ts`), start `bun run gen:daily`, + `deploy.cronSchedule = "0 5 * * *"` (UTC), `restartPolicyType: "NEVER"`. The + generator closes the pool and `exit(0)` or the next run is skipped. + Two known gaps: a run that fails at 05:00 on code that _compiles_ is still + silent (Railway IaC has no notification primitive — `webhook`/`notification` + appear nowhere in the SDK types), and tier 3 has no bank fallback. `/api/health` (`src/routes/api/health.ts` → `src/server/health.ts`) runs `select 1` against the pool and answers 200 `{"status":"ok"}` or 503 diff --git a/package.json b/package.json index 22a2d46..7a026c4 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "paraglide": "paraglide-js compile --project ./project.inlang --outdir ./src/paraglide", "generate-routes": "tsr generate", "build": "bun run paraglide && tsc --noEmit && vite build", + "typecheck:solver": "tsc --noEmit -p src/solver/tsconfig.json", "gen:icons": "bun scripts/gen-icons.ts", "start": "bun .output/server/index.mjs", "preview": "vite preview",