health says "working" about every finished run — 89 of 89
f01d5b4 (#580 AC3) added a server-side verdict so a client would stop inferring "is this alright" from two timestamps. Measured live 2026-08-15 across 89 runs on 7 instances: health is "working" on all 89, including runs that failed, were cancelled, completed, or ended needs_human days ago.
Examples: b9d9c051 (failed 2026-08-13), af691f02 (failed on the circuit breaker), 47bf3703 (cancelled).
Mechanism
workers/api/src/lib/work-report.ts:100-108 — rule 1 is run.status !== "running" ⇒ "working".
The intent is right: a closed run should carry no liveness claim. But RunHealth = "working" | "waiting" | "stalled" (:77) has no member for not applicable, so "no claim" was folded onto the member that reads as the strongest possible positive claim.
Why this misleads a user into a wrong action
The whole point of a server-side verdict is that a client can trust it instead of deriving one. A client that trusts it reads working for a run that died three days ago — strictly worse than the two timestamps it replaced, because those at least disagreed visibly. This is #580's own defect one layer up: a field that cannot express the true answer returns a false one.
A gap this measurement leaves, stated
"waiting" and "stalled" both require status === "running", and 0 of 89 runs were running at audit time — correctly, given the owner's engine limit. So two-thirds of the rule is unexercised in production. The working case is confirmed wrong; the other two are unverified, not confirmed right.
Acceptance criteria
RunHealth gains a member for a finished run — "ended", "n/a", or the health field is absent on a closed run. Whichever is chosen, no closed run reports a liveness claim.
- The tool description states what the field does and does not claim, so a client is not left inferring the inference.
- A test covers all three live states and the closed state, with the denominator stated per ADR 0002 — this bug is a missing enum member, which only a test over the whole status domain catches.
- Red demonstrated on today's code: a
failed run must not report working.
Verified vs inferred
- Verified: 89/89 measured live;
work-report.ts:77 and :100-108; the three named runs and their statuses.
- Inferred: nothing. The
waiting/stalled gap is explicitly labelled unexercised rather than claimed correct.
healthsays"working"about every finished run — 89 of 89f01d5b4(#580 AC3) added a server-side verdict so a client would stop inferring "is this alright" from two timestamps. Measured live 2026-08-15 across 89 runs on 7 instances:healthis"working"on all 89, including runs thatfailed, werecancelled,completed, or endedneeds_humandays ago.Examples:
b9d9c051(failed 2026-08-13),af691f02(failed on the circuit breaker),47bf3703(cancelled).Mechanism
workers/api/src/lib/work-report.ts:100-108— rule 1 isrun.status !== "running"⇒"working".The intent is right: a closed run should carry no liveness claim. But
RunHealth = "working" | "waiting" | "stalled"(:77) has no member for not applicable, so "no claim" was folded onto the member that reads as the strongest possible positive claim.Why this misleads a user into a wrong action
The whole point of a server-side verdict is that a client can trust it instead of deriving one. A client that trusts it reads
workingfor a run that died three days ago — strictly worse than the two timestamps it replaced, because those at least disagreed visibly. This is #580's own defect one layer up: a field that cannot express the true answer returns a false one.A gap this measurement leaves, stated
"waiting"and"stalled"both requirestatus === "running", and 0 of 89 runs were running at audit time — correctly, given the owner's engine limit. So two-thirds of the rule is unexercised in production. Theworkingcase is confirmed wrong; the other two are unverified, not confirmed right.Acceptance criteria
RunHealthgains a member for a finished run —"ended","n/a", or the health field is absent on a closed run. Whichever is chosen, no closed run reports a liveness claim.failedrun must not reportworking.Verified vs inferred
work-report.ts:77and:100-108; the three named runs and their statuses.waiting/stalledgap is explicitly labelled unexercised rather than claimed correct.