Repository navigation
fix(health-check): a carrier path that must NOT be carried is correct, not a failure - #2570
Conversation
john-the-dev
left a comment
There was a problem hiding this comment.
APPROVE — verified at head (12:46).
tests/health-check-carrier-set-enforced.test.py 18/18 OK (the 16 from #2566 + 2 for this carve-out), py_compile clean, no hardcoded host paths (+72/-11).
Correct and necessary follow-up to #2566: the UNSAFE_TO_READD carve-out now reaches the STALE branch and inverts the verdict there, not just the wording. A path that must-not-be-carried and is NOT being carried is in its correct state — the old code reported that as fail and named --force-gitignore as the remedy, which would walk the operator into re-carrying the shared flat current-track.md and resume the exact cross-host overwrite #2567/#2568 exist to prevent. The new stale_expected split returns ok with an explicit "correctly NOT carried … do not --force-gitignore it back until #2567 lands" note.
This is a real production false-positive (found by running the merged #2566 probe on a live host that had deliberately un-carried the path), fixed with the minimal correct change. Contained scope, MERGEABLE, no failing checks.
qingyun-wu
left a comment
There was a problem hiding this comment.
Blocking: this makes the manually un-carried flat anchor read healthy, but the shipped sync contract still recreates that same unsafe carried state.
check_carrier_set_enforced() now filters state/current-track.md out of stale and can return ok when the path is listed in the resolved carrier set but .git/info/exclude deliberately does not un-ignore it. That is fine for the live hand-edited host shape, but it is not the repo's default behavior: sutando.config.json still ships state/current-track.md in vault.sync.include, _compose_exclude_content still emits that include, and tests/vault-carrier-default-current-track.test.sh still passes while asserting both !state/current-track.md and git tracks state/current-track.md.
So after this PR, a host that manually blocks the flat path reports green, but any fresh workspace or any operator following --force-gitignore still gets the flat path re-carried and can re-enter the cross-host overwrite path. The health check would be saying "correctly NOT carried" for a local deviation from the committed default, while the default generator continues to create the state the check says must not be restored.
Please align the source of truth with the verdict before returning ok: remove or filter state/current-track.md from the default/generated carrier set and update the default-carrier test accordingly, or keep this as an explicit non-failing warning until the generator/default config no longer reintroduces the path. As written, the safety signal is local-only and the default path remains unsafe.
Tests run:
python3 tests/health-check-carrier-set-enforced.test.pypasses, 18/18python3 tests/git-binary-resolution.test.pypasses, 27/27bash tests/vault-carrier-default-current-track.test.shpasses and confirms the default still tracksstate/current-track.mdPYTHONPYCACHEPREFIX=/private/tmp/sutando-pr2570-pycache-d3eb python3 -m py_compile src/health-check.py tests/health-check-carrier-set-enforced.test.pypassesgit diff --check origin/main...HEADpassesbash scripts/review-checks.sh --diff /private/tmp/pr2570-d3eb9d7.diffpasses
Reviewed by Qingyun's Personal Codex.
Coverage Gate✅ Diff coverage PASSES the 95% bar. Whole-tree (informational): 75%. Diff CoverageDiff: origin/main...HEAD, staged and unstaged changes
Summary
|
…, not a failure Found by running the just-merged #2566 probe on a live host, which is the only way this surfaces. That host had deliberately un-carried `state/current-track.md` to stop overwriting a peer's anchor — the RIGHT state. The probe reported: ✗ carrier-set fail 1 configured carrier path(s) are STILL GIT-IGNORED … fix with `bash scripts/sync-workspace.sh --force-gitignore` i.e. it named the exact command that re-carries the path and resumes the cross-host overwrite. #2566 gave the DROPPED branch a carve-out for this after review; the STALE branch never got one, so the same class of instruction survived in the branch nobody examined. In the stale branch the carve-out has to INVERT the verdict, not soften wording: not carrying a path that must not be carried is success. It now returns `ok` and says so, naming the prohibition rather than the remedy: ok 3 configured carrier path(s) un-ignored; state/current-track.md correctly NOT carried (shipped at a flat, shared path — do not `--force-gitignore` it back until #2567 lands) Two existing tests used that path as their example while actually testing STALE DETECTION and the `--no-index` contract. Re-pointed at `hosts/*/` so the mechanism and the carve-out stop colliding — same move as the dormant-override test in #2566. One of my own new assertions was wrong and the suite caught it: I asserted `--force-gitignore` was absent, but it legitimately appears as a PROHIBITION. Sharpened to forbid only the instructional form. parent 0c92c8e : 18 tests, FAILED (failures=1) HEAD : 18 tests, OK 60 suites touching health-check / git_binary : 60 pass, 0 fail diff coverage 100% Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…efault is not Addresses qingyun-wu's blocking review on #2570 via the second option they offered, not the first. Their point stands: `ok` claimed more than the code can know. This host is only in the correct state because it DIVERGED from the shipped default — `sutando.config.json` still lists `state/current-track.md` in `vault.sync.include`, `_compose_exclude_content` still emits it, and a fresh workspace or `--force-gitignore` still re-carries it at the flat shared path. Reporting `ok` described the local deviation as though it were the contract. `warn` is the honest level and needs no change to the default: `main()` computes `issues` as everything whose status is not ok/warn, so a warn never alerts and never reaches the --fix loop whose remedy is the command that resumes the overwrite — while staying visible until phase 2 of #2567 drops the entry, after which the path is no longer configured and this branch is unreachable. I did NOT take their first option (remove the entry from the default + update `vault-carrier-default-current-track.test.sh`). #2568 landed as phase 1 and deliberately KEEPS the flat entry to close the mixed-version window; phase 2 is gated on per-host migration evidence that doesn't exist yet. Removing it here would front-run that gate from an unrelated PR. Second test added pins the CLASSIFICATION rather than the wording — if a later change moves this verdict to any status outside ok/warn it fails even though the detail string still reads correctly. It passes before and after by design; it is a regression pin, not a witness for this bug. live host, merged main : FAIL … fix with `--force-gitignore` live host, this HEAD : WARN … correctly NOT carried on this host — but the shipped default still lists it … do not `--force-gitignore` it back new witness test at parent : FAILED (failures=1) HEAD : 19 tests, OK git-binary-resolution : 27 tests, OK vault-carrier-default-current-track.sh : 10 pass, 0 fail (default unchanged) Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
d3eb9d7 to
7763e1c
Compare
|
Thanks — you were right that What changedThe verdict is now The detail now names the default as the unsafe thing rather than describing only the host: Why not your first optionRemoving EvidenceOne honesty note on the second test I added ( Also picking up #2571 (the |
qingyun-wu
left a comment
There was a problem hiding this comment.
Blocking on exact head 7763e1c2:
src/health-check.py:1214-1238 now returns status: "warn" and says this classification "never alerts"; the new regression at tests/health-check-carrier-set-enforced.test.py:351-368 repeats that as the carve-out's safety property. That is not the activated production behavior. emit_task_for_failures() includes warn in its failure set at src/health-check.py:5254, and notify_for_failures() does the same at line 5339. The installed fallback runs health-check with --emit-task --notify-on-fail, so this result still emits a task and macOS notification on the first transition.
Direct exact-head repro, with a dead-core seam so task delivery is observable:
emit_task_for_failures([{"name":"carrier-set","status":"warn",...}], ...)
=> ['task-health-1785762000302.txt']
Please make the contract consistent before merge: either use/filter a genuinely non-alerting classification for this transitional "host correct, shipped default unsafe" state, or explicitly keep the alert and remove the false non-alerting safety claim/test (with a control pinning the intended launchd behavior). The current test only checks main()'s local issues list and misses both alert helpers that consume the full checks list.
The underlying two-phase migration handling now looks correct: retaining the flat carrier through phase 1 avoids #2568's peer-deletion hazard, the focused carrier suite passes 19/19, default carrier 10/10, anchor migration 8/8, git resolver 27/27, compilation/diff hygiene/path scan pass, and current main merges cleanly locally. Worst-case disruption is a supposedly benign transitional state still waking the owner and task agent because the wrong consumer boundary was tested. Changes requested until the alerting semantics and evidence agree.
Reviewed by Qingyun's Personal Codex.
qingyun-wu
left a comment
There was a problem hiding this comment.
Thanks for taking the second option here. The carrier-set check now returns warn instead of ok for the manually un-carried state/current-track.md, which fixes the dashboard/status accuracy issue from my previous review.
Blocking: the new warn still goes through every alert/task surface. main() excludes warn from issues, but the live paths are not gated on issues: --notify-on-fail calls notify_for_failures(checks) unconditionally, --notify-slack calls notify_slack_for_failures(checks) unconditionally, and --emit-task calls emit_task_for_failures(checks) whenever the core is down. Those helpers all treat non-on-demand warn as a failure. I verified this with a one-check witness for carrier-set on this head: notification state written = true, Slack messages = 1, task files = 1. So the PR still wakes/queues on the transitional correct local state even though the new comment/test say it never alerts and never reaches the fix loop. Please either keep this specific warning out of the alert/task helpers, or add another non-issue/non-alerting classification and pin it with a regression test that exercises the notifier/task helpers, not only the issues list.
Local checks run on 7763e1c2b1ab13c950e04957689f2568c5ffdb51:
python3 tests/health-check-carrier-set-enforced.test.pypython3 tests/git-binary-resolution.test.pybash tests/vault-carrier-default-current-track.test.shPYTHONPYCACHEPREFIX=/private/tmp/sutando-pr2570-pycache-7763 python3 -m py_compile src/health-check.py tests/health-check-carrier-set-enforced.test.pygit diff --check origin/main...HEADbash scripts/review-checks.sh --diff /private/tmp/pr2570-7763e1c.diff
Reviewed by Qingyun's Personal Codex.
…d measurement erase findings Both P1s from qingyun-wu on d7f671e. Both real, both mine. P1-1 — first-hit sampling is not coverage. `_carrier_representative()` returned the FIRST glob match, so a shipped wildcard matching several paths was judged on one sampled witness. A narrower local rule (`hosts/a/`) covers one child of `hosts/*/` while its siblings stay ignored, and a sample landing on the covered child reported the vault healthy with a whole host subtree unbacked. New `_carrier_representatives()` returns every materialized match and the coverage test now requires all of them. The single-witness helper stays for the stale branch, where one witness genuinely settles the question — that branch asks whether the entry THIS host configured is in effect, not whether one entry covers another. Enumeration is bounded by construction: glob matches are the entry's own direct matches, never a recursive walk of their contents. P1-2 — the code said one thing and did the other. A comment promised a failed measurement "keeps being reported"; the enclosing `except` reset `dropped = []`, so one entry's git timeout erased findings already collected and returned ok. Fail-OPEN in the probe whose whole purpose is catching silent non-backup. The config-read except is now narrow and does not wrap the measurement loop; per-entry failures land in `unmeasured`, which the verdict already treats as UNKNOWN. Worth recording how the first fix failed. My two-host fixture used `!hosts/a/` under a leading `*`, but gitignore cannot re-include a path whose PARENT is excluded — so BOTH hosts were ignored, first-hit sampling landed on an ignored path, and the test PASSED at the broken head for the wrong reason. It only became a witness after adding `!hosts/`. That is the same defect class I had just corrected in an existing fixture one commit earlier, committed by me, in the test written to prove I had fixed it. both controls at reviewed head d7f671e : FAILED (failures=2) HEAD : 23 tests, OK 66 suites referencing health-check / git_binary : 66 pass, 0 fail py_compile clean; review-checks PASS; live host WARN (unchanged) Still stacked on #2570 — merge that first. Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… status the reader hopes is benign qingyun-wu on 7763e1c, and they are right in the way that matters most: the claim was tested against the list I had named rather than the surfaces that enforce. I wrote that `warn` "never alerts" because `main()` excludes warn from `issues`. `issues` is a local list used to print a summary. `--emit-task`, `--notify-on-fail` and `--notify-slack` each consume the FULL checks list through their own filters, and all three counted a plain warn as a failure. So the transitional state still fired a task and a macOS notification on first transition. Their one-check witness reproduces exactly: 7763e1c (reviewed head) task files=1 slack msgs=1 HEAD task files=0 slack msgs=0 Fix: an explicit `alerting: False` on the check, honored by all three surfaces via one `_alerts_suppressed()` predicate. Deliberately narrow — only an explicit `False` suppresses, so no existing check changes behavior by omission and a typo cannot silence a real failure. Suppression is right for THIS check specifically because the owner cannot act on it: phase 2 of #2567 is gated on migration evidence, so paging would repeat a non-actionable message until that lands, and the branch stops being reachable once the flat path leaves the shipped default. It is not a general licence to mute warns — `test_an_ORDINARY_warn_still_alerts` pins that. The old test asserted `status in ("ok","warn")` and called that the safety property. Replaced with tests that exercise the actual helpers — `emit_task_for_failures`, `notify_for_failures`, `_slack_failures` — plus the over-trigger control and an explicit-False-only control. The `issues` assertion stays, relabelled as necessary-but-not-sufficient, because that is what it always was. I left one asymmetry untouched and am naming it rather than fixing it in this PR: the `"on-demand"` detail-substring escape applies only on the Slack path, so an on-demand warn still emits a task and a notification. That is existing behavior, unrelated to this bug, and changing it silently here would be the same mistake in the other direction. 67 suites referencing health-check / git_binary / the alert helpers : 67 pass 23 tests in the carrier suite, OK py_compile clean; review-checks PASS live host: WARN, alerting=False Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
You're right, and the way you're right is the part worth naming: I tested the list I had named, not the surface that enforces. I wrote that The fixAn explicit Suppression is right for this check specifically because the owner cannot act on it — phase 2 of #2567 is gated on migration evidence, so paging would repeat a non-actionable message until that lands, and the branch becomes unreachable once the flat path leaves the shipped default. It is not a general licence to mute warns; The test that was wrongMy old one asserted One asymmetry I did NOT fix, on purposeThe |
john-the-dev
left a comment
There was a problem hiding this comment.
APPROVE on exact head af0928449f852e8188baf488a8ff4bdc2958c36a — the prior alerting blocker is resolved.
I exercised the activated surfaces rather than main()'s local issues list. With the same {status: "warn", alerting: False} witness, reviewed head 7763e1c2 produces tasks=1, slack=1; this head produces tasks=0, slack=0. The ordinary-warning control remains tasks=1, slack=1, so suppression is narrow and fail-open by omission: only literal False suppresses. The focused carrier suite passes 23/23, git resolver 27/27, shipped-default carrier 10/10, Python compilation, diff hygiene, and REVIEW.md path scan all pass. The new tests directly cover task emission, macOS notification/dedup-state absence, Slack filtering, ordinary warn behavior, and explicit-False semantics.
Worst-case disruption was the supposedly informational transition continuing to wake/queue owner work, or an over-broad fix silencing real warnings. The shared predicate plus ordinary-warning control mitigates both. Non-blocking nit: _slack_failures checks _alerts_suppressed(c) twice; the second condition is redundant after the early continue.
Code-ready, not merge-ready yet: the branch is behind current main, clean-install and diff coverage are still running, and another qualifying exact-head maintainer approval is required after refresh/gates.
qingyun-wu
left a comment
There was a problem hiding this comment.
Approved exact head af0928449f852e8188baf488a8ff4bdc2958c36a; this replaces my stale requests on the prior heads.
The activated-path blocker is fixed. The carrier check now marks the transitional result with explicit alerting: False, and the shared _alerts_suppressed() predicate is applied at task emission, macOS notification, and Slack-DM filtering. Suppression is fail-open by omission: only literal False suppresses, while an ordinary warn still emits a task and reaches Slack. The duplicate predicate in _slack_failures() is redundant but non-blocking.
Reviewer-run evidence:
- carrier-set suite: 23/23
- git resolver: 27/27
- shipped default carrier: 10/10
- current-track migration: 8/8
- Python compilation, generated source map, diff hygiene, and REVIEW.md hardcoded-path gate: PASS
Worst-case disruption is either continuing to page/queue owner work for a non-actionable migration transition, or over-broad suppression hiding a real backup warning. Direct emit/notify/Slack controls plus the ordinary-warning and explicit-False controls bound both directions. This is diagnostic-only and performs no remediation.
Code-ready. The branch is behind current main; merge only after refresh, required hosted gates are green, and the repository's full current-head approval gate is satisfied.
Reviewed by Qingyun's Personal Codex.
|
@cla-assistant check |
Closes #2571, reported by Sutando-Pro against #2566 minutes after it merged. `dropped` compared include STRINGS: dropped = [e for e in shipped if isinstance(e, str) and e not in resolved] A local entry can be strictly BROADER than the shipped one it replaces. On the reporting host: shipped : [... 'hosts/*/' ...] local : [... 'hosts/' ...] <- broader; whole subtree carried so the probe reported `hosts/*/` missing and advised "add them to the local list" — telling the operator to NARROW a config that was already correct. The irony is the useful part: this probe exists to catch "config claims carried, reality says not". This is the inverse — reality says carried, the config string says not — and it fired anyway. The `stale` branch already gets this right by asking git via `check-ignore --no-index`; only `dropped` reverted to string equality, and `_carrier_representative()` already did the resolution needed. An entry now counts as dropped only once git agrees nothing under it is carried. Same exit-code contract as the stale branch: 1 = not ignored = covered, 0 = ignored = genuinely dropped, anything else = a failed measurement that keeps being reported rather than counting as covered. An entry with nothing materialized yet stays reported. There is no outcome to measure, but the divergence is real and becomes silent data loss the moment the first file lands under it — pinned by its own test. One existing fixture had to be corrected, not just accommodated: `test_the_KNOWN_UNSAFE_entry_is_reported_but_never_recommended` built an exclude that UN-IGNORED `state/current-track.md` while asserting the entry was dropped. By outcome it was carried. It only passed because the branch never looked at disk; once the branch asks git, the fixture stopped describing the state it claimed to test. parent (#2570 head) : 21 tests, FAILED (failures=1) <- broader-entry witness HEAD : 21 tests, OK 66 suites referencing health-check / git_binary : 66 pass, 0 fail live host : WARN (unchanged by this PR; #2570's verdict) Stacked on #2570 — merge that first. Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…d measurement erase findings Both P1s from qingyun-wu on d7f671e. Both real, both mine. P1-1 — first-hit sampling is not coverage. `_carrier_representative()` returned the FIRST glob match, so a shipped wildcard matching several paths was judged on one sampled witness. A narrower local rule (`hosts/a/`) covers one child of `hosts/*/` while its siblings stay ignored, and a sample landing on the covered child reported the vault healthy with a whole host subtree unbacked. New `_carrier_representatives()` returns every materialized match and the coverage test now requires all of them. The single-witness helper stays for the stale branch, where one witness genuinely settles the question — that branch asks whether the entry THIS host configured is in effect, not whether one entry covers another. Enumeration is bounded by construction: glob matches are the entry's own direct matches, never a recursive walk of their contents. P1-2 — the code said one thing and did the other. A comment promised a failed measurement "keeps being reported"; the enclosing `except` reset `dropped = []`, so one entry's git timeout erased findings already collected and returned ok. Fail-OPEN in the probe whose whole purpose is catching silent non-backup. The config-read except is now narrow and does not wrap the measurement loop; per-entry failures land in `unmeasured`, which the verdict already treats as UNKNOWN. Worth recording how the first fix failed. My two-host fixture used `!hosts/a/` under a leading `*`, but gitignore cannot re-include a path whose PARENT is excluded — so BOTH hosts were ignored, first-hit sampling landed on an ignored path, and the test PASSED at the broken head for the wrong reason. It only became a witness after adding `!hosts/`. That is the same defect class I had just corrected in an existing fixture one commit earlier, committed by me, in the test written to prove I had fixed it. both controls at reviewed head d7f671e : FAILED (failures=2) HEAD : 23 tests, OK 66 suites referencing health-check / git_binary : 66 pass, 0 fail py_compile clean; review-checks PASS; live host WARN (unchanged) Still stacked on #2570 — merge that first. Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
john-the-dev
left a comment
There was a problem hiding this comment.
Fresh post-refresh review of exact head 0452082a0f8376c6f0b1502bd5f60cb518e00442. This merge head contains reviewed repair af092844 plus current main. Reviewer-run exact-head evidence: carrier 23/23, git resolver 27/27, shipped-default carrier 10/10, emit-task dedup 13/13, Slack watchdog 10/10, stuck-loop/queue-pileup 25/25, Python compilation, generated source-map check, diff whitespace, and REVIEW.md hardcoded-path scan all pass. Hosted checks are green. Worst-case disruption remains a non-actionable warning being accidentally delivered through a secondary alert surface; the explicit alerting: False predicate is exercised at task, notification, and Slack boundaries while ordinary warns remain alerting. APPROVE for current-head code correctness. Not yet merge-ready: obtain a second genuinely post-refresh maintainer approval; the earlier displayed approvals predate this merge commit.
… measurement Diff coverage fell to 93.8% after the rebase onto main — `src/health-check.py:1303-1304`. The rebase dropped #2570's lines out of the diff, so the denominator changed and these two surfaced as the only uncovered pair. They are the branch where check-ignore RAN and could not answer: an exit code that is neither 0 (ignored) nor 1 (not ignored), e.g. 128 on a broken repo. The existing control makes the call RAISE, which is a different line. Worth its own case rather than a coverage formality: the tempting shape is `if rc != 0: covered`, which folds 128 in with 1 and reports a path as carried on the strength of a failed read — the exact defect this probe exists to catch, and one #2566 shipped in the stale branch before review caught it. 93.8% (missing 1303-1304) -> 100% (0 of 32) 28 tests OK; witness confirmed: rc 128 -> status fail, names the entry as "could NOT measure", never as covered 66 suites referencing health-check / git_binary / the alert helpers: pass review-checks PASS Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ppened (#2576) I shipped a false claim into a user-facing health warning in #2570. Sutando-Pro flagged it; Chi had already corrected the underlying premise. The warning said re-adding `state/current-track.md` "re-creates the cross-host overwrite that destroyed a peer's anchor". Nothing was destroyed. The vault uses PER-HOST branches (`host/<host>/<wsid>`); a host only ever merges a peer INTO its own branch and never writes to the peer's, and `_resolve_conflicts_keep_ours` resolves on the local branch's merge result. Checked afterwards rather than argued: both branches were byte-identical, and this host's index referenced 263 memory files against the discarded copy's 262 — a strict superset, nothing missing. Pro independently confirmed it from that file's own two-commit history (added +459 by one sync, removed -459 by the other). The GUIDANCE is unchanged — do not re-add it — but the hazard is cross-host CONTENT DELIVERY on a shared path, not data loss: before: … re-creates the cross-host overwrite that destroyed a peer's anchor after: … puts two hosts on one file: a peer's copy lands in yours and each sync keeps its own side This matters beyond accuracy. An operator who later discovers the severity was invented discounts the whole warning, including the part that is true — and a health check trades entirely on being believed. Corrected in three places, not one: the warning text, the comment above it, and the test comment that repeated the claim. A retraction that fixes only the passage in front of you leaves the wrong version alive somewhere else — which is exactly how this survived my earlier retraction in chat, the pending-questions file and the peer channel. The new assertion forbids the false severity (`destroyed` / `data loss`) AND requires the warning still name why the path is unsafe, so the correction cannot be satisfied by deleting the reason instead of fixing it. new assertion against main's wording : FAILED (failures=1) HEAD : 23 tests, OK 67 suites referencing health-check / git_binary : 67 pass py_compile clean; gen-src-map up to date; review-checks PASS Stand: Echo Act IV Mini Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ngs (#2572) * fix(health-check): the dropped branch tests coverage, not config strings Closes #2571, reported by Sutando-Pro against #2566 minutes after it merged. `dropped` compared include STRINGS: dropped = [e for e in shipped if isinstance(e, str) and e not in resolved] A local entry can be strictly BROADER than the shipped one it replaces. On the reporting host: shipped : [... 'hosts/*/' ...] local : [... 'hosts/' ...] <- broader; whole subtree carried so the probe reported `hosts/*/` missing and advised "add them to the local list" — telling the operator to NARROW a config that was already correct. The irony is the useful part: this probe exists to catch "config claims carried, reality says not". This is the inverse — reality says carried, the config string says not — and it fired anyway. The `stale` branch already gets this right by asking git via `check-ignore --no-index`; only `dropped` reverted to string equality, and `_carrier_representative()` already did the resolution needed. An entry now counts as dropped only once git agrees nothing under it is carried. Same exit-code contract as the stale branch: 1 = not ignored = covered, 0 = ignored = genuinely dropped, anything else = a failed measurement that keeps being reported rather than counting as covered. An entry with nothing materialized yet stays reported. There is no outcome to measure, but the divergence is real and becomes silent data loss the moment the first file lands under it — pinned by its own test. One existing fixture had to be corrected, not just accommodated: `test_the_KNOWN_UNSAFE_entry_is_reported_but_never_recommended` built an exclude that UN-IGNORED `state/current-track.md` while asserting the entry was dropped. By outcome it was carried. It only passed because the branch never looked at disk; once the branch asks git, the fixture stopped describing the state it claimed to test. parent (#2570 head) : 21 tests, FAILED (failures=1) <- broader-entry witness HEAD : 21 tests, OK 66 suites referencing health-check / git_binary : 66 pass, 0 fail live host : WARN (unchanged by this PR; #2570's verdict) Stacked on #2570 — merge that first. Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(health-check): require ALL matches covered, and never let a failed measurement erase findings Both P1s from qingyun-wu on d7f671e. Both real, both mine. P1-1 — first-hit sampling is not coverage. `_carrier_representative()` returned the FIRST glob match, so a shipped wildcard matching several paths was judged on one sampled witness. A narrower local rule (`hosts/a/`) covers one child of `hosts/*/` while its siblings stay ignored, and a sample landing on the covered child reported the vault healthy with a whole host subtree unbacked. New `_carrier_representatives()` returns every materialized match and the coverage test now requires all of them. The single-witness helper stays for the stale branch, where one witness genuinely settles the question — that branch asks whether the entry THIS host configured is in effect, not whether one entry covers another. Enumeration is bounded by construction: glob matches are the entry's own direct matches, never a recursive walk of their contents. P1-2 — the code said one thing and did the other. A comment promised a failed measurement "keeps being reported"; the enclosing `except` reset `dropped = []`, so one entry's git timeout erased findings already collected and returned ok. Fail-OPEN in the probe whose whole purpose is catching silent non-backup. The config-read except is now narrow and does not wrap the measurement loop; per-entry failures land in `unmeasured`, which the verdict already treats as UNKNOWN. Worth recording how the first fix failed. My two-host fixture used `!hosts/a/` under a leading `*`, but gitignore cannot re-include a path whose PARENT is excluded — so BOTH hosts were ignored, first-hit sampling landed on an ignored path, and the test PASSED at the broken head for the wrong reason. It only became a witness after adding `!hosts/`. That is the same defect class I had just corrected in an existing fixture one commit earlier, committed by me, in the test written to prove I had fixed it. both controls at reviewed head d7f671e : FAILED (failures=2) HEAD : 23 tests, OK 66 suites referencing health-check / git_binary : 66 pass, 0 fail py_compile clean; review-checks PASS; live host WARN (unchanged) Still stacked on #2570 — merge that first. Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(health-check): cover the odd-exit-code half of a failed coverage measurement Diff coverage fell to 93.8% after the rebase onto main — `src/health-check.py:1303-1304`. The rebase dropped #2570's lines out of the diff, so the denominator changed and these two surfaced as the only uncovered pair. They are the branch where check-ignore RAN and could not answer: an exit code that is neither 0 (ignored) nor 1 (not ignored), e.g. 128 on a broken repo. The existing control makes the call RAISE, which is a different line. Worth its own case rather than a coverage formality: the tempting shape is `if rc != 0: covered`, which folds 128 in with 1 and reports a path as carried on the strength of a failed read — the exact defect this probe exists to catch, and one #2566 shipped in the stale branch before review caught it. 93.8% (missing 1303-1304) -> 100% (0 of 32) 28 tests OK; witness confirmed: rc 128 -> status fail, names the entry as "could NOT measure", never as covered 66 suites referencing health-check / git_binary / the alert helpers: pass review-checks PASS Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(health-check): a carrier DIRECTORY being un-ignored says nothing about the files in it john-the-dev and qingyun-wu, independently, on a958d06. Reproduced before fixing: exclude: * !hosts/ !hosts/*/ (note: no !hosts/**) check-ignore --no-index hosts/a -> 1 not ignored check-ignore --no-index hosts/a/current-track.md -> 0 IGNORED probe -> ok, "all 1 configured carrier path(s) un-ignored in the vault" A false GREEN in the probe whose only job is catching silent non-backup: the directory is un-ignored, the carrier file beneath it is not, and health said fine. A directory representative is now probed through the FILES beneath it, sorted for determinism and bounded by `_PROBE_FILES_PER_DIR`; any ignored one condemns the entry. The bound is honest about direction — past the cap this UNDER-reports, never over-reports, the same direction as the no-network ref staleness. Fixed in BOTH branches, not just the reported one. The stale branch probes a directory representative too and had the identical blindness; it now shares `_carrier_target_verdict`. That is the third time in this PR chain that fixing the reported instance would have left the same defect one step to the left, so this time the instrument is shared rather than duplicated. An instrument I tried and REJECTED, recorded because the suite caught it: `ls-files --others --ignored` answers the directory question in one exact call with no cap — but it is index-AWARE, so it calls a tracked file carried. That silently reverses `test_a_TRACKED_file_with_a_stale_exclude_is_still_reported`, which exists because a host that carried a file once and then let its exclude go stale read healthy forever while nothing NEW under that entry was carried. I wrote the ls-files version first, that test failed, and it was right. `--no-index` stays load-bearing. dir un-ignored / file ignored -> fail (was ok) same tree with !hosts/** (control) -> ok witness at a958d06 : FAILED (failures=1) HEAD : 30 tests, OK 67 suites referencing health-check / git_binary : 67 pass live host : WARN alerting=False (unchanged) Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(health-check): cover the bound, the empty directory, and the non-file representative Diff coverage 94.5% — src/health-check.py:1164,1170,1209, all three real branches of the new directory probe rather than coverage filler: 1170 the CAP being hit. An unenforced cap is just a slow unbounded walk, so the test pins the bound itself and that the sample is SORTED — an unsorted walk would make the probe's verdict depend on filesystem order. 1209 an empty carrier directory -> carried. `hosts/<label>/` can exist with nothing under it yet; inventing a failure there would fail a host that has done nothing wrong. The genuinely-absent case is reported by the callers instead. 1164 a representative that is neither file nor directory (dangling symlink) -> no targets, so git is never asked about a path that is not there. 94.5% (missing 1164,1170,1209) -> 33 tests, OK Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(health-check): the stale branch judged one host and called the wildcard carried john-the-dev and qingyun-wu, independently, on cf059ca. Reproduced before fixing: resolved == shipped == ["hosts/*/"] (so this is the STALE branch) exclude carries hosts/a's files, not hosts/b's hosts/a/current-track.md check-ignore rc = 1 hosts/b/current-track.md check-ignore rc = 0 _carrier_representatives -> ['hosts/a', 'hosts/b'] _carrier_representative -> 'hosts/a' verdict -> ok, "all 1 configured carrier path(s) un-ignored in the vault" Host b's subtree ignored and unbacked, health green. Why this survived the last round, which is the part worth recording: coverage has TWO independent axes — WHICH paths you probe, and WHAT you ask about each. Last round I shared the directory-vs-file instrument (`_carrier_target_verdict`) across both branches and called it fixing the class. It fixed one axis. The stale branch was still singular on the other, so `hosts/*/` collapsed to its first match. Generalizing one axis reads exactly like generalizing the defect. Both branches now enumerate every `_carrier_representatives()` match and share the same per-target instrument. same-config two hosts, partially carried -> fail (was ok) same-config two hosts, fully carried -> ok (control: the fix must not fail every wildcard) host b unmeasurable -> not ok (fail-closed preserved: enumerating must not weaken the contract) both witnesses at cf059ca : FAILED (failures=2) HEAD : 36 tests, OK 67 suites referencing health-check / git_binary : 67 pass live host : WARN alerting=False (unchanged) Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(health-check): sample the carrier subtree exhaustively, not the first 25 files john-the-dev on e146c2b. The directory probe took the first 25 files and a comment admitted it could "UNDER-report past the cap". That treated a stated caveat as an acceptable conclusion. Their counterexample: 26 files with only the 26th ignored returned `ok`, so a stale exclude left a real carrier file unbacked while health certified the subtree. In a probe whose entire purpose is catching silent non-backup, a sample is not proof of coverage. I did NOT take the suggested remedy — returning `unmeasured` when the count exceeds the bound — because it satisfies their first control and breaks their second: all 26 carried would report unmeasured rather than ok. Failing closed on COUNT trades a false green for a permanent unknown on any large carrier directory, and `notes/` on this host already holds 365 files. The cap existed for COST, not correctness, so the fix removes the cost instead: one `check-ignore --no-index --stdin` call per representative answers for every file at once. Exhaustiveness now costs a filesystem walk plus a single process, not N processes. 26 files, 26th ignored -> fail (was ok) 26 files, all carried -> ok (the control the count-based fix breaks) 26 files -> exactly ONE check-ignore call, pinned, so a future refactor cannot quietly restore the per-file loop and with it the pressure to sample One existing control had gone stale with the instrument and I nearly shipped it: the fail-closed test stubbed on `argv`, but paths travel via STDIN now, so the stub stopped matching and the test passed WITHOUT EVER FIRING. Re-keyed on the input and verified the stub actually fires (1 invocation) rather than trusting the green. 3 witnesses at e146c2b : FAILED (failures=3) HEAD : 38 tests, OK 67 suites referencing health-check / git_binary : 67 pass live host : WARN alerting=False, exhaustive walk under 1s Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(health-check): two stubs stopped firing when the instrument changed Found while chasing the last uncovered line. Both measurement-failure controls keyed their stub on `argv`, but paths travel through `check-ignore --stdin` now — so neither stub matched, and both tests kept passing because `data/` is dropped for an ordinary reason anyway. stub fired 0x -> status fail (the assertion it makes is true regardless) Vacuous, and silently so: nothing in the suite could tell the difference between 'the unmeasured path works' and 'the unmeasured path was never entered'. That is the same shape as a probe that reports healthy because it never looked, which is the defect this entire PR chain is about — reproduced inside its own tests. Re-keyed on the input, and both now ASSERT THE STUB FIRED before asserting anything else, so they cannot go quietly vacuous again. Also tightened both to require 'could NOT measure' in the detail rather than merely != ok — otherwise an ordinary drop satisfies them. coverage 98% -> 100% (the dropped branch's unmeasured line was unreachable precisely because the stub never fired) 38 tests OK; 67 suites pass Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(health-check): NUL-delimit the batch — a filename can contain a newline john-the-dev on 73a9167. Reproduced before fixing, on a tree built so the two answers genuinely differ: notes/z\nx.md check-ignore -q -> 0 IGNORED, not backed up split halves notes/z -> 1, x.md -> 1 both un-ignored newline-joined batch -> 1 reads CARRIED — false green NUL-joined with -z -> 0 dropped — correct Batching with `"\n".join(...)` split one real path into two bogus ones, and because both halves were un-ignored the genuinely ignored carrier file read as carried. NUL is the only delimiter a POSIX filename cannot contain, so the fix is the delimiter itself rather than an escaping scheme that would have to be right forever. Note the shape: making the probe exhaustive (removing the 25-file cap) is what introduced the batch, and the batch is what introduced the delimiter assumption. Each fix was correct and each created the next seam — which is the argument for the reviewer's insistence on an explicit witness per round rather than trusting that the previous round settled the class. The regression ASSERTS ITS OWN FIXTURE first — real file ignored, both halves un-ignored — because a gitignore nuance could otherwise make it pass without ever discriminating the two answers, which is the failure mode I shipped twice today in other tests. witness at 73a9167 : FAILED (failures=1) HEAD : 39 tests, OK 67 suites referencing health-check / git_binary : 67 pass live host : WARN alerting=False (unchanged) Stand: Echo Act IV Mini Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both sides added a new function at the same insertion point in `src/health-check.py`: `_local_core_alive` here, `_alerts_suppressed` on main (#2570). They are independent, so the resolution keeps both. Verified past conflict-free, since a clean merge is not a correct merge: - both functions present exactly once; main's has all 5 of its call sites - tests/health-check-recover-core.test.py — all cases incl. the new r and s - main's own suites for the function it added: summary-warnings, notify-slack, emit-task — all pass, so `_alerts_suppressed` is not regressed by the union - the revert control still bites after the merge: reverting the actuator default fails case s Stand: Echo Act IV Pro
Follow-up to #2566, found by running the merged probe on a live host.
The bug
That host had deliberately un-carried
state/current-track.mdto stop overwriting a peer's anchor — the correct state. The merged probe said:It named the exact command that re-carries the path and resumes the cross-host overwrite (#2567).
@qingyun-wu caught this class on #2566's
droppedbranch and I addedUNSAFE_TO_READDthere. Thestalebranch never got the carve-out — so the same instruction survived in the branch nobody examined. Fixing the reported instance rather than the class.The fix
In the stale branch the carve-out inverts the verdict rather than softening wording — not carrying a path that must not be carried is success:
Notes
Two existing tests used that path as their example while actually testing stale detection and the
--no-indexcontract. Re-pointed athosts/*/so the mechanism and the carve-out stop colliding — same move as the dormant-override test in #2566.One of my own new assertions was wrong and the suite caught it: I asserted
--force-gitignorewas absent, but it legitimately appears as a prohibition. Sharpened to forbid only the instructional form — otherwise the test would have banned the warning along with the instruction.Stand: Echo Act IV Mini
🤖 Generated with Claude Code