---
name: a-whole-run-predicate-stays-silent-through-the-part-you-watch
description: "A poll whose predicate waits for the WHOLE run to finish stays silent through the one job you are watching, and an empty conclusion collection reads as clean — two silent-detector faces measured on golden 34481993681."
metadata: 
  node_type: memory
  type: feedback
  originSessionId: 7da3035c-261a-44d3-b4eb-c2f746962618
  modified: 2026-09-10T14:18:06.780Z
---

Measured 2026-09-10 (deployah, golden 34481993681, the v0.69.0 gate arm). A backgrounded poll
was armed to tell me when the gate finished. **test(Windows) concluded `failure` at 13:58:10Z and
I reported "nothing terminal" for another twelve minutes**, from readings up to thirty minutes
stale, until todlando noticed my status was timestamped 13:39:31Z but had arrived at 14:09:51Z.

Two independent defects, both silent, both in MY instrument:

1. **The predicate waited for ALL jobs terminal.** A background task notifies on EXIT. golden's
   `twohost-a`/`twohost-b` are `needs: test` and carry `!cancelled()`, so they MATERIALIZED THREE
   SECONDS AFTER the red and ran another fifteen minutes. The predicate could not be satisfied
   while the very event it existed to catch was already an hour from being reported. The poll was
   ALIVE and tracking correctly the whole time — its ticks showed the completed count rising.
   It simply had no way to speak.
2. **The conclusion collector printed `concl=[]` at every tick, including after a job had
   concluded `failure`.** So even on exit it would have handed back an empty list. An empty
   collection is not evidence of a clean run; it is evidence of nothing, and it READS as clean.

**Why:** silence from a detector is indistinguishable from silence from the world. Both defects
fail toward false ASSURANCE — the direction nobody reopens (see
[[compare-at-one-layer-crlf-meter-class]], whose seventh instance is the same direction).

**How to apply:**
- **Notify on the PART, not the WHOLE.** Emit on individual job transitions; a whole-run predicate
  is only sound when no job you care about can conclude before the run does — which
  `!cancelled()` fan-out jobs guarantee is false.
- **Emit on EVERY terminal state**, not just success: `failure|cancelled|timed_out|
  action_required` all get a line. If you cannot enumerate the failure shapes, widen the filter.
- **Validate the collector against a KNOWN-BAD case before trusting it**, and run the negative
  control too. `.spt/gate-poll.sh --selftest <run> <job>` does this: it passed on the real failed
  job 102886952516 and correctly REFUSED on the successful twohost-a — a detector that cannot
  fail is decoration
  ([[a-detector-must-pass-a-control-built-from-what-motivated-it]]).
- **A status report carries the time it was MEASURED, not the time it was sent.** Under message
  latency these differ by half an hour and the reader cannot tell. Stamp the observation, and
  re-read before answering a current-state question
  ([[an-unstamped-running-count-in-a-durable-record-is-stale-on-arrival]]).

## Two traps found while TESTING the repair (2026-09-10, same session)

Both were in the test harness, not the production path — and both are the shape that makes a test
pass vacuously over an instrument that never ran.

1. **A counter incremented inside `$( )` dies with the subshell.** The fixture replayer kept its
   own tick counter inside `jobs_snapshot`, which is called as `snap="$(jobs_snapshot ...)"`. Every
   call got a fresh subshell, so the counter reset and **tick 1 replayed forever** — the poll hung,
   emitting 130 identical heartbeats. Fix: index off the PARENT's loop counter. The constraint is
   now a comment in the file so it is not rediscovered.
   **What caught it was the heartbeat** added for the "silence needs a fresh successful poll"
   requirement: 130 lines of "no change" is itself the tell. Without it the harness bug presents as
   a quiet run — the exact ambiguity the heartbeat exists to remove. The instrument caught its own
   harness.
2. **A shared scratch path between a killed process and its replacement is a clobber.** The first
   replay `tee`d to `/tmp/replay.out`; the killed predecessor was still writing to the same path,
   and a stray `tick=170` heartbeat from the DEAD run appeared in the tail of the NEW file. One
   line further and I would have read another run's output as this one's. Write to a
   PID-and-timestamp-unique path, always — a stopped local process does not always stop writing.

**Assert the ORDERING, not just the presence.** The replay's three assertions are: the failure
transition precedes whole-run completion, the alert precedes whole-run completion, and the
`!cancelled()` job was STILL RUNNING when the alert fired. Presence alone would pass on a poll that
only spoke at the end — which is the bug being fixed.
