Skip to content

docs(web/guides): correct upgrading guides against live 4.0.3 behavior (audit group 6) - #3123

Merged
bpamiri merged 2 commits into
developfrom
peter/docs-audit3-upgrading
Jun 12, 2026
Merged

docs(web/guides): correct upgrading guides against live 4.0.3 behavior (audit group 6)#3123
bpamiri merged 2 commits into
developfrom
peter/docs-audit3-upgrading

Conversation

@bpamiri

@bpamiri bpamiri commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Final-wave docs-fix PR for the 2026-06 guide behavioral audit, manifest group 6 (p2-5-upgrading): 12 findings across the three upgrading/ guide pages. Every change describes verified current behavior (live-probed on Lucee 7 / released CLI 4.0.3, or source-checked at origin/develop); broken-but-unfixed behavior is cited to its tracking issue rather than papered over.

Changes by finding

upgrading/index.mdx

  • index-01 — "groups every release under Added/Changed/Deprecated/Removed/Fixed/Security" was materially incomplete: the real CHANGELOG.md uses 28 distinct H3 heading types (Bug Fixes x42, View Enhancements x18, Model Enhancements x16, Breaking Changes, …). Reworded to "including, not limited to."
  • index-02application.$wheels.version is populated from BuildInfo reading vendor/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."
  • index-03 — dropped box.json from the version-authority list: no such file exists at the repo root.
  • index-04 — release cadence updated: latest tag is 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.mdx

  • 3x4x-04 (CORS: running global allowCorsRequests alongside wheels.middleware.Cors stacks duplicate headers — duplicate Access-Control-Allow-Origin makes browsers reject the response #3114) — the "Precedence when both are active" paragraph claimed the middleware's cfheader calls overwrite the global setting's headers. Live-disproven: the layers are independent and additivecfheader stacks, each layer emits Access-Control-* only when the Origin matches its own allow-list, and an origin allowed by both layers receives duplicate Access-Control-Allow-Origin headers 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 disable allowCorsRequests the moment the Cors middleware is configured.
  • 3x4x-08 (upgrade check + upgrade guide recommend set(csrfEncryptionKey=...) but the framework only reads csrfCookieEncryptionSecretKey — the suggested fix is inert #3115) — Item 3 recommended set(csrfEncryptionKey = ...), a name no framework code reads. The real setting is csrfCookieEncryptionSecretKey (events/init/security.cfm:30, csrf.cfc::$ensureCsrfCookieEncryptionKey). Also scoped the item to csrfStore="cookie" (default is session) and noted production throws Wheels.Security.MissingCsrfKey instead of auto-generating. Added a caution that wheels upgrade check through 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 other csrfEncryptionKey mentions (env() paragraph, Common issues).
  • 3x4x-19 — Item 8 described the wheels.Testbox upgrade-check flag as current; live run of released CLI 4.0.3 only flags wheels.Test. Annotated as develop-only / post-4.0.3.
  • 3x4x-25 — "Migrate with wheels mcp setup --force": the command does not exist (released CLI exits 2, "mcp: module not found: 'setup'"). Replaced with the manual .mcp.json snippet and a note that bare wheels mcp errors on the released launcher.
  • 3x4x-28 — browser-fixture bullet claimed "any same-named app route overrides the fixture." Live-disproven: fixtures register before config/routes.cfm and Wheels routing is first-registration-wins (Mapper.cfc:274 static index keeps first; Dispatch.cfc linear scan first-match), so app routes can NOT override fixtures. Inverted the claim and pointed at set(browserLoginAsHandler=...) for login customization.
  • 3x4x-31 — post-upgrade step 1 said bash tools/test-local.sh; tools/ exists only in the framework monorepo, not in scaffolded apps. Replaced with wheels test.

upgrading/changelog.mdx

  • changelog-04 — same exactly-six-sections correction as index-01, plus the real release-heading shape (# [4.0.3](…) => 2026-06-09). Also mentions changelog.d/ fragments so readers don't treat [Unreleased] as the complete pending picture.
  • changelog-06 — "There is no tag per snapshot" is contradicted by 335 v4.0.0-SNAPSHOT+NNNN tags (series ends at +1783 at GA cut). Corrected to "most pre-GA builds got a tag, not every build number did."

Verification

  • pnpm verify:docs exit 0 on each touched page; 3x-to-4x.mdx: 13 tagged blocks pass, the other two pages have no tagged blocks.
  • Evidence source: guide behavioral audit P2 verifier output (live Lucee 7 docker probes + released CLI 4.0.3 runs + source checks), consolidated in /tmp/p2-docs-manifest.md group 6.

🤖 Generated with Claude Code

…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>

@wheels-bot wheels-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:refname shows the latest release (currently v4.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 (tag v4.0.0 creatordate 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.md H3 headings include Bug 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-105 sets application.$wheels.version from new wheels.BuildInfo().version(); vendor/wheels/wheels.json carries "version": "@build.version@". No readable literal — confirmed.
  • index-03: no box.json at the repo root — confirmed.
  • 3x4x-04: matches issue #3114's live probe (duplicate Access-Control-Allow-Origin, additive cfheader, 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:3 defaults csrfStore = "session"; security.cfm:30 initializes csrfCookieEncryptionSecretKey; vendor/wheels/controller/csrf.cfc:148-159 throws Wheels.Security.MissingCsrfKey in production and auto-generates with a wheels_security warning elsewhere. csrfEncryptionKey has 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 setup command exists; the manual .mcp.json snippet matches the canonical one in CLAUDE.md § CLI / MCP — confirmed.
  • 3x4x-28: vendor/wheels/Mapper.cfc:273-275 keeps the first registration for a static route key (if (!StructKeyExists(...staticRoutes, local.staticKey))), and fixtures mount before config/routes.cfm (vendor/wheels/public/browser-fixtures/routes.cfm, $lockedLoadRoutes); browserLoginAsHandler is a real setting (browser-fixtures/routes.cfm:35-39). The inverted claim is correct.
  • 3x4x-31: tools/test-local.sh exists only in the framework monorepo; wheels test is the right command for scaffolded apps — confirmed.
  • changelog-06: 335 v4.0.0-SNAPSHOT+* tags exist, series ending at +1783 with 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>

@wheels-bot wheels-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 with v4.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 empty allowOrigin config (4029–4031); Allow-Origin+Vary emitted only inside the wildcard/match branches (4034–4048); Allow-Headers (4051) and Allow-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 inside if (Len(local.allowOrigin)) (102–114). Confirmed. (The unconditional Access-Control-Max-Age at Cors.cfc:149 is 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 +1442 through +1783; any build below +1442 definitively 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 retained v4.0.0-SNAPSHOT+1787 example 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

b8302fabdocs(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.

@bpamiri
bpamiri merged commit 5bddcd1 into develop Jun 12, 2026
14 checks passed
@bpamiri
bpamiri deleted the peter/docs-audit3-upgrading branch June 12, 2026 16:03
bpamiri added a commit that referenced this pull request Jun 12, 2026
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant