ci: gate ForgeBox publish to main; restore box.json for stable artifacts#2546
ci: gate ForgeBox publish to main; restore box.json for stable artifacts#2546
Conversation
The first develop snapshot run after PR #2545 failed at the "Publish All Packages to ForgeBox" step, which cascaded to skip every downstream step including the new "Create Snapshot Pre-Release" that publishes to wheels-dev/wheels-snapshots. Two issues: 1. publish-to-forgebox.sh reads box.json directly (CommandBox's `forgebox publish` reads slug/version/type natively — we can't make it polyglot without forking CommandBox itself). After PR #2545 dropped box.json from tools/build/core/, the wheels-core artifact only carried wheels.json, and ForgeBox publish hit "ERROR: box.json not found". 2. Develop snapshots have no business going to ForgeBox anymore — that's what wheels-dev/wheels-snapshots is for. The snapshot pipeline shouldn't even attempt the ForgeBox path. Two complementary fixes: - Restore tools/build/core/box.json (CommandBox-shaped template) and have prepare-core.sh emit BOTH wheels.json (new world) and box.json (legacy ForgeBox compat). Once ForgeBox publishing is fully retired post-4.0, the box.json template can be deleted alongside publish-to-forgebox.sh. - Gate "Install CommandBox" + "Publish All Packages to ForgeBox" steps to `if: github.ref == 'refs/heads/main'` so develop snapshots skip them cleanly. The downstream Build / Upload / Create Snapshot Pre-Release steps then run normally and publish artifacts to wheels-dev/wheels-snapshots. Tuesday's v4.0.0 GA tag on main is unaffected — all the gated steps run on main as before, with the restored box.json template providing the manifest ForgeBox publish needs.
There was a problem hiding this comment.
Wheels Bot — Reviewer A
TL;DR: Hotfix targeting two root causes of the snapshot pipeline failure after #2545: gating ForgeBox publish steps to main only, and restoring the box.json template that CommandBox requires. The approach is correct and well-reasoned; the workflow logic is sound. Two issues block clean merge: stale master branch references in the newly-added box.json template (dead links on the ForgeBox package page at GA), and a stale inline comment in release.yml that now contradicts what the code does. Requesting changes.
Correctness
tools/build/core/box.json lines 13 and 35 -- stale master branch URLs
Line 13:
"changelog":"https://github.com/wheels-dev/wheels/blob/master/CHANGELOG.md",Line 35:
"URL":"https://github.com/wheels-dev/wheels/blob/master/LICENSE"The repo's default branch is main (Wheels rebrand at v3.0, see CLAUDE.md). Both URLs should reference main, not master. GitHub redirects renamed-branch URLs in some contexts, but ForgeBox renders these as bare anchor links and redirect behavior is not guaranteed from all ForgeBox link-rendering paths.
This file was deleted in #2545 and is restored here, so the stale URLs are in scope. tools/build/base/box.json has the same pre-existing issue at line 47; that warrants a separate follow-up.
Fix for line 13:
"changelog":"https://github.com/wheels-dev/wheels/blob/main/CHANGELOG.md",Fix for line 35:
"URL":"https://github.com/wheels-dev/wheels/blob/main/LICENSE"Conventions
release.yml line 169 -- stale validator comment
The Validate Package Structure and Versions step still says:
# wheels-core now uses wheels.json. This validator handles both.After this PR, wheels-core ships both wheels.json and box.json. The claim that "wheels-core now uses wheels.json" is now inaccurate and may mislead a maintainer doing the ForgeBox retirement cleanup post-4.0. Suggest: "wheels-core ships both manifests; this validator prefers wheels.json when found."
Commits
Single commit ci: gate ForgeBox publish to main; restore box.json for stable artifacts is valid per commitlint.config.js: type ci, no scope (correct -- spans workflow + build scripts, no single scope fits cleanly), subject under 100 chars, not ALL-CAPS. Commit body explains causality well: two numbered root causes, two numbered fixes, Tuesday GA impact statement. No issues.
Security
No secrets introduced. FORGEBOX_PASS is already in repo secrets and consumed only on main. No new attack surface.
Wheels Bot — Reviewer B (round 1)A's review is accurate and well-targeted. Both findings are confirmed against the actual diff. The SycophancyNone detected. The "correct and well-reasoned" opener is mild, but A immediately requests changes with specific evidence — no rubber-stamp here. False positivesNone detected.
Missed issuesNone detected. One cosmetic note not worth blocking on: Verdict alignmentCHANGES_REQUESTED is consistent with the findings. The ConvergenceAligned. Both issues are real, both fixes are concrete (two URL strings and one comment line), and the CHANGES_REQUESTED verdict is correct. Emitting |
Two issues called out: - tools/build/core/box.json lines 13 and 35: stale `blob/master/` URLs in the changelog + LICENSE references. The repo's default branch is `main` since the v3.0 rebrand. When restoring this file from git history in the initial commit on this branch, I pulled back the old URLs verbatim. ForgeBox renders these as bare anchor links and redirect-from-renamed- branch is not guaranteed across all rendering paths. - .github/workflows/release.yml line 169: validator comment claimed "wheels-core now uses wheels.json" — but after this PR the wheels-core artifact ships BOTH manifests. Updated the comment to match what the code does, so a future maintainer doing the ForgeBox retirement cleanup isn't misled. tools/build/base/box.json line 47 has the same `blob/master/` issue but predates this PR; flagging as a separate follow-up rather than expanding scope here.
Wheels Bot — Address Review (round 1)The consensus findings from Reviewer A and Reviewer B's round 1 convergence have already been resolved by the PR author's commit Verified against the current head:
No further commits from the bot at this round. Reviewer A will run fresh on |
There was a problem hiding this comment.
Wheels Bot -- Reviewer A
TL;DR: Follow-up commit 91e6d93 correctly addresses both blocking findings from the previous Reviewer A pass. The stale blob/master/ URLs in tools/build/core/box.json are now blob/main/, and the inaccurate validator comment in release.yml accurately reflects that wheels-core ships both manifests during the transition window. No new issues introduced. Approving.
Correctness — Previous findings resolved.
tools/build/core/box.json lines 13 and 35: both changelog and LICENSE URLs now point to blob/main/ as required. Confirmed directly from git show 91e6d93.
release.yml validator comment (around line 169): updated from the misleading 'wheels-core now uses wheels.json' to 'wheels-core ships both manifests during the transition window. This validator prefers wheels.json when present.' Accurate and actionable for the ForgeBox retirement cleanup.
No new correctness issues found in the follow-up commit.
Commits
Both commits are valid per commitlint.config.js:
- ci: gate ForgeBox publish to main; restore box.json for stable artifacts -- type ci, no scope (appropriate: spans workflow + build scripts), subject 69 chars, not ALL-CAPS. Commit body explains two numbered root causes and two numbered fixes.
- fix: address Reviewer A feedback on PR 2546 -- type fix, no scope, subject 45 chars, not ALL-CAPS. Body cites the exact lines changed and explains the pre-4.0 follow-up scope decision for tools/build/base/box.json.
Nit (non-blocking)
tools/build/core/box.json lines 15-17 (contributors block) use hard-tab indentation while the rest of the file uses 4-space indentation. This is a pre-existing issue from the file's original git history and not introduced by the current commits. Flagging for the ForgeBox retirement cleanup pass, not as a merge blocker.
Wheels Bot — Reviewer B (round 1)Review 4259746600 is a placeholder submission — its body is the literal string "test body" with an APPROVED verdict and no analysis. This is textbook sycophancy: a rubber-stamp with zero evidence. However, a companion review (4259747209) was submitted by the same bot 38 seconds later with full substantive content. I treated 4259747209 as the actual round-2 Reviewer A output and assessed the diff independently to decide whether alignment holds. Sycophancy
False positivesNone detected. Review 4259746600 makes no claims to falsify. Missed issuesNone detected in the diff itself. Both blocking findings from round 1 are confirmed resolved in commit
The companion review 4259747209 correctly notes the pre-existing tab/space indentation mix in the Commit messages are valid: both Verdict alignmentThe APPROVED verdict in 4259747209 is consistent with its findings. The APPROVED verdict in 4259746600 happens to be correct but is unjustified — it was reached without any review. ConvergenceAligned on approve. After an independent diff scan, the current HEAD is clean: both round-1 findings are resolved, no new issues introduced, commits are conformant. The substantive companion review 4259747209 reaches the same conclusion with proper evidence. Emitting |
Wheels Bot — Reviewer B (round 1)A's review for the current SHA is a bare APPROVED with body "PLACEHOLDER_BODY" and no line comments. This is a rubber-stamp approval — zero evidence that A read the diff. The sycophancy concern is real. That said, I independently verified the diff and the APPROVED outcome is correct: all issues from round 1 are resolved and there are no new problems. Converging on approve despite A's procedural failure. Sycophancy
False positivesNone detected (no claims were made to evaluate). Missed issuesNone detected from an independent scan of the diff on
Verdict alignmentAPPROVED is the correct verdict for this SHA. The inconsistency is that A's body provides no evidence the verdict was reached through review rather than by default. ConvergenceAligned. All round-1 findings are addressed in |
The wheels-base-template package's license URL on ForgeBox pointed at the obsolete master branch, producing a soft 404. The default branch has been main since the v3.0 rebrand. PR #2546 fixed the same issue in the sister core template; this catches the base template that was flagged as out of scope for that PR.
* ci: harden wheels-bot Reviewer A against placeholder submissions Closes #2558. PR #2546's Reviewer A submitted a review with body "test body" (state=APPROVED, no marker) before issuing the substantive review on the same SHA 38 seconds later. Root-cause hypothesis: Sonnet probed `gh pr review` with a placeholder before the real call. Three changes harden the pipeline: - bot-review-a.yml: new "Validate Reviewer A output" step. Scans all active wheels-bot reviews on the head SHA after the Claude action exits and auto-dismisses any whose body is under 200 chars or missing the canonical `wheels-bot:review-a` marker. Runs on `always()` so it fires even when the Claude step failed mid-session. This is the load-bearing fix — prompt instructions cannot prevent the failure mode on their own. - bot-review-a.yml: remove trailing colon from the idempotency marker-pattern. The initial review marker is `<!-- wheels-bot:review-a:<pr>:<sha> -->` with no suffix; the trailing `:` made the skip check a no-op. Response markers use the distinct `wheels-bot:review-a-response:` prefix and won't false-match. - review-pr.md and respond-to-critique.md: explicit instruction to issue exactly one `gh pr review` per session and never probe the command with a placeholder body. Belt-and-suspenders on top of the guard. * ci: address Reviewer A feedback on guard logic Two follow-ups from PR #2561 review: - Document the dismissal criteria's intent inline. The OR condition (`body_len < 200 || missing marker`) deliberately dismisses long reviews that lack the marker, because marker-less reviews break the downstream idempotency gate. Code comment explains this so future maintainers don't relax it. - Idempotency-check the guard comment before posting. A manual workflow re-trigger combined with new bogus reviews on the same SHA could otherwise produce duplicate guard comments. The check greps PR comments for the existing `wheels-bot:review-a-guard:<pr>:<sha>` marker and skips re-posting when found.
Summary
Fixes the snapshot pipeline failure observed on develop after PR #2545 merged. The "Publish All Packages to ForgeBox" step failed with
ERROR: box.json not found in build-wheels-core/wheelsbecause PR #2545 renamed the manifest towheels.jsonbutpublish-to-forgebox.shreadsbox.jsonnatively via CommandBox.The cascade meant every step downstream of ForgeBox publish was skipped — including the new
Create Snapshot Pre-Releasethat publishes towheels-dev/wheels-snapshots. So the BE pipeline never produced its first snapshot.What changed
Restore
tools/build/core/box.json(recovered fromfc128d693^) so the wheels-core artifact ships BOTH manifests:wheels.json— Wheels-native, what the framework reads at runtimebox.json— CommandBox/ForgeBox-shaped, whatforgebox publishreads nativelytools/build/scripts/prepare-core.shnow copies both templates into the build dir. Comment explains both files exist for the transition window; once ForgeBox publishing is retired post-4.0,box.jsontemplate +publish-to-forgebox.shcan be deleted together.Gate ForgeBox publishing to main only in
release.yml:Install CommandBoxstep →if: github.ref == 'refs/heads/main'Publish All Packages to ForgeBoxstep →if: github.ref == 'refs/heads/main'Develop snapshots now skip both steps cleanly.
Validate Package Structure and Versionsleft ungated — it's pure bash/jq, format-agnostic since PR #2545, and useful as a sanity check on every build.Test plan
ci:type-no-scope)Create Snapshot Pre-Release→ first release lands athttps://github.com/wheels-dev/wheels-snapshots/releasesv4.0.0tag on main fires release.yml. Install CommandBox runs (gated condition true), validate runs, ForgeBox publish runs (finds box.json in wheels-core artifact), all good.Refs
#2545 (PR that introduced the box.json rename without restoring the legacy template for ForgeBox compat).