Repository navigation
feat(ci): enforce artifact retention from one policy table - #10478
Conversation
… days patch-*, dependency-verdict-* and findings-* are downloaded only inside the run that uploads them. patch-* goes from 7 to 3 days so a manual write-job re-run still works over a weekend; dependency-verdict-* and findings-* go to 1 day. The verify reader pages every artifact, so fewer live artifacts means fewer pages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every actions/upload-artifact step in .github/workflows and .github/actions must now set retention-days equal to its artifact family's row in .github/artifact-retention.json. A row gives the days, the readers that need the artifact and the reason for that length; `max` (90) also names the reader that needs it. Rows the inventory found over-long carry a pending-cut note and keep today's value. Three families with no reader after their run drop from 30 to 7 days: selection-audit-*, selection-red-replay-* and eval-browser-*. scripts/check-artifact-retention.sh runs in lint-repo behind the workflows filter group, with its contract test and fixtures. The three pr-verify verdict uploads, which relied on the repository default, now state retention-days: 90, the same value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ch-findings' into feat/artifact-retention-policy
…ention cuts in the policy table Stacks on perf/lane-artifact-retention-patch-findings so the table and the workflows agree in either merge order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
claude-security-review reviewed No security issues found in this pull request. critical-findings: 0 I read the whole diff (14 files) and the PR context. I also read the Trusted-path files
Retention changes
Manifests: no Instruction-surface deletions: none. Cost: nothing here can start a real charge. The shorter retention reduces artifact storage. |
|
claude-review reviewed No blocking findings. I read the full diff and the PR context, and checked the CI wiring and the What I checked
Not counted as findings
|
|
The pr-unblock lane stopped on this pull request and needs a person: the lane could not resolve every conflict.
To resume, deal with the reason above, remove the gh workflow run pr-unblock.yml -R melodic-software/claude-code-plugins -f pr-number=10478 -f activity=resolve-conflicts |
Main's #10477 sets pr-verify verdict retention per verdict (PASS 30, FAIL 90) through a write-verdict.mjs step output, which collided with this branch's literal retention-days: 90 (duplicate keys). Keep main's computed value; the policy table gains a computed-by field so the checker accepts that one expression for a row that names its script, and the pr-verify-* row drops its pending-cut, now made. Add the mutation-range row main's post-merge-select-mutation-range.yml needs. Keep findings-* at 3 days so a manual re-run of the file job still finds them (claude-review thread on artifact-retention.json). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The pr-unblock lane escalated this pull request as |
|
The pr-unblock lane stopped on this pull request and needs a person: a conflicted path is a workflow, submodule config or a settings file, which the lane does not resolve.
To resume, deal with the reason above, remove the gh workflow run pr-unblock.yml -R melodic-software/claude-code-plugins -f pr-number=10478 -f activity=resolve-conflicts |
Main's #10470 sets findings-* retention to 1 day; this branch chose 3 days after that change, so a manual re-run of the file job still finds the findings over a weekend (claude-review thread on artifact-retention.json). Keep 3 in the workflow and the table. Main's #10488 adds the pr-merge-verify-listing upload (1 day, read by the next run through listing-carry.mjs); add its row so the retention checker passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The pr-unblock lane escalated this pull request as |
|
Unattended merge: risk HIGH at head |
… 1 day main added the pr-merge-alerted-<id> upload after this table, so check-artifact-retention failed in the merge queue. Its only reader, babysit_postmerge.py --lane-alerted, is asked only for full runs created within pr-merge.yml's LOOKBACK_HOURS (6), so the 1-day minimum covers it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No related issue: owner direction 2026-10-27 (enforced artifact retention; the verify reader pages every artifact)
Summary
Nothing checked artifact retention. An
actions/upload-artifactstep with noretention-dayskeeps its artifact for the repository default of 90 days, and every kept artifact lengthens the repository-wide listing thatbabysit_verify_evidence.pypages through on each read. This adds one checked-in policy table and a PR-time check that holds every upload to it.Fix
Table:
.github/artifact-retention.json, validated against.github/artifact-retention.schema.json. One row per artifact name family (40 rows), each withretention-days,readers(each starting with a repository path the check confirms exists) and thereasonthat length is needed.max(90) is the only way to write 90, and amaxrow must name amax-readerfrom its readers. The table sits beside the other repo-owned CI config (lane-funding.json,runner-policy.json) rather than indocs/conventions/: ADR 0064 covers plugin and skill customization, and under.github/an edit to the table alone still triggers the gate through theworkflowsfilter group.Three cuts, every other row at today's value.
selection-audit-*,selection-red-replay-*(maintenance-audit-test-selection.yml) andeval-browser-*(eval-browser-dispatch.yml) drop from 30 to 7 days..work/gh-monitor/storage-2026-10-27/REPORT.md.perf(ci): shorten lane patch, dependency-verdict and findings artifact retention #10470's lane cuts are in the table:
patch-*,dependency-verdict-*andfindings-*keep 3 days.findings-*stays at 3, not 1, because thefilejob downloads it (maintenance-audit-lane-runs.yml), so a manual re-run of that job a day later must still find it.Over-long rows are marked, not changed.
skill-reply-*carries apending-cutnote (owner decision) and keeps today's value.pr-merge-dispatched-*andpr-merge-summaryare marked as under owner review.pr-verify follows perf(pr-verify): keep PASS verdicts 30 days and FAIL verdicts 90 #10477.
write-verdict.mjsretentionDayskeeps FAIL 90 days and PASS or PASS-NOTES 30, passed to the upload as${{ steps.verdict.outputs.retention-days }}. The row recordsmax(the longest) and names the script in a newcomputed-byfield; the check accepts that one expression only for a row namingcomputed-by, and the script must exist. FAIL stays at 90 becausebabysit_verify_evidence.pysetsTOO_OLD_DAYS = 80andscripts/credential-sweep.shdefaults--sinceto 90 days.Check:
scripts/check-artifact-retention.sh(logic incheck-artifact-retention.mjs, YAML parsed with theyamlpackage and the table validated withajv, both from the runner-policy install). It reads every upload step in.github/workflows/*.ymland.github/actions/*/action.yml. It fails on any of these: a step with noretention-days, a non-literal value (other than acomputed-byrow's step output), a value that differs from the row, a name that matches no family, or a row that matches no step. Matching rule, stated in the script header:<literal text before ${{>*exactly.uploadslists<file>#<job id>.Wiring: a
lint-repostep inpr-require-checks.yml, gated onrun_workflowslikeapp-key-referencesand fed to the aggregator. It is also registered incheck-affected-gates.txtand in the check-script contract registry.pr-verify: the three verdict uploads (
pr-verify.ymljobscheck-intent,check-intent-subscriptionandcheck-intent-fallback) keep main's computedretention-days. Thecarry-run-cache.mjsRETENTION_DAYScomment namesretentionDaysand the table row.mutation-range: a 7-day row for main's
post-merge-select-mutation-range.ymlupload, read bypost-merge-test-mutation.ymlonworkflow_run.Docs: a new README section, "Artifact retention", next to the check-script contract. The check's failure message also names the table and the row fields.
Verification
scripts/check-artifact-retention.test.sh: 23 passed, 0 failed (adds acomputed-byrow passing a step-output retention, the same step failing withoutcomputed-by, and acomputed-bynaming no file). The fixtures cover a missing retention-days, an unknown family, a mismatch, a prefix-only match, a composite action upload, a computed name,maxwithout or outside its readers,90written as a number, a missing reader file, a stale row, environment exits, and the real repository.scripts/check-artifact-retention.sh --checkon this tree: 50 upload steps match 40 families. After merging main:carry-run-cache.test.mjs19/19,pr-verify/workflow.test.mjswithwrite-verdict.test.mjs35/35.scripts/workflow-self-paths.test.sh40/40,scripts/check-affected-gates.test.sh13/13 andscripts/check-docs-only-gate.test.sh88/88.scripts/check-docs-only-gate.sh --checkandscripts/aggregate-hygiene-results.sh --self-testpass.scripts/check-script-contract.test.sh: 57 passed, including the new row's environment case. The 2 failures arecheck-html-assets.shwith no rootnpm cion the local host; they are unrelated.actionlintis clean on the five changed workflows..github/actions/resolve-config/callers.test.mjspasses 190/190, andpr-verify/workflow.test.mjswithcarry-run-cache.test.mjspass 36/36.scripts/check-affected.sh: 11 passed, 3 skipped. No changelog fragment is required, since no plugin changed.Related
Includes perf(ci): shorten lane patch, dependency-verdict and findings artifact retention #10470 (lane patch, dependency-verdict and findings retention), so the table matches the workflows whichever merges first.
Pending retention cuts from the 2026-10-27 inventory, each shipping separately:
skill-reply-*to 3 days (owner decision).verdict-*artifacts (owner decision).poteto's FAIL-marker redesign: known-name FAIL marker artifacts, so FAIL lookups become
name=reads instead of a full listing. Their rows will be added here when that lands.🤖 Generated with Claude Code