Skip to content

Guard template sweep deletions with a gemfile reference closure - #86

Merged
pboling merged 1 commit into
mainfrom
bug/84-sweep-variant-deletion-guard
Oct 31, 2026
Merged

pboling merged 1 commit into
mainfrom
bug/84-sweep-variant-deletion-guard

Conversation

@pboling

@pboling pboling commented Oct 31, 2026

Copy link
Copy Markdown
Contributor

Summary

The kettle-jem template sweep pruned every per-Ruby-version x_std_libs bucket
variant the destination's minimum test Ruby made irrelevant, ignoring that the
committed version-split loader (gemfiles/modular/x_std_libs.gemfile) branches
on RUBY_VERSION and eval_gemfiles each bucket variant. The 7.1.41
family-wide sweep deleted the r2/r3/r3.1 libs.gemfile variants plus the
std-lib gem variants they load across all 34 members, and CI's Ruby 3.3 probe
hit Errno::ENOENT evaluating a deleted file (run 40998206316).

This adds a reference-closure guard to the sweep's deletion decision:

  • A variant may only be deleted when no loader that itself survives the sweep
    references it.
  • References are collected from the Prism AST call records
    (eval_gemfile / require_relative), never regex scanning; branch tables
    inside if/elsif still yield every call node they contain.
  • Kept variants join the scan, so chains survive whole:
    loader -> r3/libs.gemfile -> ../../erb/r3/v5.0.gemfile.
  • Unreferenced variants are still pruned exactly as before (existing specs
    cover this and stay green).

How I tested

  • New spec: spec/integration/x_std_libs_sweep_reference_guard_spec.rb
    • loader referencing a variant file → sweep keeps the file (direct
      inactive_packaged_template_cleanup_files call and full plan_project
      recipe reports: no delete_file metadata for referenced variants);
    • loader rewritten to stop referencing → deletion allowed for the now
      unreferenced variants.
  • Probe against kettle-jem's own committed tree with a Ruby 4.0 test floor:
    sweep now emits 0 gemfile deletions; every loader target survives.
  • Full suite via mise exec -C gems/kettle-jem -- bundle exec kettle-test:
    757 examples, 0 failures.

Fixes #84

The inactive-packaged-template sweep pruned every x_std_libs bucket the
destination's minimum test Ruby made irrelevant, ignoring that the committed
version-split loader (gemfiles/modular/x_std_libs.gemfile) branches on
RUBY_VERSION and eval_gemfile's each bucket variant. The 7.1.41 family-wide
sweep deleted the r2/r3/r3.1 libs.gemfile variants plus the std-lib gem
variants they load, and CI's Ruby 3.3 probe hit Errno::ENOENT evaluating a
deleted file.

Deletion now only proceeds when no loader that itself survives the sweep
references the variant. The guard iterates an AST-collected (Prism) reference
closure over eval_gemfile / require_relative targets of the remaining
gemfiles (kept variants join the scan, so chains like loader ->
r3/libs.gemfile -> ../../erb/r3/v5.0.gemfile survive whole). Unreferenced
variants are still pruned as before.

Fixes #84
Copilot AI balanced review requested due to automatic review settings October 31, 2026 01:53

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@pboling
pboling merged commit c2f6e5a into main Oct 31, 2026
5 of 6 checks passed
@pboling
pboling deleted the bug/84-sweep-variant-deletion-guard branch October 31, 2026 01:55
pboling added a commit that referenced this pull request Oct 31, 2026
…cation (#87)

The StructuredMerge dev benchmark job resolves member dependencies
registry-only via the setup-ruby-flash appraisal root bundle install of
gems/ast-merge-git/Appraisal.root.gemfile. During pre-publication release
runs (which by design happen before the cohort publishes), members' path
gemspecs already exact-pin the unpublished lockstep version, so the root
baseline dies with a deterministic Bundler conflict:

  Because every version of ast-merge-git depends on tree_haver = 7.1.18
  and tree_haver = 7.1.18 could not be found in rubygems repository

(observed runs 40998206316 and 41152029638; PR #86 check red).

Why not the release_mode gate: the benchmark job already carries
`if: needs.detect.outputs.release_mode == ''` (since 2b667d4), and both
observed failures occur with release_mode == '' — they are release-prep
pushes to main ("Bump gem version" / "Checksums" / "Update bundle" /
unmarked "Prepare release") that carry no [kettle-family:aggregate-*]
marker, plus PRs branched from that state. A marker-based gate cannot
cover them, so the smallest correct fix makes the baseline resolvable
instead (issue #85 expected behavior).

Fix: when STRUCTUREDMERGE_DEV points at the workspace gem directories,
wire the lockstep siblings (ast-merge, tree_haver) from local paths in
the appraisal root baseline, mirroring the proven lockstep wiring in
.github/typed_core.gemfile. The benchmark job already exports
STRUCTUREDMERGE_DEV and K_JEM_TEMPLATING to the setup step, so no
workflow change is needed. Registry-only resolution (toggle unset)
remains the default.

Verified locally against the current release-prep state (7.1.18 pinned,
registry at 7.1.17):
- toggle unset: `bundle lock` reproduces the exact CI conflict
- toggle set: root baseline and the benchmark-dev appraisal lane both
  resolve, with tree_haver/ast-merge satisfied from workspace paths

Fixes #85
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.

Template sweep deletes loader-referenced per-Ruby-version Gemfile variants

2 participants