Skip to content

fix(cli): generate enum() emission, view-gen warnings, route-dup message#2884

Merged
bpamiri merged 1 commit into
developfrom
peter/cli-audit-nits
Jun 9, 2026
Merged

fix(cli): generate enum() emission, view-gen warnings, route-dup message#2884
bpamiri merged 1 commit into
developfrom
peter/cli-audit-nits

Conversation

@bpamiri

@bpamiri bpamiri commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

What & why

The final tier of CLI-audit follow-ups (after #2882 and #2883) — the remaining in-repo nits plus the wheels-bot's non-blocking review nits from #2883. Every fix reproduced + verified against the CLI in an isolated harness.

Fixes

Fix Was Now
generate model … status:enum:a,b,c the enum type was parsed but never written to the model emits enum(property="status", values="a,b,c") in config() (verified)
generate controller / scaffold views a view that failed to generate was silently skipped — the command reported success with no views warns (skip … : <reason>) so the failure is visible (M3)
generate route <name> an existing named-arg route (.resources(name="x", …)) was misreported as "Could not find insertion point" reports "Route already exists" (M5, verified)
DeployArgsParserSpec no space-form coverage for the new --role/--container flags added --role value / --container value cases
ReleaseChannel comment the explanatory comment contained a bare @build.version@ literal the build's token-replacer would garble rephrased to be clobber-proof (bot nit)

enum emission detail

enum was parsed (prop.values) but no enum() line was written. This adds buildModelEnums() (mirroring buildModelValidations()), an {{enums}} placeholder to all ModelContent.txt copies (scaffold source, shared cli/src/templates, demo app/snippets), and an explicit {{enums}} substitution in Templates.cfc (the generic {{key}} loop wasn't applying it). The migration side already mapped enum → a string column. + CodeGenSpec coverage (emits for enum props; no stray placeholder otherwise).

Verification

  • enum emission, route-dup message, view-gen warning, and the deploy-flag space-forms all reproduced in the isolated harness (fresh wheels new app for the template path; genbase copies for the rest).
  • New CodeGenSpec + DeployArgsParserSpec cases mirror the existing specs; CI's CLI suite is the validator (the spec runner needs a server that won't stay up from a .claude/worktrees worktree).

Remaining

The systemic LuCLI dispatch work (per-command --help/--verbose/--version/wheels help + brand leaks) is scoped for a dedicated upstream cybersonic/LuCLI effort — not in this repo's cli/lucli/.

…dup message

Final CLI audit nits (all reproduced + verified in the isolated harness):

- generate model name:enum:a,b,c now emits enum(property="name", values="a,b,c")
  in the model config(). The type was parsed but never written. Adds buildModelEnums()
  + an {{enums}} placeholder to all ModelContent.txt copies (scaffold source, shared
  cli/src, demo app) + an explicit substitution in Templates.cfc (M2). Migration was
  already correct (enum maps to a string column). + CodeGenSpec coverage.
- generate controller / scaffold now WARN (instead of silently skipping) when a view
  fails to generate — a controller reporting success with no views written is
  misleading (M3).
- generate route <name> now detects an existing named-arg route .resources(name="x")
  and reports 'Route already exists' instead of the misleading 'Could not find
  insertion point' (M5).
- DeployArgsParserSpec: add --role/--container space-form coverage; ReleaseChannel:
  tidy the dev-sentinel comment so the build's token replacer can't garble it
  (bot review non-blocking nits).

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 A

TL;DR: This PR correctly implements three audit fixes — enum emission in generated models, view-gen failure warnings, and named-arg route duplicate detection — plus two non-blocking nits from the prior bot review. The core logic is mechanically sound, all three ModelContent.txt copies are updated, collapseEmptyLines handles the new empty {{enums}} placeholder correctly, and DCO sign-off is present. Verdict: comment — a few minor gaps in test coverage and one low-risk defensive issue worth noting, but nothing blocking.


Correctness

routeName used unescaped inside reFindNoCase pattern — low risk, but worth hardening

cli/lucli/Module.cfc, line 2945:

var namedArgPattern = "\.resources\s*\([^)]*name\s*=\s*[""']" & routeName & "[""']";
if (reFindNoCase(namedArgPattern, content)) {

routeName is concatenated directly into a regex pattern. If a user passes a name containing ., +, *, (, or \ (all valid in a shell argument, even if unusual for Wheels route names), the character is interpreted as a regex metacharacter. The simple-form check two lines above uses the safer findNoCase (literal string). Suggested fix:

// Escape dots and other special chars so the name is matched literally
var safeRouteName = reReplace(routeName, "([\.\+\*\?\(\)\[\]\{\}\^\$\|\\])", "\\1", "all");
var namedArgPattern = "\.resources\s*\([^)]*name\s*=\s*[""']" & safeRouteName & "[""']";

Tests

1. Named-arg duplicate path in generateRoute has no direct unit test

cli/lucli/tests/specs/commands/GenerateCommandSpec.cfc, after line 200:

ScaffoldSpec.cfc:404 covers the service-level duplicate prevention (Scaffold's updateRoutes won't inject a second line). That's different from the new Module-level early-return and "Route already exists" message in generateRoute. There's no test that calls mod.generate() with ["route", "posts"] when routes.cfm already contains .resources(name="posts", ...). Suggested addition:

it("reports 'Route already exists' for a named-arg route duplicate", () => {
    var routesPath = tempRoot & "/config/routes.cfm";
    fileWrite(routesPath, 'mapper().resources(name="reviews", only="index").end();');

    mod.__arguments = ["route", "reviews"];
    mod.generate();
    // output captured via your test harness — verify no second .resources() added
    var content = fileRead(routesPath);
    var matches = reMatch('\.resources\([^)]*reviews', content);
    expect(arrayLen(matches)).toBe(1);
});

2. View-gen warning in generateController is untested

cli/lucli/Module.cfc, lines 2797–2800 — the new else branch that emits "skip …" when a view fails has no coverage in GenerateCommandSpec. Low-friction addition: mock generateView to return {success: false, error: "templates missing"} and assert the warning is emitted.


Conventions

Minor: view-gen skip message format differs between generateController and generateScaffold paths

cli/lucli/services/Scaffold.cfc, line 134:

arrayAppend(results.skipped, "view " & action & ": " & (viewResult.error ?: "generation failed"));

cli/lucli/Module.cfc, line 2800:

out("  skip    app/views/#lCase(controllerName)#/#lCase(action)#.cfm: " & ..., "yellow");

The direct-output path includes the full app/views/… path, which is more actionable. The Scaffold path only records "view index: reason". Users running wheels generate scaffold will see skip view index: generation failed without knowing the target path. Low-impact but worth aligning:

arrayAppend(results.skipped, "app/views/#lCase(pluralName)#/#action#.cfm: " & (viewResult.error ?: "generation failed"));

(Note: pluralName is in scope at line 35 of Scaffold.cfc.)


Docs

No user-visible behavior changes to the guides docs or CHANGELOG were included, consistent with the PR description marking this as a fix-tier follow-up to #2882 and #2883. A [Unreleased] CHANGELOG entry for the three fixes would be welcome given they're user-observable (enum generation was silently broken), but not blocking given the broader audit PR likely carries the entry.


Commits

Single commit fix(cli): emit generate enum(), warn on view-gen failures, fix route-dup message — 81 chars, valid type, in-scope subject, DCO Signed-off-by trailer present. Passes commitlint.

@wheels-bot

wheels-bot Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Wheels Bot — Reviewer B (round 1)

A's review is accurate and well-supported. All four findings check out against the actual diff. No sycophancy, no false positives, and no missed issues of significance. A's comment verdict (non-blocking) is consistent with the severity of the findings, all of which have concrete fixes A already supplied. Converging on changes.

Sycophancy

None detected. A identified specific findings with file/line citations and explicit reasoning for why each is non-blocking.

False positives

None detected.

  • Regex issue: Verified at cli/lucli/Module.cfc line 2945. routeName is indeed concatenated directly into the reFindNoCase pattern with no escaping. The simple-form check two lines above correctly uses literal findNoCase. A's finding and suggested reReplace fix are accurate.
  • Test gap — named-arg route detection: Verified. GenerateCommandSpec.cfc has exactly one generate route test (checks the route is present, not that a duplicate is rejected). ScaffoldSpec covers service-level deduplication, which is a different code path from Module's early-return. The gap A describes is real.
  • Test gap — view-gen warning: Verified. The diff adds a generateController else branch in Module.cfc lines 2797-2800 with no corresponding test in GenerateCommandSpec.
  • Convention nit — Scaffold skip message: Verified. Scaffold.cfc appends "view " & action & ": ..." (no path) while Module.cfc emits the full app/views/... path. A's claim that pluralName is in scope at line 35 of Scaffold.cfc is correct.

Missed issues

None detected. The changes are entirely in CLI code (cli/lucli/) — the cross-engine framework invariants in CLAUDE.md do not apply here. PR title (fix(cli): generate enum() emission, view-gen warnings, route-dup message, 72 chars) is a valid conventional-commit header. DCO trailer is present. Three ModelContent.txt copies are all updated consistently.

Verdict alignment

A's comment verdict is consistent with the findings: the regex issue is low-risk (route names rarely contain metacharacters), the test gaps are minor, and the convention nit is cosmetic. None warrant blocking the merge, but all are addressable.

Convergence

Aligned. A's findings are accurate and the supplied fixes are correct. Per the convergence rules, a comment verdict with concrete actionable findings triggers converged-changes — address-review should apply: (1) escape routeName before regex interpolation in Module.cfc, (2) add a named-arg duplicate test to GenerateCommandSpec, (3) add a view-gen warning test, and (4) include the full path in Scaffold's skipped message. The CHANGELOG note is non-blocking and can be deferred.

@bpamiri bpamiri merged commit 2d8e507 into develop Jun 9, 2026
8 checks passed
@bpamiri bpamiri deleted the peter/cli-audit-nits branch June 9, 2026 13:56
@wheels-bot

wheels-bot Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Wheels Bot — Address Review (round 1)

Applied consensus findings from Reviewer A and Reviewer B's convergence (round 1):

  • Regex hardeningcli/lucli/Module.cfc:2945-2948: route names are now escaped against the regex metacharacter set (. + * ? ( ) [ ] { } ^ $ | \) before being interpolated into the named-arg duplicate-detection pattern. (Note: the replacement string in the codebase form uses "\\\1"\\ for a literal backslash + \1 for the group-1 backref — rather than the "\\1" shown in A's hint, which would output a literal \1 instead of escaping.)
  • Scaffold skip-message alignmentcli/lucli/services/Scaffold.cfc:131-138: the M3 view-gen failure path now records app/views/<plural>/<action>.cfm: <error> so the message matches the direct generate controller output and is actionable.
  • Named-arg duplicate testcli/lucli/tests/specs/commands/GenerateCommandSpec.cfc (under describe("generate route")): pre-seeds a named-arg route, runs mod.generate(["route", ...]), and asserts exactly one .resources(...) line remains.
  • View-gen warning test — same spec (under describe("generate controller")): pre-creates the target view so generateView() returns {success: false} without --force, then asserts the captured output includes skip and the full app/views/... path. Backed by a tiny output recorder on the test-stub cli/lucli/tests/_modules/BaseModule.cfc (__captured array on out()/err()) so specs can assert on emitted warnings without an out() hook on production Module.cfc.

Both new spec cases live inside the existing xdescribe("wheels generate", ...) block — same xdescribe reason as the surrounding suite (PR #2829 / #2831 codegen-fixture work), so they will activate as part of that audit rather than running today.

The CHANGELOG note B flagged as non-blocking was intentionally deferred — the broader audit PR carries the entry.

Local test runner (tools/test-cli-local.sh) was not executable in this sandbox (requires a lucli server lifecycle outside the allowed surface) — relying on CI to confirm the change is regression-free.

The new commit will trigger a fresh Reviewer A run on the updated SHA. Convergence loop continues until reviewers align on `approve` or the outer-loop cap (5 rounds) is reached.

bpamiri added a commit that referenced this pull request Jun 10, 2026
Release-cut reconciliation ahead of the 4.0.3 GA:

- Rename [Unreleased] -> [4.0.3] with the 2026-06-09 release date and a
  summary blurb, matching the 4.0.2 promotion format (#2824).
- Consolidate the duplicated ### Changed / ### Fixed sections that
  accumulated from incremental entry additions into one Added/Changed/Fixed
  trio (same order as the 4.0.2 block).
- Drop the byte-identical duplicate #2844 (protectedControllerMethods) entry.
- Add the missing consolidated entry for the 24-command CLI audit sweep
  (#2882, #2883, #2884, #2885).
- Fix the separator below the promoted block to exactly '---' (3 dashes) so
  release.yml's release-notes awk extraction terminates correctly (the
  #2606/#2768 footgun its Validate Release Checklist step guards against).

Cutting the release branch from develop AFTER this lands avoids the 4.0.2
back-port dance (#2824) where the rename lived only on the release branch.

Signed-off-by: Peter Amiri <peter@alurium.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant