docs(api): validate View Helpers section - #2465
Conversation
| // 1. Basic telephone field with a pre-filled value | ||
| #telFieldTag(name="phone", value="555-867-5309")# | ||
|
|
||
| // 2. Telephone field with a label and a CSS class | ||
| #telFieldTag(name="mobilePhone", value="", label="Mobile Phone", class="tel-input")# | ||
|
|
||
| // 3. Telephone field with label placement and prepend/append wrappers | ||
| #telFieldTag(name="officePhone", label="Office Phone", labelPlacement="before", prepend="<div class=""field"">", append="</div>")# |
There was a problem hiding this comment.
🔴 This PR adds vendor/wheels/public/docs/reference/controller/telfielditag.txt (note the stray i between telfield and tag) which is byte-for-byte identical to the correctly-named telfieldtag.txt also added in this PR. There is no telFieldITag view helper in Wheels — only telFieldTag (defined at vendor/wheels/view/formsplain.cfc:212) — and state.json only tracks function:telFieldTag with telfieldtag.txt in its files_changed, so the misnamed file is an untracked stray that will surface as a phantom reference page on the docs site. Please delete vendor/wheels/public/docs/reference/controller/telfielditag.txt before merging.
Extended reasoning...
What the bug is
The PR creates two new files for what should be a single helper reference:
vendor/wheels/public/docs/reference/controller/telfieldtag.txt— the correctly-named reference for thetelFieldTag()view helper.vendor/wheels/public/docs/reference/controller/telfielditag.txt— a misnamed duplicate (telfield+ strayi+tag).
The two files are byte-for-byte identical (442 bytes each, diff produces no output). The trailing i in telfielditag is clearly an accidental keystroke, not a deliberate filename.
Why this slipped through
Looking at tools/docs-validation/state.json, the agent registered a single tracked entry:
"function:telFieldTag": {
...
"files_changed": [
"vendor/wheels/public/docs/reference/controller/telfieldtag.txt"
],
...
}Only telfieldtag.txt is in files_changed. The telfielditag.txt file is not tracked by the docs-validation pipeline at all — it appears the agent wrote the file once with a typo, then wrote the correct file, but never deleted the bogus one.
Why existing code doesn't prevent it
There is no link checker that cross-references reference/controller/*.txt filenames against the actual function names exported from vendor/wheels/view/*.cfc. The PR's WRITE_GLOBS regex (in tools/docs-validation/lib/tools.mjs) accepts any [a-z][a-z0-9]+.txt filename in the controller directory, so a typo passes through unchallenged.
Step-by-step proof
diff vendor/wheels/public/docs/reference/controller/telfielditag.txt vendor/wheels/public/docs/reference/controller/telfieldtag.txt→ produces no output (files are identical).ls -lon both files → both are exactly 442 bytes.grep -irn 'telFieldI\?Tag' vendor/wheels/view/→ only matchestelFieldTagatvendor/wheels/view/formsplain.cfc:212(function definition) and:223($args(name = "telFieldTag", ...)). NotelFieldITagexists.tools/docs-validation/state.jsonforfunction:telFieldTaglists onlytelfieldtag.txtinfiles_changed. There is nofunction:telFieldITagentry anywhere in the file.
Impact
- Phantom doc page — depending on how the docs site enumerates
reference/controller/(e.g. by globbing *.txt), users may see atelFieldITagreference page that points to identical content astelFieldTag, confusing anyone searching the docs. - Silent rot — because the file is untracked in
state.json, future docs-validation runs will not regenerate it. If the canonicaltelfieldtag.txtis updated, the stray will stay frozen at this version and slowly diverge. - Sitemap / link-checker confusion — any tool that walks the reference directory will treat both as valid documents.
How to fix
Delete the stray file before merging:
rm vendor/wheels/public/docs/reference/controller/telfielditag.txtNo other change is needed — the correctly-named telfieldtag.txt and the state.json entry are already correct.
| @@ -0,0 +1 @@ | |||
| <!--- Provide a `label` and the required `objectName` and `property` --->\n#telField(label="Phone Number", objectName="contact", property="phone")#\n\n<!--- Add a CSS class and a placeholder for formatting guidance --->\n#telField(label="Mobile", objectName="user", property="mobile", class="tel-input", placeholder="+1-555-000-0000")#\n\n<!--- Render telephone fields for each phone number in a nested association --->\n<fieldset>\n\t<legend>Phone Numbers</legend>\n\t<cfloop from="1" to="#ArrayLen(contact.phoneNumbers)#" index="i">\n\t\t#telField(label="Phone ##i#", objectName="contact", association="phoneNumbers", position=i, property="number")#\n\t</cfloop>\n</fieldset> No newline at end of file | |||
There was a problem hiding this comment.
🔴 The newly added vendor/wheels/public/docs/reference/controller/telfield.txt was written with literal backslash-n sequences instead of real newline characters, so the entire ~700-character file is one unreadable line (wc -l returns 0 vs 10 for sibling files like urlfield.txt/emailfield.txt). The example block will render as one mangled line on the docs site rather than the three numbered examples. Fix: rewrite the file using real line breaks like its siblings.
Extended reasoning...
What's wrong
The new reference file vendor/wheels/public/docs/reference/controller/telfield.txt (added in this PR for the telField() view helper) contains the two-character sequence \ + n everywhere a line break should appear, instead of an actual 0x0A newline byte. As a result the whole file is a single ~700-character line.
Verification
$ wc -l vendor/wheels/public/docs/reference/controller/telfield.txt vendor/wheels/public/docs/reference/controller/urlfield.txt vendor/wheels/public/docs/reference/controller/emailfield.txt
0 vendor/wheels/public/docs/reference/controller/telfield.txt
10 vendor/wheels/public/docs/reference/controller/urlfield.txt
10 vendor/wheels/public/docs/reference/controller/emailfield.txt
od -c confirms the bytes between examples are literal \ and n characters, not 0x0A:
0000100 r t y ` - - - > \ n # t e l F
0000220 " ) # \ n \ n < ! - - - A d d
The git diff for the file also shows it as a single line ending with the tell-tale \ No newline at end of file marker.
Step-by-step proof
- Open the file:
cat vendor/wheels/public/docs/reference/controller/telfield.txt - Observe a single line containing literal
\nbetween examples instead of line breaks. - Compare with the file added for the same family of helpers, e.g.
vendor/wheels/public/docs/reference/controller/urlfield.txt— that file has 10 real lines and renders as three numbered examples. wc -l vendor/.../telfield.txtreturns0(no newlines), whilewc -l vendor/.../urlfield.txtreturns10.od -c vendor/.../telfield.txt | head -5shows\followed by lowercasen(two chars), not the\\nshorthandoduses for an actual newline byte.
Why it matters
These reference files are consumed by the public docs site and by tools like cat/less/the IDE preview. The state.json summary describes the intent as "three idiomatic examples mirroring the textfield.txt reference" — that is not what readers will get. They'll see a single line of CFML wrapped with literal \n tokens, which is unreadable and obviously broken next to all the well-formatted siblings added in the same PR (urlfield.txt, emailfield.txt, colorfield.txt, datefield.txt, telfielditag.txt, telfieldtag.txt — all with real newlines).
Likely cause and fix
The writer agent appears to have passed a string containing the escape sequence \\n to the file-writer without that sequence being interpreted as newlines. The fix is to rewrite telfield.txt using real line breaks, mirroring the structure used by the sibling files added in this same PR. Note that telfielditag.txt and telfieldtag.txt (also added in this PR) have the intended content for telFieldTag correctly written with real newlines — telfield.txt is the only file with this corruption.
…OBS (#2469) The View Helpers agent run (PR #2465) hit a tool-layer constraint when trying to author the reference example for `h()`: the WRITE_GLOBS regex in tools/docs-validation/lib/tools.mjs required filenames matching `[a-z][a-z0-9]+\\.txt` (2+ chars), so `h.txt` got rejected. The agent stopped cleanly with status=needs_human, diagnosed the exact regex line that needed fixing, and drafted the reference body. This change: 1. Tightens `+` to `*` in the WRITE_GLOBS regex so single-char function names work (`h`, `e`, `q`, etc.) 2. Writes the agent's drafted content to vendor/wheels/public/docs/reference/controller/h.txt 3. Flips the state.json entry for `h` from needs_human to done with notes describing the manual resolution Closes the last gap from the v4 API docs validation rollout. With this in, all 8 sections × 378 functions are status=done. https://claude.ai/code/session_014puccJJixwdjRgMx7mPLmz Co-authored-by: Claude <noreply@anthropic.com>
Summary
Agent-driven docs validation for the View Helpers section.
docs/api/v4.0.0.jsonvendor/wheels/**/*.cfc(docblocks + narrow body fixes) andvendor/wheels/public/docs/reference/{scope}/{name}.txttools/docs-validation/state.jsonReview checklist
state.jsonentry withstatus: donehas a sensible reference example file added or updatedstate.jsonitems withstatus: needs_humandescribe the open question innotes