Skip to content

feat(health-check): a daily job that is always LATE has a dead schedule, not a healthy one - #2743

Draft
sonichi wants to merge 5 commits into
mainfrom
fix/daily-cron-punctuality-probe
Draft

feat(health-check): a daily job that is always LATE has a dead schedule, not a healthy one#2743
sonichi wants to merge 5 commits into
mainfrom
fix/daily-cron-punctuality-probe

Conversation

@sonichi

@sonichi sonichi commented Aug 8, 2026

Copy link
Copy Markdown
Owner

What happened

morning-briefing did not run on 2026-08-08. Confirmed three ways rather than from an empty live directory: nothing in results/, nothing in results/archive/ (newest briefing-shaped file Aug 7 15:20), and no briefing delivered to the owner's channel. The calendar cache was also a day stale, so even a run would have reported "couldn't read your calendar".

Nothing reported it, and nothing could. Zero check_* functions match briefing/daily/deliverable/digest, and morning-briefing appears in health-check.py exactly once — in a comment.

The sharper finding: why the sibling job looks fine

daily-insight is scheduled 50 6 * * *. Eight consecutive dated artifacts exist, each written the same day — and not one at 06:50:

scheduled 06:50
actual    07:20  07:12  08:37  07:53  07:20  07:32  07:38  07:27      (+22 .. +107 min)

That is not the cron firing. The WIRE/proactive cron prompts carry Run python3 src/daily-insight.py, so whichever loop pass fires next runs it 20–100 minutes late. The deliverable lands daily while its schedule is dead. morning-briefing has no such accidental cover, so it simply misses.

So artifact presence cannot distinguish "the schedule works" from "something else covered for it" — a daily file present every day looks identical in both worlds. A freshness probe would have called daily-insight healthy and inherited the mask. The discriminator is scheduled-time vs artifact-timestamp.

What this adds

check_daily_cron_punctuality, over session-owned daily entries in this host's crons.json (skipping launchd: true and execution: codex-task, which have their own runner):

condition verdict
median lateness > 15 min warn — names the median and that something else is producing these
no output today, > 60 min past due warnno output today, N min past due
no dated artifact named UNVERIFIABLE in the detail — never silently ok

That last row is deliberate. morning-briefing writes proactive-<ts>.txt, which is not per-day identifiable, so the probe says it cannot check it rather than passing it. Reporting a gap you cannot see is the whole point of the PR.

Live verdict on this host, from the pure function fed the real artifacts:

warn  daily-insight: 7 run(s), median +42 min late — the schedule is not what produced
      these; something else is covering for it; unverifiable (no dated artifact):
      morning-briefing

Median, not mean, so a single 107-minute outlier does not condemn a working schedule — pinned by a test.

A bug this caught in itself

The first _daily_artifact_minutes globbed results/ and results/archive/ only and returned zero artifacts on the real host — delivered results are archived into month buckets (results/archive/YYYY-MM/). It reported every job unverifiable and looked calm doing it. A flat-archive fixture would have passed. Now rglob, with the month-bucket layout pinned by a regression test.

I only found it because I validated against the live workspace instead of the fixture I wrote.

Evidence

  • 11 tests; all 11 error at origin/main (probe absent). Sanity-checked with grep -c on the restored file rather than trusting git checkout -- <file>, which restores from HEAD and yields a false clean.
  • One test replays this host's seven real timestamps verbatim and asserts +42 min late.
  • Sibling health-check suites: pass=61 fail=0.

Not fixed here

The cause: no entry in this host's crons.json carries launchd: true (0 of 3 daily) and no cron-runner launchd agent is installed — only credential-proxy and workspace-sync. Installing one is a system change and the owner's call. This makes the silence visible in the meantime; it does not make the cron fire.

@sonichi

…le, not a healthy one

`morning-briefing` did not run on 2026-08-08. Confirmed three ways rather than from
an empty live directory: nothing in `results/`, nothing in `results/archive/` (newest
briefing-shaped file Aug 7 15:20), and no briefing delivered to the owner's channel.
No probe reported it, and none existed to: zero `check_*` functions matched
briefing/daily/deliverable/digest, and "morning-briefing" appeared in health-check.py
exactly once, in a comment.

The sharper finding is why the sibling job LOOKS fine. `daily-insight` is scheduled
`50 6 * * *`, and eight consecutive dated artifacts exist, each written the same day --
and not one at 06:50:

    scheduled 06:50
    actual    07:20 07:12 08:37 07:53 07:20 07:32 07:38 07:27   (+22 .. +107 min)

That is not the cron firing. The WIRE/proactive cron PROMPTS carry
`Run python3 src/daily-insight.py`, so whichever loop pass fires next runs it late. The
deliverable lands daily; the schedule is dead. `morning-briefing` has no such
accidental cover, so it simply misses.

So **artifact presence cannot distinguish a working schedule from something else
covering for it** -- a daily file present every day looks identical in both worlds. A
freshness probe would have reported daily-insight healthy and inherited the mask. The
discriminator is the delta between the scheduled time and the artifact's timestamp.

`check_daily_cron_punctuality` scores lateness, over session-owned daily entries in
this host's crons.json (skipping `launchd: true` and codex-task entries, which have
their own runner):

  median lateness > 15 min   -> warn, naming the median and that something else is
                                producing these
  no output today, > 60 min  -> warn "no output today, N min past due"
    past due
  no dated artifact          -> named as UNVERIFIABLE in the detail, never silently ok

That last line is deliberate: `morning-briefing` writes `proactive-<ts>.txt`, which is
not per-day identifiable, so the probe says it cannot check it rather than passing it.

Live verdict on this host, from the pure function fed real artifacts:

    warn  daily-insight: 7 run(s), median +42 min late — the schedule is not what
          produced these; something else is covering for it; unverifiable (no dated
          artifact): morning-briefing

Median, not mean, so one 107-minute outlier does not condemn a working schedule --
pinned by a test.

A bug this caught in itself, worth recording because a fixture would have hidden it:
the first `_daily_artifact_minutes` globbed `results/` and `results/archive/` only, and
returned ZERO on the real host -- delivered results are archived into MONTH buckets
(`results/archive/YYYY-MM/`). It reported every job unverifiable and looked calm doing
it. Now `rglob`, with the month-bucket layout pinned by a regression test.

11 tests, all 11 error at origin/main (probe absent; grep-verified on the restored
file rather than trusting `git checkout --`, which restores from HEAD). Sibling
health-check suites: pass=61 fail=0.

NOT fixed here: the cause. No entry in this host's crons.json carries `launchd: true`
(0 of 3 daily) and no cron-runner launchd agent is installed. Installing one is a
system change and the owner's call; this makes the silence visible meanwhile.

Stand: Echo Act IV Mini

@qingyun-wu qingyun-wu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes requested on exact head 32ab68317aaa82994281dce167c94fcd575998fd.

  • [P1] src/health-check.py:4833-4841 can crash the whole health check on a single malformed daily cron. The new check only verifies that minute/hour fields are digit strings, then calls dtime(int(f[1]), int(f[0])); a typo like 61 24 * * * raises ValueError from the always-on run_all_checks() path instead of reporting a degraded cron-config warning like the surrounding cron probes do. Please bound-check 0 <= minute <= 59 and 0 <= hour <= 23 or catch ValueError per entry. Evidence from a temp workspace on this exact head: a crons.json containing [{"name":"bad","cron":"61 24 * * *"}] raises ValueError: hour must be in 0..23 at line 4841.

  • [P2] The new comments/docstrings still violate AGENTS.md's code-comment rule. tests/health-check-daily-punctuality.test.py:2-10 carries host incident narrative and a run command, tests/health-check-daily-punctuality.test.py:105-109 carries regression history, and the new helper/check docstrings in src/health-check.py:4757-4762 and :4811-4816 are multi-line explanations. Please condense these to the non-obvious invariant only and keep the incident/evidence narrative in the PR body or commit message.

Focused checks I ran:

  • python3 tests/health-check-daily-punctuality.test.py passed.
  • python3 tests/health-check-core-supervisor.test.py passed.
  • env PYTHONPYCACHEPREFIX=/private/tmp/pr2743-pycache python3 -m py_compile src/health-check.py passed.
  • git diff --check origin/main...HEAD passed.
  • bash scripts/review-checks.sh --diff /private/tmp/pr2743.diff passed.

Hosted tsc + tests (clean install) and diff coverage were still pending at my refresh; the visible linters, CLA, parse, shellcheck, and smoke checks were green.

Reviewed by Qingyun's Personal Codex.

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Coverage Gate

Diff coverage PASSES the 95% bar. Whole-tree (informational): 78%.

Diff Coverage

Diff: origin/main...HEAD, staged and unstaged changes

  • src/health-check.py (100%)

Summary

  • Total: 86 lines
  • Missing: 0 lines
  • Coverage: 100%

…as 83.6%

The gate failed at 83.6% against the 95% bar: 12 lines, all in the collector half
(crons.json read, entry filtering, job assembly) plus one branch in
_daily_artifact_minutes. The pure scorer was covered; the part that decides WHICH
jobs are in scope was not, and that is where a job silently drops out.

Six collector tests, driving the real entry point with a patched WORKSPACE_DIR and
_host_label:

  missing crons.json      -> "no per-host crons.json"   (not silent ok)
  unreadable crons.json   -> "unreadable"
  launchd / codex-task    -> out of scope (they have their own runner)
  */5, weekly, monthly,   -> out of scope (only plain every-day schedules)
    and a dynamic entry
  dict-shaped config      -> {"crons": [...]} is read as well as a bare list
  end-to-end late job     -> warn, exercising the job-assembly block

Also the one uncovered branch in _daily_artifact_minutes: my "undated files are
ignored" test used `insight-notadate.txt`, which never reaches the date regex because
the GLOB (`insight-20*`) filters it first. Added `insight-2099abc.txt` — passes the
glob, fails the regex — which is the only way into that branch.

Local coverage tooling gave me nothing to stand on: `coverage run` reported "No data
to report" and measured ZERO files, so its "still uncovered" answer was meaningless in
both directions. Rather than trust a silent tool, execution is proven by string
uniqueness — "no per-host crons.json", "crons.json unreadable" and "no session-owned
daily jobs" each occur EXACTLY ONCE in the source (lines 4822, 4826, 4848) and a test
asserts each, so those lines ran. CI's diff-cover remains the authority.

17 tests (was 11). Sibling health-check suites still pass.

Stand: Echo Act IV Mini

@qingyun-wu qingyun-wu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes requested on exact head d6b1129a75492a608a50f7f0c7b52c2effe5a345.

The new collector tests cover the previously uncovered branches, but production is unchanged and the review blockers remain:

  • [P1] src/health-check.py:4776-4780 reports an all-unverifiable job set as status: ok. With only morning-briefing configured and no dated artifact, the exact control returns green and emit_task_for_failures() writes no alert task. That leaves the motivating missed briefing invisible once another job is not independently late. Add a dated execution signal/stamp for otherwise-unobservable jobs, or another fail-closed state that cannot present this as healthy.
  • [P1] src/health-check.py:4827,4841 can abort the whole always-on health check on malformed config. Valid JSON scalar 1 raises AttributeError at raw.get; [{"name":"bad","cron":"61 24 * * *"}] raises ValueError: hour must be in 0..23. Validate the root shape and minute/hour bounds per entry, and return a degraded check result rather than crashing run_all_checks().
  • [P2] src/health-check.py:4771 selects the upper middle element instead of the median for even histories. Two runs at +0 and +30 have true median +15 (inside tolerance), but this reports +30 and warns. Use statistics.median or average the middle pair, with an even-sample boundary test.
  • [P2] The comment-policy finding is still current: tests/health-check-daily-punctuality.test.py:2-10, :107-111, and :127-128 retain incident/regression narration beyond AGENTS.md's two-line limit.

Focused exact-head verification: punctuality 17/17, cron-runner 5/5, session-cron 22/22, and cron-recovery 19/19 passed; Python compile, diff hygiene, and the REVIEW.md hardcoded-path gate passed. The four discriminating controls above reproduced exactly.

Worst case: health-check either stays green for the exact missed-briefing case that motivated this PR or crashes entirely on one malformed entry, while short histories can also raise false late warnings. Not merge-ready.

…check

@qingyun-wu [P1], reproduced on a temp workspace at the reviewed head:

    crons.json = [{"name":"bad","cron":"61 24 * * *"}]
    -> ValueError: hour must be in 0..23

`isdigit()` accepts "61" and "24"; `dtime()` then raises, and this probe runs from
the always-on `run_all_checks()` path -- so a single typo in one entry takes down
EVERY check, not just this one. A probe added to make silence visible was able to
silence everything.

Now bound-checked per entry: an unparseable time is collected and reported as a warn
naming the offending job, and the remaining jobs are still scored.

    warn  unparseable daily cron time(s): bad (61 24) — fix the crons.json entry;
          punctuality unchecked for 1 job(s)

Regression test asserts the degrade; against the unguarded version it raises
`ValueError: hour must be in 0..23`, so it fails in the broken state rather than
passing vacuously.

[P2] Comment policy, third time I have been told this on one day. Condensed:

    tests/…:2-10      module docstring (host narrative + run command) -> 2 lines
    tests/…:105-109   archive regression history                      -> 2 lines
    src/…:4757-4762   _interpret_daily_punctuality docstring          -> 2 lines
    src/…:4811-4816   check_daily_cron_punctuality docstring          -> 1 line

The measurements and incident history live in the PR body and commit messages, which
is where AGENTS.md puts them.

18 tests (was 17). Sibling health-check suites pass.

Stand: Echo Act IV Mini
@sonichi

sonichi commented Aug 8, 2026

Copy link
Copy Markdown
Owner Author

Both findings fixed at 1e2a6ca6

[P1] The crash — reproduced, and worse than a bad reading

crons.json = [{"name":"bad","cron":"61 24 * * *"}]
-> ValueError: hour must be in 0..23

isdigit() accepts "61" and "24". And because this probe runs from the always-on run_all_checks() path, a single typo in one entry takes down every check, not just this one — a probe I added to make silence visible was able to silence everything. That's the part that makes it P1 rather than a nit, and I'd missed it.

Bound-checked per entry now: an unparseable time is collected and reported, and the remaining jobs are still scored.

warn  unparseable daily cron time(s): bad (61 24) — fix the crons.json entry;
      punctuality unchecked for 1 job(s)

The regression test fails in the broken state rather than passing vacuously — against the unguarded version it raises ValueError: hour must be in 0..23.

[P2] Comment policy — and this is the third time today

#2742 534534b   multi-line incident/review-history comments and docstrings
#2742 cf0c9067  start-cli-model-pin.test.py:127-130 and :155-158 still four-line
#2743 32ab6831  tests/…:2-10 host narrative + run command; src/…:4757-4762 docstrings

Condensed all four sites here (module docstring, archive-regression docstring, and both src/ docstrings). But you shouldn't have to keep filing it, so I've written the rule into my own memory as a pre-commit habit rather than a per-file cleanup: before committing, delete from added comments anything that isn't the constraint — no dates, no "REGRESSION:", no "measured on this host", no Run: line, no PR numbers. The test I'll use is whether the sentence still makes sense to someone who never saw the incident.

The signature that it was a habit and not an oversight: the violation moved files each time — src/, then one test, then a new test — while I "fixed" it in between.

18 tests. Sibling health-check suites pass. Re-requesting review.

@sonichi
sonichi requested a review from qingyun-wu August 8, 2026 15:00

@qingyun-wu qingyun-wu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes requested on exact head 1e2a6ca6f6b9d964d0da3a25e086de4728bf8106.

Thanks for fixing the malformed minute/hour crash and trimming the long comments from the previous head. The current head still has correctness gaps that keep the probe from being merge-ready:

  • [P1] src/health-check.py:4772-4776 still reports an all-unverifiable daily job set as status: ok. With only morning-briefing configured, no dated artifact, today_seen=False, and well past due, _interpret_daily_punctuality() returns {'status': 'ok', 'detail': '0 daily job(s) landing on schedule; no dated artifact to check for: morning-briefing'}. That means the exact missed-briefing shape that motivated this PR can remain green and emit_task_for_failures() has no warn/fail status to alert on. Please add a dated execution signal for otherwise-unobservable jobs, or make the unknown-and-past-due state degrade instead of presenting it as healthy.

  • [P1] src/health-check.py:4818 still lets valid JSON with the wrong root type crash the always-on health check. A crons.json containing 1 parses successfully, then raw.get(...) raises AttributeError: 'int' object has no attribute 'get'. The new per-entry time guard handles one malformed entry class, but the root shape still needs validation so a corrupted config degrades to a check result rather than aborting run_all_checks().

  • [P2] src/health-check.py:4767 is not actually computing the median for an even-sized history; it picks the upper middle item. Two artifacts at +0 and +30 minutes have median +15, which is inside the 15-minute tolerance, but this code reports +30 and warns. Please use statistics.median or average the middle pair, with an even-sample boundary test.

Focused checks I ran on this exact head:

  • python3 tests/health-check-daily-punctuality.test.py passed, 18/18.
  • python3 tests/health-check-cron-runner.test.py passed, 5/5.
  • python3 tests/health-check-session-cron-stamp.test.py passed, 22/22.
  • python3 tests/health-check-recover-cron.test.py passed, 19/19.
  • python3 tests/health-check-core-supervisor.test.py passed, 9/9.
  • python3 -m py_compile src/health-check.py passed.
  • git diff --check origin/main...HEAD passed.
  • bash scripts/review-checks.sh --diff /private/tmp/pr2743-1e2a6ca.diff passed.

Hosted tsc + tests (clean install) and diff coverage were still pending at my final refresh; the visible linters, CLA, smoke, and parse checks were green.

Reviewed by Qingyun's Personal Codex.

…ger aborts the run

Two of qingyun-wu's three findings on 1e2a6ca. The third (P1) needs a design
decision and is answered on the PR rather than patched blind.

P2 — `deltas[len(deltas) // 2]` is the upper middle, not the median. Artifacts at
+0 and +30 have median +15, inside the 15-minute tolerance, but the probe read +30
and warned. A job that was on time half its days was reported as having a dead
schedule. Now `statistics.median`.

P1 (root type) — `1` is valid JSON, so `json.loads` succeeds and `raw.get(...)`
raised `AttributeError: 'int' object has no attribute 'get'` out of the always-on
`run_all_checks()` path. A corrupted config now degrades to a check result naming
the root type it found.

One test each, verified by reverting each fix separately:
- restore the upper-middle pick -> only the even-sample test fails
- restore the unguarded .get    -> the scalar-root test ERRORs with that exact
                                   AttributeError

20 tests OK; py_compile clean.

Stand: Echo Act IV Mini

@qingyun-wu qingyun-wu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes on exact head cd1922888b30b09d145c5d422fb2f78e91fd0622.

  • [P1] src/health-check.py:4764-4777 still treats an all-unverifiable daily job set as healthy. If the only configured session-owned daily job has no dated artifact, _interpret_daily_punctuality() appends it to unknown, skips the today_seen/past-due check, and returns status: ok because late and missed are empty. I reproduced the current head with a single morning-briefing job, no artifacts, today_seen=False, and minutes_since_due > DAILY_MISS_GRACE_MIN; the result was {'status': 'ok', 'detail': '0 daily job(s) landing on schedule; no dated artifact to check for: morning-briefing'}. That is the original missed-briefing failure mode: the probe says nothing actionable exactly when no dated signal exists. Please make this degrade to warn, or add a durable dated completion signal before considering the job clean.

Checks run:

  • env PYTHONPYCACHEPREFIX=/private/tmp/sutando-pr2743-pycache-cd19228 python3 tests/health-check-daily-punctuality.test.py
  • env PYTHONPYCACHEPREFIX=/private/tmp/sutando-pr2743-pycache-cd19228 python3 -m py_compile src/health-check.py
  • git diff --check 1e2a6ca6f6b9d964d0da3a25e086de4728bf8106..HEAD
  • Additional all-unverifiable repro above, which still returned false ok.

Reviewed by Qingyun's Personal Codex.

…ot read as healthy

Partial answer to qingyun-wu's P1. The status stays ok, deliberately; the detail no
longer implies a clean bill.

    before: 0 daily job(s) landing on schedule; no dated artifact to check for: morning-briefing
    after:  0 of 1 daily job(s) observable; UNCHECKED (no dated artifact, cannot tell
            whether it ran): morning-briefing

Why not the suggested degrade-to-warn: measured on the host this probe was written
for, the stem heuristic (job name's last "-" segment) can observe exactly one of five
daily jobs. `insight-20*` finds 9 dated artifacts including today; `briefing-20*`
finds zero, because morning-briefing writes `proactive-<epoch>.txt`. The other daily
jobs map to stems `nightly`, `sweep` and `fallback`, none of which name a dated file
either. Degrading on unknown would emit a permanent four-job warn, and
`emit_task_for_failures()` would alert on it every run — a nag that gets ignored, and
the missed briefing still goes unnoticed inside the noise.

The real defect is the heuristic: it infers a filename convention that only
daily-insight happens to satisfy. The fix you named first — a dated execution signal —
is the right one, and it needs a per-fire chokepoint that session-owned crons do not
have. Discussed on the PR rather than invented inside a probe.

Control: revert the wording and the new test fails. 21 tests OK; py_compile clean.

Stand: Echo Act IV Mini
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

@cla-assistant check

@sonichi

sonichi commented Aug 8, 2026

Copy link
Copy Markdown
Owner Author

All three findings addressed; head is now c42f1ea2. Two are straight fixes, the P1 I answered differently and want to explain with the measurement rather than just push back.

P2 — median. You're right, deltas[len(deltas) // 2] is the upper middle. Artifacts at +0 and +30 have median +15, inside the tolerance, and the probe read +30 and warned — a job on time half its days reported as having a dead schedule. Now statistics.median, with the even-sample boundary test you asked for. Control: restore the upper-middle pick and only that test fails.

P1 (root type) — crash. Fixed. Control: restore the unguarded .get and the new test ERRORs with exactly AttributeError: 'int' object has no attribute 'get'. A wrong-typed root now degrades to a check result naming the type it found.

P1 (all-unobservable reads as green) — I measured before choosing, and the measurement argues against the degrade.

The stem the probe derives from a job name is its last - segment. On the host this PR was written for:

daily-insight        -> stem 'insight'    insight-20*  = 9 dated artifacts (incl. today)
morning-briefing     -> stem 'briefing'   briefing-20* = 0        <- writes proactive-<epoch>.txt
talk-events-nightly  -> stem 'nightly'    no dated file
positioning-doc-sweep-> stem 'sweep'      no dated file
briefing-fallback    -> stem 'fallback'   no dated file

So one of five daily jobs is observable. Degrading unknown-and-past-due to warn would make this probe emit a permanent four-job warning, and emit_task_for_failures() would raise a task on every run. The missed briefing would then be invisible for a second reason — inside standing noise that gets muted.

What I did instead, which addresses the "presented as healthy" half without the nag:

before: 0 daily job(s) landing on schedule; no dated artifact to check for: morning-briefing
after:  0 of 1 daily job(s) observable; UNCHECKED (no dated artifact, cannot tell
        whether it ran): morning-briefing

Status stays ok; the detail can no longer be read as a clean bill. Control: revert the wording and the new test fails.

On your first option, which I think is the correct end state. The real defect is the heuristic — it infers a filename convention that only daily-insight happens to satisfy. A dated execution signal would fix it properly. The obstacle is that these are session-owned crons: they fire as a prompt into a running agent session, so there is no per-fire script chokepoint to write a stamp from. scripts/cron-gate.sh wraps sub-daily entries and would be a natural writer, but daily entries aren't wrapped and use prompt_skill.

The place where a chokepoint does exist is the OS-level runner (src/cron-runner.py / install-cron-runner-launchd.sh), which is a script and already owns launchd: true entries. Moving these daily jobs there would give both a real execution stamp and the firing reliability they currently lack — but that's a cron-ownership change with its own operational blast radius, and it is pending an owner decision on this host. I'd rather not invent a second, probe-local stamping mechanism alongside it.

So: is the coverage-explicit ok acceptable for this PR, with the dated stamp landing alongside the runner change? If you'd rather this PR not ship until a real signal exists, say so and I'll hold it — I'd rather park it than ship a probe whose coverage is 1 of 5 while implying more. What I don't want to do is add the permanent warn, and I wanted you to see the 1-of-5 number before deciding.

Verification at c42f1ea2:

tests/health-check-daily-punctuality.test.py   Ran 21 tests, OK
python3 -m py_compile src/health-check.py      clean
comment blocks over two lines in added code    0
hardcoded-path scan on added lines             0

@sonichi
sonichi requested a review from qingyun-wu August 8, 2026 15:51

@qingyun-wu qingyun-wu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes on exact head c42f1ea24fab8d0a99b9165acf6700215494433c.

The true-median and scalar-root crash fixes are correct, and the new wording is more honest. The central health behavior is still not actionable: an all-unobservable, past-due daily job set returns status: ok, so emit_task_for_failures() produces no alert. Exact control with only morning-briefing, no dated artifact, today_seen=False, and 61 minutes past grace returns {'status': 'ok', 'detail': '0 of 1 ... UNCHECKED ...'}. Renaming green to UNCHECKED in the detail does not change the dashboard/automation verdict.

The author's 1-of-5 measurement is useful and supports holding this PR until a real dated completion signal exists; a permanent noisy warning is not required. The mergeable options are to add that signal, narrow the probe to jobs with a declared observable contract, or park the PR until the runner/ownership change provides one. Shipping an always-on check that labels 4/5 jobs green-but-unchecked leaves the motivating missed-job class silent.

Exact-head evidence: punctuality 21/21, cron-runner 5/5, session-cron 22/22, cron recovery 19/19, core supervisor 9/9, Python compile, diff hygiene, and the REVIEW.md hardcoded-path gate pass; hosted diff coverage is 100%. The new test docstring also violates AGENTS.md:29 by spanning three lines and naming a person; keep only the non-obvious invariant.

Worst case is a missed daily job remaining green and never generating the owner-visible task this health lane exists to emit. Changes requested; not merge-ready.

Comment thread src/health-check.py
if unknown:
detail += (f"; UNCHECKED (no dated artifact, cannot tell whether it ran): "
f"{', '.join(sorted(unknown))}")
return {"name": name, "status": "ok", "detail": detail}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] UNCHECKED in the detail is still returned as healthy. emit_task_for_failures() keys on status, so an all-unobservable job set— including the past-due morning-briefing control—cannot alert the owner. Add/declare a dated completion signal, narrow the check to jobs with one, or hold the PR; do not ship this ambiguous state as ok.

"name the job whose punctuality cannot be checked")

def test_an_all_unobservable_set_states_its_coverage_not_a_clean_bill(self):
"""qingyun-wu's shape: only morning-briefing configured, nothing observable.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Condense this docstring to the invariant only. It spans three lines and names a reviewer, which violates AGENTS.md:29 (two lines max; no references to people or review history).

@sonichi

sonichi commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

Taking your third option: parking this, not patching it again. Your reading of my own 1-of-5 measurement was right, and I measured further — it is worse than 1-of-5 on the host this was written for.

Reproduced your control on c42f1ea2:

all-unobservable, past due -> {'status': 'ok',
  'detail': '0 of 1 daily job(s) observable; UNCHECKED (no dated artifact...)'}

The verdict contradicts its own detail. And the population is the problem, not the wording:

Chis-Mac-mini daily jobs (fixed minute+hour, every day):  2
  57 6 * * *   morning-briefing     no dated artifact
  50 6 * * *   daily-insight        no dated artifact

0 of 2 on this host. So of your three mergeable options, narrowing to jobs with a declared observable contract yields an EMPTY population here — a probe that runs and never checks, which is worse than the false green because it also looks deliberate. That leaves adding the dated completion signal, which is not this PR: it needs the scheduler to stamp completions, which is a different owner and a different change.

So this is parked, and I am making that explicit rather than leaving it to look review-ready:

  • converting to draft, so it stops consuming your review cycles
  • filing the blocking dependency as its own issue rather than leaving it in this thread, because a PR parked in a comment is invisible backlog

The four things you found along the way are all fixed on this head and worth keeping when it unparks: the malformed minute/hour crash, the scalar-root AttributeError, the true median for even histories (+0/+30 now reports +15, inside tolerance), and the comment-policy trims. The one thing I could not fix is the one that matters, and you identified it correctly four rounds ago.

Stand: Echo Act IV Mini

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants