Skip to content

docs: document attributeCollection + arguments scope gotcha on Adobe CF 2023#2755

Merged
bpamiri merged 6 commits into
developfrom
docs/bot-2741-attributecollection-arguments-gotcha
May 17, 2026
Merged

docs: document attributeCollection + arguments scope gotcha on Adobe CF 2023#2755
bpamiri merged 6 commits into
developfrom
docs/bot-2741-attributecollection-arguments-gotcha

Conversation

@bpamiri
Copy link
Copy Markdown
Collaborator

@bpamiri bpamiri commented May 17, 2026

Documents the Adobe CF 2023 attributeCollection + arguments scope incompatibility now that PR #2750 has shipped the canonical fix for all 13 affected wrappers in vendor/wheels/Global.cfc.

What's in this PR

Two documentation files, no code:

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 a fix/bot-* branch. The TDD gate keys on branch prefix and rejects docs-only fix/bot-* PRs. This PR carries the same content (with all reviewer feedback from #2751's review cycle already applied) on a docs/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)

Pull Request

What does this PR do?

Adds documentation explaining the Adobe CF 2023 restriction on passing the arguments scope as attributeCollection to built-in CFML tags. Documents the workaround (copy arguments into a plain struct first) and points readers to the canonical fix in #2750.

Where should the reviewer start?

CLAUDE.md invariant #10 — the tight TL;DR. Then .ai/wheels/cross-engine-compatibility.md for 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.yml against #2750's code change (already merged on develop).

Any background context you want to provide?

Adobe CF 2023 imposes a stricter type check on attributeCollection than Lucee 6/7, BoxLang, or Adobe CF 2018/2021 — it requires a plain CFML struct, not the special arguments scope object. cfheader is 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

github-actions Bot and others added 4 commits May 16, 2026 20:40
…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>
Copy link
Copy Markdown
Contributor

@wheels-bot wheels-bot Bot left a comment

Choose a reason for hiding this comment

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

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 arguments scope when passed as attributeCollection to 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 arguments scope as attributeCollection

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 arguments scope as attributeCollection

to:

Adobe CF 2023/2025 reject the arguments scope as attributeCollection


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
Copy link
Copy Markdown
Contributor

wheels-bot Bot commented May 17, 2026

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".

Sycophancy

None detected. A requested changes rather than approving despite a docs-only PR.

False positives

None detected.

  • "Adobe CF 2023+" claim: A cites vendor/wheels/Global.cfc:129. That line reads exactly: // Adobe CF 2023+ rejects the raw arguments scope as an attributeCollection; — the + is present verbatim. Confirmed.
  • $image() direct form at line 65: A claims cfimage(attributeCollection = local.args) (no quotes). Confirmed — the actual code uses the unquoted direct form, not the interpolated "#local.args#" form shown in the RIGHT example. A's nit is accurate.
  • Adobe CF 2025 in CI matrix: CLAUDE.md's own engine list reads "Lucee 5/6/7, Adobe CF 2018/2021/2023/2025, and BoxLang" — 2025 is explicitly first-class. A's claim that 2025 belongs in the affected list is well-founded.

Missed issues

None detected. The PR is docs-only; no code paths to audit for cross-engine compat. Commits are clean (docs type, subjects ≤ 100 chars, sentence-case, consistent with the prior history on this branch).

Verdict alignment

A's request-changes verdict is consistent with identifying a factual gap in the documented engine scope. Appropriate.

Convergence

Aligned 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 .ai/wheels/cross-engine-compatibility.md, and the opening sentence of invariant #10 in CLAUDE.md. A's suggested wording is correct. Recommending converged-changes so address-review can apply the fix.

@bpamiri
Copy link
Copy Markdown
Collaborator Author

bpamiri commented May 17, 2026

Reviewer A round 1 (Adobe CF 2025 omitted from affected-engine list): fixed in a466c5d90. Develop's $header() comment says "Adobe CF 2023+ rejects" — the + is load-bearing — and #2750 patched all 13 wrappers because the restriction is not 2023-specific. CLAUDE.md invariant #10 and the .ai/ section heading + body + Why paragraph + WRONG block comment all now name both 2023 and 2025. The minor nit on the RIGHT example also addressed: it now mirrors the WRONG block by showing both cfheader(... = "#local.args#") and cfimage(... = local.args) working once local.args is a plain struct, with a comment explaining why both forms are safe at that point.

@bpamiri
Copy link
Copy Markdown
Collaborator Author

bpamiri commented May 17, 2026

Reviewer B round 1 (converged-changes against 3691aa136): already applied in a466c5d90, pushed before this review queued. Origin HEAD a466c5d90 has 6 lines mentioning Adobe 2023/2025 across the two files (three updated sentences in CLAUDE.md invariant #10 plus heading/intro/Why paragraph + WRONG-block comment in the .ai/ doc).

@wheels-bot
Copy link
Copy Markdown
Contributor

wheels-bot Bot commented May 17, 2026

Wheels Bot — Address Review (round 1)

The convergence-changes verdict was emitted on 3691aa136. Between Reviewer B's converged-changes marker and this stage firing, the human collaborator pushed a466c5d90 (docs: extend attributeCollection invariant to Adobe CF 2023 and 2025), which already applies every consensus finding from Reviewer A and Reviewer B:

  • .ai/wheels/cross-engine-compatibility.md — section heading is now (Adobe CF 2023/2025); intro and Why paragraph name both engines; WRONG block comment says "crashes Adobe CF 2023 and 2025".
  • CLAUDE.md invariant Fixed bug in $findRoute() that causes blow up on unmatched named route #10 — opener, throw-clause, and "require the plain struct" clause all name 2023 and 2025.
  • RIGHT example in the .ai/ doc — now shows both cfheader(attributeCollection = "#local.args#") (string-interpolated) and cfimage(attributeCollection = local.args) (direct) with a comment explaining why both are safe once local.args is a plain struct. This addresses Reviewer A's non-blocking nit about the RIGHT example previously showing only the interpolated form while $image() uses the direct form.

Verified by diffing 3691aa136..a466c5d90 against the consensus findings; nothing else is in scope. No additional commit needed from address-review at this SHA — a duplicate commit would be churn.

The current head (a466c5d90) will trigger a fresh Reviewer A run. Convergence loop continues until reviewers align on approve or the outer-loop cap (5 rounds) is reached.

wheels-bot[bot]
wheels-bot Bot previously approved these changes May 17, 2026
Copy link
Copy Markdown
Contributor

@wheels-bot wheels-bot Bot left a comment

Choose a reason for hiding this comment

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

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 verificationvendor/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
Copy link
Copy Markdown
Contributor

wheels-bot Bot commented May 17, 2026

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.

Sycophancy

None detected. A cited specific line numbers (Global.cfc:65, Global.cfc:137, Global.cfc:129), quoted the before/after text for each fix, and confirmed via direct source inspection rather than taking the PR description at face value.

False positives

None detected.

  • A's claim that $image() uses the direct form (cfimage(attributeCollection = local.args)) — confirmed at line 65.
  • A's claim that $header() uses the string-interpolated form (cfheader(attributeCollection = "#local.args#")) — confirmed at line 137.
  • A's claim that Global.cfc line 129 carries the // Adobe CF 2023+ rejects... comment — confirmed.
  • A's reading of the CLAUDE.md and .ai/ diffs matches the actual diff contents verbatim.

Missed issues

None detected. This is a docs-only change. Commits are all docs type, sentence-case, ≤ 100 chars, consistent with the branch history and commitlint.config.js. No cross-engine code paths introduced. No test or security surface.

Verdict alignment

A's approve verdict is consistent with a docs-only PR where all previously requested changes have been correctly applied and source-verified.

Convergence

Aligned with A. The diff is accurate, complete, and consistent across both documentation files. Recommending converged-approve.

Copy link
Copy Markdown
Contributor

@wheels-bot wheels-bot Bot left a comment

Choose a reason for hiding this comment

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

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:

  1. Adobe CF 2025 coverageCLAUDE.md invariant #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 at vendor/wheels/Global.cfc:129.

  2. 13-wrapper count — The list in invariant #10 and the Reference fix block in .ai/wheels/cross-engine-compatibility.md both enumerate all 13 wrappers ($header, $cache, $content, $mail, $directory, $file, $location, $htmlhead, $image, $dbinfo, $invoke, $wddx, $zip), matching vendor/wheels/Global.cfc.

  3. 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.cfc lines 137 and 65 respectively.

  4. Merge-introduced content — The diff between the previously approved SHA (a466c5d90) and the current head shows three additions from develop (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
Copy link
Copy Markdown
Contributor

wheels-bot Bot commented May 17, 2026

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.

Sycophancy

None 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 positives

None detected.

Missed issues

None 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 docs type, sentence-case subjects, and are ≤ 100 chars. The merge commit is Git-generated and correctly excluded from commitlint scope.

Verdict alignment

A's approve is consistent with a docs-only PR where all prior requested changes have been applied, the invariant numbering is coherent after the develop merge, and no new issues exist.

Convergence

Aligned with A. The prior converged-approve on a466c5d90 holds through the mechanical develop merge — the merge commit touched nothing in the PR's own content, only absorbed develop-side additions that were independently reviewed. Recommending converged-approve.

@bpamiri bpamiri merged commit 9b2c3b8 into develop May 17, 2026
6 checks passed
@bpamiri bpamiri deleted the docs/bot-2741-attributecollection-arguments-gotcha branch May 17, 2026 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant