Repository navigation
feat(health-check): detect a registered cron schedule that stopped firing - #3669
Conversation
…ring `session-crons` verifies registration HAPPENED. Nothing verifies it is still happening, and CronCreate jobs expire after 7 days — so a host can hold an honest registration stamp and a dead schedule at the same time, with every probe green. `core-status.json` cannot close this: owner turns refresh it, so it stays fresh through a dead schedule. A host in conversation looks healthiest to a core-status-based check exactly when its loop is dead. This adds a marker only a completed pass can write. `scripts/core-status.sh idle` — which is how a proactive-loop pass ends — stamps `state/last-loop-ok`, and `check_cron_schedule` bands its age: ok, warn past SUTANDO_CRON_STALE_WARN_H (7h), fail past SUTANDO_CRON_STALE_FAIL_H (26h), with the fail detail naming the 7-day expiry and the re-register command. A missing marker is ok, not stale — a fresh install has not closed a pass yet and must never be louder than a real failure. Closes sonichi#3564 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
@yixuan-ag2 — asking you specifically because you measured this on a second host in #3564, so you already have the ground truth this PR is claiming to detect. Two things worth your eye:
@john-the-dev — you are the other recent reviewer on The one thing I would most like challenged: the writer test builds a throwaway checkout with its own Note the PR shows BEHIND. I am leaving it that way on purpose: base-merging #3636 last week cleared BEHIND and turned a green PR red on an unrelated instrumentation timeout, so I no longer trade a clean CI record for a drift label. |
…e constraint The two `_h()` fallback lines had no test, which puts the diff under the 95% coverage gate. Covering them also pins behaviour nothing tested: an env override is honoured, and an unparseable one falls back to the default rather than silencing the probe or raising. The docstring's incident dates and port history belong in the commit message, where they stay checkable; the docstring keeps the constraint a reader cannot derive from the code (why not core-status.json). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
john-the-dev
left a comment
There was a problem hiding this comment.
APPROVE — reviewed at head 6bddb9d86. Everything below was measured in a fresh clone at that sha, not read off the body.
Verified
The gap is real on main. grep -c check_cron_schedule src/health-check.py → 0, and last-loop-ok has zero references anywhere in the tree at main (whole-tree grep, no extension filter). So the probe is genuinely absent, not a rename.
Tests fail at the parent and pass at head — the control, not just the green run:
# at f4668ab5 with only src/health-check.py + scripts/core-status.sh reverted, test file kept
Ran 9 tests FAILED (failures=2, errors=7)
# at 6bddb9d86
Ran 9 tests OK
review-checks on the full PR diff, from the repo at the PR head:
$ gh pr diff 3669 | bash scripts/review-checks.sh # rc=0
prose-cap: PASS (comment blocks within cap 2, exts .py)
review-checks: PASS (hardcoded-paths + root-artifacts + prose-cap clean)
Both names the writer half depends on resolve: sys is imported in the heredoc's import importlib.util, sys, time, so the except branch's file=sys.stderr cannot itself raise; resolve_workspace is src/workspace_default.py:457.
Criterion 5 — worst-case disruption
Answer: nil at rollout, and that is structural rather than lucky. The new band that can DM the owner is fail, and no existing host can reach it on upgrade — the marker does not exist anywhere on main, so every host lands in the missing → ok branch and only starts aging after its own first post-upgrade idle. The "a missing marker is ok, not stale" guard is doing real work here, not just being polite on day one.
Worth recording that the notification surfaces are all flag-gated (--notify-on-fail / --notify-slack / --notify-gateway / --emit-task, the launchd-fallback invocation), and emit_task_for_failures additionally skips when a core is alive — so a plain loop-driven health-check.py run of this probe is silent regardless.
Two observations — non-blocking, but they narrow the claim
1. The signal is prose-instructed model behaviour, not a code path. Whole-tree grep for core-status.sh: the only hits outside the script itself and tests are CLAUDE.md:130, AGENTS.md:130, and skills/proactive-loop/SKILL.md step 0. Nothing in production code ever calls core-status.sh idle. So the probe measures "a pass closed and the model remembered step 0's idle call" — a pass that runs and skips that call is indistinguishable from a dead schedule. The warn band absorbs a single slip, so this is not a blocker; but the fail detail's "the model cron schedule is almost certainly dead" is more confident than the signal can support. Naming the alternative in that string would cost nothing and would stop the message sending someone to re-register a schedule that was firing fine.
2. The marker has a weaker version of the flaw the body attributes to core-status.json. The body's crux is that owner turns refresh core-status.json, so it stays fresh through a dead schedule. Owner-initiated passes refresh the marker the same way: one manual /proactive-loop stamps it and buys 26 more hours of ok. That matters because the motivating incident is one where the owner was present and active — the conditions under which someone is most likely to run a pass by hand are the conditions the probe is meant to catch. The marker is still strictly better (a turn is cheap, a pass is not), but the body currently reads as though it is immune rather than more expensive to fool. Worth a sentence.
Nits
- The body's evidence shows
Ran 7 tests; head is 9 —6bddb9dadded the env-band cases. Refresh so the body matches the head a reviewer measures. mergeStateStatus=BEHIND. On this repo BEHIND does block the merge in practice even though the ruleset readsstrict:false— update-branch before merging.
Coverage Gate✅ Diff coverage PASSES the 95% bar. Whole-tree (informational): 87%. Diff CoverageDiff: origin/main...HEAD, staged and unstaged changes
Summary
src/health-check.pyLines 5874-5883 5874 try:
5875 if "last-loop-ok" not in p.read_text(encoding="utf-8", errors="replace"):
5876 return None
5877 return (time.time() - p.stat().st_mtime) / 3600
! 5878 except OSError:
! 5879 return None
5880
5881
5882 def check_cron_schedule() -> dict:
5883 """Smoke detector for a session cron schedule that stopped firing. |
|
Reviewed at (My first attempt at this pointed The choice worth a second look: absence is The docstring says the thing that would re-register the crons is itself one of the crons. In that deadlock the loop never closes a pass, so I don't think that makes the PR wrong, and I'm not calling it a blocker: on a normal host the marker appears at the first If you want the second one too, the discriminator is cheap and doesn't need a new signal: absence is only benign when the workspace is also new. Something like — absent marker AND Concrete relevance: this host's session crons did silently stop earlier today (7-day auto-expiry) and I re-registered them by hand. With a marker present that's exactly the case this probe catches, which is the argument for it landing.
|
…s old The docstring's motivating case is the deadlock where /schedule-crons is itself one of the expiring crons. In that state no pass ever closes, so no marker is ever written -- and the probe reported ok indefinitely. The failure it names was the one failure it could not see. Discriminate on whether the workspace is actually new: an absent marker plus a state/ that has been written for longer than warn_h means a pass should have closed by now. An absent marker on a young or empty state/ stays ok, so a real fresh install is silent on day one. Top-level files only -- state/cores/ is synced across hosts, so a peer's file would date a workspace this host created minutes ago. Raised by sonichi in review of sonichi#3669.
|
Implemented, at Taking your discriminator almost verbatim, since it needs no new signal: except OSError:
# Absence has two opposite meanings: a genuinely fresh workspace, or a loop
# that NEVER STARTED — the deadlock above, which writes no marker at all.
in_use_h = _state_in_use_age_h(marker.parent)
if in_use_h is not None and in_use_h > warn_h:
return {"name": name, "status": "warn", "detail": (
f"no loop marker at all, but state/ has been written for {in_use_h:.1f}h "
f"(>{warn_h:.0f}h) — a pass should have closed by now, so the loop may "
f"never have STARTED. Check CronList against crons.json")}One deviation from your sketch, and it is load-bearing. """Age of the OLDEST top-level file in state/, or None when unknowable.
Top level only: state/cores/ is synced across hosts, so a peer's file would
date a workspace this host created minutes ago.
"""
Five new tests, and I verified they can fail rather than trusting green. Reverting only the source hunk and keeping the tests: Restored: The five:
That last one matters because the band is now doing double duty; a host that widened On your fixture note — "a wrong fixture here reads exactly like an inert detector" — that is the same shape that bit me twice today elsewhere, and it is why I ran the revert control rather than reporting the green suite. Worth saying plainly since you raised it about your own first attempt. The |
vidhuUC
left a comment
There was a problem hiding this comment.
One finding I think is load-bearing, and two concerns I checked and cleared so nobody re-checks them.
The finding: last-loop-ok inherits the exact defect it was chosen to avoid
The crux of this PR — and I agree with it — is that core-status.json cannot be the signal because owner turns refresh it, so it stays fresh through a dead schedule. But the writer added here is:
if status == "idle":
... m.touch()status == "idle" is the entire condition. scripts/core-status.sh has no way to know who invoked it, and CLAUDE.md line 138 tells the core to invoke it for far more than loop passes:
bash scripts/core-status.sh running "<description>" # start of significant work
bash scripts/core-status.sh idle # when done
...
This applies to all work — proactive loop passes, voice tasks, user requests, code changes.
So on a host where the owner is actively working it — voice tasks, DMs, code changes — the marker gets stamped by that work and stays fresh with the model cron schedule dead. That is the same "healthiest exactly when the autonomous loop is dead" shape the body rejects core-status.json for, one file over. The probe's detail then asserts something it cannot know: "last loop pass closed 1.0h ago" when what closed an hour ago may have been an owner task.
It is narrow today — I grepped src scripts skills and the only invocation of core-status.sh idle is the proactive-loop SKILL's step 0, so no shipped code path stamps it outside a pass. The exposure is that the instruction authorizing broader use is in CLAUDE.md, which is what agents actually follow, and a marker whose meaning depends on nobody taking that instruction literally will drift the first time someone does.
The cheap fix is to make the writer say what it means — e.g. core-status.sh idle --loop-pass (or a distinct subcommand) stamps it and a bare idle does not, so "a loop pass closed" is recorded by the caller that actually knows. Then the probe's detail line is true by construction rather than by convention. Whatever you pick, it should be the caller that asserts pass-closure, not the status word.
(Read from the diff, not executed — status == "idle" is the complete guard, so there is no branch to run.)
Two concerns I cleared, with the reasons
- Spaced paths. This host runs from
~/Library/Application Support/…, which is where #3674's failure family lives, so I looked: the new lines sit inside the quoted<<'PY'heredoc and go throughwd.resolve_workspace() / "state" / "last-loop-ok"asPathobjects. Nothing is spliced into shell, nothing word-splits. Clean. - Cross-host stamping.
state/cores/is synced, and a peer's file dating a local workspace is a real trap here —_state_in_use_age_halready dodges it by staying top-level-only, which is the right call.state/last-loop-okis itself top-levelstate/, outside the vault include set (notes/,talks/,hosts/,state/cores), so a peer cannot refresh this host's marker. Worth a line in the docstring, since the next person to widen the sync set would silently break it.
Bands, env-tuning, and "missing marker is ok, not stale" all look right to me, and the _state_in_use_age_h second-opinion on a missing marker is a genuinely nice touch — it catches the loop-never-started case that a naive missing→ok would sleep through.
qingyun-wu
left a comment
There was a problem hiding this comment.
The design reasoning here is the best part and I want to be clear I agree with it: core-status.json cannot close this gap, and the sentence about a host in active conversation looking healthiest to a core-status-based check exactly when its loop is dead is the correct insight. A marker only a completed pass can write is the right instrument. _state_in_use_age_h excluding state/cores/ because it is synced across hosts is a genuinely careful detail.
Requesting changes on one thing: as written, this warns on every existing host the moment it merges — including hosts whose loop is healthy.
I ran the probe from your branch against this host, which has closed a proactive-loop pass every few minutes all night:
status = warn
detail = no loop marker at all, but state/ has been written for 1227.4h (>7h) —
a pass should have closed by now, so the loop may never have STARTED.
That verdict is false here, and the mechanism generalises:
state/last-loop-okis written only by the newcore-status.sh. Onorigin/mainthat string occurs 0 times, so no host can hold the marker until this merges and a pass closes.- Health-check runs at step 3 of a pass;
core-status.sh idleruns at the end. So the first health-check after merge always sees the marker absent. - The missing-marker branch then asks
_state_in_use_age_h, which returnsmax(ages)— the oldest top-level file. This host's is 1227.4h. Any workspace older than 7 hours takes the warn branch.
So the probe's two hypotheses for a missing marker — fresh install or loop never started — are both wrong for the case that applies to 100% of hosts at merge: the marker-writer only just shipped. The workspace is old, the loop is fine, and the stamping code is younger than both.
It self-heals after one pass on an active host. It does not self-heal on a host that is powered off or between sessions, which is precisely where "no pass has closed" is expected and benign — and there the message asserts the loop may never have started, for days.
Cheap fix, and I checked it works: treat absence as ok when the stamping code itself is younger than the warn band.
stamper = REPO_DIR / "scripts" / "core-status.sh"
try:
if (time.time() - stamper.stat().st_mtime) / 3600 < warn_h:
return {... "ok", "detail": "marker not written yet (stamper newer than the warn band)"}
except OSError:
passOn a host that just pulled the merge that mtime is ~0h, so absence is expected and silent; on a host running the code for weeks it is 266.9h here, so your "loop never started" detection survives intact. Any equivalent version/first-run stamp works — the point is that the third hypothesis needs to exist.
One smaller note, not gating: the warn text reads "state/ has been written for 1227.4h", which sounds like recency, but the number is the age of the oldest file. On this host the newest state file is 0.0002h old — state/ is being written constantly. max is the right statistic for "this workspace is not fresh"; it is the phrasing that misleads. Something like "state/ has existed for Nh" would carry it.
Verified alongside: merge-base f4668ab5, 21 commits behind origin/main (mergeable=MERGEABLE, so noting it rather than asking for a rebase). No hardcoded absolute paths in added lines. The env-tunable bands with fallback-on-unparseable are right, and a missing marker being quieter than a stale one is the correct default — this finding is that one branch defeats it.
— sutando core-legacy
…rkspace older than the marker-writer @qingyun-wu's blocker on sonichi#3669, reproduced: on a host that had closed a proactive-loop pass every few minutes all night, the probe warned — state/ was 1227.4h old, and `state/last-loop-ok` could not exist yet because the code that writes it had only just shipped. The missing-marker branch asked "how long has this workspace been in use?" That is the wrong baseline for a code path younger than the workspace: at merge no host can hold the marker, and every workspace older than the warn band takes the warn branch. The probe's two hypotheses for a missing marker — fresh install, or a loop that never started — both omit the case that applies to 100% of hosts on merge day. `_stamper_age_h()` supplies the missing baseline from a local fact: the mtime of the installed `scripts/core-status.sh`, gated on it actually containing the stamping code. A build that cannot stamp returns None and the absence proves nothing; a stamper younger than the warn band explains the absence by itself. The warn now requires BOTH an old workspace and a stamper old enough for a pass to have closed since it arrived. Tests: two new cases fail at the previous head (the merge-day case, and the build-that-cannot-stamp case); a third pins that an old stamper with no marker still warns, which passed before and must keep passing. The two existing never-started tests now supply an old stamper explicitly — the precondition the probe requires, not a weakened assertion. 17/17. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rkspace older than the marker-writer @qingyun-wu's blocker on sonichi#3669, reproduced: on a host that had closed a proactive-loop pass every few minutes all night, the probe warned — state/ was 1227.4h old, and `state/last-loop-ok` could not exist yet because the code that writes it had only just shipped. The missing-marker branch asked "how long has this workspace been in use?" That is the wrong baseline for a code path younger than the workspace: at merge no host can hold the marker, and every workspace older than the warn band takes the warn branch. The probe's two hypotheses for a missing marker — fresh install, or a loop that never started — both omit the case that applies to 100% of hosts on merge day. `_stamper_age_h()` supplies the missing baseline from a local fact: the mtime of the installed `scripts/core-status.sh`, gated on it actually containing the stamping code. A build that cannot stamp returns None and the absence proves nothing; a stamper younger than the warn band explains the absence by itself. The warn now requires BOTH an old workspace and a stamper old enough for a pass to have closed since it arrived. Tests: two new cases fail at the previous head (the merge-day case, and the build-that-cannot-stamp case); a third pins that an old stamper with no marker still warns, which passed before and must keep passing. The two existing never-started tests now supply an old stamper explicitly — the precondition the probe requires, not a weakened assertion. 17/17. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
You're right, and the repro is the part that made it obvious — thank you for running the probe rather than reasoning about it. Fixed in The defect in one line: the missing-marker branch asked "how long has this workspace been in use?", which is the wrong baseline for a code path younger than the workspace. At merge no host can hold the marker, every workspace is older than the warn band, so every host warns. My two stated hypotheses for a missing marker — fresh install, or a loop that never started — both omit the case that applies to 100% of hosts on merge day: the writer only just shipped. The fix supplies the missing baseline from a local fact.
On the engine tree that mtime is install time (the tree is replaced on update); in a checkout it is when the code arrived. Both are the semantics the probe actually wanted. On the tests, since two of the existing ones changed and I'd rather you hear why from me than find it. Control, stated precisely. Reverting The one thing I did not do is give the marker a self-seeding fallback — writing a "first observed" sentinel from the probe. It would also work, but it makes a read-only health check a writer of the state it judges, and I would rather not add that for a case a file mtime already answers. |
…rative to the PR review-checks' prose-cap failed the previous commit: prose-cap: src/health-check.py:5864 comment block is 3 lines (cap 2) The block explained WHY the merge-day case exists, which is the PR body's job. Two lines now state only what a reader of the branch needs: a writer younger than the warn band cannot have had a pass close since it arrived, so its absence is explained without indicting the loop. review-checks.sh --diff on the cumulative PR diff: PASS. Suite 17/17. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
CI note, so the red is not read as part of the fix. The gate did not report a coverage number at all — it refused, because the suite aborted first. Two things rule this branch out as the cause:
The earlier failure on I cannot re-run it: Suite at head: |
60ce207 to
537fa3c
Compare
|
Heads-up on the force-push you'll see here, @qingyun-wu: it was authorship-only and the tree is byte-identical. No code changed. Two commits on this branch were attributed to a second GitHub identity that had never signed the CLA, which held Your requested change is NOT addressed by this push and is still open. I did not want the new head to read as a fix. Nothing here needs re-reviewing on account of the force-push itself. |
|
@cla-assistant check |
qingyun-wu
left a comment
There was a problem hiding this comment.
APPROVE at exact head 9c5389961. My blocker is fixed, and I checked both directions rather than just the one I complained about.
The false positive is gone. Same probe, same live host, both commits:
a5cc09fd2 (the commit I blocked)
status=warn
"no loop marker at all, but state/ has been written for 2845.7h (>7h) —
a pass should have closed by now, so the loop may never have STARTED"
(_stamper_age_h does not exist at this commit)
9c5389961 (head)
status=ok
"no loop marker yet, but the stamping code is only 0.0h old (<7h) —
no pass has had time to close since it was installed"
_stamper_age_h = 0.012
That reproduces my original finding exactly — I reported 1227.4h then, it reads 2845.7h now because more wall-clock has passed, same mechanism — so the pass at head is discriminating rather than incidental.
The probe can still fire, which is the half a suppression fix usually breaks. I backdated only the worktree's scripts/core-status.sh to make the stamper look old, leaving the marker absent — the genuinely-dead-loop case:
_stamper_age_h = 128.9 h
status = warn
"no loop marker in the 128.9h since the stamping code was installed, and
state/ has been written for 2845.7h (>7h) — a pass should have closed by now"
So it suppresses the merge-day false positive without turning the probe off. _stamper_age_h keying on whether core-status.sh actually contains last-loop-ok — returning None when this build does not stamp at all — is the right shape: it distinguishes "cannot stamp" from "did not stamp", which are different verdicts.
One thing you should know before reading the green: john-the-dev's APPROVED is dated 2026-09-01, which predates both my block (09-02) and the current head. Once my request-changes clears, reviewDecision will read APPROVED on the strength of a review that never saw this code. That is a display artifact, not a second opinion — worth a re-request from him rather than treating the badge as two approvals.
I am sorry this sat for four days; the fix landed on 09-02 and my block was the thing holding it, not anything you owed.
|
@john-the-dev — a re-approval ask, with the reason it should be cheap. You approved What actually landed after yours, measured rather than described: One authored commit, comment-only, plus two base merges. So the code you approved is the code that is there; the diff you would be re-reading is a comment rewrite and whatever main brought in. CI is 20 SUCCESS at head and If you would rather re-read it properly than take my word on the diff shape, that is the better instinct and I am not asking you to skip it — I am only saying the delta is small enough that it should not cost you much. Stand: Echo Act IV Mini |
john-the-dev
left a comment
There was a problem hiding this comment.
Re-approving at 9c5389961, replacing my stale approval at 6bddb9d86.
What I actually re-read. compare 6bddb9d86...9c5389961 shows 47 commits and ~100 files, but that is almost entirely base movement — main merged in three times. Against the merge-base, this PR's own contribution is unchanged in shape: 372 lines across scripts/core-status.sh, src/health-check.py, and the liveness test. Of those three, only one changed since I approved:
tests/health-check-cron-schedule-liveness.test.py +98/-0
So the review surface was 98 added test lines, not a hundred files. Worth saying because the raw compare invites either skimming a huge diff or rubber-stamping it.
The added cases are the right ones, and they are all the same shape — absence is not evidence:
test_a_newly_installed_stamper_does_not_convict_an_old_workspace— @qingyun-wu's reported merge-day case: a stamper younger than the warn band cannot explain a missing marker, so it must not warn.test_a_build_that_cannot_stamp_is_ok_not_a_warn— a build with no stamping capability isok, not a fault.test_an_unreadable_state_dir_is_ok_not_a_warn— unreadable is UNKNOWN, not broken.test_a_peers_synced_core_file_does_not_age_a_fresh_workspace— a peer's synced file must not manufacture age on this host.test_absent_marker_on_a_young_state_dir_stays_ok, withtest_an_old_stamper_with_no_marker_still_warnsas the two-sided partner so the guard cannot silence a real fault.
That last pairing is what makes this a guard rather than a mute button: the young-dir escape and the old-stamper warn are tested against each other.
Mutation-checked rather than assumed: neutering the merge-day escape fails exactly one test and restoring clears it, so the new coverage is load-bearing.
Suite passes at this head. @qingyun-wu's CHANGES_REQUESTED at a5cc09fd2 is already cleared by their own approval at this head, so with this the PR carries two approvals at the current head rather than one plus a stale one.
|
The install-age proxy is reset by ordinary git operations, and it fails toward silence.
Isolated it with the workspace held identical — Same workspace, same absent marker, opposite verdict. So on a host whose loop has been dead for weeks, one checkout buys 7 hours of The direction is what makes it worth raising rather than noting: it fails toward "ok", which is the state the probe exists to disprove. And the coupling is unlucky — someone investigating a dead schedule is likely to pull or switch branches, which re-silences the detector at precisely the moment it is being consulted. The docstring's reasoning for not using the commit date is right, and I am not arguing for it. A signal that survives a checkout would have to live outside the repo — e.g. Not casting a verdict: two approvals stand, this adds evidence rather than a third opinion, and the blind spot is bounded at Stand: Echo Act IV Mini |
Closes #3564.
The gap
session-cronsverifies that registration happened — it reads theschedule-crons-stamp.jsona boot writes. Nothing verifies that registrationis still effective.
CronCreatejobs expire after 7 days, so a long-livedhost can hold a perfectly honest registration stamp and a dead schedule at the
same time, with every existing probe green.
core-status.jsoncannot close this, and that is the crux: owner turns refreshit, so it stays fresh straight through a dead schedule. A host in active
conversation looks healthiest to a core-status-based check exactly when its
autonomous loop is dead.
The fix
A marker only a completed pass can write.
scripts/core-status.sh idle— which is how a proactive-loop pass ends —stamps
<workspace>/state/last-loop-ok(+11 lines).runningdoes not.check_cron_scheduleinsrc/health-check.pybands that marker's age(+50 lines): ok / warn past
SUTANDO_CRON_STALE_WARN_H(7h) / fail pastSUTANDO_CRON_STALE_FAIL_H(26h). The fail detail names the 7-day expiry andthe re-register command, so the warn is actionable without a second lookup.
SUTANDO_CRON_STALE_WARN_H/_FAIL_H); an unparseable value falls back to the default rather than silencing the probe.ok, not stale. A fresh install has not closed apass yet, and a new probe must never be louder on day one than on a real
failure.
Evidence
The probe, band by band (loaded from this branch, temp workspace, marker
backdated):
The writer, both polarities (real
core-status.shround trip against athrowaway checkout whose
sutando.config.local.jsonpoints at a tempworkspace):
Tests — before/after, actual output.
Source files taken from the merge base, test file from HEAD:
At HEAD:
Notes for reviewers
$SUTANDO_WORKSPACEis not usable to isolate the writer test. v0.8(fix(workspace-v0.8): strip $SUTANDO_WORKSPACE from resolver + colored warnings [DRAFT] #1440) removed it from the resolution order, so setting it leaves the write
landing in the real workspace while the test reads an empty temp dir — a
green-looking test asserting nothing. The writer test therefore builds a
throwaway checkout with a
sutando.config.local.json, and_find_repo_rootanchors on the tracked
sutando.config.json, so both config files have to bepresent. It also asserts the script's stdout path is inside the temp
workspace, so a future resolution change fails loudly instead of silently
testing the wrong directory.
FileNotFoundErrorintook— is deliberately NOT in this PR. It is aseparate defect in a different resolution path and deserves its own change;
bundling it would make this diff two concerns. Their second-host measurements
on health-check cannot detect that a session's cron schedule has silently EXPIRED (registration is checked; liveness is not) #3564 are what confirmed this is not a single-host artifact.
WORKSPACE_DIR, the module-level path every other probe inhealth-check.pyalready uses; no new resolution path is introduced.🤖 Generated with Claude Code