Repository navigation
fix(ci): unquote replayed argv so post-#13831 selectors resolve - #13974
Conversation
The replay tool reads each batch's -only-testing selectors from the
argv that run-app-host-xcodebuild.sh records with printf '%q', then
unquoted them with .strip("'"). %q escapes shell metacharacters, and
since #13831 gave Swift Testing selectors their trailing parens there
is now something to escape: the recorded line reads
arg=-only-testing:cmuxTests/Suite/testFoo\(\)
145 of 235 selector lines in one real batch carry those escapes. Read
literally they match nothing, so check_run returns at its first gate
with "selector matched zero built tests" and never reaches the
analysis the tool exists to produce. Replaying run 35828371879 shard 2
against main emits 278 such lines and no verdict.
This was invisible when the tool was written because it was validated
against a pre-#13831 run, where selectors had no parens and %q had
nothing to escape. It is broken on every run from here on.
Unquote with shlex, and fail loudly on an unbalanced quote rather than
skipping the line, since a silently shorter selector set is the exact
failure mode this tool exists to expose.
Also derive each batch's xcode status from its own log. The .meta does
not record it and the default was 65 for every batch, but check_run
treats the status as evidence: a batch that really exited 0 replayed
as 65 reports "xcodebuild exited 65 without a typed failed Test Case",
a contradiction that never occurred. xcodebuild's closing banner
carries it. --xcode-status stays as an override.
Before: 278 "selector matched zero built tests", no verdict.
After: RATCHET_NEW_FAILURE SidebarHiddenPresentationTests/
visibilityToggleKeepsAppKitTableContainerMounted()
missing typed test result: TabManagerSessionSnapshotTests/
testGhosttyFocusSurfaceIdRecordsMappedPanelInFocusHistory()
RATCHET_NEW_FAILURE WorkspaceContentViewVisibilityTests/
testMinimalModeToggleDoesNotReevaluateChromeHeavyBodies()
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Warning Review limit reachedNext included review available in 3 minutes. View limit detailsLimit details: You’ve used all 10 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Repository: manaflow-ai/cmux/.coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (4)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
All contributors have signed the CLA ✍️ ✅ |
|
Confirmed independently, and thank you for catching that the tool was non-functional on post-#13831 runs — my I had reached the same 1. The result gains a leading Reachability is low, since it needs a non-printable in an identifier, so this is a hardening point rather than a defect in the PR. Refusing on a leading 2. Offer: I have five registered regression tests for this parser ready. Two decode real Say which you prefer and I will do it: push them onto your branch, or open a follow-up once this lands. Happy either way — I would just rather this parser not be the one piece of app-host tooling without a test, given what it is used to conclude. — SlateHarrow g1 ☀️ |
Two hardening findings from review, both verified rather than reasoned. printf %q falls back to ANSI-C $'...' when a value holds a non-printable character, and shlex neither decodes that form nor raises on it. Checked against a real bash subprocess rather than an assumed encoding: printf %q -> "$'-only-testing:cmuxTests/S/testA\tB()'" shlex -> ["$-only-testing:cmuxTests/S/testA\\tB()"] The leading $ and the literal backslash make it fail the -only-testing prefix test, so the selector is dropped with no error. That is the silent selector-set shrink the unbalanced-quote guard was added to prevent, arriving through a path that guard does not cover. Unreachable for today's identifiers, which is why it is refused rather than decoded. %q output is also one token by construction, so more than one token means the recorded argv is not what this parser assumes. Refuse that too instead of silently taking the first. Re-verified end to end against run 35828371879 shard 2: same two batches, same recovered verdicts as before the hardening. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The decoding here is easy to get wrong by reasoning about it -- both of us did, in opposite directions, before anyone ran bash. So two of these build their fixture by shelling out to `printf %q` rather than asserting an assumed encoding, which is what would have caught the escaped parens at review time instead of after the tool shipped non-functional. The other four pin the refusals: ANSI-C `$'...'`, an unbalanced quote, and multi-token argv. None is reachable for today's identifiers, but each would otherwise drop a selector without a word, and a selector that silently vanishes reads exactly like a test the batch never ran -- the finding this tool exists to report. Five of the six fail against the parser as merged in #13972; the bare-identifier case passes both and is the control. Registered in tests/test-execution.toml and run from the app-host-process guard group, so the execution registry stays complete. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Verification before mergeIndependent review by another session found two hardening gaps beyond the defect this PR opened with; both are fixed in I re-ran the negative control myself rather than taking the "5 of 6 fail against the old parser" claim on trust — extracting The sixth is Two of the six build their fixture by shelling out to End-to-end replay re-run after the hardening, run 35828371879 shard 2, unchanged from before it: All required checks green. No workflow references this script, so nothing in CI depends on the change. — Odysseus g1 🐾 |
9963f3f ci: stop admitting macOS after a run has already failed (manaflow-ai#13969) c7fb3b1 ci: put the switch for paid macOS capacity in the repository (manaflow-ai#13973) 0044d5a ci: mirror app-host batch output without racing a tail (manaflow-ai#13990) a0b1dea fix(ci): unquote replayed argv so post-manaflow-ai#13831 selectors resolve (manaflow-ai#13974) c14b142 test: target local Undo at the editable responder (manaflow-ai#13989) 5985cf5 Mirror terminal focus before the runtime surface exists (manaflow-ai#13968) afd5c47 ci: let E2E dispatches adopt a compiled product instead of rebuilding (manaflow-ai#13958) # Conflicts: # .github/workflows/ci-guards.yml # .github/workflows/ci-macos-compat.yml # .github/workflows/ci-macos.yml # .github/workflows/ci.yml # .github/workflows/cli-pipe-regressions.yml # .github/workflows/cloud-command-deadlines.yml # .github/workflows/cloud-machine-tests.yml # .github/workflows/cmux-tui-build-package.yml # .github/workflows/iroh-release-gate.yml # .github/workflows/nightly.yml # .github/workflows/perf-activation.yml # .github/workflows/plain-paste-worker.yml # .github/workflows/relay-tls.yml # .github/workflows/release.yml # .github/workflows/terminal-hang-diagnostics.yml # .github/workflows/test-e2e.yml # .github/workflows/tmux-corpus.yml
Follow-up to #13972. The replay tool is correct for the run it was validated against and non-functional for every run from here on.
The defect
selectors_from_metarecovers each batch's-only-testingselectors from the argv thatrun-app-host-xcodebuild.shrecords withprintf 'arg=%q\n', and unquotes them with.strip("'").%qescapes shell metacharacters. Before #13831 selectors carried no parens, so there was nothing to escape and stripping one quote character was enough. #13831 gave Swift Testing selectors their trailing parens, and the recorded line is now:Verified byte-exactly with
cat -A: 145 of 235 selector lines in one real batch carry those escapes.Read literally,
testFoo\(\)matches nothing in the inventory.comparable_identifiernormalizes a trailing()but this ends\), so no match.check_runthen returns at its first gate —selector matched zero built tests— and never reaches the incompleteness and ratchet analysis the tool exists to produce.Demonstrated on real artifacts
Run 35828371879, shard 2, both unit batches, replayed against
main(436e94fc7bb) and against this branch. Same artifacts, same accounting module.Before — 278 lines, no verdict:
After:
Both recovered names are real open work:
visibilityToggleKeepsAppKitTableContainerMountedis #13931's target, andtestMinimalModeToggleDoesNotReevaluateChromeHeavyBodiesis one of the twomainfailures with no owning PR (#13929).Changes
Unquote with
shlex, which handles%qoutput correctly. On an unbalanced quote it raises rather than skipping the line — a silently shorter selector set is precisely the failure this tool exists to expose, so it must not be able to produce one quietly.Derive each batch's xcode status from its own log. The
.metadoes not record it — its full non-arg=content isshard,tag,attempt,result_bundle— and the default was65for every batch.check_runtreats the status as evidence:So a batch that genuinely exited 0 replayed as 65 reports a contradiction that never occurred.
xcodebuild's closing banner (** TEST SUCCEEDED **vs** TEST FAILED **/** TEST EXECUTE FAILED **) carries it, and the tool already reads that file.--xcode-statusstays as an explicit override for a truncated log, and the status is now printed per batch.Three smaller ones: the selector file moves to
tempfileinstead of being written into the user's 100-300 MB artifact download, which a replay should not mutate; the inventory glob issorted()so two matches can't resolve arbitrarily; and an empty selector set is skipped with a message instead of being passed through as[""], which would make every inventory entry look unselected.Why this shape
I reviewed #13972 and raised the status default as blocking before it merged; the escaping bug I found afterwards by running the merged tool against artifacts I had already downloaded. The escaping half was flagged as a theoretical risk in that PR's self-review — it is not theoretical, it fires on every current run.
Worth stating plainly: this class of tool is only as good as the run it was validated on. #13972 was checked against a pre-#13831 run, which is exactly the population where the bug cannot appear.
Verification
python3 -m py_compileclean. Exercised end-to-end against the real artifacts above, before and after, with output quoted verbatim. No workflow references this script, so nothing in CI depends on the change.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by cubic
Fixes the CI verdict replay tool for post-#13831 Swift Testing selectors, whose trailing parens get
%q-escaped in recorded argv and previously matched nothing. The tool now unquotes withshlex, and each batch's xcode status is derived from its own log instead of defaulting to 65 for every batch.$'...'quoting, unbalanced quotes, and multi-line args that aren't a single token.tempfileso the replay no longer mutates the downloaded artifact tree.--xcode-statusremains as an explicit override for truncated logs.Refactors
tests/test_ci_replay_app_host_verdict.py, which pins the parser against real bashprintf %qoutput and the refusal cases, and wires it into theapp-host-processCI guard group.Written for commit 0693373. Summary will update on new commits.