docs: document attributeCollection + arguments scope gotcha on Adobe CF 2023#2755
Conversation
…CF 2023 Add cross-engine invariant #10 to CLAUDE.md and a matching section to .ai/wheels/cross-engine-compatibility.md: Adobe CF 2023 rejects the raw arguments scope passed as attributeCollection (e.g. cfheader), while Lucee 6/7, BoxLang, and Adobe 2018/2021 accept it. Fix is to copy into a plain struct first. Follows fix in vendor/wheels/Global.cfc::$header (#2741). Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Reviewer A's round-2 sub-nit and round-3 finding (and Reviewer B's convergence in the broader round) flagged that CLAUDE.md invariant #10 named only `cfheader`, while the underlying restriction applies to every built-in CFML tag that accepts `attributeCollection`. PR #2750 has since merged, patching all 12 affected wrappers in `vendor/wheels/Global.cfc` uniformly — which is hard evidence the broader rule is correct. Generalize invariant #10 in CLAUDE.md to "any built-in CFML tag", enumerate the 12 affected wrappers, and call out the two attribute forms (`"##arguments##"` and direct-struct). Update `.ai/wheels/cross-engine-compatibility.md` to match: WRONG block now shows both forms, the Reference link points to #2750 (the canonical multi-site fix), and the $dbinfo() per-call rebuild note is preserved as guidance for helpers that write through `arguments` between tag invocations. Docs-only — no code change. Addresses the substantive review feedback that survived the rebase onto #2750. Signed-off-by: Peter Amiri <peter@alurium.com>
…mple Reviewer A round 5: invariant #10's inline description of "the string-interpolated form" used `"##arguments##"`. The double-hash is CFML's escape for a literal `#` character — a reader copy-pasting it into CFScript would get the string `#arguments#` rather than evaluating the arguments scope, the opposite of what the invariant warns against. The companion .ai/wheels/cross-engine-compatibility.md section at line 238 already uses single hashes correctly; align CLAUDE.md to match. Signed-off-by: Peter Amiri <peter@alurium.com>
…riant Reviewer B round 7: the enumerated list of affected `Global.cfc` wrappers has 13 items (cfheader, cfcache, cfcontent, cfmail, cfdirectory, cffile, cflocation, cfhtmlhead, cfimage, cfdbinfo, cfinvoke, cfwddx, cfzip) but both CLAUDE.md invariant #10 and .ai/wheels/cross-engine-compatibility.md said "12". Verified against develop's `vendor/wheels/Global.cfc` — 13 distinct wrapper functions forward `arguments` to a `cf*(attributeCollection = ...)` site (cfmailparam and cfmailpart are correctly excluded — they use the pre-built `local.i` struct, not the arguments scope). Pure number fix in two places. Signed-off-by: Peter Amiri <peter@alurium.com>
There was a problem hiding this comment.
Wheels Bot — Reviewer A
TL;DR: This docs-only PR adds a well-researched invariant for the Adobe CF 2023 attributeCollection + arguments scope incompatibility. The WRONG/RIGHT examples match the actual implementation in vendor/wheels/Global.cfc, the 13-wrapper count checks out, and the $dbinfo() per-call rebuild caveat is accurate. However, the documented engine scope is factually incomplete: the code being documented explicitly says "Adobe CF 2023+", but both CLAUDE.md and .ai/wheels/cross-engine-compatibility.md only say "Adobe CF 2023". Adobe CF 2025 is omitted from the affected-engine list despite being in the CI matrix. Requesting changes on that correctness ground.
Correctness
Adobe CF 2025 is missing from the affected-engine matrix.
vendor/wheels/Global.cfc:129-130 reads:
// Adobe CF 2023+ rejects the raw `arguments` scope as an attributeCollection;
// copy into a plain struct first. Also strip `statusText` (removed in Adobe CF 2025).The + is deliberate — the restriction is present in both Adobe CF 2023 and Adobe CF 2025 (and presumably any future release that inherits the same type checker). The fix in #2750 applies uniformly to all 13 wrappers precisely because the issue is not limited to a single engine version.
Yet both documentation files state only "Adobe CF 2023":
.ai/wheels/cross-engine-compatibility.md:238:
Adobe CF 2023 rejects the raw
argumentsscope when passed asattributeCollectionto any built-in CFML tag
Engine matrix row (.ai/wheels/cross-engine-compatibility.md:253 context):
Lucee 6/7 + BoxLang + Adobe 2018/2021 accept; Adobe 2023 rejects
CLAUDE.md:49 (invariant #10):
Adobe CF 2023 rejects the
argumentsscope asattributeCollection
Adobe CF 2025 is a first-class entry in the CI matrix (tools/test-matrix.sh adobe2025 mysql) and in CLAUDE.md's own engine list ("Lucee 5/6/7, Adobe CF 2018/2021/2023/2025, and BoxLang"). A developer reading invariant #10 and seeing only "Adobe CF 2023" has no signal to guard on Adobe CF 2025. The invariant section is the canonical checklist for cross-engine correctness, so an understatement here is a real correctness risk.
Suggested fixes:
In .ai/wheels/cross-engine-compatibility.md, change the section heading and body to:
### `attributeCollection` with the `arguments` Scope (Adobe CF 2023/2025)
Adobe CF 2023 and 2025 reject the raw `arguments` scope when passed as `attributeCollection`
to *any* built-in CFML tag ...Update the engine matrix line from:
Lucee 6/7 + BoxLang + Adobe 2018/2021 accept; Adobe 2023 rejects
to:
Lucee 6/7 + BoxLang + Adobe 2018/2021 accept; Adobe 2023 and 2025 reject
In CLAUDE.md invariant #10, change the opening from:
Adobe CF 2023 rejects the
argumentsscope asattributeCollection
to:
Adobe CF 2023/2025 reject the
argumentsscope asattributeCollection
Minor Nit (non-blocking)
The RIGHT example in .ai/wheels/cross-engine-compatibility.md:250 shows only the string-interpolated form:
cfheader(attributeCollection = "#local.args#");The actual $image() implementation uses the direct form without quotes (cfimage(attributeCollection = local.args) at vendor/wheels/Global.cfc:65). A brief note that both the direct form and the "#local.args#" form work once local.args is a plain struct (because neither form passes the special arguments scope object) would make the RIGHT example more complete. This is editorial — the example is not wrong, just incomplete.
Commits
All four commits use docs type, subjects are sentence-case, ≤ 100 characters, and describe the "what" clearly. No issues.
3691aa136 docs: correct wrapper count from 12 to 13 in attributeCollection invariant
f1d372342 docs(claude): use single-hash CFML interpolation in invariant #10 example
c9dd78c8e docs: generalize attributeCollection gotcha to any built-in CFML tag
b0b596ccd docs: document attributeCollection + arguments scope gotcha on Adobe CF 2023
The rest of the diff — the 13-wrapper enumeration, the $dbinfo() per-call rebuild caveat, the WRONG/RIGHT examples, and the placement of invariant #10 — all check out against the source code. The fix needed is narrow: extend "Adobe CF 2023" to "Adobe CF 2023/2025" (or "Adobe CF 2023+") in the section heading, the engine matrix line, and invariant #10's opening sentence.
Reviewer A round 1 on #2755 caught a real correctness gap: develop's `Global.cfc::$header()` comment explicitly says "Adobe CF 2023+ rejects the raw arguments scope" — the `+` is load-bearing — and #2750 patched all 13 wrappers precisely because the restriction extends past 2023. The docs as previously written named only "Adobe CF 2023", giving a developer reading invariant #10 no signal to guard their code on Adobe CF 2025. Updates: - CLAUDE.md invariant #10: "Adobe CF 2023" → "Adobe CF 2023 and 2025" throughout (opener, throw clause, "require the plain struct" clause). - .ai/wheels/cross-engine-compatibility.md: section heading is "(Adobe CF 2023/2025)"; intro and Why paragraph name both engines; WRONG block comment says "crashes Adobe CF 2023 and 2025". - RIGHT example in the .ai/ doc now mirrors the WRONG block by showing both invocation forms working once `local.args` is a plain struct (cfheader interpolated form + cfimage direct form), with a brief comment explaining why both are safe at that point — addresses Reviewer A's non-blocking nit that the original RIGHT example showed only the string-interpolated form while $image() uses the direct form. Engine matrix is unchanged otherwise: Lucee 6/7 + BoxLang + Adobe 2018/2021 still accept; Adobe 2023/2025 reject. Signed-off-by: Peter Amiri <peter@alurium.com>
Wheels Bot — Reviewer B (round 1)A's review is accurate and well-grounded. Both findings are verified against the source; the main correctness issue (Adobe CF 2025 omitted from the affected-engine list) is real and A's suggested three-location fix is the right remedy. Converging on "request-changes". SycophancyNone detected. A requested changes rather than approving despite a docs-only PR. False positivesNone detected.
Missed issuesNone detected. The PR is docs-only; no code paths to audit for cross-engine compat. Commits are clean ( Verdict alignmentA's ConvergenceAligned with A. The fix is narrow and unambiguous: change "Adobe CF 2023" to "Adobe CF 2023/2025" (or "Adobe CF 2023+") in three places — the section heading and one body sentence in |
|
Reviewer A round 1 (Adobe CF 2025 omitted from affected-engine list): fixed in |
|
Reviewer B round 1 ( |
Wheels Bot — Address Review (round 1)The convergence-changes verdict was emitted on
Verified by diffing The current head ( |
There was a problem hiding this comment.
Wheels Bot — Reviewer A
TL;DR: This is a docs-only PR adding an invariant for the Adobe CF 2023/2025 attributeCollection + arguments scope incompatibility. The previous review (SHA 3691aa136) requested changes because Adobe CF 2025 was absent from the affected-engine list. The new commit (a466c5d90) directly resolves that: the .ai/ section heading, the prose, the WRONG/RIGHT examples, the Why block, and CLAUDE.md invariant #10 all now consistently say "Adobe CF 2023 and 2025" or "Adobe CF 2023/2025". The previous minor nit — RIGHT example showing only the string-interpolated form — is also resolved: both cfheader(attributeCollection = local.args) and cfimage(attributeCollection = local.args) now appear. The diff is clean; approving.
Correctness
The previous --request-changes issue is fully addressed. Specific before/after:
.ai/wheels/cross-engine-compatibility.md section heading (was Adobe CF 2023):
### `attributeCollection` with the `arguments` Scope (Adobe CF 2023/2025)
Matches the CI matrix (adobe2023, adobe2025) and the comment at vendor/wheels/Global.cfc:129 (// Adobe CF 2023+ rejects...).
CLAUDE.md invariant #10 (was Adobe CF 2023 rejects):
10. **Adobe CF 2023 and 2025 reject the `arguments` scope as `attributeCollection` on *any* built-in CFML tag.**
Consistent with the engine list in the preamble ("Lucee 5/6/7, Adobe CF 2018/2021/2023/2025, and BoxLang").
Source code verification — vendor/wheels/Global.cfc read directly. The 13 wrappers listed in the PR ($header, $cache, $content, $mail, $directory, $file, $location, $htmlhead, $image, $dbinfo, $invoke, $wddx, $zip) match the 13 functions that copy arguments to a plain struct before calling the built-in tag. The $dbinfo() four-call rebuild pattern (lines 429–459) is accurate: arguments is mutated between calls (arguments.type = "dbnames", arguments.dbname = ..., arguments.type = local.type) and a fresh local.args copy is built before each cfdbinfo call.
Previous nit resolved: the RIGHT block now shows both the direct form (cfimage(attributeCollection = local.args)) and the string-interpolated form (cfheader(attributeCollection = "#local.args#")), matching how $image() and $header() are actually implemented in Global.cfc (lines 65 and 137 respectively).
Commits
All five commits use docs type, sentence-case subjects, and are ≤ 100 characters:
a466c5d90 docs: extend attributeCollection invariant to Adobe CF 2023 and 2025
3691aa136 docs: correct wrapper count from 12 to 13 in attributeCollection invariant
f1d372342 docs(claude): use single-hash CFML interpolation in invariant #10 example
c9dd78c8e docs: generalize attributeCollection gotcha to any built-in CFML tag
b0b596ccd docs: document attributeCollection + arguments scope gotcha on Adobe CF 2023
Commit-message linter reports passing. No issues.
No further findings. Tests, security, and conventions checks are all N/A for a docs-only change.
Wheels Bot — Reviewer B (round 1)A's review checks out. Every source-code citation is accurate, the previous requested changes are fully addressed in the diff, and the approval is appropriate for a docs-only PR with no behavior changes. SycophancyNone detected. A cited specific line numbers ( False positivesNone detected.
Missed issuesNone detected. This is a docs-only change. Commits are all Verdict alignmentA's ConvergenceAligned with A. The diff is accurate, complete, and consistent across both documentation files. Recommending |
There was a problem hiding this comment.
Wheels Bot — Reviewer A
TL;DR: This docs-only PR adds the attributeCollection + arguments scope invariant for Adobe CF 2023/2025. The previous review cycle fully resolved all raised issues (Adobe CF 2025 coverage, 13-wrapper count, both RIGHT call forms). The current head (f0f3492b5) is a merge commit that updated the branch with develop — it brought in the BoxLang catch-scope section (#2754), the Oracle DDL auto-commit section, and the lockingSpec test fix, all of which landed on develop independently. The PR diff against develop is clean and correct. Approving.
Correctness
All previously raised issues are resolved:
-
Adobe CF 2025 coverage —
CLAUDE.mdinvariant #10 and the.ai/section heading both say "Adobe CF 2023 and 2025" / "Adobe CF 2023/2025". Consistent with the engine list in CLAUDE.md's preamble and the// Adobe CF 2023+ rejects...comment atvendor/wheels/Global.cfc:129. -
13-wrapper count — The list in invariant #10 and the Reference fix block in
.ai/wheels/cross-engine-compatibility.mdboth enumerate all 13 wrappers ($header,$cache,$content,$mail,$directory,$file,$location,$htmlhead,$image,$dbinfo,$invoke,$wddx,$zip), matchingvendor/wheels/Global.cfc. -
Both RIGHT call forms present — The RIGHT block in the
.ai/doc shows both:cfheader(attributeCollection = "#local.args#"); // string-interpolated (matches $header()) cfimage(attributeCollection = local.args); // direct struct (matches $image())
This matches the actual implementations at
vendor/wheels/Global.cfclines 137 and 65 respectively. -
Merge-introduced content — The diff between the previously approved SHA (
a466c5d90) and the current head shows three additions fromdevelop(4a8ebfc11, #2754): the BoxLang catch-scope section in.ai/, the Oracle DDL auto-commit section in.ai/, and CLAUDE.md invariant #11 (BoxLang catch scope). All three are correct, well-referenced, and complement the PR's own content. The renumbering (old #10 → #11) resolves cleanly in the merge.
Commits
All commits use docs type, sentence-case subjects, and are ≤ 100 characters:
f0f3492b5 Merge branch 'develop' into docs/bot-2741-attributecollection-arguments-gotcha
a466c5d90 docs: extend attributeCollection invariant to Adobe CF 2023 and 2025
3691aa136 docs: correct wrapper count from 12 to 13 in attributeCollection invariant
f1d372342 docs(claude): use single-hash CFML interpolation in invariant #10 example
c9dd78c8e docs: generalize attributeCollection gotcha to any built-in CFML tag
b0b596ccd docs: document attributeCollection + arguments scope gotcha on Adobe CF 2023
The merge commit subject is Git-generated and not subject to commitlint. No issues.
Tests, security, and conventions checks are all N/A for a docs-only change. No further findings.
Wheels Bot — Reviewer B (round 1)A's review checks out. The diff matches A's description, source citations are consistent with prior-verified lines, and approval is appropriate for this docs-only PR. SycophancyNone detected. A cited specific line numbers, quoted before/after text for each fix, and confirmed via direct source inspection rather than taking the PR description at face value. False positivesNone detected.
Missed issuesNone detected. This is a docs-only change with no code paths, no security surface, and no cross-engine code to audit. All commits use the Verdict alignmentA's ConvergenceAligned with A. The prior |
Documents the Adobe CF 2023
attributeCollection+argumentsscope incompatibility now that PR #2750 has shipped the canonical fix for all 13 affected wrappers invendor/wheels/Global.cfc.What's in this PR
Two documentation files, no code:
CLAUDE.mdinvariant Fixed bug in $findRoute() that causes blow up on unmatched named route #10 (Cross-Engine Invariants section) — new bullet that generalizes the rule to any built-in CFML tag, enumerates all 13 affected wrappers (cfheader,cfcache,cfcontent,cfmail,cfdirectory,cffile,cflocation,cfhtmlhead,cfimage,cfdbinfo,cfinvoke,cfwddx,cfzip), and calls out both attribute forms (string-interpolated"#arguments#"and direct-structarguments). Links to fix(dispatch): copy arguments to a plain struct in $header() for Adobe CF 2023 #2750 as the canonical fix..ai/wheels/cross-engine-compatibility.md— full reference section under "Cross-Engine Gotchas" with WRONG/RIGHT code block, the engine matrix (Lucee 6/7 + BoxLang + Adobe 2018/2021 accept; Adobe 2023 rejects), the why (stricter type check onattributeCollection), the$dbinfo()per-call rebuild caveat, and a reference link to PR fix(dispatch): copy arguments to a plain struct in $header() for Adobe CF 2023 #2750.Why this PR exists separately from #2751
PR #2751 originated as a fix+docs PR for #2741. #2750 merged first with a broader fix (all 13 wrappers, not just
$header()), so rebasing #2751 dropped its code commits and left it docs-only on afix/bot-*branch. The TDD gate keys on branch prefix and rejects docs-onlyfix/bot-*PRs. This PR carries the same content (with all reviewer feedback from #2751's review cycle already applied) on adocs/bot-*branch where the gate naturally no-ops.#2751 will be closed in favor of this PR.
Reviewer feedback already applied (from #2751's review cycle)
cfheader-only to "any built-in CFML tag" (rounds 2 + 3)"#arguments#"(CFML interpolation), not"##arguments##"(CFML literal-hash escape) (round 5).ai/doc points to fix PR fix(dispatch): copy arguments to a plain struct in $header() for Adobe CF 2023 #2750, not just issue Adobe CF (2023 + 2025): cfheader(attributeCollection) throws 'Failed to add HTML header' — blocks all tests #2741Pull Request
What does this PR do?
Adds documentation explaining the Adobe CF 2023 restriction on passing the
argumentsscope asattributeCollectionto built-in CFML tags. Documents the workaround (copyargumentsinto a plain struct first) and points readers to the canonical fix in #2750.Where should the reviewer start?
CLAUDE.mdinvariant #10 — the tight TL;DR. Then.ai/wheels/cross-engine-compatibility.mdfor the full WRONG/RIGHT reference.How should this be manually tested?
Documentation-only — no behavior change to test. The underlying compatibility claim is verified by
compat-matrix.ymlagainst #2750's code change (already merged on develop).Any background context you want to provide?
Adobe CF 2023 imposes a stricter type check on
attributeCollectionthan Lucee 6/7, BoxLang, or Adobe CF 2018/2021 — it requires a plain CFML struct, not the specialargumentsscope object.cfheaderis the dispatch-path blocker because$header()runs on every request; the other 12 helpers fail as soon as the corresponding helper is called. PR #2750 patched all 13 sites uniformly; this PR captures the rule so future development doesn't reintroduce it.What are the relevant tickets?
Refs #2741, #2750. Supersedes #2751.
Checklist
.ai/wheels/cross-engine-compatibility.md