feat(macos): name the files a sweep could not refresh, up to a bound - #150
Merged
h1d3mun3 merged 1 commit intoJul 28, 2026
Merged
Conversation
The sweep reported counts only — "ok=40 unstable=1". That answers "is one file wrong or are hundreds?", which is what changes how alarmed to be. It does not answer "which one", which is what decides whether to care at all: `unstable` on a build artefact while a host-side build is running is expected; the same verdict on a source file is not. The remedy is identical either way (`down --macos && up --macos`), so this is diagnosis rather than action. That is exactly why it is bounded: a host-side build running during a sweep can legitimately leave hundreds of files `unstable`, and the attach-path warnings go to the operator's terminal. The guest now prints its counts on the FIRST line — the host still reads that as the summary, so the existing verdict matching is unchanged — and below it up to _MACOS_SWEEP_DETAIL (5) lines naming individual failures, then "and N more". The truncation is stated rather than silent, because a list that quietly stops at five reads as "there were only five". Only the three classes the host actually warns about are named: `unstable`, `nomap`, `msyncfail`. `gone` and `empty` are normal — a file removed by a build between the host's `find` and the guest's `open` is routine, and naming those would turn the warning into noise nobody reads. Filenames are sanitised for display. macOS permits a newline in a filename, and an unsanitised one would split a single failure across two output lines, so the host would print half a path as though it were a second failure. There is a test for that, driven with a real newline in a real filename. tests/41 gains six assertions: the counts stay on line one, the cap holds at the requested value, the truncation notice appears, a clean sweep prints nothing but the summary, a newline-bearing filename stays on one line, and the host surfaces both the named file and the notice. Two existing assertions needed updating for the new shape rather than for a defect: one compared the whole output where it now means the summary line, and one asserted the retry count was the final argument when the detail cap is now last. The second is stronger for it — it pins both arguments in order, so a swap that gave 5 retries and named 3 failures no longer passes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
🧭 Egress drift reminderThis PR changes the egress core ( If this change alters the egress posture, please:
Non-blocking reminder. It does not verify correctness (that is the egress fail-closed E2E + |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to the merged #124 / #135 series, branched from the current
stack/virtiofs-staleness-2026-07.Why
The sweep reported counts only:
That answers "is one file wrong or are hundreds?" — which is what changes how alarmed to be. It
does not answer "which one", and that is what decides whether to care at all:
unstable /…/.build/foo.ounstable /…/src/main.swiftThe remedy is identical either way (
down --macos && up --macos), so this is diagnosis, notaction — which is exactly why it is bounded rather than exhaustive.
What changed
The guest prints its counts on the first line — the host still reads that as the summary, so the
existing verdict matching is unchanged — and below it up to
_MACOS_SWEEP_DETAIL(5) lines namingindividual failures, then
and N more.The truncation is stated, not silent. A list that quietly stops at five reads as "there were only
five", which is the failure class this whole series exists to remove.
Only the three classes the host actually warns about are named —
unstable,nomap,msyncfail.goneandemptyare normal: a file removed by a build between the host'sfindandthe guest's
openis routine, and naming those would turn the warning into noise nobody reads.Filenames are sanitised for display. macOS permits a newline in a filename, and an unsanitised one
would split a single failure across two output lines — so the host would print half a path as though
it were a second failure. Tested with a real newline in a real filename.
Tests —
tests/41, 47 → 55 assertionsSix new ones: counts stay on line one, the cap holds at the requested value, the truncation notice
appears, a clean sweep prints nothing but the summary, a newline-bearing filename stays on one line,
and the host surfaces both the named file and the notice.
Two existing assertions were updated for the new shape, not for a defect — one compared the whole
output where it now means the summary line, and one asserted the retry count was the final argument
when the detail cap is now last. The second is stronger for it: it pins both arguments in order,
so a swap that silently gave 5 retries and named 3 failures no longer passes.
Mutation check — 6/6 detected
make offline-tests→ ALL GREEN (29 scripts).Scope
No behaviour change to the sweep itself — same files invalidated, same verdicts, same remedy. This
only widens what the operator is told when something goes wrong, and the failure path it reports on
has never fired in a real environment; it is reachable by construction, not observed.
🤖 Generated with Claude Code