docs(web/guides): correct upgrading guides against live 4.0.3 behavior (audit group 6) - #3123
Conversation
…r (audit group 6) Fixes 12 findings from the 2026-06 guide behavioral audit (p2-5-upgrading): upgrading/index.mdx - versioning policy: CHANGELOG headings are not limited to the six Keep-a-Changelog sections - version sources: drop nonexistent box.json; application.$wheels.version comes from BuildInfo/vendor/wheels/wheels.json (placeholder @build.version@ in source), not a literal - release cadence: latest tag is v4.0.3 (GA 2026-06-09), drop stale SNAPSHOT+1524 framing upgrading/3x-to-4x.mdx - CORS both-paths section: layers are additive, not overwriting; duplicate Access-Control-Allow-Origin breaks browsers — instruct disabling the global setting (#3114) - Item 3: setting name is csrfCookieEncryptionSecretKey (csrfEncryptionKey is inert); cookie-store-only scope + production throws Wheels.Security.MissingCsrfKey (#3115) - Item 8: wheels.Testbox upgrade-check flag is post-4.0.3 (develop only) - MCP deprecation: wheels mcp setup --force does not exist; document manual .mcp.json - browser fixtures: routing is first-registration-wins — app routes can NOT override fixtures; point at browserLoginAsHandler - post-upgrade step 1: wheels test (tools/test-local.sh is monorepo-only) upgrading/changelog.mdx - same heading-list correction; release-heading shape shown - [Unreleased]: mention changelog.d/ fragments as the pending-entry mechanism - snapshot Aside: SNAPSHOT tags exist (series ends at +1783), not 'no tag per snapshot' verify:docs exit 0 on all three pages (13 tagged blocks pass on 3x-to-4x.mdx). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
There was a problem hiding this comment.
Wheels Bot — Reviewer
TL;DR — This PR corrects 12 stale/wrong claims across the three upgrading/ guide pages against live 4.0.3 behavior. I independently verified the factual claims against the repo's tags, CHANGELOG.md, framework source, the CLI source at both v4.0.3 and develop, and issues #3114/#3115 — 11 of the 12 findings check out exactly as described. However, one of the new date claims is itself wrong: the GA date for 4.0 is stated as 2026-06-09, but 4.0.0 shipped 2026-05-12 (2026-06-09 is the 4.0.3 date). In a PR whose entire purpose is replacing stale version/date facts with verified ones, that's a correctness finding, so the verdict is request changes. One small fix and this is good to merge.
Correctness
upgrading/index.mdx:34 — wrong GA date for the 4.0 line.
git tag --sort=-v:refnameshows the latest release (currentlyv4.0.3; the 4.0 line went GA 2026-06-09).
The 4.0 line went GA when v4.0.0 was cut, and that was 2026-05-12, not 2026-06-09:
CHANGELOG.md:236:# [4.0.0](https://github.com/wheels-dev/wheels/releases/tag/v4.0.0) => 2026-05-12(tagv4.0.0creatordate 2026-05-11)CHANGELOG.md:62:# [4.0.3](…) => 2026-06-09— 2026-06-09 is the v4.0.3 release date, which this sentence conflates with the GA date. (The PR body and commit message repeat the same conflation — "4.0 GA shipped 2026-06-09" — but the doc line is what needs fixing.)
Suggested wording:
shows the latest release (currently `v4.0.3`, released 2026-06-09; the 4.0 line went GA with `v4.0.0` on 2026-05-12).
Docs
upgrading/changelog.mdx:114 — "Most pre-GA snapshot builds got their own tag" overstates tag coverage (non-blocking). The v4.0.0-SNAPSHOT+NNNN tag series spans +1442 through +1783 (335 tags, near-contiguous within that window) — any build number below +1442 definitively has no tag. The sentence's hedge ("not every build number did") and the fallback advice are fine, but a reader on an early snapshot could conclude their build "probably has a tag" when it can't. Consider stating the range, e.g. "Later pre-GA snapshot builds got their own tag (the tagged series spans +1442 through +1783, where the 4.0.0 GA was cut)". The fix correctly replaces the flat-wrong "There is no tag per snapshot" either way.
Verified claims (for the record)
Everything else in the diff survived independent verification — listing it so a human merging this doesn't have to re-check:
- index-01 / changelog-04:
CHANGELOG.mdH3 headings includeBug Fixes,Breaking Changes,Model/View/Controller Enhancements,Miscellaneous, etc. — far beyond the six Keep-a-Changelog sections. Confirmed by heading scan. - index-02:
vendor/wheels/events/onapplicationstart.cfc:104-105setsapplication.$wheels.versionfromnew wheels.BuildInfo().version();vendor/wheels/wheels.jsoncarries"version": "@build.version@". No readable literal — confirmed. - index-03: no
box.jsonat the repo root — confirmed. - 3x4x-04: matches issue #3114's live probe (duplicate
Access-Control-Allow-Origin, additivecfheader, OPTIONS handled solely by the global path, middleware skipping the root/congrats route) — confirmed against the issue's observed-output section. - 3x4x-08:
vendor/wheels/events/init/security.cfm:3defaultscsrfStore = "session";security.cfm:30initializescsrfCookieEncryptionSecretKey;vendor/wheels/controller/csrf.cfc:148-159throwsWheels.Security.MissingCsrfKeyin production and auto-generates with awheels_securitywarning elsewhere.csrfEncryptionKeyhas zero framework consumers (only the CLI-rule spec references it, per #3115). All confirmed. - 3x4x-19:
git grep 'wheels\.Testbox' v4.0.3 -- cli/lucli/Module.cfc→ zero hits;origin/develop→ 3 hits (Module.cfc:4412,4430,4434). The combined upgrade-check rule is indeed develop-only / post-4.0.3 — confirmed. - 3x4x-25: no
wheels mcp setupcommand exists; the manual.mcp.jsonsnippet matches the canonical one inCLAUDE.md§ CLI / MCP — confirmed. - 3x4x-28:
vendor/wheels/Mapper.cfc:273-275keeps the first registration for a static route key (if (!StructKeyExists(...staticRoutes, local.staticKey))), and fixtures mount beforeconfig/routes.cfm(vendor/wheels/public/browser-fixtures/routes.cfm,$lockedLoadRoutes);browserLoginAsHandleris a real setting (browser-fixtures/routes.cfm:35-39). The inverted claim is correct. - 3x4x-31:
tools/test-local.shexists only in the framework monorepo;wheels testis the right command for scaffolded apps — confirmed. - changelog-06: 335
v4.0.0-SNAPSHOT+*tags exist, series ending at+1783with GA cut immediately after (tag dates 2026-05-10 → 2026-05-11) — confirmed (subject to the coverage nit above).
Commits
Single commit 02ee23210, header docs(web/guides): correct upgrading guides against live 4.0.3 behavior (audit group 6) — valid type, ≤ 100 chars, informative body, DCO sign-off matches the author identity (Peter Amiri <peter@alurium.com>). No changelog fragment needed (docs-type change). No findings — though note the commit body repeats the GA-date error; since the repo squash-merges with the PR title, no rewrite is needed.
…ng guides The 4.0 line went GA 2026-05-12 with v4.0.0 (CHANGELOG.md:236); 2026-06-09 is v4.0.3's release date — say both instead of conflating them. The legacy global CORS path (Global.cfc $setCORSHeaders) emits Access-Control-Allow-Headers and Access-Control-Allow-Methods unconditionally whenever allowCorsRequests is on and the origin config is non-empty; only Access-Control-Allow-Origin (+Vary) is origin-gated. Scope the origin-gate claim to Allow-Origin and note the middleware is the layer that gates all of its headers on the match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
There was a problem hiding this comment.
Wheels Bot — Reviewer
TL;DR — Re-review at head b8302fab. The previous round's single blocking finding (wrong GA date in upgrading/index.mdx) is fixed exactly as requested, and the new commit additionally tightens the CORS origin-gating description — I verified that new claim against the framework source and it is accurate. No Correctness, Cross-engine, or Security findings remain, so per the supersede rule this review approves to clear the prior CHANGES_REQUESTED. Two non-blocking docs nits remain (below); neither needs to hold up the merge.
Previously blocking — now resolved
Wrong GA date for the 4.0 line (upgrading/index.mdx:34) — resolved in b8302fab:
shows the latest release (currently
v4.0.3, released 2026-06-09; the 4.0 line went GA 2026-05-12 withv4.0.0)
Verified against CHANGELOG.md:236 (# [4.0.0](…) => 2026-05-12) and CHANGELOG.md:62 (# [4.0.3](…) => 2026-06-09); tag dates concur (v4.0.0 2026-05-11 PT, v4.0.3 2026-06-09 PT). This matches the suggested wording from the prior review verbatim.
Newly verified in this round
b8302fab also rewrites the CORS coexistence bullet (upgrading/3x-to-4x.mdx:95) to scope the origin-gate claim: the legacy layer now correctly described as emitting Access-Control-Allow-Headers / Access-Control-Allow-Methods regardless of the request origin, with only Access-Control-Allow-Origin (+Vary) origin-gated, and the middleware as the layer that gates all of its headers on the match. Checked against source:
vendor/wheels/Global.cfc::$setCORSHeaders— early-return only on emptyallowOriginconfig (4029–4031);Allow-Origin+Varyemitted only inside the wildcard/match branches (4034–4048);Allow-Headers(4051) andAllow-Methods(4081, or the by-route branch) emitted unconditionally afterward. Confirmed.vendor/wheels/middleware/Cors.cfc::$headersFor— every header the middleware emits on non-OPTIONS requests sits insideif (Len(local.allowOrigin))(102–114). Confirmed. (The unconditionalAccess-Control-Max-AgeatCors.cfc:149is OPTIONS-only, and in the both-active scenario this bullet describes, OPTIONS never reaches the middleware — so the claim is accurate in context.)
All other hunks are byte-identical to the previously reviewed commit 02ee232, whose 11 remaining findings were independently verified in the prior review (CHANGELOG heading taxonomy, BuildInfo/wheels.json version sourcing, no root box.json, #3114 CORS additivity, csrfCookieEncryptionSecretKey + #3115, wheels.Testbox develop-only upgrade-check rule, no wheels mcp setup, first-registration-wins fixture routes per Mapper.cfc:273-275, wheels test for scaffolded apps, snapshot-tag correction). Nothing to re-litigate.
Docs (non-blocking)
upgrading/changelog.mdx:113— "Most pre-GA snapshot builds got their own tag" still overstates coverage (carried over from the prior review's nit). The tag series spans+1442through+1783; any build below+1442definitively has no tag, and 342 build numbers out of ~1783 is not "most." Stating the range ("the tagged series spans+1442–+1783") would also make the retainedv4.0.0-SNAPSHOT+1787example read more coherently next to "runs to+1783." Fine to address in a follow-up or not at all.- The PR body's index-04 bullet still says "4.0 GA shipped 2026-06-09" — since this repo squash-merges and the PR body typically lands as the commit body, consider editing that one line so the landing commit doesn't re-record the conflation the diff fixes.
Commits
b8302fab — docs(web/guides): fix GA date and CORS origin-gating scope in upgrading guides: valid type, header 78 chars, body explains the why with source citations, DCO sign-off matches the author identity. 02ee232 passed in the prior round. No changelog fragment needed (docs-type change). No findings.
…commend-set-csrfencr Reconciles this bot PR with #3123, which rewrote the 3x-to-4x upgrade guide's CSRF-key section on develop after this branch was cut. Resolution: - 3x-to-4x.mdx: develop's version wins wholesale — #3123 already covers everything this branch changed (csrfCookieEncryptionSecretKey naming, csrfStore="cookie" scoping, production-throws note, the #3115 caution Aside, and the corrected Common-issues bullet), strictly superseding this branch's three hunks. - Module.cfc, UpgradeCheckCoverageSpec.cfc, upgrade.mdx, and the changelog.d fragment auto-merged cleanly and remain this branch's contribution (the upgrade-check rule fix itself is still absent from develop). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
Summary
Final-wave docs-fix PR for the 2026-06 guide behavioral audit, manifest group 6 (
p2-5-upgrading): 12 findings across the threeupgrading/guide pages. Every change describes verified current behavior (live-probed on Lucee 7 / released CLI 4.0.3, or source-checked atorigin/develop); broken-but-unfixed behavior is cited to its tracking issue rather than papered over.Changes by finding
upgrading/index.mdxCHANGELOG.mduses 28 distinct H3 heading types (Bug Fixesx42,View Enhancementsx18,Model Enhancementsx16,Breaking Changes, …). Reworded to "including, not limited to."application.$wheels.versionis populated fromBuildInforeadingvendor/wheels/wheels.json(onapplicationstart.cfc:105); the in-source manifest carries the@build.version@placeholder. Removed the implication of a readable literal and the stale "As of this snapshot, 4.0.0."box.jsonfrom the version-authority list: no such file exists at the repo root.v4.0.3(4.0 GA shipped 2026-06-09); the "currently v4.0.0-SNAPSHOT+1524 on the way to GA" framing was stale.upgrading/3x-to-4x.mdxcfheadercalls overwrite the global setting's headers. Live-disproven: the layers are independent and additive —cfheaderstacks, each layer emitsAccess-Control-*only when the Origin matches its own allow-list, and an origin allowed by both layers receives duplicateAccess-Control-Allow-Originheaders that browsers reject per the Fetch spec. Rewritten to describe the additive behavior, note the middleware doesn't run on the public root/congrats route, and instruct migrators to disableallowCorsRequeststhe moment theCorsmiddleware is configured.set(csrfEncryptionKey = ...), a name no framework code reads. The real setting iscsrfCookieEncryptionSecretKey(events/init/security.cfm:30,csrf.cfc::$ensureCsrfCookieEncryptionKey). Also scoped the item tocsrfStore="cookie"(default issession) and noted production throwsWheels.Security.MissingCsrfKeyinstead of auto-generating. Added a caution thatwheels upgrade checkthrough 4.0.3 still recommends the inert name (the CLI rule fix is upgrade check + upgrade guide recommend set(csrfEncryptionKey=...) but the framework only reads csrfCookieEncryptionSecretKey — the suggested fix is inert #3115 code scope, not this PR). Fixed the two othercsrfEncryptionKeymentions (env() paragraph, Common issues).wheels.Testboxupgrade-check flag as current; live run of released CLI 4.0.3 only flagswheels.Test. Annotated as develop-only / post-4.0.3.wheels mcp setup --force": the command does not exist (released CLI exits 2, "mcp: module not found: 'setup'"). Replaced with the manual.mcp.jsonsnippet and a note that barewheels mcperrors on the released launcher.config/routes.cfmand Wheels routing is first-registration-wins (Mapper.cfc:274static index keeps first;Dispatch.cfclinear scan first-match), so app routes can NOT override fixtures. Inverted the claim and pointed atset(browserLoginAsHandler=...)for login customization.bash tools/test-local.sh;tools/exists only in the framework monorepo, not in scaffolded apps. Replaced withwheels test.upgrading/changelog.mdx# [4.0.3](…) => 2026-06-09). Also mentionschangelog.d/fragments so readers don't treat[Unreleased]as the complete pending picture.v4.0.0-SNAPSHOT+NNNNtags (series ends at+1783at GA cut). Corrected to "most pre-GA builds got a tag, not every build number did."Verification
pnpm verify:docsexit 0 on each touched page;3x-to-4x.mdx: 13 tagged blocks pass, the other two pages have no tagged blocks./tmp/p2-docs-manifest.mdgroup 6.🤖 Generated with Claude Code