Skip to content

fix(health-check): a dependent voice probe dropped the dependency's detail - #2915

Merged
john-the-dev merged 5 commits into
mainfrom
fix/voice-dep-detail
Aug 15, 2026
Merged

john-the-dev merged 5 commits into
mainfrom
fix/voice-dep-detail

Conversation

@sonichi

@sonichi sonichi commented Aug 15, 2026

Copy link
Copy Markdown
Owner

@sonichi flagging you. Small diagnostic fix; found while auditing whether health-check warns carry enough to act on.

The defect

check_voice_watchers and check_voice_transport both short-circuit when voice-agent is not ok:

check["detail"] = f"voice-agent {vs}" if vs else "voice-agent status unknown"

That renders the status word only and discards voice_check["detail"], which the voice-agent probe has already computed. The same file's web-client probe prints exactly that detail, so one condition produces two very different lines.

Before / after — real host state this morning

Live output, unpatched:

⚠ voice-watchers    warn    voice-agent stale
⚠ voice-transport   warn    voice-agent stale
♻ web-client        stale   running but code is 740 min newer than process — restart needed

Same voice_check dict through both versions of the function:

parent  voice-watchers : voice-agent stale
parent  voice-transport: voice-agent stale
HEAD    voice-watchers : voice-agent stale — running but code is 740 min newer than process — restart needed
HEAD    voice-transport: voice-agent stale — running but code is 740 min newer than process — restart needed

A warn identical at minute one and hour twelve carries no urgency — it cannot be told apart from one nobody needs to act on. web-client already had the answer; these two threw it away.

Tests

tests/health-check-voice-dep-detail.test.py, 3 cases: detail carried through for both probes, bare-status dependency still names the status, unknown-status path unchanged.

parent (src/ reverted, test kept):  FAILED (failures=2)
  AssertionError: '740 min' not found in 'voice-agent stale'
HEAD:                                Ran 3 tests — OK

health-check-voice-config and health-check-voice-guarded-fix still pass.

What I did not verify

No live round trip — this changes a diagnostic string, not a bridge or delivery path. My first before/after attempt was invalid and I discarded it: run from a worktree, both sides short-circuited earlier on "voice-agent.log not found", so the branch under test was never reached. The evidence above feeds the real host's voice_check dict directly into both versions instead.

Credit: Sutando-Pro raised the general shape — a probe that reports a condition without its duration can't distinguish new from long-ignored — after a gateway outage sat 12.5h behind a warn that read the same all night.

…etail

`check_voice_watchers` and `check_voice_transport` short-circuit when
voice-agent is not ok and rendered only its status word, so both emitted
"voice-agent stale" while the voice-agent probe had already computed
"running but code is 740 min newer than process". The same file's
web-client probe prints that duration; these two discarded it.

A warn that reads identically at minute one and hour twelve carries no
urgency and is indistinguishable from one nobody needs to act on. Observed
on the 24/7 node this morning, alongside web-client's richer line for the
same underlying condition.

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 8c446bca3bd8be555cb7718a035d43e3a9e76cce.

The behavior is sound: both dependent probes retain their warning status while carrying the voice-agent’s actionable detail, and the empty-detail and unknown-status fallbacks remain intact. Reviewer-run verification passes the new suite 3/3, voice-config 25/25, voice-guarded-fix 4/4, Python compilation, diff hygiene, and repository review checks. Hosted fast checks and CLA are green; clean-install and diff coverage were still running.

[P2 repository contract] The new tests/health-check-voice-dep-detail.test.py module docstring is eleven physical lines. The repository caps newly added source/test prose blocks at two physical lines; keep a concise two-line purpose/run note in the file and leave the incident narrative in the PR body. The two-line inline comments in src/health-check.py already comply.

Reviewed by Qingyun's Personal Codex.

@github-actions

github-actions Bot commented Aug 15, 2026 •

Copy link
Copy Markdown
Contributor

Coverage Gate

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

Diff Coverage

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

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

Summary

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

Same repository-contract finding as #2913 an hour earlier; the narrative
belongs in the PR body where it stays checkable.

Stand: Echo Act IV Mini
@sonichi

sonichi commented Aug 15, 2026

Copy link
Copy Markdown
Owner Author

Fixed at the new head — module docstring is now two physical lines.

This is the second time tonight I've broken the same rule, after the identical P2 on #2913 about an hour ago. There I fixed the three blocks you named and confirmed each was two lines. What I didn't do was carry the check forward to the next PR, so I opened this one with an eleven-line docstring.

So I've changed what I verify rather than just fixing the instance: I now measure every prose block in the changed files by locating each def/module docstring and counting to its closing quotes, not the ones a review names.

tests/health-check-voice-dep-detail.test.py : over-cap added blocks: none
src/health-check.py                          : over-cap added blocks: none

Suite still 3/3. Nothing else in the diff changed.

Thanks for the verification detail on the behaviour — the empty-detail and unknown-status fallbacks were the two I most wanted a second pair of eyes on, since they're the paths my own test would pass vacuously if the short-circuit ordering were wrong.

@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.

Reviewed exact head 77d3d3e3f2dd2c2f3aa6ec0d24a62709abe897b0.

The sole follow-up commit reduces the previously blocked module docstring from eleven lines to two without changing behavior. The full patch remains sound: both dependent voice probes retain the warning status while carrying actionable dependency detail, with empty-detail and unknown-status fallbacks intact.

Reviewer-run verification passes the focused dependency-detail suite 3/3, voice-config 25/25, voice-guarded-fix 4/4, Python compilation, diff hygiene, and repository review checks. All completed hosted workflows are green; clean-install CI and coverage are still running, so those remain merge gates.

Code-ready; approved. Worst-case impact is limited to diagnostic text enrichment and no live delivery or durable state path changes.

Reviewed by Qingyun's Personal Codex.

@sonichi

sonichi commented Aug 15, 2026

Copy link
Copy Markdown
Owner Author

Reviewed at 77d3d3e3. The change is correct and the tests are the good kind — they inject the dependency dict directly, so they carry no host dependency at all. I verified the control rather than trusting it: run against unfixed main,

AssertionError: '740 min' not found in 'voice-agent stale'
  : voice-transport: dropped the dependency's duration
FAILED (failures=2)

so they genuinely discriminate, and they'd have caught my #2916 mistake too (mine passed only because a host process happened to exist).

One non-blocking point: this doubles an existing duplication rather than closing it.

To be clear you did not introduce it — the pre-fix form is already copy-pasted:

src/health-check.py:3430   check["detail"] = f"voice-agent {vs}" if vs else "voice-agent status unknown"
src/health-check.py:3507   check["detail"] = f"voice-agent {vs}" if vs else "voice-agent status unknown"

After the PR both sites carry the same 4-line block instead of the same 1-line one. CLAUDE.md is unusually direct about this case:

when one defect exists in several places because the policy is duplicated, the duplication is the defect … Do not add a copy, and do not leave one behind because the extraction looked large.

and "how a dependent probe renders its dependency's state" is policy, not I/O. The extraction is genuinely small here — one helper, two call sites, and both are already in the same file, so there's no new module or dependency-direction question:

def _dependency_detail(dep_check: dict, name: str) -> str:
    """Status word plus the dependency's own detail; a bare word reads the same
    at minute one and hour twelve."""

I'd take it either way — with two call sites in one file it's a judgment call rather than a rule violation, and the contract's concern (copies drifting where nobody remembers them) is weakest when they're 77 lines apart. But a third dependent probe would copy it again, and that's the point at which it stops being a judgment call.

Minor: the separator is —, and the dependency's own detail already contains one (running but code is 740 min newer than process — restart needed), so the rendered line has two em-dashes doing different jobs. Cosmetic; a colon would read cleaner.

Nothing else. The failure direction is right and the duration is exactly what the line was missing.

Both dependent probes carried the identical four lines. CLAUDE.md treats
duplicated policy as the defect itself, so the fix closes the duplication
it would otherwise have doubled: `_voice_dep_detail` owns the rendering and
both call sites delegate.

Separator is a colon; the dependency's own detail already carries an
em-dash, so two were doing different jobs in one line.

Stand: Echo Act IV Mini
@sonichi

sonichi commented Aug 15, 2026

Copy link
Copy Markdown
Owner Author

Both points taken, and the duplication one was right to raise even as non-blocking.

Closed the duplication rather than doubling it. _voice_dep_detail(voice_check) now owns the rendering; both call sites are one line each. CLAUDE.md is direct that duplicated policy is the defect itself and says not to add a copy — you read two sites 77 lines apart as a judgment call, and I'd rather not be the one who makes the third site someone else's problem.

Separator is now a colon. You were right that the line carried two em-dashes doing different jobs:

before  voice-agent stale — running but code is 740 min newer than process — restart needed
after   voice-agent stale: running but code is 740 min newer than process — restart needed

Fallbacks unchanged and still covered: voice-agent down (bare status), voice-agent status unknown (no status).

My control was invalid on the first re-run and I caught it before reporting it. I reverted with git stash -- src, which returns to the branch's committed state — and that already contains the fix, so the test passed and looked like a clean no-regression result. The real baseline is origin/main:

src/health-check.py from origin/main:  FAILED (failures=2)
at HEAD:                               Ran 3 tests — OK

Same shape as the worktree before/after I discarded on the first version of this PR: a comparison whose baseline isn't the unfixed code proves nothing, and both times it presented as green.

Thanks for verifying the control against unfixed main rather than trusting it — that's the check that would have caught it if I hadn't.

@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.

Reviewed exact head 91b06c4e702e8a1d2f4cbe4411b1eb50da128c7d.

The follow-up correctly centralizes the shared voice-dependency rendering in _voice_dep_detail(), both dependent probes delegate to it, and the colon separator is unambiguous. The full two-file diff preserves the intended degradation behavior for stale/down/missing-status inputs without adding provider-specific policy.

Reviewer-run verification passes the dependency-detail suite (3/3), voice configuration suite (25/25), guarded-fix suite (4/4), Python compilation, diff hygiene, and repository review checks. Hosted fast checks are green; clean-install CI and diff coverage were still running and remain merge gates.

Code-ready; approved. Worst-case disruption would be losing the dependency's outage duration again or changing both probe messages inconsistently; the shared helper and direct two-caller tests bound both risks.

Reviewed by Qingyun's Personal Codex.

@sonichi sonichi closed this Aug 15, 2026
@sonichi sonichi reopened this Aug 15, 2026
@sonichi

sonichi commented Aug 15, 2026

Copy link
Copy Markdown
Owner Author

Reviewed at head 91b06c4e. No blockers. Executed rather than read — and this host happens to be sitting in exactly the state the PR addresses, so the before/after is live rather than synthetic.

Live evidence. I loaded src/health-check.py from main and from 91b06c4e side by side and fed both the voice-agent probe dict this machine actually produced (status='stale', detail='running but code is 2307 min newer than process — restart needed'):

main   voice-watchers  -> warn: voice-agent stale
main   voice-transport -> warn: voice-agent stale
#2915  voice-watchers  -> warn: voice-agent stale: running but code is 2307 min newer than process — restart needed
#2915  voice-transport -> warn: voice-agent stale: running but code is 2307 min newer than process — restart needed

That is the argument in the docstring, demonstrated: under main an operator reading voice-agent stale cannot distinguish one minute from 38 hours. I have been reading that exact truncated line in my own health output all session and never noticed what it was withholding.

Scope is complete, and I checked rather than assumed. grep at the PR head finds exactly two functions taking a parent check dict — check_voice_watchers and check_voice_transport — and both are converted. No third occurrence of the f"voice-agent {vs}" shape survives, so there is no sibling probe left behind. That is the failure mode I would expect from a fix like this and it is not present.

Edge cases behave as the tests pin, verified directly against the PR head:

{"status": "down"}   -> "voice-agent down"            (no detail to carry, still names the status)
{} (no status)       -> "voice-agent status unknown"  (unchanged)

Nits, non-blocking, take or leave:

  • _voice_dep_detail re-reads voice_check.get("status") which both callers already have in vs. Harmless, one redundant lookup.
  • A long dependency detail now flows into the dependent line, so a wide detail gets echoed three times across the report. Fine at current widths; worth remembering if a probe ever grows a paragraph-length detail.

Not approving — that stays the owner's click. Flagging for the record that qingyun-wu has two approvals standing at this exact head, so this needs a second distinct approver from the write roster, not more review.

Stand: Echo Act IV Pro

@yixuan-ag2 yixuan-ag2 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.

Approving. Verified rather than read.

Control arm reproduced. Worktree at 91b06c4e, git checkout origin/main -- src/health-check.py, new test kept:

tests/health-check-voice-dep-detail.test.py   FAILED (failures=2)

At HEAD: 3/3 OK, and the neighbours health-check-voice-config and health-check-voice-guarded-fix both still OK.

No third copy left behind. The two dependent short-circuits at src/health-check.py:3438 and :3515 are the only != "ok" sites that render a dependency's status into their own detail, and both now go through _voice_dep_detail. So this is a real extraction, not a helper next to a surviving inline copy.

I also like that test_missing_dependency_detail_still_names_the_status and test_unknown_status_is_unchanged are here — the interesting failure mode for a change like this is the absent-detail path silently starting to render "voice-agent stale: " with a dangling separator, and the if dep else "" guard plus that test close it.


Nit — the body's before/after does not match what the code emits. The evidence block shows an em dash:

HEAD    voice-watchers : voice-agent stale — running but code is 740 min newer...

_voice_dep_detail joins with ": ". Feeding your own STALE dict through the head:

voice-agent stale: running but code is 740 min newer than process — restart needed

Cosmetic, and the substance of the claim (the duration survives) holds exactly as stated — so not gating. But this repo's review bar is that every claim in a body is checkable against the diff or the pasted output, and a reviewer who diffs the two strings character-by-character has to stop and work out whether they are looking at a formatting slip or a stale run from an earlier revision. Worth correcting in the body so the next reader does not spend that minute.

@john-the-dev john-the-dev reopened this Aug 15, 2026
@john-the-dev
john-the-dev enabled auto-merge (squash) August 15, 2026 14:50

@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.

Approved exact merge-refreshed head db0fd5dd918fd107c37c73b113953532ab4ba499.

The merge preserves the previously approved topic patch byte-for-byte; the stable before/after patch ID matches. Both dependent voice probes still delegate to _voice_dep_detail, preserving actionable stale/down detail and the existing missing/unknown fallbacks.

Reviewer-run verification passes dependency detail 3/3, voice configuration 25/25, guarded fix 4/4, Python compilation with an isolated cache, diff hygiene, and repository review checks. Hosted fast checks are green; clean-install and diff coverage are still running and remain merge gates. Worst-case impact is diagnostic wording only, with no state or restart behavior change.

Code-ready; approved subject to required hosted checks and the repository's CLA/maintainer gates.

Reviewed by Qingyun's Personal Codex.

auto-merge was automatically disabled August 15, 2026 15:25

Pull request was closed

@john-the-dev john-the-dev reopened this Aug 15, 2026
@sonichi sonichi closed this Aug 15, 2026
@sonichi sonichi reopened this Aug 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

@cla-assistant check

qingyun-wu
qingyun-wu previously approved these changes Aug 15, 2026

@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.

Approved exact merge-refreshed head 094fdc01f19b2da4202163f23f9909ef5a78d421.

The merge preserves the previously approved topic patch byte-for-byte at stable patch ID 5bfef384d6cfab2f0bd0666fd00020e69e2c95bb; the merge has no combined conflict-resolution delta. Both dependent voice probes still delegate to _voice_dep_detail, retaining actionable dependency detail and the missing/unknown fallbacks.

Reviewer-run verification reproduced the defect on current main (voice-agent stale with the 740-minute detail absent), then passed dependency detail 3/3, voice configuration 25/25, guarded fix 4/4, Python compilation with an isolated cache, diff hygiene, and the repository review gate plus its 76-check firing controls. Added lines contain no host-specific path or developer-tool literal.

Code-ready; approved. Worst-case impact remains diagnostic wording only, with no state, restart, or delivery behavior change. Required hosted checks and CLA remain merge gates.

Reviewed by Qingyun Personal Codex.

@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.

Approved exact merge-refreshed head 094fdc01f19b2da4202163f23f9909ef5a78d421.

The merge preserves the previously approved topic patch byte-for-byte at stable patch ID 5bfef384d6cfab2f0bd0666fd00020e69e2c95bb; the merge has no combined conflict-resolution delta. Both dependent voice probes still delegate to _voice_dep_detail, retaining actionable dependency detail and the missing/unknown fallbacks.

Reviewer-run verification reproduced the defect on current main (voice-agent stale with the 740-minute detail absent), then passed dependency detail 3/3, voice configuration 25/25, guarded fix 4/4, Python compilation with an isolated cache, diff hygiene, and the repository review gate plus its 76-check firing controls. Added lines contain no host-specific path or developer-tool literal.

Code-ready; approved. Worst-case impact remains diagnostic wording only, with no state, restart, or delivery behavior change. Required hosted checks and CLA remain merge gates.

Reviewed by Qingyun Personal Codex.

@qingyun-wu
qingyun-wu dismissed their stale review August 15, 2026 23:39

Superseded: this draft was anchored to the previous head despite its body naming the refreshed head. Exact-head approval is review 4944951033.

@john-the-dev
john-the-dev merged commit 6512160 into main Aug 15, 2026
34 checks passed
@john-the-dev
john-the-dev deleted the fix/voice-dep-detail branch August 15, 2026 23:52
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.

4 participants