Skip to content

fix: anchor app-template rootPath to GetCurrentTemplatePath for subfolder stability (#3025)#3244

Merged
bpamiri merged 1 commit into
developfrom
peter/issue-3025-rootpath-anchor
Jun 22, 2026
Merged

fix: anchor app-template rootPath to GetCurrentTemplatePath for subfolder stability (#3025)#3244
bpamiri merged 1 commit into
developfrom
peter/issue-3025-rootpath-anchor

Conversation

@bpamiri

@bpamiri bpamiri commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Ships the separable folded-in item from #3025 (the reporter's point 1): harden the application template's rootPath anchor so it stays stable when a request bootstraps under a subfolder. This is independent of the larger request-scoped-overlay work tracked in #3025 (for which I posted a design plan separately).

The bug

The app template set:

this.wheels.rootPath = GetDirectoryFromPath(GetBaseTemplatePath());

GetBaseTemplatePath() is the directory of whatever file was originally requested. When a request bootstraps under a subfolder (e.g. the web test runner), the base template is not the public front controller, so rootPath mis-anchors. Because rootPath seeds this.name via the commented Hash(rootPath) pattern (the issue-359 shared-app-name fix), an unstable value silently splits one app across two application scopes — a contributor to the "they fight each other / reload=true fixes it" symptom in #3025 / #2887.

The fix

this.wheels.rootPath = GetDirectoryFromPath(GetCurrentTemplatePath());

GetCurrentTemplatePath() is always this Application.cfc's own path (the public/ dir), stable regardless of the requested base template.

  • Value-identical for a normal front-controller request — both BIFs resolve to public/, so existing apps that uncommented Hash(rootPath) keep the same app name.
  • Deliberately not the reporter's dir & "../" form: that would shift the value to the app root and change that hash for every existing user. The contract here is stability, not a specific level — the only consumer is the per-app-directory identity hash, for which public/ is fine as long as it's stable.
  • Same idiom already used two lines down in vendor/wheels/rocketunit_tests/Application.cfc for this.webrootDir.

Applied consistently to the wheels new scaffold (cli/lucli/templates/app/public/Application.cfc), the demo app (public/Application.cfc), both examples, and the legacy test app.

Verification

This is a template/bootstrap change that runs only under a live HTTP context (not unit-testable in the spec runner), so validated end-to-end:

Refs #3025, #2887

🤖 Generated with Claude Code

…lder stability

The application template set `this.wheels.rootPath` from
`GetDirectoryFromPath(GetBaseTemplatePath())` — the directory of whatever file
was originally requested. When a request bootstraps under a subfolder (e.g. the
web test runner), the base template is not the public front controller, so
rootPath mis-anchors. Because rootPath seeds `this.name` via `Hash(rootPath)`
(the issue-359 shared-app-name pattern), an unstable value silently splits one
app across two application scopes — a contributor to the "reload=true fixes it"
symptom in #3025/#2887.

Anchor to `GetCurrentTemplatePath()` instead — always this Application.cfc's own
path (the public dir), stable regardless of the requested base template. The
value is identical for a normal front-controller request, so existing apps that
uncommented `Hash(rootPath)` keep the same app name. (Deliberately not the
reporter's `dir & "../"` form, which would shift the value to the app root and
change that hash for every existing user — stability, not level, is the fix.)
Same idiom already used two lines down in rocketunit_tests/Application.cfc for
`this.webrootDir`.

Applied to the `wheels new` scaffold, the demo app, both examples, and the
legacy test app. Validated: demo app reload/boot clean; onboarding harness
(wheels new -> start -> migrate -> generate -> test) green (45/0).

Refs #3025, #2887

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Peter Amiri <petera@pai.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 retargets the application template's this.wheels.rootPath from GetDirectoryFromPath(GetBaseTemplatePath()) to GetDirectoryFromPath(GetCurrentTemplatePath()) so the value stays stable when a request bootstraps under a subfolder (e.g. the test runner), preventing the Hash(rootPath) app-name seed from splitting one app across two application scopes. I verified the correctness claims hold and the change is value-identical for normal requests. Verdict: comment — no blocking findings, one minor comment-accuracy nit worth tidying.

Correctness

The central claims check out:

  • Framework path resolution is unaffected. application.$wheels.rootPath is derived independently from cgi.script_name via Global.cfc::$resolveFrameworkPaths (vendor/wheels/Global.cfc:2619) and assigned in vendor/wheels/events/onapplicationstart.cfc:158/:368 — it does not read this.wheels.rootPath. So the only consumer of the template's this.wheels.rootPath is the (commented) Hash(rootPath) app-name seed. The blast radius is exactly what the PR body claims.
  • Value-identical for a normal front-controller request. In the Application.cfc pseudo-constructor, GetCurrentTemplatePath() resolves to this file's own path and GetBaseTemplatePath() to the requested index.cfm — both in public/, so GetDirectoryFromPath(...) is the same. Apps that uncommented // this.name = Hash(this.wheels.rootPath); keep the same hash. The two diverge only under subfolder bootstrap, which is the bug being fixed.

Conventions

Minor nit (non-blocking): in cli/lucli/templates/app/public/Application.cfc:9 the new comment says rootPath "seeds this.name via Hash(rootPath) below", but that scaffold file sets this.name = createUUID(); (line 16) and, unlike the demo/example apps, carries no // this.name = Hash(this.wheels.rootPath); line below. The other four files (public/Application.cfc:13, both examples, rocketunit) do have that commented line, so the comment is accurate there. For the scaffold the rationale is forward-looking only (it holds if a user later enables the Hash). Consider softening the scaffold comment (e.g. "if you enable the Hash(rootPath) app-name pattern") so it does not reference a line that is not present in that file.

Cross-engine

No concerns. GetCurrentTemplatePath() is a universal BIF and is already relied on two lines down for this.webrootDir in vendor/wheels/rocketunit_tests/Application.cfc:18. No closures, struct member functions, reserved scopes, or Left(str,0) patterns introduced.

Tests

No automated test added. Accepted: this is an Application.cfc pseudo-constructor / BIF-behavior change that only manifests under a live HTTP bootstrap and is not reachable from the spec runner. The PR documents end-to-end validation via the onboarding harness (tools/test-onboarding.sh, 45 passed) and a manual demo-app boot, which is the right surface for this class of change.

Docs / Commits

  • Changelog fragment changelog.d/3025-rootpath-anchor.fixed.md is correctly named (<slug>.fixed.md) and is a single complete bullet — follows the fragment system, no direct CHANGELOG.md edit. Good.
  • Commit cf5db38 conforms to commitlint: type fix, header well under 100 chars, not ALL-CAPS, and the body explains the why. PR title matches the landing subject.

Security

None. No SQL, user input, or secret-handling touched.

@bpamiri bpamiri merged commit 181cb6d into develop Jun 22, 2026
11 of 12 checks passed
@bpamiri bpamiri deleted the peter/issue-3025-rootpath-anchor branch June 22, 2026 16:21
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