Overview
agents/conductors/health/health.sh has no STALE branch. When PyAutoHeart returns
its freshness tier the card correctly prints adopted verdict = stale with a score,
then the recommendation prints "UNKNOWN — could not obtain a verdict from the
vitals faculty", the triage counts read 0 blocker(s) · 0 real warning(s) · 0 expected first-run gap(s), and the script exits 4 (unknown).
PyAutoHeart/AGENTS.md and heart/readiness.py make STALE a first-class tier
(nothing known-bad; some evidence missing or expired; remedy = re-run the check),
and AUTONOMY.md leg 4 treats STALE as passing the dev-ship gate. So a machine
caller today cannot distinguish "Heart says STALE" from "Heart unreachable" — the
two conditions collapse onto exit 4 and the same UNKNOWN headline.
Reproduced on a live health run 2026-08-05.
Plan
- Teach the triage item classifier to walk
stale_reasons alongside red_reasons
and yellow_reasons, so stale evidence becomes triage items instead of vanishing.
- Give stale items their own kind,
evidence-gap — actionable ("re-run the named
check") and therefore distinct from the existing baseline-gap bucket, which is
rendered as "accept, not action items".
- Add a STALE branch to the recommendation chain that names the top evidence gap and
cites a real refresh entry point, never an invented one.
- Give STALE its own exit code so a caller can branch on it, and update the header's
documented exit-code table to match.
- Add contract tests under
tests/ covering all three sites.
Detailed implementation plan
Affected Repositories
- PyAutoBrain (primary, only code change)
- PyAutoMind (registry/prompt lifecycle only)
PyAutoHeart is referenced (its readiness.py defines the tier and emits
stale_reasons) but needs no change — Heart already computes and exports the
tier correctly; this is purely a Brain-side consumer bug.
Branch Survey
| Repository |
Current Branch |
Dirty? |
| ./PyAutoBrain |
claude/health-conductor-stale-verdict-6ve1sl (== origin/main) |
clean |
| ./PyAutoMind |
claude/health-conductor-stale-verdict-6ve1sl |
prompt file only |
Branch: claude/health-conductor-stale-verdict-6ve1sl (mandated by the session;
supersedes the feature/<task-name> convention). No worktree claim conflicts —
active.md has no in-flight task touching PyAutoBrain.
Implementation Steps
-
agents/conductors/health/health.sh — _triage, item classifier (~line 187).
Read stale = list(r.get("stale_reasons") or []) and iterate
(("red", red), ("yellow", yellow), ("stale", stale)). Keep the existing
red-severity override and add its stale counterpart: when severity == "stale",
force kind = "evidence-gap" — severity wins over the keyword class, exactly as
it already does for red. Add evidence-gap to KIND_RANK (rank 1: actionable,
below real-problem, above advisory/baseline-gap) and "stale": 2 to
SEV_RANK. blocks_green is true for an evidence gap: re-running it is the path
to GREEN. Add an evidence_gaps count to the emitted counts object (additive —
existing keys keep their meaning).
-
agents/conductors/health/health.sh — recommendation chain (~line 234).
Insert a STALE branch after warn_real and before the
gaps or verdict == "yellow" branch, keyed on verdict == "stale" or evidence.
Action refresh-evidence; headline names the top evidence gap; detail states the
tier's semantics (re-run the check, do not fix code) and that the dev-ship gate
treats STALE as passing while a release still requires GREEN. Command comes from a
capability → refresh map of real entry points only:
validate → pyauto-brain release validate (delegated — the release conductor
owns the MCP GitHub boundary), verify_install → pyauto-heart verify_install,
continuous-check capabilities (repo_state, version_skew, worktree_drift,
script_timing, ci_status, open_prs, unknown) → pyauto-heart tick.
Capabilities with no known refresh entry point (test_run, url_check) get
command: None and are named in the detail — never an invented command, matching
the file's existing "cite a fix only for a named failure class" discipline.
Prefer the validate gap when present (it is the hard gate that makes GREEN
reachable), else the top-ranked evidence gap.
-
agents/conductors/health/health.sh — _exit_code_for (~line 304).
Add stale) return 6 ;;. Decision + rationale: the free slot 1 is rejected
because the shell's own generic failure is 1 (a missing _common.sh, a failed
readlink) and STALE is the tier AUTONOMY.md leg 4 treats as passing — a
crash must never be readable as a passing verdict. This is the same reasoning the
header already applies to usage errors ("exits 5 — kept distinct from the verdict
codes so misuse is never read as a real YELLOW"). 6 sits outside the existing
0–5 block, is never produced by bash or python in this script, and is unambiguous
to a machine caller.
-
agents/conductors/health/health.sh — header exit-code table (~line 52).
Document 6 stale, with the one-line rationale for why it is not 1.
-
_render_triage_human. Mark stale items ? (Heart's own tier glyph) rather
than !; add an "Evidence gaps (re-run the named check — nothing is known-bad)"
section and the evidence_gaps count to the counts line.
-
tests/test_health_conductor.py (new). Hermetic contract tests that pipe a
fabricated readiness JSON through the conductor's triage engine and assert:
stale reasons become items; the recommendation is refresh-evidence (not
refresh/UNKNOWN); counts are non-zero; the exit code is 6 and distinct from
unknown's 4, green's 0, yellow's 2, red's 3, usage's 5; the header's documented
table matches _exit_code_for; red/yellow/green behaviour is unchanged
(regression guard); and a Heart with no stale_reasons key behaves exactly as
before (the tier is additive).
Key Files
agents/conductors/health/health.sh — the conductor; all four change sites.
tests/test_health_conductor.py — new coverage.
PyAutoHeart/heart/readiness.py — reference for the tier's semantics (unchanged).
AUTONOMY.md leg 4 — why STALE must be machine-distinguishable (unchanged).
Testing
python3 -m pytest tests/test_health_conductor.py plus the existing suite, and a
manual conductor run against a stubbed stale-only readiness payload to confirm the
rendered card, the recommendation, and the exit code.
Original Prompt
Click to expand starting prompt
# Bug: the health conductor mis-reports a STALE verdict as UNKNOWN.
Type: bug
Target: PyAutoBrain
Repos:
- PyAutoBrain
- PyAutoHeart
Difficulty: small
Autonomy: supervised
Priority: high
Status: formalised
Bug: the health conductor mis-reports a STALE verdict as UNKNOWN. In PyAutoBrain
agents/conductors/health/health.sh the recommendation chain branches on green /
blockers / real-warnings / (gaps or yellow) and otherwise falls through to an UNKNOWN
branch, and _exit_code_for maps only green/yellow/red with a catch-all 4. When
PyAutoHeart returns STALE the card correctly prints 'adopted verdict = stale' with a
score, then the recommendation incorrectly prints 'UNKNOWN - could not obtain a verdict
from the vitals faculty' and the script exits 4. The triage item classifier only walks
the red and yellow reason lists, so stale reasons are dropped and the counts wrongly
read 0 blockers / 0 warnings / 0 gaps. PyAutoHeart AGENTS.md makes STALE a first-class
freshness tier that the dev-ship gate treats as passing, so a caller cannot distinguish
'Heart says STALE' from 'Heart unreachable'. Reproduced on a live health run 2026-08-05.
<!-- formalised by the Intake (Conception) Agent on 2026-08-05 from user-intake -->
Overview
agents/conductors/health/health.shhas no STALE branch. When PyAutoHeart returnsits freshness tier the card correctly prints
adopted verdict = stalewith a score,then the recommendation prints "UNKNOWN — could not obtain a verdict from the
vitals faculty", the triage counts read
0 blocker(s) · 0 real warning(s) · 0 expected first-run gap(s), and the script exits 4 (unknown).PyAutoHeart/AGENTS.mdandheart/readiness.pymake STALE a first-class tier(nothing known-bad; some evidence missing or expired; remedy = re-run the check),
and
AUTONOMY.mdleg 4 treats STALE as passing the dev-ship gate. So a machinecaller today cannot distinguish "Heart says STALE" from "Heart unreachable" — the
two conditions collapse onto exit 4 and the same UNKNOWN headline.
Reproduced on a live health run 2026-08-05.
Plan
stale_reasonsalongsidered_reasonsand
yellow_reasons, so stale evidence becomes triage items instead of vanishing.evidence-gap— actionable ("re-run the namedcheck") and therefore distinct from the existing
baseline-gapbucket, which isrendered as "accept, not action items".
cites a real refresh entry point, never an invented one.
documented exit-code table to match.
tests/covering all three sites.Detailed implementation plan
Affected Repositories
PyAutoHeartis referenced (itsreadiness.pydefines the tier and emitsstale_reasons) but needs no change — Heart already computes and exports thetier correctly; this is purely a Brain-side consumer bug.
Branch Survey
Branch:
claude/health-conductor-stale-verdict-6ve1sl(mandated by the session;supersedes the
feature/<task-name>convention). No worktree claim conflicts —active.mdhas no in-flight task touching PyAutoBrain.Implementation Steps
agents/conductors/health/health.sh—_triage, item classifier (~line 187).Read
stale = list(r.get("stale_reasons") or [])and iterate(("red", red), ("yellow", yellow), ("stale", stale)). Keep the existingred-severity override and add its stale counterpart: when
severity == "stale",force
kind = "evidence-gap"— severity wins over the keyword class, exactly asit already does for red. Add
evidence-gaptoKIND_RANK(rank 1: actionable,below
real-problem, aboveadvisory/baseline-gap) and"stale": 2toSEV_RANK.blocks_greenis true for an evidence gap: re-running it is the pathto GREEN. Add an
evidence_gapscount to the emittedcountsobject (additive —existing keys keep their meaning).
agents/conductors/health/health.sh— recommendation chain (~line 234).Insert a STALE branch after
warn_realand before thegaps or verdict == "yellow"branch, keyed onverdict == "stale" or evidence.Action
refresh-evidence; headline names the top evidence gap; detail states thetier's semantics (re-run the check, do not fix code) and that the dev-ship gate
treats STALE as passing while a release still requires GREEN. Command comes from a
capability → refresh map of real entry points only:
validate→pyauto-brain release validate(delegated — the release conductorowns the MCP GitHub boundary),
verify_install→pyauto-heart verify_install,continuous-check capabilities (
repo_state,version_skew,worktree_drift,script_timing,ci_status,open_prs,unknown) →pyauto-heart tick.Capabilities with no known refresh entry point (
test_run,url_check) getcommand: Noneand are named in the detail — never an invented command, matchingthe file's existing "cite a fix only for a named failure class" discipline.
Prefer the
validategap when present (it is the hard gate that makes GREENreachable), else the top-ranked evidence gap.
agents/conductors/health/health.sh—_exit_code_for(~line 304).Add
stale) return 6 ;;. Decision + rationale: the free slot1is rejectedbecause the shell's own generic failure is 1 (a missing
_common.sh, a failedreadlink) and STALE is the tierAUTONOMY.mdleg 4 treats as passing — acrash must never be readable as a passing verdict. This is the same reasoning the
header already applies to usage errors ("exits 5 — kept distinct from the verdict
codes so misuse is never read as a real YELLOW").
6sits outside the existing0–5 block, is never produced by bash or python in this script, and is unambiguous
to a machine caller.
agents/conductors/health/health.sh— header exit-code table (~line 52).Document
6 stale, with the one-line rationale for why it is not1._render_triage_human. Mark stale items?(Heart's own tier glyph) ratherthan
!; add an "Evidence gaps (re-run the named check — nothing is known-bad)"section and the
evidence_gapscount to the counts line.tests/test_health_conductor.py(new). Hermetic contract tests that pipe afabricated readiness JSON through the conductor's triage engine and assert:
stale reasons become items; the recommendation is
refresh-evidence(notrefresh/UNKNOWN); counts are non-zero; the exit code is 6 and distinct fromunknown's 4, green's 0, yellow's 2, red's 3, usage's 5; the header's documented
table matches
_exit_code_for; red/yellow/green behaviour is unchanged(regression guard); and a Heart with no
stale_reasonskey behaves exactly asbefore (the tier is additive).
Key Files
agents/conductors/health/health.sh— the conductor; all four change sites.tests/test_health_conductor.py— new coverage.PyAutoHeart/heart/readiness.py— reference for the tier's semantics (unchanged).AUTONOMY.mdleg 4 — why STALE must be machine-distinguishable (unchanged).Testing
python3 -m pytest tests/test_health_conductor.pyplus the existing suite, and amanual conductor run against a stubbed stale-only readiness payload to confirm the
rendered card, the recommendation, and the exit code.
Original Prompt
Click to expand starting prompt