feat(migrate): --auto-apply mode for mechanically-rewritable codemod findings#540
Merged
Conversation
bokelley
added a commit
that referenced
this pull request
May 4, 2026
…auto-apply Per review on #540 — a generated_poc import mixing a known numbered asset (Assets81) with an unknown one (Assets149) was getting half-rewritten: Input : from adcp.types.generated_poc.core.format import Assets81, Assets149 Output: from adcp.types.generated_poc.core.format import VideoFormatAsset, Assets149 leaving VideoFormatAsset imported from a private module path that doesn't export it — guaranteed ImportError in adopter source. Root cause: step 1 (file-wide Assets<N> substitution) ran before step 2 (import-path safety check) had a chance to veto the line. Fix: line-by-line rewrite. For each generated_poc single-line import, compute the post-numbered-substitution symbol set up-front; only run both substitutions when every symbol on the line is in ``_AUTO_APPLY_PUBLIC_SYMBOLS``. Mixed-unsafe lines are left entirely alone. Non-import lines still get free numbered substitution. Scan-time also fixed: numbered references on a mixed-unsafe import line now report ``flag_numbered`` instead of ``auto_applied`` so the report matches the file content. Adds regression test ``test_auto_apply_mixed_numbered_known_unknown_does_not_corrupt_import``. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
392db89 to
17df4b9
Compare
bokelley
added a commit
that referenced
this pull request
May 4, 2026
…to-apply Per review on #540 — a generated_poc import mixing a known numbered asset (Assets81) with an unknown one (Assets149) was getting half-rewritten: Input : from adcp.types.generated_poc.core.format import Assets81, Assets149 Output: from adcp.types.generated_poc.core.format import VideoFormatAsset, Assets149 leaving VideoFormatAsset imported from a private module path that doesn't export it — guaranteed ImportError in adopter source. Root cause: step 1 (file-wide Assets<N> substitution) ran before step 2 (import-path safety check) had a chance to veto the line. Fix: line-by-line rewrite. For each generated_poc single-line import, compute the post-numbered-substitution symbol set up-front; only run both substitutions when every symbol on the line is in ``_AUTO_APPLY_PUBLIC_SYMBOLS``. Mixed-unsafe lines are left entirely alone. Non-import lines still get free numbered substitution. Scan-time also fixed: numbered references on a mixed-unsafe import line now report ``flag_numbered`` instead of ``auto_applied`` so the report matches the file content. Adds regression test ``test_auto_apply_mixed_numbered_known_unknown_does_not_corrupt_import``. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…findings Extends `python -m adcp.migrate v3-to-v4` with `--auto-apply`: rewrites the ~78% of findings that are mechanically safe (flag_private + flag_numbered with known aliases) while leaving flag_removed findings for human review. - Add NUMBERED_ASSETS_RENAMES dict mapping Assets<N> to semantic aliases - Add _AUTO_APPLY_PUBLIC_SYMBOLS frozenset for safe-rewrite eligibility - Add auto_applied field to Report; route kind==auto_applied there - Two-pass rewrite: (1) numbered asset substitution, (2) generated_poc import path fix for lines where all symbols have public equivalents - Fix pre-existing silent-drop bug: unknown symbols on mixed import lines were silently discarded; now always emit flag_private - --auto-apply implies --apply; enforced before dirty-tree guard - JSON report gains auto_applied array (additive, no version bump) - 16 new tests (total 49, all pass) Closes #512 https://claude.ai/code/session_01MiPRbdJUEFBes5zzUGd5Vb
- Text report hints at --auto-apply when flag_private/flag_numbered findings remain and the flag was not used (discoverability) - --apply help text cross-links --auto-apply - Dirty-tree error shows --auto-apply when that flag was used - Exit code semantics (0/1/2) documented in argparse description - MIGRATION_v3_to_v4.md: add --auto-apply example + description - 2 new tests for tip-line presence/absence (51 total, all pass) https://claude.ai/code/session_01MiPRbdJUEFBes5zzUGd5Vb
Two bugs found in pre-PR review: 1. apply_changes=False guard missing on auto-apply rewrite block. run(apply_changes=False, auto_apply=True) was silently writing files because the auto_apply block only checked `auto_apply and auto_apply_hits` with no apply_changes guard. Fixed by requiring apply_changes too. 2. all_known check excluded numbered-asset symbols on mixed lines. A line like `from ...generated_poc import Assets81, ContextObject` got all_known=False (Assets81 not in GENERATED_POC_SYMBOL_MAP), so ContextObject was flagged even though both symbols are auto-applicable. Fixed: all_known now treats numbered assets as resolvable when auto_apply=True. New tests: - test_dry_run_with_auto_apply_does_not_write_files (regression guard) - test_auto_apply_numbered_plus_known_symbol_same_line (mismatch case) 53 tests total, all pass. https://claude.ai/code/session_01MiPRbdJUEFBes5zzUGd5Vb
…auto_apply contract - Remove misplaced "Pre-existing silent-drop bug fix" section header that sat above the discoverability tests; reattach it immediately before test_mixed_line_unknown_symbol_not_silently_dropped - scan_file docstring now documents that auto_apply=True without apply_changes=True produces findings but never writes files https://claude.ai/code/session_01MiPRbdJUEFBes5zzUGd5Vb
…to-apply Per review on #540 — a generated_poc import mixing a known numbered asset (Assets81) with an unknown one (Assets149) was getting half-rewritten: Input : from adcp.types.generated_poc.core.format import Assets81, Assets149 Output: from adcp.types.generated_poc.core.format import VideoFormatAsset, Assets149 leaving VideoFormatAsset imported from a private module path that doesn't export it — guaranteed ImportError in adopter source. Root cause: step 1 (file-wide Assets<N> substitution) ran before step 2 (import-path safety check) had a chance to veto the line. Fix: line-by-line rewrite. For each generated_poc single-line import, compute the post-numbered-substitution symbol set up-front; only run both substitutions when every symbol on the line is in ``_AUTO_APPLY_PUBLIC_SYMBOLS``. Mixed-unsafe lines are left entirely alone. Non-import lines still get free numbered substitution. Scan-time also fixed: numbered references on a mixed-unsafe import line now report ``flag_numbered`` instead of ``auto_applied`` so the report matches the file content. Adds regression test ``test_auto_apply_mixed_numbered_known_unknown_does_not_corrupt_import``. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
17df4b9 to
ce10f70
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #512
Summary
python -m adcp.migrate v3-to-v4with--auto-apply: rewrites the ~78% of findings that are mechanically safe while leavingflag_removedfindings for human review.flag_private—from adcp.types.generated_poc.X import Symbollines are rewritten tofrom adcp.types import Symbolwhen every symbol on the line has a verified public alias inGENERATED_POC_SYMBOL_MAP. Mixed lines (any unknown symbol) remain flagged.flag_numbered—Assets<N>symbols with entries in the newNUMBERED_ASSETS_RENAMEStable (Assets81–Assets106) are substituted with their semantic aliases (VideoFormatAsset, etc.). Unknown numbered assets remain flagged.generated_pocimport-path fix where all post-rename symbols are in_AUTO_APPLY_PUBLIC_SYMBOLS.--auto-applyimplies--apply; enforced before the dirty-tree guard.auto_appliedarray (additive, no version bump).--applyusers.MIGRATION_v3_to_v4.mdupdated with--auto-applyexample and description.generated_pocimport lines were silently dropped from the report; they now always produce aflag_privatefinding.What was tested
pytest tests/test_migrate_v3_to_v4.py)ruff check src/adcp/migrate/ tests/test_migrate_v3_to_v4.py— cleanmypy src/adcp/migrate/— zero errors in migrate/ filesKey test coverage:
test_dry_run_with_auto_apply_does_not_write_files—apply_changes=False, auto_apply=Truemust not writetest_auto_apply_numbered_plus_known_symbol_same_line— mixed numbered + known symbol line is fully auto-appliedtest_auto_apply_mixed_line_not_rewritten— unknown symbol prevents rewrite of that linetest_auto_apply_idempotent— second pass is a no-optest_auto_apply_exits_nonzero_when_flag_removed_remain— CI gate is preservedPre-PR expert review
DX expert — LGTM with fixes applied:
--auto-applywhenflag_private/flag_numberedfindings remain--applyhelp cross-links--auto-apply--auto-applywhen that flag was usedMIGRATION_v3_to_v4.mdupdatedCode reviewer — found 2 bugs, both fixed:
apply_changes=False, auto_apply=Truewas silently writing files — guarded withapply_changes and auto_apply and auto_apply_hitsall_knowncheck excluded numbered-asset symbols on mixed lines (Assets81, ContextObject) — fixed to treatNUMBERED_ASSETS_RENAMESkeys as resolvable whenauto_apply=Truehttps://claude.ai/code/session_01MiPRbdJUEFBes5zzUGd5Vb
Generated by Claude Code