Found while implementing #14094 (job handler data reach) — adjacent to that card's seam, but a different defect class, so filed rather than folded in.
Measured
packages/runtime/src/app-plugin.ts, the declarative-job registration block, hands IJobService.schedule this wrapper:
async(jobCtx: any)=>{awaithandler({ ...jobCtx,jobId: jobName,bundle: this.bundle, ... });},The arrow has a block body and the awaited value is discarded, so the wrapper is a Promise<void>. JobHandler is declared (context) => Promise<void | JobRunOutcome> (packages/spec/src/contracts/job-service.ts), and all three shipped adapters map a resolved { outcome: 'degraded', reason } onto a run status distinct from success — but a declarative job's outcome never reaches them.
Consequence
#6617's degraded channel is unreachable from defineJob. A declarative job that ran to completion while its work did not happen (store unavailable, zero rows matched) is recorded as success, with reason dropped. The three-outcome table in content/docs/automation/jobs.mdx documents the behaviour a declarative author does not get.
The imperative path is unaffected: a handler registered straight on IJobService.schedule returns its outcome to the adapter as documented. Only the defineStack({ jobs, functions }) route loses it.
Shape of the fix
Return the handler's resolved value from the wrapper rather than swallowing it. One expression; the interesting part is a regression test that a declarative job resolving { outcome: 'degraded' } lands a run status distinct from success (DbJobAdapter is the adapter that records it).
Unassigned and untriaged.
Generated by Claude Code
Generated by Claude Code
Found while implementing #14094 (job handler data reach) — adjacent to that card's seam, but a different defect class, so filed rather than folded in.
Measured
packages/runtime/src/app-plugin.ts, the declarative-job registration block, handsIJobService.schedulethis wrapper:The arrow has a block body and the awaited value is discarded, so the wrapper is a
Promise<void>.JobHandleris declared(context) => Promise<void | JobRunOutcome>(packages/spec/src/contracts/job-service.ts), and all three shipped adapters map a resolved{ outcome: 'degraded', reason }onto a run status distinct fromsuccess— but a declarative job's outcome never reaches them.Consequence
#6617's degraded channel is unreachable from
defineJob. A declarative job that ran to completion while its work did not happen (store unavailable, zero rows matched) is recorded assuccess, withreasondropped. The three-outcome table incontent/docs/automation/jobs.mdxdocuments the behaviour a declarative author does not get.The imperative path is unaffected: a handler registered straight on
IJobService.schedulereturns its outcome to the adapter as documented. Only thedefineStack({ jobs, functions })route loses it.Shape of the fix
Return the handler's resolved value from the wrapper rather than swallowing it. One expression; the interesting part is a regression test that a declarative job resolving
{ outcome: 'degraded' }lands a run status distinct fromsuccess(DbJobAdapteris the adapter that records it).Unassigned and untriaged.
Generated by Claude Code
Generated by Claude Code