MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-3470

(motir-core) DECLARE the catch-up disposition beside the cron — a `defineJob` option a scheduled job cannot omit, on all 14

Done
Description

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

  1. A catchUp field on DefineJobOptions in lib/jobs/defineJob.ts, typed so that a definition supplying cron must 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.
  2. The same field carried onto EngineJobDefinition in lib/jobs/engine/registry.ts and written by registerEngineJob, beside the cron it qualifies. defineJob is the single choke point every job passes through; registering here is what makes the table complete BY CONSTRUCTION, which is the argument that file and lib/jobs/schedules.ts both already record.
  3. 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's config object is what inngest.createFunction receives; catchUp is an engine-side fact and belongs only in registerEngineJob, exactly as the engine's maxAttempts translation 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 cron job that omits catchUp does not type-check — asserted by a compile-level check (a @ts-expect-error fixture in the test suite), because a rule enforced only by review is not enforced.
  • An EVENT-triggered definition may not supply catchUp at 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-null catchUp — asserted by walking the registry after importing lib/jobs/registry, never against a transcribed list of 14. The test imports the registry for its side effect and says why, as tests/jobs/schedule-health.test.ts already 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.opts for 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 walks engineScheduledJobs() at line 86) is extended rather than duplicated.

Context refs

  • lib/jobs/defineJob.tsDefineJobOptions, JobIdAndTrigger's discriminated union, and the registerEngineJob call that carries engine-side facts
  • lib/jobs/engine/registry.tsEngineJobDefinition, registerEngineJob, engineScheduledJobs()
  • lib/jobs/schedules.ts — the completeness-by-construction argument in full
  • lib/jobs/definitions/ — the 14 files, each with its schedule constant
  • tests/jobs/engine-units.test.ts · tests/jobs/schedule-health.test.ts — the registry-walking suites and the side-effect-import precedent
  • docs/decisions/job-queue-foundation.md — the amendment this card implements verbatim