test(migrator): drop migrator system tables between specs (fixes #2664) - #2685
Conversation
There was a problem hiding this comment.
Wheels Bot — Reviewer A
TL;DR: This PR correctly fixes a flaky-test root cause (#2664) by adding beforeEach/afterEach table-cleanup to the "Tests that migrateTo" describe block and adding a regression spec. The approach is mechanically sound and matches the cleanup pattern already in place for the F15 Phase 1/2 blocks immediately below. Two minor nits below — neither is blocking.
Correctness
The fix is correct. The bug: "uses specified versions table name" (line 158) called migrateTo(001) with application.wheels.migratorTableName = "c_o_r_e_migrator_versions", which caused the migrator to create c_o_r_e_migrator_versions + the fk_wheels_level foreign key. The old afterEach never dropped those tables. On a second pass through the same database, the FK creation collided on MySQL/H2/SQL Server/Oracle (engine-scoped FK namespaces).
Drop order is correct (lines 67-68 and 81-82):
for (local.t in ["wheels_migrator_versions", "c_o_r_e_migrator_versions", "wheels_levels", "c_o_r_e_levels"]) {
try { migration.dropTable(local.t); } catch (any e) {}
}Versions tables (child, holds the fk_wheels_level FK) are dropped before levels tables (parent). Dropping the child removes the constraint, so the parent drop succeeds on all engines. ✓
Interaction with deleteMigratorVersions (line 70): after the new drop loop, deleteMigratorVersions(2) runs DELETE FROM #tableName# WHERE core_level = :levelId against a table that was just dropped. This is already handled — helperFunctions.cfm:8-23 wraps the DELETE in a try/catch with the explicit comment "Table may not exist yet on the very first migrator-spec run". No new risk introduced. ✓
Regression spec assertion (line 177):
expect(listFindNoCase(ValueList(info.table_name), "c_o_r_e_migrator_versions")).toBe(0)If $dbinfo returns an empty query (table absent), ValueList returns "", listFindNoCase returns 0, assertion passes. Edge case is handled correctly. ✓
Tests
Minor nit — CockroachDB skip on regression spec is overly conservative (line 175):
it("drops the migrator system tables between specs (regression: ##2664)", () => {
if (_isCockroachDB) return; // <- unnecessaryThe new afterEach runs the drop loop for every engine, including CockroachDB. The table will be absent on CockroachDB too, so toBe(0) would pass. The skip makes the regression spec invisible on CockroachDB, which means a future regression that breaks cleanup on CockroachDB would go undetected.
Suggested fix: remove the guard, or add a comment explaining why CockroachDB is intentionally excluded (there does not appear to be a reason here).
Conventions
Minor nit — loop variable naming inconsistency in the new beforeEach block (lines 60 vs 67):
// existing code immediately above the new lines
for (local.table in ["c_o_r_e_bunyips", ...]) {
migration.dropTable(local.table)
}
// new code
for (local.t in ["wheels_migrator_versions", ...]) {
try { migration.dropTable(local.t); } catch (any e) {}
}The abbreviated local.t beside local.table in the same beforeEach body is slightly jarring. Renaming local.t → local.table throughout the new additions would be consistent with the surrounding code.
Commits
test(migrator): drop migrator system tables between specs to fix #2664 — valid type, valid scope, 66-char header, not ALL-CAPS. ✓
One minor observation: the phrase "to fix #2664" in the commit subject means GitHub will not auto-close the issue from the commit itself (that requires a bare Fixes #2664 keyword). The PR body already has Fixes #2664, so the issue will close on merge — noting the asymmetry for completeness.
Both nits are cosmetic. No correctness, cross-engine compatibility, or security concerns. This change is safe to merge after addressing or consciously accepting the CockroachDB skip point.
There was a problem hiding this comment.
Wheels Bot — Reviewer A
TL;DR: This follow-up commit addresses both nits from the previous Reviewer A round: the abbreviated loop variable local.t in the two new drop loops has been renamed to local.table for consistency, and the unnecessary CockroachDB guard on the regression spec has been removed. The fix is mechanically correct, the nits are cleanly resolved, and the change is safe to merge subject to one note on DCO sign-offs below.
Correctness
Both previous nits resolved correctly:
Variable rename (lines 67-68, 81-82 in final file):
// before
for (local.t in ["wheels_migrator_versions", "c_o_r_e_migrator_versions", "wheels_levels", "c_o_r_e_levels"]) {
try { migration.dropTable(local.t); } catch (any e) {}
}
// after
for (local.table in ["wheels_migrator_versions", "c_o_r_e_migrator_versions", "wheels_levels", "c_o_r_e_levels"]) {
try { migration.dropTable(local.table); } catch (any e) {}
}Consistent with local.table used in the existing beforeEach drop loop immediately above. ✓
CockroachDB guard removed (line 177 in final file):
it("drops the migrator system tables between specs (regression: ##2664)", () => {
var info = g.$dbinfo(datasource = application.wheels.dataSourceName, type = "tables", pattern = "c_o_r_e_migrator_versions")
expect(listFindNoCase(ValueList(info.table_name), "c_o_r_e_migrator_versions")).toBe(0)
})The guard was unnecessary since afterEach now drops the table on every engine. Without the guard, a cleanup regression on CockroachDB would now be caught by this spec. ✓
The added comment explaining why all engines run the regression spec is clear and accurate. ✓
Commits
One note — DCO sign-off trailers are absent on both commits:
38aa4e8ed test(migrator): address Reviewer A nits on #2664 cleanup (Claude <noreply@anthropic.com>)
0ca373dab test(migrator): drop migrator system tables between specs to fix #2664 (Claude <noreply@anthropic.com>)
Neither ends with a Signed-off-by: trailer. Per CONTRIBUTING.md § DCO and the shared bot rails, every bot-authored commit requires the trailer. The DCO App check is not currently appearing in the PR's CI checks list, but if it is enabled as a required gate it would block merge. Worth squashing and re-signing if the DCO App is active, or confirming it is not enforced for this repo.
Commitlint itself passes (Validate Commit Messages: pass) — types are valid, subjects are ≤ 100 chars, not ALL-CAPS. ✓
Tests
Lucee 7 + SQLite (LuCLI) is still pending at time of review. No concerns expected since the change is test-only, but the matrix result should be green before merging.
No correctness, cross-engine, or security concerns. The change is genuinely clean once the DCO question is resolved.
Wheels Bot — Reviewer B (round 1)A's review is accurate. The nit fixes from the prior round are correctly verified against the diff, the DCO concern is real and appropriately flagged, and A's COMMENTED state rather than APPROVED is the right call given the open items. No sycophancy, no false positives, no missed issues. SycophancyNone detected. A submitted as COMMENTED, not APPROVED, and explicitly called out the DCO sign-off gap rather than waving it through. False positivesNone detected. I verified A's claims against the diff:
Missed issuesNone. Independent checks I ran:
Verdict alignmentA's COMMENTED state is consistent with the findings: the code itself is clean, but there are two open non-code items (DCO sign-off absent on both commits; CI pending at review time) that warrant human eyes before merge. Requesting changes would be too strong for a process question; approving would be premature with CI still running. COMMENTED is the right call. ConvergenceA and B are aligned: the code changes are mechanically correct, the nits from the prior Reviewer A round are fully resolved, and the only remaining items (DCO trailer and green CI) are human process gates rather than code issues. The bot review cycle is complete for this SHA. |
Wheels Bot — Reviewer B (round 1)A's correctness analysis is sound, but both nits are false positives — A cited code that does not appear in the actual diff. Since the two raised issues do not exist, the PR is clean. Converging to approve. SycophancyNone detected. A's favorable verdict is backed by specific line-level reasoning on drop order, the False positivesFP 1 — CockroachDB skip guard does not exist. A writes (under "Minor nit — CockroachDB skip on regression spec is overly conservative") that the new FP 2 — Loop variable A writes (under "Minor nit — loop variable naming inconsistency") that the new code uses for (local.table in ["wheels_migrator_versions", "c_o_r_e_migrator_versions", "wheels_levels", "c_o_r_e_levels"]) {
try { migration.dropTable(local.table); } catch (any e) {}
}The naming is already consistent. No rename is needed. A fabricated the variable name. Missed issuesNone detected. Drop order (child-before-parent to remove the FK before the parent table), the Verdict alignmentA submitted ConvergenceA and B are aligned. The PR has no real deficiencies. Both of A's raised issues were based on code that is not in the diff. The underlying correctness analysis is accurate. Converging on approve. |
The "Tests that migrateTo :: uses specified versions table name" case creates the c_o_r_e_migrator_versions table with the fk_wheels_level foreign key but never tears it down. Re-runs against MySQL / H2 / SQL Server / Oracle then fail with "duplicate constraint name" because the FK namespace is engine-scoped on those databases. Extend the describe block's beforeEach/afterEach with the same cleanup pattern the neighbouring "F15 Phase 1" block already uses: drop both wheels_* and c_o_r_e_* variants of the migrator versions and levels tables, child first so the FK back-reference is gone before the parent. Add a small regression assertion immediately after the failing spec so future regressions stay caught. Signed-off-by: Claude <noreply@anthropic.com>
- Drop the unnecessary CockroachDB guard on the new regression spec. The afterEach drops the table on every engine, so the assertion is meaningful (and protects against cleanup gaps) on Cockroach too. - Rename the new loop variables from local.t to local.table for consistency with the existing drop loop earlier in beforeEach. Signed-off-by: Claude <noreply@anthropic.com>
38aa4e8 to
1fa02fb
Compare
There was a problem hiding this comment.
Wheels Bot — Reviewer A
TL;DR: This PR fixes flaky migrator tests (#2664) by adding beforeEach/afterEach cleanup for the migrator system tables that the "uses specified versions table name" spec creates but never dropped, along with a regression assertion. A previous review round (at 38aa4e8ed) covered this change in depth and confirmed both nits were resolved. The current head is a rebase of that same content onto a newer base, giving new commit SHAs — the diff itself is unchanged and clean. No new concerns are introduced.
Correctness
Drop order is correct: wheels_migrator_versions / c_o_r_e_migrator_versions (child, FK holder) before wheels_levels / c_o_r_e_levels (parent) in both beforeEach (line 67) and afterEach (line 81). Dropping the child removes fk_wheels_level, so the parent drops cleanly on all engines. ✓
Regression spec (lines 176–179) queries type="tables" after afterEach has run; an empty result from $dbinfo produces ValueList = "", listFindNoCase = 0, so toBe(0) passes correctly even when the table was never created. ✓
Tests
- Lucee 7 + SQLite (LuCLI): pass ✓
- Validate Commit Messages: pass ✓
- Bot PR TDD Gate: pass ✓
- CockroachDB guard removed from regression spec — all engines now exercise the cleanup assertion ✓
local.tableused consistently (not abbreviatedlocal.t) ✓
Commits
One outstanding concern first raised in round 2: both commits were authored by the Claude bot and carry no Signed-off-by: trailer:
d81426b2b test(migrator): drop migrator system tables between specs to fix #2664
1fa02fb1b test(migrator): address Reviewer A nits on #2664 cleanup
CONTRIBUTING.md § DCO states the DCO GitHub App is a required status check. The app is not appearing in this PR's current check suite, so merge may not be blocked in practice — but if DCO enforcement is ever re-enabled, these commits will fail retroactively. A human maintainer should confirm whether bot-authored commits are exempt or whether a squash-and-sign is needed before merge.
Commitlint itself passes: types (test) and scopes (migrator) are valid, subjects are ≤ 100 chars, not ALL-CAPS. ✓
No correctness, cross-engine compatibility, or security concerns. The change is otherwise ready to merge pending DCO confirmation.
Wheels Bot — Reviewer B (round 1)A's correctness analysis is sound, but there is one factual error in the DCO section. The trailers exist — A described them incorrectly. Not converging until A corrects the record. SycophancyNone detected. A submitted as COMMENTED, not APPROVED, and explicitly flagged a process question (DCO) as requiring human eyes. The favorable code verdict is backed by specific line-level reasoning on drop order and the regression-spec assertion logic. False positivesFP 1 — Both commits do carry Signed-off-by trailers. A writes: "both commits were authored by the Claude bot and carry no Signed-off-by: trailer." Checking the actual commits: Both commits have a A's underlying instinct (check the DCO status before merge) remains correct; only the factual description of the symptom is wrong. Missed issuesNone detected. Independent scan:
Verdict alignmentA's COMMENTED state is appropriate given the open process question. COMMENTED rather than APPROVED is the right call when a DCO-status question needs a human eye before merge, even if the underlying concern was described imprecisely. ConvergenceNot aligned. A must correct the DCO claim: the trailers are present, the question is whether the signer identity ( |
There was a problem hiding this comment.
Wheels Bot — Reviewer A response (round 1)
B's false-positive finding is confirmed by the git log. Both commits carry Signed-off-by: Claude <noreply@anthropic.com> matching the commit author identity, so the signer-equals-author DCO requirement is satisfied at the Git level. My claim that "no Signed-off-by: trailer" was present was factually wrong and I retract it. The residual question B correctly identified — whether Claude <noreply@anthropic.com> satisfies the repo's DCO App configuration versus the canonical bot identity wheels-bot[bot] <wheels-bot[bot]@users.noreply.github.com> — is the accurate framing of the concern. No other findings by B require a response; B confirmed the drop order, try/catch idiom, regression spec, and nit resolution are all correct, and detected no missed issues.
Conceded points
- DCO description was wrong. My review stated "both commits carry no Signed-off-by: trailer."
git logshows both commits haveSigned-off-by: Claude <noreply@anthropic.com>. The accurate concern is: trailers are present, but using theClaude <noreply@anthropic.com>author identity rather than the canonical bot identity. Since Git author and signer match, author-equals-signer is satisfied. The open question for a human maintainer is whether the repo's DCO App configuration requires thewheels-bot[bot]GitHub App identity specifically, or accepts any matching author/signer pair.
Defended points
- COMMENTED verdict is still appropriate. The DCO identity question — even correctly described — is a human policy call that should be confirmed before merge. A code-clean PR with an unresolved process gate warrants COMMENT rather than APPROVE. No change to the verdict is needed, only the description of why.
Updated verdict
Still COMMENT: code is clean, nits from prior round are resolved, and the only remaining item is a human confirmation that Claude <noreply@anthropic.com> satisfies the repo's DCO App policy — not a code issue, but a merge-gate the maintainer should consciously accept.
Fixes #2664.
Summary
migratorSpec.cfc's"Tests that migrateTo :: uses specified versions table name"case createsc_o_r_e_migrator_versionswith thefk_wheels_levelforeign key but never tears it down. When the matrix re-runs the spec against the same database, the FK creation collides with "duplicate constraint name" on MySQL / H2 / SQL Server / Oracle (engine-scoped FK namespaces). Cockroach + Postgres silently tolerate the redefinition, which is why this only surfaces on a subset of matrix rows (run #25837380625).This is a pure test-cleanup bug — production migrator logic is correct.
Fix shape
"Tests that migrateTo"describe block'sbeforeEach/afterEachwith the same cleanup pattern the neighbouring"F15 Phase 1"block already uses (vendor/wheels/tests/specs/migrator/migratorSpec.cfc:163-182). Versions tables first, levels tables last, so thefk_wheels_levelback-reference is gone before the parent. Dropping the table drops the FK with it, sidestepping per-DBDROP CONSTRAINTsyntax differences."uses specified versions table name"asserting thatc_o_r_e_migrator_versionsis dropped between specs.Why this over the issue's other options
vendor/wheels/Migrator.cfc:470to accept a configurable FK name, which is a real API change.migrateTo(001)without a paired down step, so this would need a new fixture.Test plan
sqlite,h2,mysql,postgres,sqlserver,cockroachdb(Oracle is soft-fail per ci: Oracle datasource broken across all engines — Invalid URL, missing DBMS_LOCK, constraint cleanup #2663).migratorSpecreports 0 errors on MySQL / H2 / SQL Server (was 1 error each on Lucee 6 in run #25837380625)."drops the migrator system tables between specs (regression: #2664)"passes.Related: #2649, #2663.
Generated by Claude Code