Skip to content

fix(seed): roll back transaction and exit non-zero when seedOnce entries fail - #2984

Closed
wheels-bot[bot] wants to merge 2 commits into
developfrom
fix/bot-2973-seeder-reports-success-and-commits-when-individual
Closed

wheels-bot[bot] wants to merge 2 commits into
developfrom
fix/bot-2973-seeder-reports-success-and-commits-when-individual

Conversation

@wheels-bot

@wheels-bot wheels-bot Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Seeder.runSeeds() previously committed the wrapping transaction and returned success=true even when individual seedOnce() calls recorded action="failed", so a half-applied seed file looked identical to a fully-applied one in CI and in wheels seed output. This change tracks totalFailed, rolls back the transaction when any entry fails, names the failing models in message, and bubbles totalFailed through the CLI bridge (vendor/wheels/public/views/cli.cfm::runDbSeed) so wheels seed exits non-zero via the existing parseCliResponse → Wheels.Cli.CommandFailed path. seedOnce() stays idempotent, so the caller can fix the offending entry and re-run safely.

The rollback-vs-commit-with-report decision called out in the issue is resolved as rollback, documented in the runSeeds() docblock. Rationale: the wrapping transaction already signalled intent for atomicity; "half-applied" is the bug being fixed; and seedOnce()'s idempotency makes retry-after-fix safe.

Related Issue

Fixes #2973

Type of Change

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

Feature Completeness Checklist

  • DCO sign-off -- commit carries Signed-off-by:
  • Tests -- two new specs in vendor/wheels/tests/specs/seederSpec.cfc plus a withfailure/seeds.cfm fixture; failing → passing locally
  • Framework Docs -- left for bot-update-docs.yml follow-up
  • AI Reference Docs -- left for bot-update-docs.yml follow-up
  • CLAUDE.md -- left for bot-update-docs.yml follow-up
  • CHANGELOG.md -- entry added under [Unreleased] → Fixed
  • Test runner passes -- ran the full core suite against Lucee 7 + SQLite locally: 4257 pass, 0 fail, 0 error (prior to the fix the same run showed 1 fail + 1 error from the two new specs)

Test Plan

  • vendor/wheels/tests/_assets/seeder/withfailure/seeds.cfm exercises one valid seedOnce(author, ...) followed by an invalid seedOnce(user, ...) (user model requires username, password, firstname, lastname; supplying only username forces validation failure).
  • New spec returns success=false and rolls back when a seedOnce() entry fails validation asserts result.success === false, result.totalFailed >= 1, result.totalCreated === 0, message includes "failed", and the would-have-been-created author cannot be found post-run (rollback verified at the data level, not just the return struct).
  • New spec initializes totalFailed alongside totalCreated and totalSkipped covers the counter contract on init().

…ies fail

Seeder.runSeeds() previously committed the wrapping transaction and returned
success=true even when individual seedOnce() calls recorded action="failed",
so a half-applied seed file looked identical to a fully-applied one in CI and
in `wheels seed` output. The framework now tracks totalFailed, rolls back the
transaction on any failed entry, names the failing models in the message,
and surfaces totalFailed in the response envelope so the CLI bridge can exit
non-zero via the existing parseCliResponse path. seedOnce() stays idempotent.

Fixes #2973

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

PR #2987 (d654586, issue #2973) already shipped the equivalent seeder
partial-failure fix on develop, so this resolution converges the branch
onto develop's implementation:

- CHANGELOG.md, vendor/wheels/Seeder.cfc, vendor/wheels/public/views/cli.cfm:
  conflicts resolved by taking develop's side (#2987 includes the
  changelog.d/seeder-partial-failure.fixed.md fragment; this branch's
  direct [Unreleased] edit predates the fragment convention).
- vendor/wheels/tests/specs/seederSpec.cfc: restored to develop's version;
  the auto-merged duplicate spec asserted totalCreated=0 on failure, which
  contradicts #2987's shipped semantics (pre-rollback attempted count).
- vendor/wheels/tests/_assets/seeder/withfailure/: removed; develop's
  partialfailure asset covers the same scenario.

The resulting tree is identical to origin/develop.

Signed-off-by: Peter Amiri <peter@alurium.com>
@bpamiri

bpamiri commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Conflict resolution + disposition summary

Recommendation: close this PR as superseded by #2987. Every functional change here already shipped to develop via #2987 (d6545863e, merged 2026-06-10), which fixed issue #2973 (now closed). The branch has been converged onto develop so it is no longer conflicting, and its diff against develop is now empty — merging it would be a no-op.

Findings addressed

None — this PR had zero reviews, zero comments, and zero review threads (draft; the bot review loop never fired), so there was no reviewer feedback to implement.

Conflicts resolved (merge commit 5ebb7727b)

All three resolved by taking develop's side, since #2987 subsumes this branch's implementation:

  • CHANGELOG.md — this branch's direct [Unreleased] edit predates the changelog.d fragment convention (feat(docs): changelog.d fragment system for conflict-free unreleased entries #2994); develop already documents the fix in changelog.d/seeder-partial-failure.fixed.md.
  • vendor/wheels/Seeder.cfc — develop's version has the same totalFailed init/rollback/return-struct surface plus a $failedEntriesSummary() helper (vendor/wheels/Seeder.cfc:236) that names each failed entry's first error, which this branch's inline loop did not.
  • vendor/wheels/public/views/cli.cfm — develop already bubbles totalFailed into the dbSeed envelope (vendor/wheels/public/views/cli.cfm:902).

Two near-duplicates that auto-merged were also dropped in the same resolution:

  • vendor/wheels/tests/specs/seederSpec.cfc — restored to develop's version. This branch's duplicate rollback spec asserted totalCreated == 0 on failure, which contradicts fix(seed): fail and roll back when seedOnce entries fail validation #2987's shipped semantics (failure path returns the pre-rollback attempted count with an "All changes were rolled back" message — see vendor/wheels/Seeder.cfc:100-106). Keeping it would have broken CI. Develop's equivalent spec is returns failure and rolls back when a seedOnce entry fails validation (vendor/wheels/tests/specs/seederSpec.cfc:72).
  • vendor/wheels/tests/_assets/seeder/withfailure/ — removed; develop's partialfailure asset exercises the same one-good-one-invalid scenario.

Test evidence

git diff origin/develop HEAD is empty — the resulting tree is byte-identical to develop head 945e0c7dd, which CI already validated (including the #2987 seeder specs). A local run on this tree would literally re-test develop, so none was performed.

CI note

The earlier Auto-Label PR failure was a transient HttpError: Requires authentication while the labeler fetched its config at a stale ref — the same check passes on other branches in the same window, and this PR never touched .github/. Not PR-caused.

@wheels-bot wheels-bot Bot left a comment

Copy link
Copy Markdown
Contributor Author

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 is superseded. The merge commit at HEAD (5ebb7727b) explicitly resolved conflicts by taking develop's side across all changed files, leaving the PR with zero additions and zero deletions against develop. Merging it would be a no-op. I'm commenting rather than approving or requesting changes because there is no live diff to act on — the fix already shipped via PR #2987. The original fix commit (8f7c3e72b) had two issues worth noting for the record.


Correctness

totalCreated hardcoded to 0 in the failure-return path — the original fix commit set totalCreated = 0 in the rollback branch of runSeeds():

// vendor/wheels/Seeder.cfc (commit 8f7c3e72b, ~line 104)
return {
    success = false,
    message = "Seeding failed: ...",
    totalCreated = 0,     // hardcoded
    ...
};

This means callers cannot distinguish "nothing was attempted" from "entries were attempted but then rolled back." PR #2987 correctly returns totalCreated = this.totalCreated so the pre-rollback attempted count is preserved. The new spec in this PR reinforces the wrong contract by asserting expect(local.result.totalCreated).toBe(0) — a spec that would have failed against #2987's shipped implementation. The merge commit body acknowledges this directly: "the auto-merged duplicate spec asserted totalCreated=0 on failure, which contradicts #2987's shipped semantics (pre-rollback attempted count)."


Conventions

Direct CHANGELOG.md edit — the fix commit added a bullet directly under [Unreleased] -> Fixed in CHANGELOG.md. Per CLAUDE.md section "Changelog entries":

User-facing fix/feat PRs add a fragment file, never a direct CHANGELOG.md edit. Direct [Unreleased] edits recreate the same-anchor merge conflicts the fragment system removes.

The correct artifact is changelog.d/<slug>.fixed.md. PR #2987 used changelog.d/seeder-partial-failure.fixed.md correctly; the conflict-resolution merge commit took that side.

The PR checklist marks [x] CHANGELOG.md -- entry added under [Unreleased] as complete, which signals success for the wrong approach. Future bot runs should write a changelog.d/ fragment from the start.


Status

The resulting tree at HEAD is identical to origin/develop. This PR should be closed without merging — the fix for issue #2973 is already live via #2987.

@wheels-bot

wheels-bot Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

Wheels Bot — Reviewer B (round 1)

A's review is accurate and complete. The PR is confirmed as a no-op against develop (gh pr diff returns empty; the merge commit message explicitly states "The resulting tree is identical to origin/develop"). PR #2987 (merged 2026-06-10) already shipped the equivalent fix for issue #2973. A correctly recommends closing without merging.

Sycophancy

None detected. A did not approve; the COMMENTED state and "close without merging" recommendation are appropriate given the empty diff.

False positives

None detected. I verified each claim:

  • Zero diff against develop — confirmed by empty gh pr diff 2984 output and by the merge commit stat showing only .ai/ / .claude/ / .github/ files belonging to develop's side of the resolution.
  • totalCreated = 0 hardcoded in the original fix commit — confirmed by the PR description's own test-plan section, which explicitly states the new spec asserts result.totalCreated === 0, and by the merge commit message noting this contradicts fix(seed): fail and roll back when seedOnce entries fail validation #2987's shipped semantics (pre-rollback attempted count).
  • Direct CHANGELOG.md edit — confirmed by the PR checklist: [x] CHANGELOG.md -- entry added under [Unreleased] → Fixed. CLAUDE.md is unambiguous that changelog.d/<slug>.<type>.md fragments are the required form.

Missed issues

None detected. Given the diff is empty there is no live code to flag. A's two historical observations (hardcoded counter, wrong changelog artifact) are accurate and serve as useful record-keeping. Commit linting: the original fix commit header (fix(seed): roll back transaction and exit non-zero when seedOnce entries fail) is 73 chars and passes.

Verdict alignment

A's COMMENTED verdict is consistent with the finding: no live diff means neither APPROVE nor REQUEST_CHANGES is appropriate. The underlying issue is already resolved upstream.

Convergence

Aligned. Both A and B agree: this PR is a no-op superseded by #2987 and should be closed without merging. No code changes are needed on this branch. A human should close the PR.

@bpamiri

bpamiri commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Closing as superseded: the equivalent seeder partial-failure fix for #2973 shipped to develop via #2987 (d654586). This branch was converged onto develop (empty diff) before closing — see the detailed supersession evidence in the comment above.

@bpamiri bpamiri closed this Jun 10, 2026
@bpamiri
bpamiri deleted the fix/bot-2973-seeder-reports-success-and-commits-when-individual branch June 10, 2026 22:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Seeder reports success and commits when individual seedOnce() entries failed

1 participant