MOTIR-3470Done
(motir-core) DECLARE the catch-up disposition beside the cron — a `defineJob` option a scheduled job cannot omit, on all 14
Turn the amendment's per-job table into a declaration a scheduled job cannot omit, and apply it to all 14.
What this card writes
- A
catchUpfield onDefineJobOptionsinlib/jobs/defineJob.ts, typed so that a definition supplyingcronmust supply it too. The union is already discriminated in this file —JobIdAndTrigger<N>is a two-arm union distinguishing the 1:1-convention job from an additional consumer — so the pattern for making one option conditional on another is established here and does not need inventing. - The same field carried onto
EngineJobDefinitioninlib/jobs/engine/registry.tsand written byregisterEngineJob, beside thecronit qualifies.defineJobis the single choke point every job passes through; registering here is what makes the table complete BY CONSTRUCTION, which is the argument that file andlib/jobs/schedules.tsboth already record. - The disposition on each of the 14 definitions, taken from the amendment — not re-derived here. If a job's right answer looks wrong while writing it, that is a comment on the decision card, not a quiet edit.
What it must NOT do
- It must not add a default. A default is how a cron job added next year inherits a disposition nobody chose for it, which is the exact failure the decision card exists to prevent. If the amendment chose a default anyway, this card implements the amendment and says so in a comment naming the section.
- It must not change any cron expression, threshold or handler. The schedule constants stay byte-identical; the story asserts that.
- It must not forward the option to Inngest.
defineJob'sconfigobject is whatinngest.createFunctionreceives;catchUpis an engine-side fact and belongs only inregisterEngineJob, exactly as the engine'smaxAttemptstranslation already sits outside the Inngest config.
Why this is its own card and not part of the scheduler
It is purely additive and nothing reads it yet — the scheduler is its first consumer. That is the same shape registerEngineJob itself shipped in (MOTIR-3421's pass, "PURELY ADDITIVE … this table is written and never read"), and it keeps the scheduler's diff to a loop rather than a loop plus fourteen touched definition files.
Acceptance criteria
- A
cronjob that omitscatchUpdoes not type-check — asserted by a compile-level check (a@ts-expect-errorfixture in the test suite), because a rule enforced only by review is not enforced. - An EVENT-triggered definition may not supply
catchUpat all, or supplying it is a type error — the option is meaningless without a schedule and an accepted-but-ignored field is a lie. - Every id returned by
engineScheduledJobs()carries a non-nullcatchUp— asserted by walking the registry after importinglib/jobs/registry, never against a transcribed list of 14. The test imports the registry for its side effect and says why, astests/jobs/schedule-health.test.tsalready does. - The value on each of the 14 matches the amendment's table, and the test that checks this reads the ids from the registry so a new cron job fails it rather than slipping past.
fn.optsfor every job is unchanged — the Inngest config a job syncs with must not move because of this card. Assert the forwarded config, not just that the app builds.- The 14 schedule constants are byte-identical to their pre-card values.
tests/jobs/engine-units.test.ts(which already walksengineScheduledJobs()at line 86) is extended rather than duplicated.
Context refs
lib/jobs/defineJob.ts—DefineJobOptions,JobIdAndTrigger's discriminated union, and theregisterEngineJobcall that carries engine-side factslib/jobs/engine/registry.ts—EngineJobDefinition,registerEngineJob,engineScheduledJobs()lib/jobs/schedules.ts— the completeness-by-construction argument in fulllib/jobs/definitions/— the 14 files, each with its schedule constanttests/jobs/engine-units.test.ts·tests/jobs/schedule-health.test.ts— the registry-walking suites and the side-effect-import precedentdocs/decisions/job-queue-foundation.md— the amendment this card implements verbatim