Skip to content

fix(ci): stop ten artifact uploads discarding their hidden paths - #2091

Merged
thymikee merged 2 commits into
mainfrom
claude/upload-artifact-hidden-paths
Aug 27, 2026
Merged

fix(ci): stop ten artifact uploads discarding their hidden paths#2091
thymikee merged 2 commits into
mainfrom
claude/upload-artifact-hidden-paths

Conversation

@thymikee

Copy link
Copy Markdown
Member

actions/upload-artifact has excluded hidden files and directories by default since v4.4, and this repository pins v4.6.2 and writes most of its diagnostics under .tmp. Ten upload steps across seven files were therefore uploading nothing from those paths.

workflow artifact if-no-files-found
macos.yml host XCTest xcresult bundle warn
mutation-affected.yml ×3 report, shards, lane envelope warn / unset
mutation-weekly.yml ×2 report, shards warn / unset
replays-nightly.yml fuzz output ignore
xctest-nightly.yml results warn
test-app-build-cache.yml fixture tarball error
1874-diagnose.yml per-iteration logs ignore

Most pair the omission with warn or ignore, so they fail silently. test-app-build-cache sets error, so that one does not.

How it surfaced

The #1874 diagnose loop was dispatched to collect per-iteration logs. The summary arrived with its cadence excerpt and none of the logs it points at.tmp is hidden, so every per-iteration log that workflow has ever kept had been discarded. Checking whether anything else did the same found nine more.

Why a guard rather than a wrapper

A shared upload wrapper would be a shallow mirror of the action's options across artifacts with genuinely different owners — mutation reports, fixture caches, XCTest bundles, session diagnostics. The policy question is one rule ("a hidden path needs the flag") and belongs in one place; the artifact itself belongs to the workflow that produces it. test/ci/upload-artifact-hidden-paths.test.ts centralises the policy and leaves each workflow declaring its own artifact.

Validation

Parse-only, no device lane. The guard walks every workflow and composite action; dropping any single flag turns it red (verified against xctest-nightly.yml). Format, lint, typecheck and test/ci green.

Not claimed: that this explains any specific past failure. The last eight Test App Build Cache runs on main are green, and the most recent published zero artifacts — consistent with no rebuild being selected, which proves nothing either way about the upload path.

Split out of #2059 on review; that PR keeps the diagnose-loop behaviour and will drop its duplicate of these changes once this lands.

`actions/upload-artifact` has excluded hidden files and directories by default
since v4.4 (this repository pins v4.6.2), and most diagnostics here are written
under `.tmp`. Ten upload steps across seven files therefore uploaded nothing
from those paths: macos.yml's xcresult bundle, both mutation lanes' reports and
shards, replays-nightly's fuzz output, xctest-nightly's results,
test-app-build-cache's fixture tarball, and 1874-diagnose's per-iteration logs.

Most fail silently, since they pair the omission with `if-no-files-found: warn`
or `ignore`. test-app-build-cache sets `error`, so that one does not.

A structural guard rather than a shared upload wrapper: the wrapper would be a
shallow mirror of the action's options over artifacts with different owners,
while the policy question — a hidden path needs the flag — is one rule that
belongs in one place. Each workflow still declares its own artifact.

test/ci/upload-artifact-hidden-paths.test.ts holds it across every workflow and
composite action, and is red if any single flag is dropped.
@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
JS raw 2.48 MB 2.48 MB 0 B
JS gzip 834.0 kB 834.0 kB 0 B
npm tarball 957.2 kB 957.2 kB 0 B
npm unpacked 3.32 MB 3.32 MB 0 B

npm unpacked components

Component Base Current Diff
JS / dist source 2.63 MB 2.63 MB 0 B
Apple runner source/project 581.1 kB 581.1 kB 0 B
macOS helper source 54.8 kB 54.8 kB 0 B
Android helper artifacts 0 B 0 B 0 B
Other package files 45.3 kB 45.3 kB 0 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 29.1 ms 28.1 ms -1.0 ms
CLI --help 81.0 ms 79.1 ms -1.9 ms

Top changed chunks: no changes in the largest emitted chunks.

Top changed packed files

No changed packed files.

thymikee added a commit that referenced this pull request Aug 27, 2026
…ents

The hidden-path upload fixes and their guard move to #2091, per review: one
rule, ten uploads, artifacts with different owners. This branch keeps the
diagnose loop's own behaviour.

Comments cut to the rule added in #2087. What the narration explained now lives
in names and types — `MeasuredVerdict` separates xcodebuild's three words from
the two the loop derives, `exitContradictsMeasured` names the rule that a
nonzero exit outranks a green measured test, and each shape's `name` says what
the case is. Two constants remain, citing measured CI numbers that cannot be
encoded.

The entry-point test spawns once rather than once per shape. Nine
`--experimental-strip-types` subprocesses made it slow and contention-sensitive
in a lane that runs it alongside other subprocess tests, and they were
re-covering what the direct table already asserts; one representative invocation
proves the wiring. 3.7s to 0.07s.
@thymikee

Copy link
Copy Markdown
Member Author

[P2] Make the hidden-upload guard cover every supported config file. configuredFiles() accepts only *.yml and assumes one-level action.yml, but GitHub supports workflow .yaml, action.yaml, and nested local-action directories. A hidden upload in any of those valid shapes bypasses this structural gate. Discover both extensions recursively and plant the missing-shape violation red. Also remove the new action-version/history comment from the test under current main’s implementation-comment rule. Current static paths are otherwise correctly covered and exact-head CI is green.

thymikee added a commit that referenced this pull request Aug 27, 2026
…my revert orphaned

Two review findings on the diagnose loop.

The upload step carried a comment describing an `include-hidden-files` input it
does not set: I split that fix out to #2091 and my revert removed the line but
left the prose. Comment gone. The flag itself arrives with #2091, which carries
this workflow's upload along with the nine others.

The `rc` fix was only asserted through `readIteration`, so dropping or
miswiring the CLI argument would have restored the false pass and the lost
evidence with the suite still green. The entry-point test now runs both an
`rc=0` slow pass and an `rc=65` green measured test, asserting the printed
verdict, the summary line's `rc=`, and the evidence file. Verified red against
both mutations: hardcoding `0` for the argument, and dropping the rule that a
nonzero exit outranks the measured verdict.

Remaining comments are the module's one-line pointer to its caller and the
measured CI numbers behind SLOW_PASS_MS.
The guard read `.github/workflows/*.yml` and assumed local actions live one
directory deep as `action.yml`. GitHub also reads `.yaml` for both, and local
actions nest, so a hidden-path upload in any of those shapes passed the gate.

It now walks the `.github` tree recursively for either extension, and a second
test plants the three shapes the old scan missed and asserts all three are
found — executable rather than a one-off manual check. Red against narrowing the
extension, against dropping the recursive walk, and against removing any single
real flag.

Also drops the action-version note under the comment rule in #2087; the version
behaviour belongs in the PR, and the assertion message already says what the
omission costs.
@thymikee

Copy link
Copy Markdown
Member Author

Fixed in 8f90ef5dcb.

The scan was too narrow — you are right on all three shapes. It read .github/workflows/*.yml and assumed local actions sit one directory deep as action.yml. GitHub also accepts .yaml for both, and local actions nest. It now walks the .github tree recursively for either extension: 34 YAML files, up from the 24 the old shape reached.

Rather than plant the violation by hand once, the shape coverage is now a second test: it fabricates the three shapes the old scan missed — workflows/*.yaml, a nested actions/a/b/action.yaml, and a shallow actions/a/action.yml — and asserts all three are reported. That stays true as the repo grows.

Planted red three ways:

scan misses .yaml       -> caught
scan is not recursive   -> caught
a real flag dropped     -> caught

Action-version comment removed under the #2087 rule. The v4.4 default change is PR history, and the assertion message already carries what the omission costs.

🤖 Addressed by Claude Code

@thymikee

thymikee commented Aug 27, 2026

Copy link
Copy Markdown
Member Author

Re-reviewed exact head 8f90ef5dcb: all ten hidden-path uploads opt in, and the guard recursively covers both YAML extensions plus nested local actions with planted missing-shape proof. No remaining code/comment-policy finding; exact-head CI and all native smokes are green, CLEAN/MERGEABLE. Merge-ready.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Aug 27, 2026
@thymikee
thymikee merged commit 539e848 into main Aug 27, 2026
21 checks passed
@thymikee
thymikee deleted the claude/upload-artifact-hidden-paths branch August 27, 2026 18:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant