Skip to content

test(cli): cover every shipped onApplicationEnd handler for #3379 - #3381

Merged
bpamiri merged 3 commits into
developfrom
cursor/3379-onapplicationend-spec-coverage-f0c8
Aug 20, 2026
Merged

test(cli): cover every shipped onApplicationEnd handler for #3379#3381
bpamiri merged 3 commits into
developfrom
cursor/3379-onapplicationend-spec-coverage-f0c8

Conversation

@bpamiri

@bpamiri bpamiri commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

Human follow-up on the wheels-bot draft #3380. Keeps the bot's onApplicationEnd() guard as-is and closes the review gap: the structural spec now scans every shipped Application.cfc that declares onApplicationEnd, not just the CLI template and demo app.

This branch is based on fix/bot-3379-element-wo-is-undefined-in-a-java-object-of-type-c @ e9699f473 and includes those bot commits plus the spec coverage change. Merging this PR is sufficient; leave #3380 open as draft unless a maintainer prefers to close it as superseded.

Related Issue

Refs #3379

Improves #3380 (does not replace the bot draft unless this PR is the one merged).

What is actually broken

On Adobe ColdFusion 2023, public/Application.cfc onApplicationEnd() fires synchronously during applicationStop() teardown. Bare application.wo can resolve against a torn-down scope / Java String[] and throw Element wo is undefined in a Java object of type class [Ljava.lang.String;. The captured stack is the recovery path (onRequestStart$simpleLock$handleRestartAppRequestapplicationStop()onApplicationEnd). Overnight idle reclaim is believed to call the same handler the same way. The site stays dead until a CF service restart; ?reload=true does not recover.

Existing 4.0.5 apps must apply the same edit to their own public/Application.cfc. That is expected — this change cannot patch live user apps from the vendor tree.

What was verified

  • The bot's guard is the correct fix. It routes through arguments.applicationScope.wo and short-circuits with StructKeyExists on wo, wheels, and wheels.eventPath. That matches the $wheelsBrowserLauncher cleanup already in the same handler (the only dependable reference at shutdown).
  • Happy path is unchanged: in normal operation application.wo and arguments.applicationScope.wo are the same instance.
  • No other shipped Application.cfc still has the unguarded application.wo dereference inside onApplicationEnd. Test-only copies (vendor/wheels/tests, rocketunit_tests, cli/lucli/tests) and empty miscellaneous/Application.cfc stubs do not declare the handler.
  • Did not replace the guard. Did not chase a new overnight timeout/reinit race.

Spec coverage change

vendor/wheels/tests/specs/cli/OnApplicationEndScopeGuardSpec.cfc now asserts the same three source-shape checks on:

  • cli/lucli/templates/app/public/Application.cfc
  • public/Application.cfc
  • examples/starter-app/public/Application.cfc (was patched, previously untested)
  • examples/tweet/public/Application.cfc (was patched, previously untested)

A discovery it() walks cli/lucli/templates, public/, and examples/ and fails if any shipped Application.cfc that declares onApplicationEnd is missing from that list, so the coverage gap cannot recur.

The per-file assertions are unchanged (no live application.wo.*, route through arguments.applicationScope.wo, StructKeyExists before the dereference). Failing → passing structural-spec pattern is preserved.

Type of Change

  • Bug fix
  • New feature
  • Enhancement to existing feature
  • Documentation update
  • Refactoring

Feature Completeness Checklist

Test Plan

The failure only manifests on Adobe CF during real applicationStop() teardown, which cannot be reproduced inside a spec without killing the runner. Local verification of the structural guard:

curl -sL "http://localhost:8080/wheels/core/tests?db=sqlite&directory=wheels.tests.specs.cli&format=json"

Result on this SHA: 145 pass, 0 fail, 0 error, 23 bundles. The new spec reported 5 passing examples.

CI that must go green

These are green on this SHA:

  • Bot PR TDD Gate (no-op on this human cursor/ branch; the structural spec pattern is unchanged)
  • Conventional commit / Validate Commit Messages
  • Smoke: testing (Lucee 7) — this timed out at 20m on the bot SHA (e9699f473); green here
  • Smoke: production (Lucee 7)
  • Smoke: testing (Adobe 2023) and Smoke: production (Adobe 2023)
  • Lucee 7 + SQLite (LuCLI)

verify may still be running (docs check; not a smoke). No full engine × DB matrix. Leave approve-on-develop to Peter. Do not merge from this PR.

Screenshots / Output

N/A — structural spec + existing handler guard.

Open in Web Open in Cursor 

github-actions Bot and others added 3 commits August 18, 2026 18:16
…rvive Adobe teardown

On Adobe ColdFusion 2023 the live application scope is unreliable during
applicationStop() teardown, so bare application.wo could resolve to a stale
Java String[] and throw "Element wo is undefined in a Java object of type
class [Ljava.lang.String;", erroring the whole site until a CF service
restart. onApplicationEnd() now invokes the Wheels global through the
passed-in arguments.applicationScope.wo, guarded with StructKeyExists, so a
partially reclaimed scope degrades to a no-op. Applied to the CLI app
template, the demo app, and the bundled example apps.

Refs #3379

Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
…Adobe CF

Add cross-engine invariant #19 to CLAUDE.md and a matching section to
.ai/wheels/cross-engine-compatibility.md: during applicationStop()
teardown on Adobe CF 2023, bare application.wo can resolve to a stale
Java String[] and throw 'Element wo is undefined...'. Route
onApplicationEnd() through arguments.applicationScope.wo instead and
guard with StructKeyExists (#3379, fixed in #3380).

Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
…scope guard

The #3380 structural spec only scanned the CLI template and demo
Application.cfc. The same teardown guard was applied to the bundled
example apps, so a revert there would have gone uncaught. Extend the
targets list and add a discovery check over the shipped trees so a
newly added onApplicationEnd copy cannot slip the list.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Peter Amiri <peter@alurium.com>
@bpamiri
bpamiri marked this pull request as ready for review August 20, 2026 00:42

@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 extends the #3379 structural guard so OnApplicationEndScopeGuardSpec now asserts the Adobe-CF teardown fix across every shipped Application.cfc that declares onApplicationEnd (CLI template, demo app, and both bundled example apps), plus a discovery it() that fails if a new shipped copy ever slips the targets list. It closes the coverage gap left by the bot draft #3380, whose framework/docs changes are carried along in the base commits. The diff is clean, mirrors established prior art, and I verified the discovery logic against the actual repo tree. Verdict: approve.

Correctness

No issues. I confirmed the discovery it() will pass rather than false-fail:

  • The four listed targets are exactly the shipped Application.cfc files that declare onApplicationEnd. The sibling public/miscellaneous/Application.cfc stubs under each root exist but declare no onApplicationEnd handler, so $discoverShippedOnApplicationEndHandlers skips them (grep 'function onApplicationEnd' over the miscellaneous/Application.cfc files returns no matches). The discovered set therefore equals the targets set, matching the PR's "5 pass" claim.
  • The manual brace-matching body extractor and the per-file assertions (no application.wo., must route through arguments.applicationScope.wo, guard-before-deref ordering via guardPos < derefPos) are copied verbatim from the passing OnErrorFallbackGuardSpec, so the shape is trusted prior art.

Cross-engine

No issues found; I checked the new discovery helper specifically:

  • vendor/wheels/tests/specs/cli/OnApplicationEndScopeGuardSpec.cfc:168Left(rootNormalized, Len(rootNormalized) - 1) is guarded by Len(rootNormalized) > 1 at line 167, so the length argument is never 0 and this avoids the Lucee 7 Left(str, 0) crash (CLAUDE.md cross-engine invariant #8).
  • Loop-variable capture for the per-file specs uses the (function(relPath){ ... })(rel) IIFE form (matching OnErrorFallbackGuardSpec), so each it() binds its own path rather than the final iteration's.
  • No compile hazards for the all-engine directory="wheels.tests.specs" sweep: no (new X()).method() receiver (invariant 16a), no zero-arg call through application scope in a closure (16b), no inline closure as a constructor named arg (invariant 5). reFindNoCase(..., content, 1, true) uses the standard 4-arg struct form.
  • Private $-prefixed helpers called by bare name from inside the it() closures is fine here — this is a directly-instantiated spec, not a $integrateComponents()-mixed model/controller, and it mirrors $stripCfmlComments usage in the sibling spec.

Docs

CLAUDE.md (invariant #19) and .ai/wheels/cross-engine-compatibility.md carry the teardown-hazard write-up, and changelog.d/3379-onapplicationend-scope-guard.fixed.md uses the correct fragment form (<slug>.fixed.md) rather than a direct CHANGELOG.md [Unreleased] edit. All consistent with the code. (These landed on the base #3380 commits and appear in the diff because the PR is based on develop.)

Commits

All three conform to commitlint.config.js: test(cli): …, docs: …, fix(config): … — valid types, subjects <= 100 chars, not ALL-CAPS, DCO signed-off.

Nice touch: the discovery walk turns a passive "did someone remember to add the new file?" into an enforced invariant, which is exactly the failure mode that motivated widening the spec.

@bpamiri
bpamiri merged commit 2d2f9a5 into develop Aug 20, 2026
17 checks passed
@bpamiri
bpamiri deleted the cursor/3379-onapplicationend-spec-coverage-f0c8 branch August 20, 2026 01:19
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.

2 participants