Skip to main content

series-rules

The per-series rule-config schema (fields, constraints, verification status) and the procedure for adding a new series or verifying an existing one. Encodes the never-guess discipline: the shipped Lemons/Lucky Dog/ChampCar configs were read from the rulebooks on 2026-08-19 and are PARTIAL, and the fields still unverified must never be filled in from memory. TRIGGER when touching config/series/*.yaml, packages/domain/src/series-rules.ts, the rule_configs table, or any planner code that consumes rule values. DO NOT trigger for unrelated schema work or UI changes.

Aller à l'installation

Informations de source

Dépôt
weaties/pitlog
Dernière activité de la source
19 août 2026 à 18:51
Langue détectée de SKILL.md
anglais
Étoiles
0
Forks
0

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
series-rules
description
The per-series rule-config schema (fields, constraints, verification status) and the procedure for adding a new series or verifying an existing one. Encodes the never-guess discipline: the shipped Lemons/Lucky Dog/ChampCar configs were read from the rulebooks on 2026-08-19 and are PARTIAL, and the fields still unverified must never be filled in from memory. TRIGGER when touching config/series/*.yaml, packages/domain/src/series-rules.ts, the rule_configs table, or any planner code that consumes rule values. DO NOT trigger for unrelated schema work or UI changes.
# Series rule configs SPEC §5.1: **rule configs are data, not code.** They are YAML on disk for the shipped defaults (`config/series/*.yaml`) and versioned JSON rows in `rule_configs` once an admin edits them. One schema governs both, in `packages/domain/src/series-rules.ts`. ## Where the shipped configs actually stand All three were read from the published rulebooks on **2026-08-19** and carry a `verification.source` naming the sections. All three are **PARTIAL**, not VERIFIED: a few fields the rulebooks simply do not address are still unverified and still show on the plan. They differ in ways that change a schedule, which is the whole reason these are data and not code: | | Lemons | Lucky Dog | ChampCar | |---|---|---|---| | minimum stop | none | 5 min | 5 min (fuel stops, pit-in to pit-out) | | driver change during fuelling | no | no | **yes** | | max stint | none | 2 h | 2 h | | rest between stints | none | 60 min | 60 min | | min drivers | 2, 3 from 24 h | per event pack | 2 / 3 / 4 by length | ## `null` means "no such rule" A null is a **checked answer**, not a blank waiting to be filled. Lemons imposes no minimum stop and no stint limits at all; writing 1800 there would make the planner refuse legal Lemons schedules. If you find a null and think it looks unfinished, read the rulebook before touching it. ## The never-guess discipline — read this first **SPEC §3 lists per-series rule details as an OPEN ITEM owned by Dan. Nobody has read the rulebooks yet.** Every value in every shipped config is a structurally-valid placeholder that exists so the schema, migrations, and planner plumbing can be built and tested. Therefore: - **Do not invent rule values.** Not "a reasonable minimum stop time", not "what Lemons probably requires". A plausible wrong number is worse than an obvious placeholder, because it will be believed. - **Do not change `verification.status` without a `source`.** The status is a claim that someone read a rulebook. - **The planner must surface `unverifiedFields()`.** SPEC §5.1 requires showing assumptions, never a bare number. A schedule built on placeholders has to say so on screen. If a task needs real rule values, that task is blocked on SPEC §3. Say so. ## Schema shape `parseSeriesRules(yamlOrObject)` throws a `ZodError` on anything malformed — configs are small and hand-edited, so failing loudly beats coercing. The object is `.strict()`, so a typo in a field name is an error rather than a silently ignored key. ```yaml schema_version: 1 # must equal SERIES_RULES_SCHEMA_VERSION series_key: lemons # lowercase alnum slug; matches filename AND series.key display_name: 24 Hours of Lemons config_version: 1 # bump on every edit; rule_configs keeps history per version verification: status: UNVERIFIED # UNVERIFIED | PARTIAL | VERIFIED source: null # citation once checked checked_at: null # YYYY-MM-DD verified_fields: [] # dotted paths, only meaningful for PARTIAL pit: min_stop_seconds: # > 0 engine_off_for_fueling: # bool driver_in_car_during_fueling: # bool driver_change_during_fueling: # bool max_crew_over_wall: # int > 0 or null fueling: max_fuel_capacity_gallons: # > 0 or null — series cap, not the car's tank refuel_allowed_under_yellow: # bool fuel_can_only: # bool max_can_size_gallons: # > 0 or null driver: min_stint_seconds: # > 0, or null where the series imposes none max_stint_seconds: # >= min_stint_seconds when both are set max_consecutive_stint_seconds: # > 0 min_rest_seconds: # > 0, or null. Time out of the car between # stints. Binds hard on a two-driver entry. min_drivers_per_event: # a list of tiers, because every series makes # this a function of race length: # - min_race_hours: 0 # drivers: 2 # - min_race_hours: 9 # drivers: 3 # Read longest-first by minDriversForRace(). max_share_of_race: # fraction in (0, 1] ``` Two subtleties in the implementation worth not undoing: - `verification` uses zod's **`.prefault({})`, not `.default({})`** — in zod 4 `.default()` bypasses parsing, so the nested per-field defaults would never apply and `status` would come back `undefined`. - `driverFields` is a standalone object literal because `driverSchema` is wrapped by `.refine()`, and a refined schema has no `.shape` to enumerate for `RULE_FIELD_PATHS`. ## Adding a series 1. **Create `config/series/<key>.yaml`.** `<key>` is a lowercase alphanumeric slug and must equal `series_key` and the filename stem. Copy an existing file including its "!!! UNVERIFIED !!!" header — that header is load-bearing documentation, not boilerplate. 2. **Keep `status: UNVERIFIED`** unless you have actually read the rulebook. A search result, a forum post, or a summary of one is not a rulebook. 3. **Register it in the seed:** add the key to `SERIES_KEYS` and give it a `SERIES_IDS` and `RULE_CONFIG_IDS` entry in `packages/db/src/seed-data.ts`. Ids are fixed UUIDs so reseeding is deterministic. 4. **Update the shipped-set assertion** in `packages/domain/src/series-rules.test.ts` — it asserts the exact filename list on purpose, so a new series cannot appear without someone noticing. 5. `make seed`, then `make check`. No code changes are needed anywhere else. If you find yourself adding a `switch` on `series_key`, that is the rule engine leaking into code — put the difference in the config schema instead. ## Verifying a series 1. Read the current rulebook. Cite it. 2. Replace the placeholder values. 3. Fill `verification.source` (URL or document + revision) and `checked_at`. 4. List the dotted paths you actually checked in `verified_fields`, and set `status: PARTIAL`. Only use `VERIFIED` when **every** field in `RULE_FIELD_PATHS` has been confirmed. 5. Bump `config_version`. 6. `make seed`. The `verification_status` column on `rule_configs` is denormalised from the blob so the UI can badge a config without parsing it — reseeding keeps them in step. ## Adding a rule *field* Adding a field changes the contract for every series at once: - Add it to the right sub-schema in `series-rules.ts`. It is automatically picked up by `RULE_FIELD_PATHS` and therefore by `unverifiedFields()`. - Add it to **all three** shipped YAML files, or `.strict()` parsing of the others still passes but `unverifiedFields()` starts reporting a field nobody has heard of. Prefer a nullable field with a `null` placeholder over inventing a default. - Bump `SERIES_RULES_SCHEMA_VERSION` **only** if the change is backwards-incompatible with configs already stored in `rule_configs`. Adding an optional/nullable field is not.
Voir sur GitHub