Repository navigation
feat: nightly release-readiness summary (wiki page) - #655
juhovainio wants to merge 17 commits into
Conversation
rominf
left a comment
There was a problem hiding this comment.
🔴 Automated review · pr-review-watcher · 7235dd9
This automation never files a GitHub approval, so no approving review will
appear here whatever the outcome — the merge decision stays with a human
reviewer.
Round 1 — every finding below is new this round.
Review — needs work
Full review of the whole change.
No ticket named. The description misstates the change: see the last two blocking findings.
Blocking
-
The GO verdict fails open when the E2E evidence is missing —
xtask/src/release_readiness.rs:312-319,xtask/src/release_readiness.rs:495-498,.github/workflows/nightly.yml:1735-1781
total_e2e_failuresreturns.unwrap_or(0)when there is no| **Total**row. That is whatconsolidated_summary_markdown(crates/e2e-report/src/consolidated.rs:966-970) writes when no lane uploaded a report. It is also what an empty or partialsupport-matrix.mdyields when thee2e-report-nightlystep fails, because the artifact upload there runsif: always(). A probe run returned 0 failures for an empty file, for the real "no report.json files" output, and for anEMPTY-status-only table, so each of these publishes "✅ GO". A lane that times out before uploading is not counted as a failure either, and the six lanes are allcontinue-on-error. The verdict never receivesneeds.e2e-report-nightly.resultor any per-lane result. The testtotal_e2e_failures_defaults_to_zero_without_a_totals_rowpins this fail-open behaviour.
Confidence 100 · logic · Fix: return NO-GO (or UNKNOWN) when the Total row is missing or fewer platforms are present than expected. Pass the e2e-report and lane job results into the xtask. Invert the test. -
Nights with no new commits publish a false NO-GO —
xtask/src/release_readiness.rs:91-93,.github/workflows/nightly.yml:207
Whennightlysetsskip=true, thenightlyjob succeeds,windows-nightlyisskipped, andwindows_result != "success"adds the failing gate "windows build (skipped)". The verdict is then NO-GO, andpublish-release-readiness-wikipublishes it becauserelease-readiness-nightlysucceeded.
Confidence 85 · logic · Fix: treatskippedas "no build this night" (or skip the whole release-readiness chain whenneeds.nightly.outputs.skip == 'true'). Do not count it as a failed gate. -
Text from issues any GitHub user can file reaches the public wiki unescaped and unreviewed —
xtask/src/release_readiness.rs:253-291,xtask/src/release_readiness.rs:390-395,.github/workflows/nightly.yml:1826-1858,.github/workflows/nightly.yml:1916-1925.github/ISSUE_TEMPLATE/bug_report.md:11auto-applieslabels: bug, so any GitHub user controls entries inknown_issues.- The raw titles go into
table.mdas unescaped markdown. A probe rendered injected image and link markdown verbatim. That file is written to$GITHUB_STEP_SUMMARYand to the publicRelease-Readinesswiki page. - Titles and 240-character body excerpts are also the LLM prompt. At the pinned SHA, ai-inference joins the system prompt and the user prompt into one
copilot -pstring, so the prompt's "Hard rules" carry no more weight than injected text. - The model's response is published with
cat, with no filtering. An attacker can therefore put links, a fake "GO" claim, or text that drops real blockers from "Known Issues" on the project wiki. - Command execution is not possible, because
copilot-allow-toolsis unset.
Confidence 85 · architectural · Fix: escape titles or render issues as
#NNNlinks only. Either keep the narrative as a run artifact or step summary, or feed the model only maintainer-authored inputs (commit subjects), never issue bodies. -
The verdict, gate assembly and table rendering are untested —
xtask/src/release_readiness.rs:71-116,xtask/src/release_readiness.rs:321-400
These mutations all left the 6 tests green (cargo test -p xtask release_readiness, 6 run):- nightly gate removed
- E2E gate removed
- verdict inverted
- Build-row check broken
- issue sort reversed
rfind→findinextract_pr_number- the
excerptboundary<=→<
No test reaches
run,render_tableorcollect_known_issues. That includes the GO/NO-GO logic the page exists to publish.Test verdicts:
- All six tests are in a new module, so verdict (1) does not apply.
- (2) The categorize tests catch the scope-filter,
!and suffix-strip mutations. - (2)
extract_pr_number_reads_trailing_referencemissesrfind→find. - (2)
excerpt_…misses the boundary mutation. - (2)
total_e2e_failures_reads_the_totals_rowcatches column-index mutations. - (2) The defaults-to-zero test pins the defect above.
Confidence 100 · logic · Fix: extract the gate/verdict computation into a pure function and test it, including skipped and cancelled results and a missing report. Snapshot-test
render_table. -
The wiki "degenerate-output guard" can never trip —
.github/workflows/nightly.yml:1903-1909,.github/workflows/nightly.yml:1866-1868
The guard grepstable.mdfor| Area | Evidence | Status |, butrender_tablewrites that header unconditionally (release_readiness.rs:335). The publish job also only runs whenrelease-readiness-nightlysucceeded, so the file always exists. The comment "same degenerate-output guard" aspublish-e2e-wikiis false: that guard catches an empty consolidation and is covered bywiki_publish_guard_stops_on_the_generators_empty_outputinxtask/src/workflow_contract.rs. The new job has no contract test, unlikepublish-e2e-wiki'snightly_publishes_the_consolidated_matrix_to_the_wiki. Together with the first finding, an empty E2E night publishes GO.
Confidence 85 · logic · Fix: make the guard test real evidence (e.g. that a Total row was parsed, carried as a field in facts.json). Add a workflow-contract test like the one #590 added. -
The Strix Windows nightly runner move is bundled in, unmentioned, and incomplete —
.github/workflows/nightly.yml:917-926,.github/workflows/nightly.yml:1115-1118,docs/ci-hardware-testing.md:60-74- Out of scope: commit 51d125a moves
e2e-gpu-nightly-strix-windowsfromnativetodevlab-dispatch, a behaviour change unrelated to the release-readiness feature (AGENTS.md §11: one logical change per PR). - Docs left stale:
docs/ci-hardware-testing.mdstill says both nightly Strix lanes "still pin thenativelabel" and that moving them "is a separate, not-yet-made decision" (AGENTS.md §5 docs-sync). - Comment left stale: the moved job still says "The persistent runner workspace keeps those paths valid across scenarios and subsequent runs". That is false on the fresh-per-job pool, and the per-PR twin in
e2e-selfhosted.ymlsays "RUNNER_WORKSPACE is fresh every job". - No contract test: no test pins the moved lane's labels. The WSL lane has
nightly_wsl_lane_shares_the_per_pr_pool_labels. - Contradicted commit claim: the message says "no registered runner carries native anymore", but
e2e-gpu-nightly-strix(nightly.yml:716) still pinsnative.
Confidence 85 · architectural · Fix: move this to its own PR, with the doc, comment and contract-test updates.
- Out of scope: commit 51d125a moves
-
Three commits use a placeholder identity and fail the required signature gate — commits 49070b1, e654b4c, 7235dd9
These three are authored, committed and signed off astest <test@example.com>. CI "Commit signatures + sign-off" fails on exactly these three ("signature is not GitHub-Verified"). AGENTS.md §2 requires the employer identity and a valid DCO sign-off. The squash body would also carry the bogusSigned-off-by.
Confidence 100 · mechanical · Fix: re-author and re-sign these commits under the real identity. -
"Test (affected crates)" fails — CI on 7235dd9
It fails atcargo nextest run --locked -p rocm-core --lib --features e2e-test-hookswith "the package 'rocm-core' does not contain this feature". The merge-base 34fbdfe is 24 commits behind the base tip, which added that feature (#510). The cause is the stale base, not this code, but the required check is red.
Confidence 100 · mechanical · Fix: rebase onto the current base and re-run. -
The description claims "no new secret — uses
permissions: models: read", and the code does the opposite —.github/workflows/nightly.yml:1786-1800,.github/workflows/nightly.yml:1836-1840
The narrative job needs a newsecrets.COPILOT_PAT(a Copilot-licensed PAT, per its own comment) and declares onlycontents: read. Nothing in the diff hasmodels: read. A maintainer reading the description would not know a new PAT must be provisioned.
Confidence 100 · mechanical · Fix: correct the description. Also document the secret and its minimum scope. -
The description omits work the change does — PR description
It does not mention:- the Strix Windows runner-label move;
- the comment rewrites in
e2e-wsl-nightly; - the new
COPILOT_PATdependency; - the unpinned npm install.
Its "degenerate-output guard" claim is not delivered (see above).
Confidence 85 · mechanical · Fix: narrow the PR to the feature and update the description to match the code.
Non-blocking
-
Unpinned
npm install -g @github/copilotruns withCOPILOT_PATin the environment —.github/workflows/nightly.yml:1818,.github/workflows/nightly.yml:1836-1840
Each night installs the latest version with no version pin, and the job holds a secret. This is the same supply-chain reasoning as AGENTS.md §6's action pinning. Separately, the checkout at:1805keeps its credentials, which this job does not need.
Confidence 85 · architectural · Fix: pin@github/copilot@x.y.z, and setpersist-credentials: falseon that checkout. -
actions/ai-inferencepin comment is# v3, not# vX.Y.Z—.github/workflows/nightly.yml:1836
The SHA matches upstream'sv3tag, which is the release name. Nov3.x.ytag exists, so §6's comment form cannot be met literally. Note thatv3is the kind of tag upstream re-points.
Confidence 70 · mechanical · Fix: keep the SHA. Note in the comment that no patch tag exists, or wait for one. -
always()where!cancelled()fits —.github/workflows/nightly.yml:1746,.github/workflows/nightly.yml:1801
Both jobs run after a workflow cancel, and the narrative job uses the PAT when it does. The publish job is already gated with!cancelled().
Confidence 85 · mechanical · Fix: use!cancelled(). -
Commit classification misses user-facing changes without saying so —
xtask/src/release_readiness.rs:181-224
These are dropped:- ticket-prefixed subjects such as
EAI-7404: make runtime activation and rollback transactional (#424)(32 of the 374 commits on the base tip); - capitalised
Fix …/Feat:and spacedfeat (cli):; Revert "…"subjects, so the revertedfeatstill lists as new.
extract_pr_numberalso takes the last(#anywhere in the subject, not only a trailing one, despite its doc. Probe:fix: handle (#12) refsrenders… (#12)twice. The table never reports how many commits went unclassified, and--limit 100caps the issue list while the header says "(N open)".
Confidence 85 · logic · Fix: match the type case-insensitively, report the unclassified count, anchor the PR match to the end of the subject, and note any truncation. - ticket-prefixed subjects such as
-
The two wiki publish jobs can race —
.github/workflows/nightly.yml:1880-1882
publish-e2e-wikiandpublish-release-readiness-wikipush to the same wiki repo in the same run. They use different concurrency groups and neither retries, so a non-fast-forward rejection fails one of them.
Confidence 70 · logic · Fix: share one concurrency group, orpull --rebaseand retry on push. -
The prompt contradicts itself —
.github/prompts/release-readiness-narrative.txt:25-35
Section 3 asks the model to highlight "failing gates", and the hard rules forbid "any pass/fail/status judgment".
Confidence 70 · mechanical · Fix: allow restatingfailing_gatesverbatim and forbid only the model's own verdict. -
Commit history would put false or noisy claims into the squash body — commits 834ae24, e654b4c, 300abb0, cc75a79
834ae24 ("temporarily narrow") and its revert are noise. 300abb0's "switch … to gpt-4.1" is undone by cc75a79, and the two give different reasons for the model choice. 51d125a's "no registered runner carries native anymore" is contradicted by the Linux nightly lane, as noted above.
Confidence 85 · mechanical · Fix: squash or reword these before merge so the squash body describes the final state.
Decisions for the author
-
Overlapping "release readiness" name — non-blocking-improvement
scripts/release_readiness.pyis already the release gate under that name: AGENTS.md §8,docs/release-trust.md, andnightly.yml:15,154,246,294. The new "GO" ignores what that gate checks:publish-nightly;- the production-trust gate state;
- clippy, smoke, and the required GPU-lane set.
A different name ("nightly health / release-notes preview"), or listing the unchecked gates on the page, would stop readers mistaking it for the gate.
-
New xtask module vs. extending
crates/e2e-report— tradeoff
e2e-reportalready owns per-platform PASS/FAIL and expected-vs-actual reconciliation. Having it emit a machine-readable verdict would remove the scraping of rendered markdown, which is the root of the first finding. A separate module and page keep the release-preview concern apart from the support matrix. Both are reasonable; confirm the choice was deliberate. -
Release baseline includes pre-release tags — tradeoff
git describe --match 'v*'matches-rcand-previewtags, so "since last release" can mean "since the last RC". It resolves tov0.2.0today.
Positive signals
- The verdict, counts and PR numbers are computed outside the LLM step, and the publish job tolerates a missing narrative.
- The
GITHUB_OUTPUTheredoc uses a random delimiter for content holding untrusted data, and the LLM response reaches the shell throughenv:, not${{ }}interpolation. - ai-inference is used without
copilot-allow-tools, so injected text cannot run commands.
Deployment notes
- Needs a new repository secret,
COPILOT_PAT: a Copilot-licensed PAT. Its minimum scope is undocumented. - Creates and overwrites a new
Release-Readinesswiki page nightly. The wiki must already be initialised. - Moves the nightly Strix Windows lane onto the DevLab Dispatch pool, which adds load to the pool the per-PR lanes use. Commit 834ae24's message reports this lane hanging to its 90-minute timeout there.
What this covered
All four changed files read completely (.github/prompts/release-readiness-narrative.txt, .github/workflows/nightly.yml, xtask/src/main.rs, xtask/src/release_readiness.rs), plus crates/e2e-report consolidation, xtask/src/workflow_contract.rs, e2e-selfhosted.yml, docs/ci-hardware-testing.md, scripts/release_readiness.py, and ai-inference's source at the pinned SHA. Reviewed against prw-base, merge-base 34fbdfe…7235dd94 (merges cleanly with the base tip). What ran: cargo test -p xtask release_readiness (6 tests ran), cargo clippy -p xtask --all-targets -D warnings (clean), and 16 single-branch mutations plus probe inputs. All four passes ran, fanned out to independent workers alongside a design pass.
Did not run:
- Signature verification locally (no keys); CI's result was used instead.
- actionlint (not installed).
- The xtask coverage measurement (the CI coverage check is green).
- Confirmation that the
claude-sonnet-5.5slug is valid, or of the claim that the native Windows runner is unregistered.
"E2E tests (MI300X)" was still queued.
Not reconciled against any PR discussion here.
7235dd9 to
367acd3
Compare
|
Thanks for the thorough review — addressed everything below. Branch was rebased onto current Blocking, addressed in
|
rominf
left a comment
There was a problem hiding this comment.
🔴 Automated review · pr-review-watcher · 367acd3
This automation never files a GitHub approval, so no approving review will
appear here whatever the outcome — the merge decision stays with a human
reviewer.
Round 2 — full review again: the round-1 head (7235dd9) no longer exists after the force-push. Each finding is marked new or standing. Round 1's change request was dismissed by the author. This change request restates every objection that still holds.
Round-1 objections settled this round:
- Skipped nights publish a false NO-GO: resolved. The review did not re-find it. When asked afterwards, the reviewer confirmed
assemble_factsnow passesskipped, and a test pins that. - Strix Windows runner move: resolved. It is gone from the diff (moved to #682).
- Placeholder commit identity: resolved. All 9 commits are GitHub-Verified under the author's own identity.
- "Test (affected crates)" failure: resolved. It is green after the rebase.
- Description scope and secrets claim: resolved. The rewritten description was not re-found as a mismatch.
- Dead wiki guard: resolved. The guard now trips. What it now causes is the new finding about NO-GO never being published.
- The untrusted-issue-text objection still holds; it is restated at the end of Blocking.
- Unpinned
npm install(non-blocking in round 1): mostly resolved. The CLI is now pinned to an exact version, no secret is present at install time, and the checkout no longer keeps credentials. One gap remains: the CLI's dependencydetect-libc ^2.1.2still floats. It is loaded inside the step that holdsCOPILOT_PAT, so a bad future release would run with that token in reach. Pinning it,--ignore-scripts, or a committed lockfile would close the gap. Not gating.
Self-hosted lanes not reporting at this head: "E2E tests (MI300X)" and "E2E tests (Strix Halo, Ubuntu) (release)" are queued, and "E2E tests (Strix Halo, Ubuntu) (nightly)" is in progress. That is missing evidence, not a defect. Every hosted check passed.
Review — needs work
Full review of the whole change.
The description names ROCMAI-568, which cannot be retrieved from here. The PR adds cargo xtask release-readiness and three nightly jobs that publish a GO/NO-GO page to the repo wiki.
Blocking
- standing (narrowed) — The E2E gate gives GO when most platforms reported nothing —
xtask/src/release_readiness.rs:347-353,xtask/src/release_readiness.rs:126-130,.github/workflows/nightly.yml(release-readiness-nightlyneeds:)total_e2e_failuresreads only theFailcell of the consolidated**Total**row.consolidated_summary_markdown_from_reports(crates/e2e-report/src/consolidated.rs:1032-1076) adds up only the reports that were actually downloaded.- The GPU lanes are
continue-on-error. A lane that dies before uploadingreport.json(preflight failure, timeout, runner loss) simply drops out of the Total. A platform with zero scenarios (EMPTY) adds 0. - The job never looks at the lane results or at
needs.e2e-report-nightly.result. So one passing platform out of six gives GO, and the table says "0 failure(s) across all platforms". - This contradicts the module's own rule for
e2e_fail_total("treated as a failing gate rather than silently reading as zero failures"). It also contradicts the description's claim that "E2E evidence that's missing … now fails the gate explicitly". Only a missing Total row fails it. - Confidence 85 · logic · Fix: gate on every platform row's
Statusbeing PASS and on an expected platform set, or pass the lane job results in as gates.
- new — A NO-GO is never published, so the wiki keeps showing the previous verdict —
xtask/src/release_readiness.rs:386-391,.github/workflows/nightly.yml(publish-release-readiness-wikiguard and itsresult == 'success'condition),xtask/src/workflow_contract.rs(release_readiness_wiki_publish_guard_stops_on_unreadable_e2e_evidence)- When E2E evidence is unreadable,
render_tableleaves out the| Area | Evidence | Status |header on purpose. The guard then exits 0 without publishing, and the new contract test requires exactly that. - Every other failure has the same effect, because the publish job only runs when
release-readiness-nightlysucceeded. Examples: the artifact download fails,git describefails, orghfails. - An empty report is a realistic case:
e2e-report-nightlyredirects intosupport-matrix.mdbefore cargo runs, so a cargo failure leaves an empty file. - On exactly the nights when readiness is unknown, the page keeps the last GO. Keeping the last good page makes sense for the support-matrix page this job copies. For a verdict page it fails in the wrong direction.
- Confidence 85 · logic · Fix: publish a NO-GO / "evidence unavailable" page in these cases. Keep the guard only for a truly empty file, keyed on a line
render_tablealways emits.
- When E2E evidence is unreadable,
- standing (narrowed) — Several of the new gate checks have no test that fails when they break —
xtask/src/release_readiness.rs:120,:128,:397,:406- The reviewer made four changes at once and all 14
release_readinesstests still passed:- the
Some(n) if n > 0E2E check made to never fire - the
nightly_resultcheck removed - the Build cell forced to ✅
- the E2E cell forced to ✅
- the
- No test covers E2E failures > 0 giving NO-GO, a Linux nightly failure giving NO-GO, or either ❌ cell. The description says assembly was extracted so "the GO/NO-GO logic is directly unit-tested". That is only partly true.
- Confidence 100 · mechanical · Fix: add one test for each case, so that each of the four changes above fails a test.
- The reviewer made four changes at once and all 14
- standing — round 1 rated this non-blocking. This change request does not rest on it, and it gates nothing on its own. — The
actions/ai-inferencepin is commented# v3, not# vX.Y.Z—.github/workflows/nightly.yml(Draft narrativestep)- AGENTS.md §6 requires a full SHA "with a trailing
# vX.Y.Zcomment, never a moving tag". - Checked via
gh api:2c43c91…is the lightweight major tagv3. Nov3.x.yexists yet, so neither the reader nor Dependabot can tell which release is pinned. - Confidence 85 · mechanical · Fix: pin to the latest semver release (
v2.1.1), or get a maintainer to accept the exception explicitly and note it in the comment.
- AGENTS.md §6 requires a full SHA "with a trailing
- standing (round 1) — Text from outsiders' issues still reaches the public wiki, and the escaping fix can be bypassed —
xtask/src/release_readiness.rs(escape_markdown,collect_known_issues),.github/workflows/nightly.yml(Read facts for prompt,Draft narrative,Push page to the wiki)
This round's blind review did not report it as blocking: it rated the narrative path non-blocking at 70. It was put to the reviewer afterwards as a standing objection, with the author's defence ("addedescape_markdown(), applied to every known-issue title"). The verdict below comes from that follow-up question and is anchored evidence, not a blind finding. Most of the objection still holds:- Titles: the escaping can be bypassed.
escape_markdowndoes not escape\. A title written as\[click\](https://evil.example)comes out with doubled backslashes, and under CommonMark that renders as a live link intable.md. The reviewer ranescape_markdownon it and read the result against the escape rules, but could not render it (no renderer installed). Bare URLs also pass through and are autolinked. Raw HTML is neutralised. - The narrative path is unchanged. Issue titles and 240-character body excerpts are still the LLM prompt. At the pinned SHA the system prompt and the user prompt are one string.
narrative.mdis stillcat'd onto the wiki unfiltered. An outsider can therefore try, every night and unattended, to get links, prose implying GO, or a "Known Issues" list that drops real blockers onto the official project wiki. - Limits: whether it works depends on the model following the injected text. The mechanical verdict line and the raw issue list above it cannot be changed. There is no command execution.
- Unverified: whether GitHub honours the bug template's automatic
buglabel, since a licence comment comes before it. If it does not, a triager applyingbugis the gate. That narrows who can do this but does not remove it. - Fix: escape
\first, or render issues as#NNNlinks only. Either keep the narrative as a run artifact or step summary, or feed the model only maintainer-authored inputs, never issue bodies.
- Titles: the escaping can be bypassed.
Non-blocking
- new — Untrusted issue text reaches the LLM, and its output is published to the wiki unescaped —
xtask/src/release_readiness.rs:288-327,.github/workflows/nightly.yml(Read facts for prompt,Push page to the wiki)- Open
bugissues come from outside contributors (the bug template asks forlabels: bug). Their titles and 240-character body excerpts are inlined as the prompt. - At this SHA the action joins the system prompt and the user prompt into one string, so the prompt's rules can be overridden.
narrative.mdiscat'd onto the official wiki. Issue titles are escaped in the table, but the narrative is not escaped at all.- The token and permissions are scoped well, so this is limited to content: links, images, or prose contradicting the mechanical verdict.
- Confidence 70 · architectural · Fix: restrict input to issues from maintainers, or drop the body excerpts. Strip links and images from the narrative before publishing.
- Open
- new — Commit subjects are written to the wiki unescaped —
xtask/src/release_readiness.rs:419,:422. Squash subjects are contributor-written PR titles, while issue titles already go throughescape_markdown. Confidence 70 · logic · Fix: escapee.subjecttoo. - new — "👍 N" counts every reaction type —
xtask/src/release_readiness.rs:321,:446. It sumsusers.totalCountover allreactionGroups, including 👎 and confused. Confidence 85 · logic · Fix: filter toTHUMBS_UP, or label the number "reactions". - standing (round 1) — The known-issue count is silently capped at 100 —
xtask/src/release_readiness.rs:299-300,:432-435. With--limit 100, the header shows "(100 open)" once there are more than 100 open bugs. Confidence 70 · logic · Fix: paginate, or print "100+" when the cap is hit. - new —
!counts as a breaking change for any commit type —xtask/src/release_readiness.rs:216,:236. Unscopedchore!:,docs!:,ci!:andtest!:subjects land in the end-user "Breaking Changes" list. The scope filter does not catch them. Confidence 70 · logic · Fix: count as breaking only for user-facing types. - standing (round 1) — A PR suffix without a leading space is printed twice —
xtask/src/release_readiness.rs:229-233. Forfix: x(#12),pr = 12is extracted, but only" (#12)"is stripped, so it renders asx(#12) (#12). Confidence 70 · mechanical · Fix: strip the exact span thatextract_pr_numbermatched. - standing (round 1) — The baseline tag pattern also matches prerelease tags —
.github/workflows/nightly.yml(since_tag=$(git describe --tags --abbrev=0 --match 'v*')). The repo hasv0.2.0-rc.1,v0.1.0-preview.1and similar tags. Once an RC is tagged on main, "since the last release" becomes "since the RC". Confidence 70 · logic · Fix: add--exclude 'v*-*'. - new — The new page and its secret are not documented —
docs/ci-hardware-testing.md(thepublish-e2e-wikiparagraph). The doc covers the E2E wiki page and its one-time setup. Nothing underdocs/mentions theRelease-Readinesspage, theCOPILOT_PATprerequisite, orcargo xtask release-readiness. Confidence 70 · mechanical · Fix: extend that paragraph.
Decisions for the author
- Name collision with the existing release gate — tradeoff
scripts/release_readiness.py(documented indocs/release-trust.mdanddocs/testing.md, and referenced innightly.yml's env comments) is the signing/trust release gate.cargo xtask release-readinessis a nightly summary with its own GO/NO-GO.- Sharing the name is convenient. The cost is that readers may take one for the other, especially since both say "release readiness".
- The Build row shows ✅ on a no-op night — non-blocking-improvement
- On a skip night,
nightlysucceeds without building andwindows-nightlyis skipped. - The row "Build (Linux + Windows nightly) ✅" reads as "built and passed". "Not built (no new commits)" would be more accurate.
- Accepting
skippedfornightly_resultdoes nothing, because that job has noif:.
- On a skip night,
Positive signals
- The verdict, counts and PR numbers are computed without the LLM, and the narrative job is
continue-on-errorwith an optional artifact download. A broken LLM step cannot change the table. - The new contract test runs the real bash guard from
nightly.ymlagainst realrender_tableoutput instead of a pinned string. Removingexit 0from the guard made it fail. - The LLM response reaches the shell only through
env:andprintf '%s\n', never inline${{ }}.GITHUB_OUTPUTuses a random heredoc delimiter. - Each job has narrow permissions (
contents: read/issues: read), and both checkouts usepersist-credentials: false. Every other new action pin was verified viagh apito match its# vX.Y.Zcomment. - A failing
git logorgh issue listaborts the run instead of producing an empty list.
Deployment notes
- Requires a
COPILOT_PATrepo secret holding a Copilot-licensed PAT. Without it the narrative job fails (non-blocking) and the page has no narrative. - Requires at least one non-prerelease
v*tag reachable from main. Without one,git describefails and the page is never published. - Uses the existing repo wiki, which must already be initialized (same prerequisite as
publish-e2e-wiki).
What this covered
- Read every changed file completely against
21be0034…367acd35:xtask/src/release_readiness.rs,xtask/src/main.rs,xtask/src/workflow_contract.rs,.github/workflows/nightly.ymland.github/prompts/release-readiness-narrative.txt. Also read the jobs these depend on innightly.yml, the consolidated-report generator incrates/e2e-report, the bug issue template, and the docs that mention the nightly wiki. - Two read-only workers covered the code passes (xtask module; workflow + contract test). The reviewer ran the agent-instruction, history and code-comment passes and the design questions itself, so those are not independent.
- CI at this head: every hosted check passed, including commit signatures/DCO. Three self-hosted GPU lanes (MI300X, Strix Halo Ubuntu nightly and release) were still queued or running. That is missing evidence, not a defect.
- Did not run:
- prior-changes pass — no access to earlier review threads, by design.
- workflow end-to-end and
actionlint— not runnable here. - ROCMAI-568 — no tracker access.
- Not checked: whether Copilot CLI 1.0.97 accepts the
claude-sonnet-5.5slug. - Not reconciled against the PR's discussion or earlier reviews. Standing objections were settled separately, as noted above.
|
Addressed the blocking findings from @rominf's review (5522757577):
Also fixed the two non-blocking findings: On the two "decisions for the author" items, left as-is deliberately:
|
Mirrors the existing E2E support-matrix automation: a new `cargo xtask release-readiness` subcommand computes a GO/NO-GO verdict, status table, and categorized commit/known-issue facts purely mechanically from nightly build results, the E2E report, and `git`/`gh` data. A separate narrative job hands those facts to the GitHub Copilot CLI (via actions/ai-inference) to draft prose summaries and curate known issues by end-user relevance, and the verdict/table/counts are never left to that step. Publishes to the Release-Readiness wiki page nightly, same guard pattern as the existing E2E wiki job. Signed-off-by: Juho Vainio <juho.vainio@amd.com>
…susing an ai-inference output as an input Two bugs surfaced by the first live run with COPILOT_PAT: the job had no actions/checkout step, so system-prompt-file (read from the repo) always failed with "file not found"; and response-file was passed as an input, but actions/ai-inference only exposes it as an *output* (the path it already wrote the response to) — the action logged an "unexpected input" warning and never produced release-readiness/narrative.md. Add the checkout step, and write steps.draft.outputs.response to narrative.md ourselves instead of guessing a response-file path. Signed-off-by: Juho Vainio <juho.vainio@amd.com>
claude-sonnet-4.5 is disabled under this org's Copilot model policy
("Model ... is not available"). Tried gpt-4.1 (the action's own default,
enabled for every Copilot license) first, but Copilot CLI's --model slugs
use dots, not the Anthropic API's hyphenated IDs, and claude-sonnet-4.5 was
retired when Claude Sonnet 5.5 went GA — claude-sonnet-5.5 is the current
slug and is enabled for this org.
Signed-off-by: Juho Vainio <juho.vainio@amd.com>
ai-inference's {{var}}/file_input templating only applies to a
structured .prompt.yml loaded via prompt-file. This job uses an
inline prompt string, so file_input was silently ignored and the
model literally received the text "{{facts}}" -- it correctly
refused to draft a narrative rather than invent facts, so the job
"succeeded" with an empty/refusal narrative.md every run.
Read facts.json into a step output and interpolate it directly.
Signed-off-by: Juho Vainio <juho.vainio@amd.com>
facts.json has no trailing newline, so the closing delimiter line got appended to its last line instead of starting its own line, which the $GITHUB_OUTPUT file-command parser requires. Add a bare `echo` between the cat and the delimiter to guarantee one regardless of whether the source file ends with a newline. Signed-off-by: Juho Vainio <juho.vainio@amd.com>
categorize() bucketed commits purely by Conventional Commit type (feat/fix), ignoring scope entirely. This let CI/workflow-internal commits like fix(nightly) and fix(ci) leak into the nightly release- readiness summary's Bug Fixes section, which should only describe end-user-facing functionality and fixes. Add an INTERNAL_SCOPES denylist and drop commits scoped entirely to those (ci, nightly, github, hooks, xtask, build, deps, e2e variants). A multi-scope commit is kept if any of its scopes falls outside the denylist, so a fix touching both CI and real CLI behavior is still surfaced. Signed-off-by: Juho Vainio <juho.vainio@amd.com>
release_readiness.rs previously had several correctness bugs:
- total_e2e_failures() defaulted to 0 failures when the E2E report's
**Total** row was missing or unparseable, so a broken/truncated report
silently produced a GO verdict instead of failing the gate. It now
returns Option<u64>, and a None reads as a failing gate
("E2E (report unreadable)").
- A legitimately skipped nightly/windows job (a no-op night) was treated
as a gate failure. "skipped" now passes the gate the same as "success".
- Untrusted GitHub issue titles were interpolated into the generated wiki
page unescaped. escape_markdown() now neutralizes markdown/table-
breaking characters before known-issue titles reach render_table.
- extract_pr_number() matched "(#NNN)" anywhere in a commit subject,
including mid-sentence parentheticals; it now only matches a trailing
"(#NNN)".
Also extracted assemble_facts() as a pure function (no git/gh I/O) out of
run(), so the GO/NO-GO logic is directly unit-testable.
In workflow_contract.rs, render_table() now drops the
"| Area | Evidence | Status |" header when E2E evidence is unreadable,
which makes nightly.yml's existing publish guard
(grep -q '^| Area | Evidence | Status |') an actual signal instead of
structurally dead code. Added a test that runs that guard snippet against
both degenerate and well-formed table output.
Signed-off-by: Juho Vainio <juho.vainio@amd.com>
Hard Rules already forbade "any pass/fail/status judgment" from the narrative step, but section 3's instruction told it to highlight "failing gates" anyway. Reworded it to ask for the evidence behind each gate instead of a judgment on whether it clears the bar. Signed-off-by: Juho Vainio <juho.vainio@amd.com>
…eds) - Pin "npm install -g @github/copilot" to 1.0.97 instead of floating latest. - Add persist-credentials: false to the release-readiness-nightly and release-readiness-narrative checkout steps; neither job pushes. - Change if: always() to if: !cancelled() on both jobs, matching publish-e2e-wiki's existing reasoning: still run on a failure, not on a cancelled run. Signed-off-by: Juho Vainio <juho.vainio@amd.com>
- Thread per-lane E2E results (--e2e-lane-result NAME=RESULT, repeatable) through to the verdict so a lane that dies before uploading its report.json (preflight failure, timeout, runner loss) still fails the release-readiness verdict instead of silently reading as zero failures. - render_table no longer omits the table header when E2E evidence is unreadable; unreadable evidence is itself a NO-GO signal and should be shown, not hidden. - Escape markdown in commit subjects before they're interpolated into the rendered table, preventing a crafted subject line from breaking table formatting. - Only count THUMBS_UP reactions (not all reaction kinds) when ranking known issues, and bump the gh issue list limit from 100 to 1000 so older issues aren't silently excluded. - Replace extract_pr_number with split_trailing_pr_reference for production code; the former is kept test-only so its existing unit tests keep compiling unchanged. - Fix categorize() to only treat a trailing '!' as breaking for feat/fix commit kinds, and to stop double-appending the PR suffix. Signed-off-by: Juho Vainio <juho.vainio@amd.com>
…wiki path - release-readiness-nightly now needs: the 6 GPU/WSL E2E lane jobs (not just the consolidated e2e-report-nightly), and passes each lane's own needs.<job>.result to cargo xtask release-readiness via a repeated --e2e-lane-result flag, so a lane that dies before producing a report still fails the verdict. - since_tag resolution now excludes pre-release tags (v*-*) so the commit-bucketing window starts at the last real release, not a prerelease/RC tag. - Strip markdown links/images out of the LLM-drafted narrative before publishing it to the public wiki, since the narrative text is untrusted-derived and could otherwise smuggle a redirect. - Document why actions/ai-inference is pinned to a bare major tag (v3): that project releases under bare-major tags rather than vX.Y.Z, and this SHA is exactly what the genuine, non-prerelease v3 release points to, predating the repo's current main — a frozen release, not a moving alias. Signed-off-by: Juho Vainio <juho.vainio@amd.com>
Explain what release-readiness-narrative and publish-release-readiness-wiki do, the cargo xtask release-readiness gating inputs (nightly Linux/Windows build results, E2E failure total, each GPU/WSL lane's own result, commit bucketing since the last release tag), the COPILOT_PAT prerequisite, and that the Release-Readiness wiki page shares publish-e2e-wiki's one-time setup/skip guards. Signed-off-by: Juho Vainio <juho.vainio@amd.com>
7cfce6a to
1cb356d
Compare
rominf
left a comment
There was a problem hiding this comment.
🔴 Automated review · pr-review-watcher · 1cb356d
This automation never files a GitHub approval, so no approving review will
appear here whatever the outcome — the merge decision stays with a human
reviewer.
Round 3 — full review again: the round-2 head (367acd3) no longer exists after the force-push. Each finding is marked new or standing. Round 2's change request was dismissed by the author. This change request restates every objection that still holds.
Round-2 objections settled this round:
- E2E gate gives GO when lanes upload no report: still holds. It was re-found blind (first item under Blocking). The new
--e2e-lane-resultgate does not close it. Commit 40f5d62's message also says "a lane that dies before producing a report still fails the verdict", and that sentence would land on main with the squash. - New gate checks have no test that fails when they break: still holds. It was re-found blind with a new set of surviving mutations (fourth and third items under Blocking).
- NO-GO never published: partly resolved. The blind review reported only a related non-blocking item. When asked afterwards (anchored evidence, not a blind finding), the reviewer confirmed:
- An empty or unreadable E2E report now publishes a NO-GO page. That part is resolved.
- Any failure of
release-readiness-nightlystill publishes nothing, and the wiki keeps the last page, which may say GO. The causes are a missing report artifact or file,git describe,gh issue list, or the xtask build. This part is restated as the last item under Blocking.
- Untrusted issue text reaches the public wiki: partly resolved.
- The narrative half still holds and was re-found blind (second item under Blocking).
- The title half was put to the reviewer afterwards (anchored). The backslash bypass is fixed:
escape_markdownnow doubles\, and a test catches removing that. Commit subjects now go through the same escaping. - Bare URLs in titles and subjects still pass through unescaped and would likely be autolinked. This was not rendered to confirm. It is folded into the narrative item rather than gated on separately.
# v3pin comment (not gating): still holds. It was re-found as non-blocking below.- Copilot CLI's floating
detect-libc ^2.1.2dependency in theCOPILOT_PATstep (not gating): not re-checked this round.
CI at this head (from the driver, compared against main's own runs):
E2E testsfails with the same dashboard-quit and full-model-name scenarios on main's latest CI run (6186f15), so it does not gate.E2E tests (Strix Halo, Windows, current)failed on a 404 downloading an external llama.cpp release. The same lane also failed on main at c7a0d65. This PR does not touch that path.- The consolidated report failed downstream of the lanes, and MI300X was cancelled.
- The method lists these under Blocking. This change request does not rest on them; re-running after a rebase should settle them.
Review — needs work
Full review of the whole change.
The description names Jira ROCMAI-568, which could not be retrieved from here (no tracker tool). The description's account of the change is out of date in places (see Blocking).
Blocking
-
standing — The new per-lane E2E gate can never fire for a failed lane, and it leaves out the W7900 lane —
.github/workflows/nightly.yml:1701-1710,.github/workflows/nightly.yml:1747-1752,xtask/src/release_readiness.rs:134-144,xtask/src/main.rs(--e2e-lane-resulthelp),docs/ci-hardware-testing.md:199-203- Why it never fires: every lane job sets
continue-on-error: true, soneeds.<lane>.resultreadssuccesseven when the lane failed. Nightly run 39103436218 shows this:- Both Strix Halo Windows lane jobs concluded
failure. - In the same run,
e2e-report-nightly's annotation says:lane e2e-gpu-nightly-strix-windows ran (needs result: success) but uploaded no e2e-gpu-strix-windows-release-report. - Run 39554529729 shows all 7 lanes reporting
"success"inNEEDSeven though three of them failed.
- Both Strix Halo Windows lane jobs concluded
- Consequence: a lane that dies before uploading drops out of the
**Total**row, and the verdict can still read GO. The code comment, the--e2e-lane-resulthelp and the docs sentence all say this case fails the gate. The code governs here: those statements describe a gate that does not work. - W7900: separately,
e2e-gpu-nightly-w7900is ine2e-report-nightly'sneedsandLANE_REPORTS, but not in the new job'sneedsor in its lane list. - The signal that does work:
needs.e2e-report-nightly.result. That job's "Check every lane that ran uploaded its report" step exists for exactly this case. Release readiness already lists the job inneedsbut never gates on its result. - Confidence 100 · logic · Fix: gate on
needs.e2e-report-nightly.result, or reuse its artifact-list check. Drop the--e2e-lane-resultplumbing or correct what it claims. Add a contract test that ties any lane list toLANE_REPORTS.
- Why it never fires: every lane job sets
-
standing (narrative half) — The link-stripping
seddoes not stop what its comment says it stops, and its input is attacker-controllable —.github/workflows/nightly.yml(publish step,sed -E 's/!?\[([^]]*)\]\([^)]*\)/\1/g')- The comment says the narrative "can't smuggle a redirect or tracking pixel onto the public wiki page".
- I ran the sed. These pass through unchanged:
<img src="https://example.com/p.png">- reference-style
[a][1]with[1]: https://example.com/x - bare URLs and autolinks
- Nested
[outer [inner](https://a.example)](https://b.example)comes out as a live link:outer [inner](https://b.example). - Who can inject:
.github/ISSUE_TEMPLATE/bug_report.mdsetslabels: bug, so any GitHub user's issue title plus a 240-character body excerpt goes into the LLM prompt. The LLM output is then published to the public wiki. - Confidence 100 · logic (security) · Fix: render the narrative as plain text (escape it, or put it in a fenced block), or allowlist its output. At minimum, correct the comment so it does not claim protection that is not there.
-
new —
collect_known_issues_counts_only_thumbs_up_reactionsnever calls production logic —xtask/src/release_readiness.rs:816-828- The test re-implements
filter(THUMBS_UP).map(..).sum()inline. The only thing it shares with production is the serde shape. - Replacing the production filter with "count all reactions", or reversing the sort, still passes. Both mutations were run.
- Confidence 100 · mechanical · Fix: extract the
RawIssue→KnownIssuemapping and sort into a pure function, and test that function.
- The test re-implements
-
standing — Several branches the change introduces are not exercised by any test. Each mutation below was run alone against
cargo test -p xtask release_readiness(24 tests) and survived:- The verdict headline.
## Release Readiness — ✅ GOvs❌ NO-GOis never asserted; swapping them passes. (release_readiness.rs:406-413) - PR-number rendering. Dropping the
(#N)suffix from rendered entries passes. (:452-459) - Treating
skippedas passing for the nightly job and for lanes. Only the Windows twin is tested. (:123,:141) - The
n > 0boundary. Changing it ton > 1passes. (:131) escape_markdown's newline collapsing and its</>escaping. Removing either passes. (:394,:396)- The
ends_with(')')guard insplit_trailing_pr_reference. Removing it passes, and it is not equivalent: thelen()-1slice can then panic on a subject ending in a multibyte character. (:269) - Confidence 100 · mechanical · Fix: add an assertion for each.
- The verdict headline.
-
new — The PR description misstates the change
- It says "the table header is omitted when E2E evidence is unreadable, so the guard can actually trip". The code does the opposite.
render_tablealways emits the header (release_readiness.rs:416-427), and the new contract test asserts that unreadable evidence reaches the publish step. - It does not mention the per-lane
--e2e-lane-resultgate added in 40f5d62, which is the main gating change in the later commits. - It says the job mirrors the E2E wiki job's guards.
publish-e2e-wikialso skips whene2e-report-nightlyfails; this job does not. - Confidence 90 · Fix: update the description to match the code. Narrow it; don't add work to fit it.
- It says "the table header is omitted when E2E evidence is unreadable, so the guard can actually trip". The code does the opposite.
-
new — does not gate (see the CI note above) — Required CI checks are failing at 1cb356d
E2E tests(CI):dash-esc-menu-quit-row-confirms-when-servingregressed (TUI quit timeout).E2E tests (Strix Halo, Windows, current): 404/403 errors downloading external llama.cpp and TheRock artifacts.E2E consolidated report (self-hosted)is failing, andE2E tests (MI300X, current)was cancelled.- These failures are in code paths this PR does not touch, so they may be shared with main. I did not compare against main.
- Confidence 100 · Fix: re-run or rebase once main is green.
-
standing (round 2, narrowed), unverified blind this round — When
release-readiness-nightlyfails, nothing is published, so the wiki keeps the previous verdict —.github/workflows/nightly.yml(publish-release-readiness-wiki'sneeds.release-readiness-nightly.result == 'success'condition),xtask/src/release_readiness.rs:89-90,:332-337- This round's blind review rated a related item non-blocking at 75 (the second item under Non-blocking). The rest comes from the follow-up question and is anchored evidence.
- The job fails outright, rather than producing a NO-GO page, when:
- the E2E report artifact or file is missing (the
?at:89); git describefails;gh issue listfails (:332-337), which runs before the E2E report is read, so a flaky issue listing alone suppresses the page;- the xtask build fails.
- the E2E report artifact or file is missing (the
- In each case the page keeps whatever the last successful night published, which may be GO, and nothing on the page marks it stale. For a verdict page that fails in the wrong direction.
- Fix: publish a NO-GO / "evidence unavailable" page when the job cannot reach a verdict. A fallback publish step on
failure()would do it, as would a staleness line naming the run that produced the page.
Non-blocking
- new — The docs paragraph is inaccurate beyond the lane sentence —
docs/ci-hardware-testing.md:199-211- It opens "On
main", butrelease-readiness-nightlyandrelease-readiness-narrativehave no ref guard. They run on any branch dispatch and use theCOPILOT_PATsecret there. - It says "same … guards as
publish-e2e-wiki", which is not true (see the description finding). - Confidence 85.
- It opens "On
- new — A missing E2E report publishes nothing, and the wiki keeps the previous verdict, possibly GO —
xtask/src/release_readiness.rs:89-90- A missing artifact or file fails the job via
read_to_string(...)?. Only a report that is present but unparseable becomes NO-GO. - The comment at
:416-420("a NO-GO page must still publish") holds only for that second case. - Confidence 75.
- A missing artifact or file fails the job via
- new — The status table hides which gate failed —
xtask/src/release_readiness.rs:421-441failing_gatesis never rendered intable.md.- When a lane is cancelled, the row reads
| E2E | 0 failure(s) across all platforms | ❌ |: the evidence says zero failures while the status is red. - Confidence 85.
- standing — The
actions/ai-inferencepin comment is# v3, not the# vX.Y.Zform AGENTS.md §6 requires —.github/workflows/nightly.yml(Draft narrative step)- The SHA does match the lightweight
v3tag, and nov3.x.ytag exists, so this is a reasoned exception. - But the comment's statement that the action "tags its releases as bare majors" is wrong: v2.x.y and v1.x.y semver tags exist.
- Confidence 85.
- The SHA does match the lightweight
- new —
extract_pr_numberis a#[cfg(test)]wrapper that only forwards tosplit_trailing_pr_reference—xtask/src/release_readiness.rs:281-284. The tests could call the real function directly. Confidence 80. - new — The
--since-taghelp text is out of step with the workflow —xtask/src/main.rs. The help cites--match 'v*', but the workflow also passes--exclude 'v*-*'. Confidence 85.
Decisions for the author
- LLM-drafted prose from public issue text, published to a public wiki — tradeoff. The prose makes the page more readable. The cost is a narrative that any issue filer can steer, which the prompt cannot fully prevent. The alternative is the mechanical table alone, or a narrative restricted to commit data. Confirm that this exposure is deliberate.
- Both wiki publish jobs push to the same wiki under different concurrency groups, with no retry — tradeoff. They seldom overlap in practice (seconds-long jobs, minutes apart). Overlap needs runner queueing, and the loser then fails non-fast-forward. A shared group such as
nightly-wikiremoves the race.
Positive signals
- Keeping the verdict and counts fully mechanical (
assemble_facts), with the LLM only drafting prose, cleanly separates what is trusted from what is not. - The new contract test runs the real publish guard, extracted from
nightly.yml, againstrender_table's real output rather than a pinned string. Both guard mutations were caught. - The facts are inlined through a
with:expression with a random delimiter rather than through a shell, so there is no shell injection from issue titles.
Deployment notes
- The
COPILOT_PATrepo secret must exist (a Copilot-licensed PAT), or the narrative job fails and the page shows its placeholder line. - The wiki must already be initialised, the same prerequisite as
publish-e2e-wiki. - The
@github/copilot@1.0.97install and theclaude-sonnet-5.5model slug are pinned inrun:andwith:, so Dependabot will not bump them. - A non-prerelease
v*tag must be reachable from main, or the job fails before publishing.v0.2.0satisfies this today.
What this covered
All 6 changed files were read completely, along with the existing nightly.yml lane jobs, e2e-report-nightly and publish-e2e-wiki, crates/e2e-report's consolidated markdown format, and the issue templates. Range: prw-base (6186f15)…1cb356de.
Ran two independent read-only workers: an xtask code pass with 27 single-branch mutations plus 2 workflow-guard mutations, and a workflow/docs/policy pass. I re-checked their key claims myself against run annotations and by running the sed.
cargo test -p xtask release_readiness(24 tests) andcargo clippy -p xtask --all-targets -D warningspass, as the worker ran them.- The design questions (Step 7) were judged inline by me, not by independent workers.
Did not run:
- Prior-changes pass: would need other PRs' review threads.
- The new jobs end to end: no run at this head has exercised them.
- Copilot model slug and CLI version: not checked.
- Ticket: ROCMAI-568 is not retrievable here.
The PR's discussion was not reconciled here. Standing objections were settled separately, as noted above.
- publish-release-readiness-wiki now runs on release-readiness-nightly failure too, publishing an explicit EVIDENCE UNAVAILABLE notice instead of silently leaving a stale verdict on the wiki with no sign it's stale. - render_table lists the actual failing_gates reasons beneath the status table, since a cancelled E2E lane otherwise renders as a contradictory "0 failure(s)" next to a red status glyph. - Fix the actions/ai-inference pin comment: that action tags full semver releases, not bare majors only. - Correct docs/ci-hardware-testing.md's release-readiness section: release-readiness-nightly/-narrative have no main/repo guard, and publish-release-readiness-wiki's guards are no longer identical to publish-e2e-wiki's. - Update the PR description to match current behavior and record deliberately-unchanged judgment calls from review. Signed-off-by: Juho Vainio <juho.vainio@amd.com>
…iling_pr_reference
Round-3 review flagged that removing the ends_with(')') guard still
passed every existing test, because none of them exercised a subject
ending in a multibyte character after a mid-sentence (#N) reference.
Signed-off-by: Juho Vainio <juho.vainio@amd.com>
|
Addressed the latest review (id 5600395338) at Blocking
Non-blocking
All fixes verified via |
Addressed in 2ada576 (see summary comment). All blocking findings fixed and pinned by new tests; non-blocking items fixed except two explicit judgment calls called out in the PR description.
rominf
left a comment
There was a problem hiding this comment.
🔴 Automated review · pr-review-watcher · 2ada576
This automation never files a GitHub approval, so no approving review will
appear here whatever the outcome — the merge decision stays with a human
reviewer.
Round 4 — full review of the whole change at 2ada576 (not narrowed: some round-3 objections, such as the commit messages and missing tests, cannot be scoped to a file). Each finding is marked new or standing. Round 3's change request was dismissed by the author. This change request restates every objection that still holds.
Round-3 objections settled this round:
- Per-lane E2E gate never fires; W7900 missing. The blind review did not re-find it in this form. When asked afterwards (anchored evidence, not a blind finding), the reviewer confirmed:
- Code: resolved.
--e2e-lane-resultis gone. The job now gates one2e-report-nightly, whoseLANE_REPORTSincludes W7900. The blind review raised a separate new gap (only thereleaseleg of each lane is checked, fourth item under Blocking). - Commit messages: still holds. It is restated as the last item under Blocking.
- Code: resolved.
- Link-stripping
sedlets links through; narrative built from outsiders' issue text: still holds. It was re-found blind in a new form: the escapingsedthat replaced it never doubles\(second item under Blocking). - Thumbs-up test never calls production code: resolved. The blind review did not re-find it. Asked afterwards (anchored), the reviewer re-ran both named mutations against
build_known_issues, and each now fails the test. - Branches that survive mutation: still holds. It was re-found blind with a new set of surviving mutations (seventh item under Blocking). The round-3 specific set (headline,
(#N),skipped,n > 0, newline/angle escaping,ends_with(')')) is now covered. - Failed
release-readiness-nightlypublishes nothing, wiki keeps the old (maybe GO) page: resolved. The blind review did not re-find it. Asked afterwards (anchored), the reviewer confirmed that each listed cause now reaches the EVIDENCE UNAVAILABLE page. Its residue (no test pins the new!= 'skipped'/!cancelled()conditions) is already part of the seventh item under Blocking. - PR description misstates the change: still holds, in new places. It is folded into the first, second and fourth items under Blocking. On its own a description mismatch does not gate, because the squash body is built from commit messages.
CI at this head (from the driver, compared against main's latest CI run at 32834b2):
windows-build-and-testfails on this PR's own new test, and passes on main. This gates (first item under Blocking).Test (affected crates)fails inpreflight_runs_the_real_reclaim_assert_clear, a pre-existing test this PR does not touch. It passes on main, and the branch predates the main commit that addresses it, so a rebase should settle it. Does not gate.E2E testsfails with the samedash-gen-tps-expiry-boundary/dash-esc-menu-quit-row-confirms-when-servingregressions as main's own run. Does not gate.- The
actions/ai-inferencepin item (sixth under Blocking) was rated non-blocking last round. Nothing new makes it a defect beyond what was known, so this change request does not rest on it.
Review — needs work
Full review of the whole change.
Ticket ROCMAI-568 is named but could not be retrieved from here, because no tracker tool is available. The description was compared against the diff; Blocking items 1, 2 and 4 cover where it overstates.
Blocking
-
new — A test this PR adds fails on the required Windows lane, and the description says the CI failures are unrelated —
xtask/src/workflow_contract.rs:3557(publish_release_readiness_wiki_escapes_markdown_link_and_html_syntax)- The test runs
Command::new("bash")but has no#[cfg(unix)]. Its siblingrelease_readiness_wiki_publish_guard_handles_missing_degenerate_and_well_formed_tables(:3431) and the other bash-driven tests in the file have that guard. - On
windows-build-and-test(job 119771938583),bashresolves to the WSL launcher, which has no distro installed. The run ended:panicked at xtask\src\workflow_contract.rs:3602:13: sed command failed … "Windows Subsystem for Linux has no installed distributions"and340 passed; 1 failed. - The description says "The CI check failures showing on this PR are pre-existing flakes unrelated to this diff". For this check, that is wrong.
- Confidence 100 · mechanical · Fix: add
#[cfg(unix)]like the sibling test, and correct the description.
- The test runs
-
standing (narrative escaping, re-found blind in a new form) — The wiki escaping of the LLM narrative can be bypassed with a backslash, and the description claims a backslash step that is not there —
.github/workflows/nightly.yml(thesed … release-readiness/narrative.mdline inpublish-release-readiness-wiki)- The actual command is
sed -e 's/\[/\\[/g' -e 's/\]/\\]/g' -e 's/</\</g' -e 's/>/\>/g'. It never doubles\. - The input
\[click\](https://evil.example)comes out as\\[click\\](https://evil.example). GitHub's markdown renderer (gh api markdown) turns that into a live<a href="https://evil.example">, and!\[img\](url)behaves the same way. - The narrative is LLM output drafted from untrusted issue and commit text, so a prompt injection can reach this.
- The description says the sed "doubles
\and escapes[,],<,>". The code governs here: the doubling is not in the command. - Confidence 100 · logic · Fix: add
-e 's/\\/\\\\/g'as the first expression, and add this input to the escape test.
- The actual command is
-
new — A lane report that is empty or unparseable still gives GO —
xtask/src/release_readiness.rs:381-387(total_e2e_failures),:129-133- The verdict reads only the
Failcell of the**Total**row and never reads any platform'sStatus. - When a report has no
platform.json,crates/e2e-reportuses its legacy counts. For areport.jsonof[]ornot json, it renders| … | 0 | 0 | 0 | 0 | n/a | EMPTY |. The lane did upload an artifact, so the lane-report check passes too. - Verified with a temporary test through
load_platform_reports→consolidated_summary_markdown→total_e2e_failures→assemble_facts. Both inputs gaveSome(0)andVerdict::Go. - Also,
total_e2e_failures_reads_the_totals_rowuses a hand-copied table, although the doc comment says parsing the rendered row "keeps this in lockstep" with the renderer. A column reorder inconsolidated.rs:1083would feed the wrong column into the gate, and no test would notice. - Confidence 100 · logic · Fix: fail on any platform row whose status is not
PASS. Better: havee2e-reportemit a machine-readable summary and gate on that, and test it against real renderer output.
- The verdict reads only the
-
new — The lane-report gate covers only the
releaseleg of each lane, but the code, docs and description say it covers every lane —release_readiness.rs:134-143,xtask/src/main.rs(--e2e-report-job-resulthelp),docs/ci-hardware-testing.md:199-204,nightly.yml:1588-1596- Every E2E lane runs
channel: [release, nightly].LANE_REPORTSlists only*-release-report, and the job's own comment says the release leg "stands for the whole lane". - So a
nightly-channel leg that dies before uploading drops out of the Total row, ande2e-report-nightlystill succeeds, giving GO. - That weakness was already in
e2e-report-nightly. This PR makes its result release-gate evidence, and states "a lane that dies before uploading a report still fails the gate" in the description, the docs and the help text. - Confidence 85 · logic · Fix: check both channel legs in
LANE_REPORTS, or narrow the three claims to match.
- Every E2E lane runs
-
new — The stale-evidence notice describes content that is not on the page —
nightly.yml:1895- The notice ends "Any verdict below this line predates this run and does not reflect it."
- The job then runs
cp "/tmp/${page}" "wiki/${page}", which replaces the whole page. Nothing is below the line, and the previous verdict is deleted rather than kept. - Confidence 85 · mechanical · Fix: reword it (e.g. "No verdict was computed for this run"), or append the previous page body if keeping it is the intent.
-
standing (rated non-blocking last round; this change request does not rest on it) — The
actions/ai-inferencepin has a# v3comment, not the required# vX.Y.Z, and the comment explaining it is wrong for v3 —nightly.yml(theDraft narrativestep)- AGENTS.md §6: "pin … to a full commit SHA with a trailing
# vX.Y.Zcomment, never a moving tag". gh api repos/actions/ai-inference/git/matching-refs/tags/vlistsv2.1.1and earlier, plus only the floatingv3→2c43c91a…. There is nov3.x.ytag.- The workflow comment and the description say the action tags full semver releases alongside the major alias. That does not hold for the line pinned here.
- Confidence 85 · mechanical · Fix: pin a semver-tagged release (e.g.
v2.1.1,a7805884…) if its interface fits, or record a documented exception and correct the comment.
- AGENTS.md §6: "pin … to a full commit SHA with a trailing
-
standing (untested branches, re-found blind with a new set) — Much of the new workflow gating has no test that fails when it breaks
- Each of these mutations, made alone, left
cargo test -p xtask workflow_contractgreen (70 passed):- removing
if: ${{ !cancelled() }}fromrelease-readiness-nightly. A failede2e-report-nightlythen skips the readiness job and the publish job, so the wiki keeps a stale GO.release_readiness_nightly_gates_on_the_e2e_report_job_not_individual_lanesstill passes, so its name claims more than it checks. - changing the publish job's
!= 'skipped'to== 'success', or dropping its!cancelled() - dropping the
refs/heads/mainguard - feeding
--windows-resultfromneeds.nightly.result - inlining the narrative as
${{ }}inrun:(expression injection) - replacing the random
GITHUB_OUTPUTdelimiter with a fixedEOF - dropping
persist-credentials: false
- removing
- In
release_readiness.rs, these survivedcargo test -p xtask release_readiness(36 passed):- taking the scope from
headinstead ofhead_no_bang(:237-239), sofix(ci)!:leaks into Breaking Changes - dropping
.trim()inis_internal_only_scope(:215), sofix(core, ci)is misclassified - removing
*,_and the backtick, or'\r', fromescape_markdown(:395-397)
- taking the scope from
- With the production change reverted, every new test fails, because the jobs and functions it calls no longer exist.
- Confidence 100 · mechanical · Fix: assert these conditions, and add the two categorisation cases (bang with an internal scope; a space after the comma).
- Each of these mutations, made alone, left
-
standing (round 3, commit-message half), settled by putting it to the reviewer: anchored evidence, not a blind finding — Commit messages that would form the squash body still describe behaviour this PR no longer has
- This repository squash-merges, and the squash body is built from the commit messages, so these land on
main. No later message in the range corrects them:fc76d6aand40f5d62describe the per-lane--e2e-lane-resultgate, including "a lane that dies before producing a report still fails the verdict".1cb356dsays the gate uses "each GPU/WSL lane's own result".e20b631removed that gate, but its message does not say so, and no message says the gate moved toe2e-report-nightly.40f5d62says links and images are stripped from the narrative. The code now escapes brackets and angle brackets instead, and no message says so.fc76d6asaysextract_pr_number"is kept test-only". The function no longer exists.- On the
actions/ai-inferencetags,40f5d62says "bare-major tags" ande20b631says "full semver releases". Neither holds for the pinnedv3line.
- I checked the
e20b631message myself and confirmed it has no correction. - Fix: reword the commits (rebase), or have the squash body rewritten to describe the final behaviour before merge.
- This repository squash-merges, and the squash body is built from the commit messages, so these land on
Non-blocking
- new — The LLM narrative can render headings and tables, so it can print a fake verdict —
nightly.yml(the## Narrativesection)- Only
[ ] < >are escaped. A prompt-injected narrative could render## Release Readiness — ✅ GOor a fake| Area | Evidence | Status |table under a real NO-GO. That undercuts the guarantee that the verdict stays mechanical. - Confidence 70 · logic · Fix: put the narrative in a blockquote or
<details>labelled as LLM-drafted, or escape a leading#,|and>on each line.
- Only
- standing (was a tradeoff last round) — The two wiki publish jobs can race on the same wiki repo —
publish-e2e-wikiandpublish-release-readiness-wiki- They use separate concurrency groups, and each does a depth-1 clone, a commit and a
git push. If the pushes overlap, the second is rejected as non-fast-forward and its job goes red. - The description treats this as a retry question, but sharing one concurrency group (e.g.
wiki-push) would prevent it outright. - Confidence 70 · logic.
- They use separate concurrency groups, and each does a depth-1 clone, a commit and a
- new — A broken consolidated-report upload shows "EVIDENCE UNAVAILABLE" rather than NO-GO — the
release-readiness-nightly"Download consolidated nightly report" step has nocontinue-on-error. Ife2e-report-nightlydies before writingconsolidated/, the page shows the notice, although the failed report job is itself a known NO-GO. Confidence 70 · logic.
Decisions for the author
- The name
release-readinessis already in use — non-blocking-improvement.scripts/release_readiness.pyis the release trust gate (AGENTS.md §8,docs/release-trust.md, thenightly.ymlenv comments). The newcargo xtask release-readiness/release_readiness.rsis an unrelated nightly summary. A distinct name (e.g.readiness-report) would stop contributors and agents confusing the two. - A skipped build counts as a pass — tradeoff.
skippedis accepted fornightly,windows-nightlyande2e-report-nightly. That is safe today, becauseskip=trueonly happens when there are no commits since the last published nightly, and that nightly exists only if both builds succeeded. The cost is that the Build row shows ✅ on nights with no build at all. - Dropped scopes include
deps— tradeoff.fix(deps): …commits, such as a security bump to a shipped dependency, can affect end users but are left out of Bug Fixes.
Positive signals
assemble_factsis a pure function, so the GO/NO-GO rules are unit-tested at their boundaries (e.g. exactly one failure).- A missing Total row and an empty bundle both fail safe to NO-GO, and
git/ghnon-zero exits arebail!ed rather than swallowed. - The narrative reaches the shell through
env: NARRATIVErather than${{ }}inrun:. The facts are inlined with a random 16-hexGITHUB_OUTPUTdelimiter. - At this SHA,
ai-inferencepasses no--allow-tool, so an injection through the facts can only affect the text output. - The guard test runs the workflow's real shell block against real
render_tableoutput rather than a pinned string, which closes the hand-copied-guard gap from the sibling wiki job.
Deployment notes
- Needs a Copilot-licensed PAT in the
COPILOT_PATrepository secret. Without it, the narrative job fails (it is allowed to) and the page publishes without prose. - Publishes a new
Release-Readinesswiki page onmain, and needs the wiki already initialised (it is a prerequisite shared withpublish-e2e-wiki).
What this covered
- Read: every changed file in full,
32834b29…2ada5764(prw-base...HEAD). That includesxtask/src/release_readiness.rs, thextask/src/main.rscommand, the three newnightly.ymljobs, the newworkflow_contract.rstests, the prompt file and the docs paragraph. Also read: thee2e-report-nightly,publish-e2e-wiki, lane and trigger sections ofnightly.yml, and the renderer incrates/e2e-report/src/consolidated.rs. - Passes: code passes in two coupled groups (Rust logic; workflow plus contract tests) as independent read-only workers. Agent-instruction adherence, history, code-comment and design passes ran in the driver's context because of the 2-worker cap, so they were not independent. The prior-changes pass read the earlier automated reviews on #590, the sibling wiki-publish PR.
- CI, as data:
windows-build-and-testfails on this PR's own test (Blocking item 1).Test (affected crates)fails inpreflight_runs_the_real_reclaim_assert_clear(coreutils: unknown program 'llama-server'). The branch does not include5dfa9a8(#712, which addresses multicall coreutils and is onmain).E2E testsfails on twodash-*scenarios and on missingresolved modellines.
- Not done: ROCMAI-568 was not retrievable here. Not reconciled against this PR's review discussion.
- Check both the release and nightly artifact legs of a channel-matrixed lane independently in the report-check shell script, instead of one leg standing in for the whole lane; add a test covering a single missing leg. - Add mutation-coverage tests for nightly.yml's release-readiness gating: the release-readiness-nightly !cancelled() guard, --windows-result sourced from the Windows job (not the Linux one), the exact publish-release-readiness-wiki guard string, persist-credentials: false on both checkout steps, the random GITHUB_OUTPUT delimiter, and the narrative reaching the shell only via env rather than an inlined expression. - Add mutation-coverage tests for release_readiness.rs's categorize (scope read from head_no_bang, not head; whitespace trimmed around scope names) and escape_markdown (emphasis/code markers and bare carriage returns). - Re-pin actions/ai-inference to its real v2.1.1 semver release (v3 is a floating major alias with no semver tag yet) and set provider: copilot explicitly, since v2.1.1's default provider differs from v3's. - Fix a clippy unnested-or-patterns lint in total_e2e_failures. Signed-off-by: Juho Vainio <juho.vainio@amd.com>
|
Addressed in c333065 (round 3 of feedback): Blocking — fixed:
Non-blocking — fixed this round (not just acknowledged):
Judgment call — deliberately left as-is:
Other non-blocking items (LLM narrative fake-heading/table risk, two wiki-publish jobs racing, the "EVIDENCE UNAVAILABLE" download-failure edge case, and the three "decisions for the author" items — Build/test/lint: |
rominf
left a comment
There was a problem hiding this comment.
🔴 Automated review · pr-review-watcher · c333065
This automation never files a GitHub approval, so no approving review will
appear here whatever the outcome — the merge decision stays with a human
reviewer.
Round 5 — full review of the whole change at c333065 (not narrowed: the commit-message and missing-test objections cannot be scoped to a file). Each finding is marked new or standing. Round 4's change request was dismissed by the author. This change request restates every objection that still holds, and answers the author's round-4 summary comment.
Round-4 objections settled this round. None was re-found blind. Each was then put to the reviewer (anchored evidence, not a blind finding):
- Windows-lane failure of the new bash test: resolved. The test now has
#[cfg(unix)], andwindows-build-and-testpasses at this head (350 passed, 0 failed). - Backslash bypass of the narrative
sed: resolved. The line now starts with-e 's/\\/\\\\/g'. The reviewer ran it on the three bypass inputs and rendered the result withgh api markdown; no attacker link or image survives. Bare-URL autolinks remain, as the workflow comment says. - Empty or unparseable lane report gives GO: half resolved. An
EMPTYplatform row now counts as a failure. The other half still holds: the parser is tested only against hand-written tables, never againste2e-report's real output. That is folded into the first item under Blocking, whose fix already asks for exactly that test. - Only the
releaseleg of each lane is checked: resolved. All 7 channel-matrixed lanes now list both legs inLANE_REPORTS, and the help text, code comment and docs match. One stale comment remains (first item under Non-blocking). The PR description does not mention the change (fourth item under Blocking). - Stale-evidence notice refers to a verdict below the line: resolved. It now ends "No verdict was computed for this run."
# v3pin: resolved. The driver checked that it is nowactions/ai-inference@a7805884… # v2.1.1.- Untested workflow and gate branches and commit messages describing removed behaviour both still hold, and both were re-found blind (second, third and fifth items under Blocking). On the commit messages, the author proposes fixing them at merge time. Until the history or the squash body is actually reworded, the false claims land on
main, so this still gates.
CI at this head, compared by the driver against main (latest CI run at ea1d871):
Test (affected crates)fails inpreflight_runs_the_real_reclaim_assert_clear. This PR's code does not cause it: the branch predates5dfa9a8(#712), which fixes it, andmainpasses this job. A rebase settles it. This was rated non-gating last round, so this change request does not rest on it (sixth item under Blocking).E2E testsfails on the samedash-*quit scenarios asmain's own run. Does not gate.E2E tests (Strix Halo, Windows, current)failed to download the TheRock tarball on the runner (infrastructure).E2E consolidated report (self-hosted)fails because of that lane, which is correct. Neither gates.
Review — needs work
Full review of the whole change.
Implements ROCMAI-568 (nightly release-readiness wiki page). The ticket and the description agree on the feature. The description leaves out the LANE_REPORTS change, and the commit messages describe behaviour the code no longer has (both under Blocking).
Blocking
-
new — The E2E failure count is inflated about 90-fold, so the verdict can never be GO and the wiki prints a false failure count. —
xtask/src/release_readiness.rs:399-417(total_e2e_failures); its tests atxtask/src/release_readiness.rs:658-682- The "silently empty platform" pass checks every
|line in the document, not only the summary table. consolidated_summary_markdownwrites more tables after the summary: the expectation grid and command coverage. Their rows (| Scenario | …,| automations-01 … | ✅ |) have a non-numeric cell 5 and a non-PASS cell 8, so each row counts as one failure.- I ran the parser logic on the real
support-matrix.mdfrom nightly run 39554529729. The**Total**row has Fail = 7, and the function adds 620 phantom failures, for 627. - The parser tests only feed hand-written 4-line summary snippets, so they never see the producer's real output. The same blind spot would also miss a column reorder, which could silently read 0 failures and give a false GO.
- Confidence 100 · logic · Fix: scan only the rows between the
| Platformheader and the| **Total**row. Add a test that runse2e-report's realconsolidated_summary_markdown(with sidecars, so the grid renders) and parses its output.
- The "silently empty platform" pass checks every
-
standing (untested branches, re-found blind with a new set) — The gate logic has no tests that can fail: a cancelled or timed-out build reads as GO with every test green. —
xtask/src/release_readiness.rs:123-128,175-192,311-339- I replaced both build gates with
== "failure". All 46release_readinesstests still pass, socancelledortimed_outonnightly/windows-nightlywould yield GO. - A worker's mutation run also found that making
git log/gh issue listfailures return empty lists survives.run,collect_commit_subjectsandcollect_known_issueshave no tests. - Confidence 100 · logic · Fix: add
cancelledandtimed_outcases for both build gates, and failure-path tests for the two subprocess collectors (behind a seam if needed).
- I replaced both build gates with
-
standing (untested branches, re-found blind with a new set) — The workflow contract tests leave load-bearing wiring unpinned, and one test claims more than it checks. —
.github/workflows/nightly.yml:1736,:1867,:1874;xtask/src/workflow_contract.rs:3760-3770- I removed
continue-on-errorfrom both publish-job downloads and also hard-coded--nightly-result "success". All 75workflow_contracttests still pass. - Without
continue-on-error, download-artifact fails whenever there is no narrative, which is every night untilCOPILOT_PATexists. That fails the publish job and makes the "evidence unavailable" path unreachable. - The worker also found that these single mutations survive:
- dropping
release-readiness-narrativefrom the publish job'sneeds(the publish job then races the narrative); - dropping
fetch-depth: 0(git describethen fails every night); - renaming the page so it overwrites
E2E-Support-Matrix.md.
- dropping
release_readiness_narrative_reaches_the_shell_only_through_envonly checks that the safe lines are present (job.contains(...)). A second step that inlines${{ steps.draft.outputs.response }}intorun:would still pass, so the "only" in its name is a claim the test cannot fail on.- Confidence 100 · logic · Fix: pin these items in the contract tests. Make the env test also assert that
steps.draft.outputs.responseappears nowhere in the job except theNARRATIVE:env line (and theif:).
- I removed
-
new — The description does not mention the LANE_REPORTS change, which changes when a per-PR check fails. —
.github/workflows/nightly.yml:1575-1619,.github/workflows/e2e-selfhosted.yml:1691-1734,xtask/src/workflow_contract.rs(LANE_REPORTS tests)- Both workflows now require the
nightlyleg's artifact as well as thereleaseleg's for every channel-matrixed lane. Ine2e-selfhosted.ymlthat is the per-PR "E2E consolidated report (self-hosted)" check. - None of the Summary or "Changes since…" sections mentions it, so a reader of the description would not know a PR-gating check got stricter.
- Confidence 85 · architectural · Fix: describe it in the PR body, or split it into its own PR as was done with #682.
- Both workflows now require the
-
standing (round 3, re-found blind) — Commit messages that will land in the squash body describe behaviour the code no longer has. — commits
40f5d62,fc76d6a,ef489f5,1cb356d- They claim:
- a repeatable
--e2e-lane-resultflag (git grepfinds none at HEAD); release-readiness-nightlyneeding "the 6 GPU/WSL E2E lane jobs" (it needse2e-report-nightly);extract_pr_number"kept test-only" (it is gone);- "Strip markdown links/images" (replaced by escaping);
- a bare-
v3pin as "a frozen release, not a moving alias" (re-pinned to v2.1.1, and the later message calls v3 floating); - in
ef489f5, thatrender_tabledrops the header (reversed infc76d6a).
- a repeatable
- On main, that permanent record would describe a flag and gating design that never shipped.
- Confidence 85 · mechanical · Fix: squash or reword the history so the landed body describes the final design.
- They claim:
-
standing (rated non-gating last round; this change request does not rest on it) — The required check "Test (affected crates)" is red because the branch is behind main; this PR's code does not cause it. —
xtask/src/workflow_contract.rs:2895(preflight_runs_the_real_reclaim_assert_clear)- The failure is the multicall-coreutils decoy problem fixed on main by
5dfa9a8(#712). The branch's merge-base2d2dfc7predates that commit, 12 commits behindprw-base. Main's latest CI passes this job. - Confidence 100 · mechanical · Fix: rebase onto current main.
- The failure is the multicall-coreutils decoy problem fixed on main by
Non-blocking
-
new — Stale comment. —
xtask/src/workflow_contract.rs:1089- It still says "a channel axis below is checked through its
releaseleg", which this PR changes to checking both legs. - Confidence 90 · mechanical · Fix: update the sentence.
- It still says "a channel axis below is checked through its
-
new — A test's failure message gives the wrong reason. —
xtask/src/workflow_contract.rs:3737-3741(release_readiness_jobs_checkout_without_persisting_credentials)- The message says a leaked token "would let anything injected … push with repo write access", but both jobs have
contents: read. The check is worth keeping; only the stated reason is wrong. - Confidence 85 · mechanical · Fix: reword to the real exposure (a readable token reachable from later steps).
- The message says a leaked token "would let anything injected … push with repo write access", but both jobs have
-
new — Anyone who files a
bugissue can steer the published narrative. —.github/prompts/release-readiness-narrative.txt;xtask/src/release_readiness.rsbuild_known_issues/excerpt(…, 240)- The bug-report template auto-applies
bug, and 240-character body excerpts of open bug issues go into the prompt. Any GitHub user can therefore inject text such as "state all gates passed" into prose published on the official wiki. - The sed escaping neutralises markup but not misleading prose. The prompt's hard rules are the only defence.
- The description's "Left unchanged" note covers exposure of public text, not steering of the output.
- Confidence 70 · architectural · Fix: label the narrative section as LLM-drafted from untrusted input, or feed only titles.
- The bug-report template auto-applies
-
new — Breaking changes on types other than
feat/fixare dropped from every bucket, and a test asserts that. —xtask/src/release_readiness.rs:234-236; testcategorize_does_not_treat_a_bang_on_other_types_as_breaking- Conventional Commits allows
!on any type, sorefactor(cli)!:vanishes from the page. No such commits exist today. - Confidence 70 · logic · Fix: put any
type!:in Breaking.
- Conventional Commits allows
-
standing (was a tradeoff last round) — The Build row shows ✅ when
windows-nightlywas skipped. —xtask/src/release_readiness.rs:462-470- On a no-change night the row "Build (Linux + Windows nightly) | ✅" claims a pass with no Windows build behind it.
- Confidence 70 · logic · Fix: render skipped as "not run" rather than ✅.
Decisions for the author
- new — Every lane's failures count toward NO-GO, including lanes that are deliberately non-blocking (W7900, MI350P). — tradeoff
- The real 2026-10-21 report had Total Fail = 7, so even after fixing the inflation the verdict will likely be NO-GO most nights.
- A strict gate is defensible, but a verdict that is always NO-GO stops carrying signal.
- Confirm that counting non-blocking lanes is intended, or gate only on the required lanes.
Positive signals
- The facts reach
GITHUB_OUTPUTbehind a random delimiter, and the LLM response reaches the shell only throughenv:. Together these keep untrusted issue text out of expression interpolation. - The publish job writes an explicit "EVIDENCE UNAVAILABLE" page when the facts job fails, instead of leaving a stale GO on the wiki.
assemble_factsandbuild_known_issuesare pure functions, which keeps the verdict logic testable withoutgit/gh.
Deployment notes
- The narrative job needs a Copilot-licensed PAT in the
COPILOT_PATrepo secret. Until it exists the narrative is skipped every night, and the publish job depends on its download steps'continue-on-errorto still publish. - The new
Release-Readinesswiki page needs the same one-time wiki initialisation asE2E-Support-Matrix. - The per-PR "E2E consolidated report (self-hosted)" check now fails when the Strix Ubuntu
nightlyleg uploads no report, as well as thereleaseleg.
What this covered
I read every file in the change completely: the new xtask/src/release_readiness.rs, the main.rs wiring, the changed workflow_contract.rs tests, the new and changed jobs in nightly.yml and e2e-selfhosted.yml, the prompt and the docs hunk. I also read the e2e-report producer of support-matrix.md and the jobs these depend on or mirror. Reviewed range: 2d2dfc7…c333065a.
Two read-only workers ran in parallel: Rust logic, and workflows plus contract tests. I verified their headline findings myself:
- the 627 count, by re-running the parser logic on the downloaded artifact;
- the build-gate mutation: 46/46 tests pass;
- the workflow mutations: 75/75 tests pass.
The agent-instruction check (AGENTS.md: leak scan clean, action pins, docs sync), the history pass, CI attribution and the intent check (PR body, ROCMAI-568 by key) were run by me, the driver, not by an independent worker.
CI attribution for the failing checks:
- "E2E tests" (mock): the same two dash scenarios fail on main.
- "E2E tests (Strix Halo, Windows)": runner infrastructure (HTTP 403 on the TheRock tarball, GPU preflight).
- "E2E consolidated report (self-hosted)": fails correctly, downstream of the Windows lane.
Did not run:
- prior-changes: review comments on earlier PRs touching these files were not consulted, per this run's no-comments constraint.
routing/behavioralfor the LLM prompt: no API access.
Not reconciled against any discussion here. A worker left the scratch directory .rr-probe/ (the downloaded artifact) in the checkout.
- categorize(): treat `!` on any Conventional Commits type as breaking, not just feat!/fix!. - render_table(): render "not run" instead of a false (check mark) when the Windows nightly build was skipped. - Propagate the new Facts::build_skipped field to the two direct Facts literals in workflow_contract.rs tests. Signed-off-by: Juho Vainio <juho.vainio@amd.com>
Addressed in 78ae588 (see summary comment).
rominf
left a comment
There was a problem hiding this comment.
🔴 Automated review · pr-review-watcher · 78ae588
This automation never files a GitHub approval, so no approving review will
appear here whatever the outcome — the merge decision stays with a human
reviewer.
Round 6. This is a full review of the whole change at 78ae588. It was not narrowed, because the commit-message objection cannot be scoped to a file. Each finding is marked new or standing. The author dismissed round 5's change request.
This change request rests on one item only: the standing commit-message objection, the last item under Blocking. The two new items under Blocking are real, but they do not gate:
- Red checks.
Test (affected crates)and hostedE2E testsare fixed onmain(#712, #713/#719), and this branch predates those fixes, so a rebase clears them.E2E tests (MI300X, current)also fails onmain's own latest completed runs (39948978595, 39947062610). The Strix Windows lane failed downloading the external tarball, which is an infrastructure fault, and the consolidated report fails downstream of that lane, as it should. - Untested delimiter newline. I checked its consequence. If the line is removed, only the narrative job fails, and that job is
continue-on-error, so the page publishes without a narrative. The code is correct today, so this missing guard is below the gating floor.
The round-5 objections were settled as follows. None was re-found by the blind review. Each was then put to the reviewer one at a time, so the evidence below is anchored, not blind:
-
E2E failure count inflated ~90×: resolved.
total_e2e_failuresnow scans only the rows between| Platformand| **Total**. The reviewer re-widened the slice to the end of the document.total_e2e_failures_ignores_the_expectation_grid_and_command_coverage_tables, which builds its input with the realconsolidated_summary_markdown, then failed withSome(2)instead ofSome(0). One gap remains in that test: it writes noplatform.jsonsidecar, so the expectation-grid table never renders and its rows are never parsed. The same slice excludes those rows, so there is no live defect. The 627-versus-7 figure was not re-derived. -
A cancelled or timed-out build reads as GO with all tests green: resolved. The reviewer changed both build gates to
== "failure", and 4 of 58 tests then failed (the cancelled and timed-out cases for each build). Making either collector return an empty list on failure is now caught too, bycollect_commit_subjects_fails_on_a_bogus_since_tagandcollect_known_issues_in_fails_outside_a_github_repo. Still open:run()and themain.rsargument mapping have no test. That is carried as the non-blocking wiring item below. -
Workflow contract wiring that survived mutation: resolved. The reviewer applied each round-5 mutation on its own. Each failed exactly one of the 79
workflow_contracttests:- dropping
continue-on-erroron either publish download; - hard-coding
--nightly-result; - dropping
release-readiness-narrativefromneeds; - dropping
fetch-depth: 0; - renaming the page to
E2E-Support-Matrix.md; - adding a step that inlines
steps.draft.outputs.responseintorun:.
Observation, not tested: most of these are
contains-style checks, so a matching line inside a YAML comment could satisfy some of them. - dropping
-
The description omitted the LANE_REPORTS change: resolved. It now has its own paragraph.
-
Commit messages that describe removed behaviour: still holds. I checked this myself; it is restated as the last item under Blocking.
Review — needs work
Full review of the whole change.
Jira ROCMAI-568 is named but could not be retrieved here (no tracker tool). The description matches what the diff does, except for the two non-blocking inaccuracies listed below.
Blocking
- new (does not gate; see banner) — The head commit has five red checks, all caused outside this diff, and all fixed on
mainor infrastructure-related —Test (affected crates),E2E tests,E2E tests (MI300X, current),E2E tests (Strix Halo, Windows, current),E2E consolidated report (self-hosted)Test (affected crates)fails onlyworkflow_contract::tests::preflight_runs_the_real_reclaim_assert_clear(coreutils: unknown program 'llama-server'). That is the multicall-coreutils decoy problem fixed onmainby 5dfa9a8 (#712).- Hosted
E2E testsfails on dash quit timeouts and short-name serve steps. #713 and #719 onmainaddress the quit timeouts, andmain's latestE2E tests(run 39950566642) is green. - MI300X fails on a vLLM
"auto" tool choice400. - Strix Windows fails because the external TheRock tarball download failed six times. The self-hosted consolidated check then correctly reports that lane's missing report.
- The branch is 15 commits behind
mainand merges cleanly (git merge-tree). On the merged tree,cargo test -p xtask --binsran 375 tests and all passed, including the reclaim test and all 58 release-readiness tests.cargo clippy -p xtask --all-targets -- -D warningsis clean. - Confidence 85 (the red checks come from the rollup; the attribution comes from the logs and
main's runs) · mechanical · Fix: rebase ontomainand re-run until green.
- new (does not gate; see banner) — The newline written before the
GITHUB_OUTPUTdelimiter is load-bearing, and no test exercises it —.github/workflows/nightly.yml:1799-1801,xtask/src/release_readiness.rs(run→write_parented)facts.jsonis written withserde_json::to_string_prettyand has no trailing newline. Without the bareecho, the delimiter lands on the}line and the step output is never terminated. That is exactly the bug commit 45d3cd5 fixed in this PR.- Verification: I deleted that
echoand re-rancargo test -p xtask --bins release_readiness. All 58 tests still passed, includingrelease_readiness_narrative_delimiter_is_random_not_fixed. - Confidence 100 · mechanical · Fix: extend the contract test to run the extracted step against a
facts.jsonwith no trailing newline and parse the output file. Alternatively, end the file with\ninrunand assert that.
- standing (round 3 onwards; this is what gates) — The commit messages that will form the squash body describe behaviour the code no longer has. — commits
40f5d624,fc76d6a8,ef489f5d,1cb356de- The history is unchanged at this head. The four commits still claim:
- a repeatable
--e2e-lane-resultflag (git grepat HEAD finds none); - that
release-readiness-nightlyneeds "the 6 GPU/WSL E2E lane jobs" (it needse2e-report-nightly); - that
extract_pr_numberis "kept test-only" (it no longer exists); - "Strip markdown links/images" (replaced by escaping);
- that the bare-
v3pin is "a frozen release, not a moving alias" (it was re-pinned to v2.1.1); - that
render_tabledrops the header (reversed infc76d6a8).
- a repeatable
- The description says these "will be reworded in the squash". That plan does not work here:
- This repository's squash setting is
squash_merge_commit_message: COMMIT_MESSAGES, so the squash body is built from these commit messages. - rocm-cli merges through the merge queue, which builds that commit itself and offers no step where the body can be edited.
- Unless the history is rewritten before the PR is queued, these claims land on
mainas the permanent record.
- This repository's squash setting is
- Confidence 85 · mechanical · Fix: before queueing, squash or reword the branch history (for example, one commit whose message describes the final design), then force-push.
- The history is unchanged at this head. The four commits still claim:
Non-blocking
- new — The "EVIDENCE UNAVAILABLE" notice can be false, and when it is, it overwrites a valid page —
.github/workflows/nightly.yml(publish-release-readiness-wiki, the! -f table.mdbranch)- The table download is
continue-on-error: true, so a transient download failure afterrelease-readiness-nightlysucceeded also takes this branch. - The page then says "release-readiness-nightly failed before it could compute a verdict", which is not what happened. That breaks AGENTS.md §3's rule that a printed message must match the behaviour.
- Confidence 70 · logic · Fix: pass
needs.release-readiness-nightly.resultthroughenv:and derive the wording from it.
- The table download is
- new — The test for
collect_known_issues_inpasses without the branch it targets —xtask/src/release_readiness.rs(testcollect_known_issues_in_fails_outside_a_github_repo)- Per the review worker's mutation run, the test still passes with the
!output.status.success()check removed, because the JSON-parse error text also containsgh issue list. The code still fails closed either way. - Confidence 100 (worker run, not repeated by me) · mechanical · Fix: assert on "
gh issue listfailed".
- Per the review worker's mutation run, the test still passes with the
- new — Nothing tests the
main.rs→release_readiness::runwiring, and its five result strings are untyped —xtask/src/main.rs:396-412- Swapping
windows_resultande2e_report_job_resultwould compile and keep every test green. - A typo such as
succeswould read as a failed gate rather than as an error. - Confidence 70 · architectural · Fix: use a clap
ValueEnumJobResult(or an inputs struct) and testassemble_factsthrough it.
- Swapping
- new —
skippedcounts as passing fore2e-report-nightly, which is never legitimately skipped —xtask/src/release_readiness.rs:147- That job is
if: always(). For the build gates, "skipped" has a real meaning (a no-op night); for this gate it has none, and a test pins the lenient behaviour. - Today the separate artifact download would fail first, which hides this.
- Confidence 70 · logic · Fix: accept only
successfor this gate.
- That job is
- new — The
""status arm intotal_e2e_failuresis unreachable —xtask/src/release_readiness.rs:437- The producer only emits PASS, FAIL or EMPTY for platform rows. Removing the arm leaves all tests green.
- Confidence 70 · mechanical · Fix: drop the arm, or add the fixture that needs it.
- new — A
**Total**line before the header panics instead of returningNone—xtask/src/release_readiness.rs:424- When
total_idxis less thanheader_idx,lines[header_idx + 1..total_idx]panics. That contradicts the function's contract that a broken report returnsNone. The outcome still fails closed. - Confidence 70 · mechanical · Fix: search for Total only after
header_idx.
- When
- new — Stale or incorrect comments —
xtask/src/release_readiness.rs:63-66,.github/workflows/nightly.yml(ai-inference pin comment),docs/ci-hardware-testing.md:204- The
failing_gatesdoc omits theE2E (lane report check: …)gate. - "per AGENTS.md's full-semver-tag policy" is wrong: AGENTS.md §6 requires a full commit SHA plus a
# vX.Y.Zcomment. The pin itself is correct. I checkeda7805884…againstv2.1.1;providerandsystem-prompt-fileexist there, and the default provider isgithub-models. - "Unlike the wiki-publish jobs below" is wrong:
publish-e2e-wikiis described above that sentence. - Confidence 85 · mechanical.
- The
- new — Cosmetic branches that no test exercises —
xtask/src/release_readiness.rs- The tie-break on issue number in
build_known_issues, the exact-240 boundary inexcerpt, and thenightly_result == "skipped"half ofbuild_skippedall survive single-branch mutation. - Confidence 85 · mechanical.
- The tie-break on issue number in
- new — Breaking-change commits of internal types reach the user-facing Breaking list —
xtask/src/release_readiness.rs:240-246- Only scopes are filtered, so
ci!:,build!:andchore!:land under "Breaking Changes". - Confidence 70 · logic · Fix: if that matches the intent, also drop internal types on the
!path.
- Only scopes are filtered, so
- new — The
sdk_versionaxis is now handled differently from thechannelaxis next to it —.github/workflows/e2e-selfhosted.yml(around line 1088),xtask/src/workflow_contract.rs(uploaded_report_artifact)- The new reasoning ("either leg can die independently, so check both") applies equally to the
-n-1/-n-2legs, which are still represented bycurrent. That is pre-existing, but the two are now stated side by side. - Confidence 70 · architectural · Follow-up.
- The new reasoning ("either leg can die independently, so check both") applies equally to the
- new — The description contradicts itself on escaping — PR body
- The second-round section says issue-title escaping "covers text fed into the LLM prompt". It does not:
escape_markdownruns only inrender_table, andfacts.jsoncarries the raw titles. - The commit messages "address second/third/fourth round of review feedback" convey nothing either. Squash-merge collapses them, and the description says the squash body will be reworded.
- The second-round section says issue-title escaping "covers text fed into the LLM prompt". It does not:
Decisions for the author
- The E2E gate fails on any failure in any lane and either channel — tradeoff
- The ROCm
nightly-channel legs test upstream SDK nightlies. With this PR'sLANE_REPORTSchange, a nightly leg that dies (for example, on a TheRock nightly download) now failse2e-report-nightlyand so yields NO-GO. - It also fails the per-PR
E2E consolidated report (self-hosted)check when the Strix Ubuntunightlyreport is missing. - For: stricter evidence, and no lane vanishes silently. Against: the verdict can sit at NO-GO for upstream or infrastructure reasons, which weakens its signal. The description already flags the non-blocking-lanes half of this.
- The ROCm
- The name collides with the existing release gate — non-blocking-improvement
scripts/release_readiness.pyis already "release readiness" (dist-asset and signature verification, cited in AGENTS.md §8 anddocs/testing.md).- A different name, such as
nightly-verdict, would keep "run release readiness" unambiguous.
COPILOT_PATversus the built-in token — tradeoff- A review worker cited a GitHub changelog (2026-07-02) saying that Copilot CLI accepts the built-in token with
copilot-requests: writewhen org policy allows it. That would remove a long-lived PAT from a step that reads untrusted text. - I did not verify this. If it is wrong, the PAT is required, as the comment and description state.
- A review worker cited a GitHub changelog (2026-07-02) saying that Copilot CLI accepts the built-in token with
- Narrative steering through
bug-labeled issue text — answered-by-intent- PR description: "Narrative-steering via
bug-labeled issue titles/excerpts … is a real exposure, but fixing it … is a product decision … left for a follow-up." - Otherwise this would have been non-blocking. ai-inference v2.1.1 passes no
--allow-tool, so the risk is steered prose rather than tool use. Backticks and bare URLs in the narrative are not escaped. - Confirm the follow-up is still planned before
COPILOT_PATis set.
- PR description: "Narrative-steering via
- A missing
support-matrix.mdaborts the job instead of producing a NO-GO table — answered-by-intent- PR description: "A genuinely missing E2E report file … still fails the
release-readiness-nightlyjob viaread_to_string(...)?… the wiki-publish job's 'evidence unavailable' fallback … already covers this case." - Otherwise this would have been non-blocking, because the
render_tablecomment implies that unreadable evidence still publishes a table.
- PR description: "A genuinely missing E2E report file … still fails the
Positive signals
- The gate reads
e2e-report-nightly's own result, not the lane results, whichcontinue-on-erroralways reports assuccess. Lanes added toLANE_REPORTSlater are covered automatically. - The verdict is computed only in the pure
assemble_facts. The LLM output reaches the shell only throughenv:, behind a random heredoc delimiter. The sed escaping doubles backslashes first, so a pre-escaped\[cannot slip a live link through. - The grid-slicing regression test builds its input with the real
e2e_report::consolidated_summary_markdownrather than a hand-written snippet, so it tracks format drift in the producer. - The publish job's
!= 'skipped'condition means an outright upstream failure replaces a stale GO on the wiki instead of leaving it in place.
Deployment notes
- The narrative step needs a Copilot-licensed PAT in the
COPILOT_PATrepo secret. Without it the job fails,continue-on-errorhides the failure, and the page publishes without a narrative. - This creates a new
Release-Readinesswiki page. It relies on the wiki already existing, which the E2E matrix page already requires. - Every PR's
E2E consolidated report (self-hosted)check now also requires the Strix Ubuntunightlyleg's report. The nightlye2e-report-nightlyjob requires both legs for all seven lanes.
What this covered
-
Read: every file in
main...HEAD(2d2dfc7…78ae5883), completely, split into two coupled groups, each read by an independent worker:- group 1:
release_readiness.rs,main.rsand the prompt; - group 2: both workflows,
workflow_contract.rsand the docs.
Also read: the
e2e-reportproducer (consolidated.rs), the source of the pinned ai-inference action, and the history ofLANE_REPORTS. - group 1:
-
Ran:
- 58 release-readiness tests plus 78
workflow_contracttests at HEAD, with single-branch mutations; - the full xtask suite (375 tests) and xtask clippy, on a local merge with
main; - a mutation check confirming the delimiter gap.
- 58 release-readiness tests plus 78
-
Did not run:
- the design-review step as independent workers; I ran it myself because of the session's two-worker cap;
- the prior-changes pass (by instruction, no earlier review comments were read);
cargo xtask coverageagainst the xtask floor;actionlint(not installed).
-
The test
release_readiness_wiki_publish_guard_…was judged by reading only, because it writes to/tmp. -
No prompt-injection content was found in the checkout.
-
This report was not reconciled against the PR's discussion.
- facts.json now always ends with a trailing newline, so the $GITHUB_OUTPUT heredoc in nightly.yml's "Read facts for prompt" step can't land its closing delimiter on the same line as the JSON's closing brace even if that step's own echo guard is ever dropped. - e2e-report-nightly's result no longer accepts "skipped" as a passing gate; that job is if: always() and has no legitimate no-op-night skip. - total_e2e_failures no longer panics when a **Total** row precedes the | Platform header; it now searches for Total only after the header index. - Dropped the unreachable "" status arm in total_e2e_failures (the producer only ever emits PASS, FAIL or EMPTY). - collect_known_issues_in_fails_outside_a_github_repo now asserts the specific `gh issue list` failed message instead of a substring both the bail! and JSON-parse-error paths happen to share. - Fixed stale comments: the failing_gates doc omitted the lane report check gate, nightly.yml's ai-inference pin comment named the wrong AGENTS.md policy, and ci-hardware-testing.md pointed "below" at a section that's actually above. - Added tests for three previously-untested branches: the known-issue reaction tie-break, excerpt's exact-character-limit boundary, and build_skipped's skipped half for both the nightly and windows build gates. Left for a reply comment rather than guessed at: the commit-message history-rewrite objection (conflicts with this pass not force-pushing) and whether internal-type breaking commits (ci!:, chore!:) should be dropped from the Breaking bucket (reviewer explicitly flagged this as intent-dependent). Signed-off-by: Juho Vainio <juho.vainio@amd.com>
|
Addressed in Blocking — fixed:
Non-blocking — fixed this round:
Left unchanged (judgment call, not an oversight):
Note on |
|
Addressed in Blocking (non-gating per the review's own banner):
Blocking (this is what gates) — left unchanged, judgment call not an oversight:
Non-blocking — fixed:
Non-blocking — left unchanged (deliberate deferrals, not oversights):
All of the above is also now in the PR description under "Changes since the fourth round of review." |
Addressed in 0c5f1fe (see PR description's "Changes since the fourth round of review" section and inline reply comment). The two remaining blocking items (commit-message history-rewrite objection; internal-type breaking-commit classification) are explained as deliberate judgment calls in that reply, not guessed-at code changes.
Summary
cargo xtask release-readiness, which mechanically computes a GO/NO-GO verdict, categorized commits (New Features / Bug Fixes / Breaking Changes), known issues, and an Area/Evidence/Status table from git history, job results, and openbug-labeled issues.release-readiness-nightly→release-readiness-narrative→publish-release-readiness-wiki) that drafts short prose from those facts viaactions/ai-inference(using theCOPILOT_PATsecret, a Copilot-licensed PAT — the Copilot CLI that action shells out to does not accept a bareGITHUB_TOKEN) and publishes aRelease-Readinesswiki page.publish-release-readiness-wikishares the E2E support-matrix wiki job's branch/repo gate, own concurrency group, and degenerate-output guard, but additionally still runs (with an explicit "evidence unavailable" notice) whenrelease-readiness-nightlyitself fails outright, instead of leaving the wiki showing a stale verdict with no sign it's stale.release-readiness-nightly/release-readiness-narrativethemselves have no branch/repo guard — they run on any branch this workflow is dispatched on.ci,nightly,github,hooks,xtask,build,deps,e2e*) are excluded from the Bug Fixes / New Features summary, so the page stays focused on end-user-facing functionality and a summarized hardware-validation (E2E) result rather than CI housekeeping.Jira: ROCMAI-568
Changes since the automated review
e2e-report-nightlyjob's own result (--e2e-report-job-result), not individual per-lane results, so a lane that dies before uploading a report still fails the gate instead of silently vanishing from the consolidated totals."E2E (report unreadable)") instead of silently reading as zero failures. The status table's header always renders regardless (confirmed by test); this case does not trippublish-release-readiness-wiki's degenerate-output guard, which only trips when the table has no header row at all (e.g. a crash before writing anything).nightly/windows-nightlyjob (a no-op night) no longer causes a false NO-GO.extract_pr_numberno longer matches a mid-sentence(#NNN)parenthetical.assemble_factsfunction so the GO/NO-GO logic is directly unit-tested (previously zero coverage on the orchestration/rendering path).mainand re-authored 3 commits that had picked up the wrong git identity.Changes since the second round of review
publish-release-readiness-wikinow runs (instead of being skipped entirely) whenrelease-readiness-nightlyfails outright, publishing an explicit "EVIDENCE UNAVAILABLE" notice to the wiki rather than silently leaving a stale verdict in place with no indication it's stale.render_table's status table now lists the actualfailing_gatesreason strings beneath the Area/Evidence/Status table (e.g.E2E (lane report check: cancelled)), since a cancelled lane otherwise renders as a contradictory "0 failure(s)" next to a red ❌.publish-release-readiness-wiki'sseddoubles\and escapes[,],<,>instead of trying to strip[text](url)patterns). The old stripping regex left<img>tags, reference-style[a][1]links, and nested[outer [inner](url)](url)links untouched or still live; escaping brackets/angle-brackets can't be bypassed by nesting, since an escaped bracket is never re-parsed as link/image syntax. This is distinct from the issue-title escaping above: that covers titles asrender_tablerenders them into the wiki's status table, this covers the LLM's own drafted output on its way to the same page. Neither coversfacts.jsonitself, which is what the LLM prompt is actually built from and still carries raw, unescaped titles.build_known_issuesmapping/sort function out ofcollect_known_issues, so its test exercises the real production filter/sort instead of a parallel reimplementation that would pass even if the production logic broke.skippedtreated as passing for the nightly build, the Windows build, and the E2E report job (each asserted separately), the exactn > 0vsn > 1failure-count boundary,escape_markdown's backslash-doubling/newline-collapsing/angle-bracket-escaping, and a multibyte-safe guard insplit_trailing_pr_reference(removing it could panic by slicing mid-character on a subject ending in a multibyte character after a mid-sentence(#N)reference).actions/ai-inferencepin comment: that action tags full semver releases (v1.0.0,v2.1.1, ...) alongside a floating major alias, not bare majors only — the SHA pin still freezes an exact commit either way.docs/ci-hardware-testing.md's release-readiness section: it previously (incorrectly) scoped the whole feature tomainand claimed the wiki-publish guards are identical topublish-e2e-wiki's.LANE_REPORTSnow requires both thereleaseandnightlyleg's uploaded report for every channel-matrixed lane, not just thereleaseleg, in bothnightly.ymlande2e-selfhosted.yml. Ine2e-selfhosted.ymlthis means the per-PR "E2E consolidated report (self-hosted)" check now also fails if the Strix Ubuntunightlyleg uploads no report, not just itsreleaseleg.Left unchanged (judgment calls, not oversights)
publish-e2e-wikijob and this repo's public issue tracker already operate under, so it isn't a new exposure introduced here.publish-e2e-wikiandpublish-release-readiness-wikiuse separate concurrency groups (each only serializes against itself) and neither retries a transient wiki-clone failure; a retry/backoff story for wiki pushes would be a repo-wide improvement, not something specific to this PR's new job.release-readiness-nightlyjob viaread_to_string(...)?rather than producing a NO-GO page directly; the wiki-publish job's "evidence unavailable" fallback (above) already covers this case at the publish step, so the page never goes stale or silently shows a wrong verdict — only the job's own logs say why the page didn't update, and that's within the same tolerance the equivalentpublish-e2e-wikipath already accepts.Changes since the third round of review
total_e2e_failuresnow scans only the summary table's row range (between the| Platformheader and the| **Total**row), instead of every|-delimited line in the document — it was also matching rows from the expectation-grid and command-coverage tablese2e-reportprints after the summary, which inflated the failure count roughly 90-fold against a real report and made the verdict unable to ever read GO. Added a regression test againste2e_report::consolidated_summary_markdown's real output, not a hand-written snippet.nightly,windows-nightly) now treatcancelled/timed_outas failures instead of reading as GO. Added failure-path tests forcollect_commit_subjectsandcollect_known_issues(behind acurrent_dirseam) so agit/ghfailure is no longer an untested branch.fetch-depth: 0onrelease-readiness-nightly's checkout, the publish job'sneedson both upstream jobs, the twocontinue-on-error: trueartifact downloads, the distinct wiki page names, and the dynamic--nightly-resultread; and made the env-only-reaches-the-shell test fail if any other line in the job also referencessteps.draft.outputs.response.categorizenow puts anytype!:(not justfeat!/fix!) in the Breaking bucket, matching Conventional Commits' actual grammar.windows-nightlywas skipped, instead of claiming a pass with no Windows build behind it.workflow_contract.rs(no behavior change).Left unchanged (judgment calls, not oversights)
--e2e-lane-resultflag, "6 GPU/WSL E2E lane jobs", link-stripping, etc.) are left as-is in this pass; correcting them means rewriting already-pushed history, which this PR doesn't force-push to do. They'll be reworded in the squash-merge body at merge time instead.Test (affected crates)failing onpreflight_runs_the_real_reclaim_assert_clearis the pre-existing multicall-coreutils decoy issue fixed onmainby fix(ci): keep the GPU reclaim decoys alive on multicall coreutils #712; this branch's merge-base predates that fix. A rebase (not a code change in this diff) settles it, and it was already rated non-gating.bug-labeled issue titles/excerpts (any GitHub user can author text an LLM then drafts into wiki prose) is a real exposure, but fixing it (labeling the section as LLM-drafted from untrusted input, or feeding only titles) is a product decision about how much narrative detail to keep, not a one-line fix; left for a follow-up.Changes since the fourth round of review
facts.jsonnow always ends with a trailing newline, so the$GITHUB_OUTPUTheredoc delimiter innightly.yml's "Read facts for prompt" step can't land on the same line as the JSON's closing brace even if that step's ownechoguard is ever dropped.e2e-report-nightly's result no longer acceptsskippedas a passing gate; that job isif: always()and has no legitimate no-op-night skip.total_e2e_failuresno longer panics when a**Total**row precedes the| Platformheader; it now searches for Total only after the header index.""status arm intotal_e2e_failures(the producer only ever emits PASS, FAIL, or EMPTY).collect_known_issues_in_fails_outside_a_github_reponow asserts the specificgh issue listfailure message instead of a substring both thebail!and JSON-parse-error paths happen to share.failing_gatesdoc omitted the lane-report-check gate;nightly.yml'sai-inferencepin comment named the wrong AGENTS.md policy;ci-hardware-testing.mdpointed "below" at a section that's actually above.excerpt's exact-character-limit boundary, andbuild_skipped's skipped half for both the nightly and Windows build gates.Left unchanged (judgment calls, not oversights)
COMMIT_MESSAGES) builds the squash body verbatim from these commit messages and the merge queue has no step to edit it, this needs to happen as an actual history rewrite before the PR is queued, not "at merge time" as earlier rounds assumed.ci!:,chore!:,build!:) should be dropped from the Breaking bucket is left as the reviewer explicitly flagged it as intent-dependent; no such commits exist in this branch today, so it doesn't affect the current page's output either way.publish-release-readiness-wiki's "EVIDENCE UNAVAILABLE" notice can still be wrong when it's a transient table-download failure rather than an actualrelease-readiness-nightlyfailure (both take the same! -f table.mdbranch); narrowing this needs threadingneeds.release-readiness-nightly.resultthroughenv:and is left for a follow-up.main.rs→release_readiness::run's argument wiring and its 5 result strings remain untested and untyped (a swappedwindows_result/e2e_report_job_resultor a typo likesucceswould compile and read as a failed gate rather than an error); aValueEnumJobResultwould be the fix, left for a follow-up since it's a larger refactor ofmain.rs's argument surface than this pass's scope.sdk_versionaxis being checked differently from thechannelaxis inworkflow_contract.rspredates this PR; this round only put the two side by side, so it's left as a follow-up rather than a fix bundled into an unrelated pass.Test plan
cargo test -p xtask(full suite, 371 tests, including unit tests for the fixes above and workflow-contract tests exercising the real publish guards — including the three-way missing/degenerate/well-formed table guard and the narrative-escaping sed onpublish-release-readiness-wiki— against actual extracted shell snippets, not pinned strings)cargo clippy -p xtask --all-targets --all-features -- -D warningscargo fmt -p xtask --checkcargo xtask release-readinessend-to-end locally against this branch's real commit history and a fake E2E report, inspectedtable.mdoutputnightly.ymlon this branch (run 38396499964) and confirmedrelease-readiness-nightlyandrelease-readiness-narrativecomplete successfully; downloaded and read thenarrative.mdartifact to confirm it's genuine grounded prose citing real PR/issue numbers, not a refusal or empty output