You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
DbJobAdapter.replay() writes its synthetic sys_job_run row regardless of recordRuns — an operator who switched run history off still accumulates replay rows #9633
Found while fixing #9611 (measured, not inferred — the corrected recordRuns JSDoc had to name this exception in order to be true). ⛔ Filed rather than absorbed: #9611 is comment-only by ruling and this is a behavioural question needing a disposition.
The inconsistency
packages/services/service-job/src/db-job-adapter.ts has exactly two callers of startRun, and only one consults the flag:
replay() then always calls finishRun(runId, ...) on that id, on all three arms (terminal status read off the inner execution, success, and the catch). So with recordRuns: false:
every scheduled and triggered execution writes nothing (intended), and
every replay() writes one complete sys_job_run row with trigger: 'replay' (probably not intended).
The result is a sys_job_run table that an operator believes is switched off and which nonetheless fills, slowly and exclusively, with replay rows — the least representative sample of the job's history, and one with no non-replay rows beside it for context.
Why the flag reads as intended to cover it
recordRuns is documented (after #9611) as the on/off switch for run history, and listExecutionsByStatus reads sys_job_run for every trigger kind without distinguishing them. Nothing in the field's contract carves replay out; the carve-out is an artifact of replay() being written to solve a different problem — #5548's synthetic row exists to force the trigger: 'replay' tag, and #7734 widened its terminal-status handling — and the recordRuns gate landing only on the wrap path.
Dispositions
replay() honours the flag — wrap both startRun and the finishRun calls the same way wrap does. Consistent with the field's documented meaning; costs the replay tag when history is off, which is already the case for every other execution.
Recommendation: (1), on the contract-first reading — one flag, one meaning, no second de-facto rule at a call site. But it is a real product call about what an operator is asking for when they disable run history, so it wants a decision rather than a guess.
Note there is no test coverage of recordRuns in either direction today (recorded in #9631), so whichever disposition is chosen needs its own pin.
Found while fixing #9611 (measured, not inferred — the corrected
recordRunsJSDoc had to name this exception in order to be true). ⛔ Filed rather than absorbed: #9611 is comment-only by ruling and this is a behavioural question needing a disposition.The inconsistency
packages/services/service-job/src/db-job-adapter.tshas exactly two callers ofstartRun, and only one consults the flag:replay()then always callsfinishRun(runId, ...)on that id, on all three arms (terminal status read off the inner execution, success, and the catch). So withrecordRuns: false:replay()writes one completesys_job_runrow withtrigger: 'replay'(probably not intended).The result is a
sys_job_runtable that an operator believes is switched off and which nonetheless fills, slowly and exclusively, with replay rows — the least representative sample of the job's history, and one with no non-replay rows beside it for context.Why the flag reads as intended to cover it
recordRunsis documented (after #9611) as the on/off switch for run history, andlistExecutionsByStatusreadssys_job_runfor every trigger kind without distinguishing them. Nothing in the field's contract carves replay out; the carve-out is an artifact ofreplay()being written to solve a different problem — #5548's synthetic row exists to force thetrigger: 'replay'tag, and #7734 widened its terminal-status handling — and therecordRunsgate landing only on thewrappath.Dispositions
replay()honours the flag — wrap bothstartRunand thefinishRuncalls the same waywrapdoes. Consistent with the field's documented meaning; costs the replay tag when history is off, which is already the case for every other execution..d.tsJSDoc comments inpackages/services/*describe behaviour their code does not have —MemoryCacheAdapter's "LRU-style eviction" is insertion-order, andDbJobAdapterOptions.recordRunsis documented as a numeric cap defaulting to none but is a boolean defaulting to true #9611 states it as observed behaviour, not as a designed guarantee) rather than being an emergent property of two call sites.Recommendation: (1), on the contract-first reading — one flag, one meaning, no second de-facto rule at a call site. But it is a real product call about what an operator is asking for when they disable run history, so it wants a decision rather than a guess.
Note there is no test coverage of
recordRunsin either direction today (recorded in #9631), so whichever disposition is chosen needs its own pin.Refs: #9611 · #9631 · #5548 · #7734
Generated by Claude Code