Context
With 111 open PRs (100 from toddr-bot, 11 community), we need a merge strategy that maximizes value while minimizing rebase churn. This issue provides a recommended merge order based on file-level conflict analysis and CI status.
Methodology: Each PR was scored by how many other open PRs touch the same non-test source files. Lower score = fewer conflicts after merging. CI status was verified for all PRs.
See also: #440 (duplicate PR triage)
Phase 1: Zero-Conflict, Test-Only PRs (merge immediately)
These PRs touch only test files or auxiliary files. Zero source-file conflicts with any other PR. All CI-passing.
| PR |
Title |
Conflicts |
CI |
| #365 |
regression tests for CHECK bareword handle (GH #246) |
0 |
✅ |
| #398 |
regression tests for issue #133 (wordlike operator after method call) |
0 |
✅ |
| #427 |
regression tests for ternary label false positives |
0 |
✅ |
| #355 |
exclude Ham-DXCC-Lookup from dependent modules test |
1 |
✅ |
| #356 |
exclude Dist-Zilla-Plugin-Subversion from dependents testing |
1 |
✅ |
Value: 5 merges with zero rebase risk to any other PR.
Phase 2: Duplicate Resolution (close losers per #440)
Before merging anything else, close the weaker half of each duplicate cluster. Recommended winners:
| Keep |
Close |
Cluster |
Rationale |
| #391 |
#390 |
PPI::Exception caller tracking |
#391 has comprehensive tests; #390 is a subset |
| #363 |
#333 |
UTF-8 decode on use utf8 |
Identical fix; #333 is CI-failing anyway |
| #393 |
#362, #386 |
Minimum Perl version / IO::String |
#393 (5.008001 Lancaster) supersedes #362 (5.008); #386 is a subset |
| #414 |
#399, #376 |
Element->namespace / Package block |
#414 is the most complete implementation |
| #404 |
#353 |
DESTROY cleanup |
#404 is more targeted; #353 touches more files (14 conflicts) |
| #388 |
#307 |
Whitespace between sigil and identifier |
#388 is bot-generated against current master, cleaner diff |
| #438 or #434 |
the other |
Encoding for Document->new |
Human decision needed — #438 (simpler API, CI-failing) vs #434 (richer API, CI-passing). Recommend #434 |
Closing 9+ PRs reduces the open count and eliminates future conflict sources.
Phase 3: Low-Conflict Bug Fixes (1-5 conflict score, CI-passing)
Merge in this order (ascending conflict score):
| Order |
PR |
Title |
Score |
Files |
| 1 |
#377 |
__DATA__ no longer causes incomplete documents |
2 |
4 |
| 2 |
#359 |
verify BEGIN/UNITCHECK/CHECK/INIT/END behaviour |
3 |
5 |
| 3 |
#391 |
PPI::Exception unit tests + fix throw() caller tracking |
3 |
2 |
| 4 |
#429 |
minus operator no longer splits namespaced words |
3 |
2 |
| 5 |
#368 |
document 'continue' type in Statement::Compound |
4 |
2 |
| 6 |
#375 |
close double diamond (<<>>) operator |
4 |
3 |
| 7 |
#401 |
parse qw with comment before first delimiter |
4 |
2 |
| 8 |
#383 |
recognize %/ as magic variable |
5 |
5 |
| 9 |
#404 |
stop Node::DESTROY from corrupting still-referenced children |
5 |
2 |
| 10 |
#418 |
allow passing a string reference to PPI::Dumper->new |
5 |
2 |
| 11 |
#421 |
declare Perl::Critic < 1.122 as incompatible via x_breaks |
5 |
2 |
| 12 |
#385 |
normalize file permissions to prevent executable metadata files |
5 |
2 |
Value: 12 targeted fixes with minimal rebase ripple.
Phase 4: Medium-Conflict Bug Fixes (5-15 conflict score, CI-passing)
These touch core files but are focused enough to merge cleanly in sequence.
4A: Tokenizer operator/parsing fixes (group — share Tokenizer.pm and Whitespace.pm)
| Order |
PR |
Title |
Score |
| 1 |
#387 |
dot after value-producing token is concat, not float |
7 |
| 2 |
#378 |
treat << as bit shift after numeric tokens |
7 |
| 3 |
#380 |
track repeated regex modifiers like s///ee |
7 |
| 4 |
#339 |
treat // as regexp match after Perl builtins |
15 |
| 5 |
#426 |
recognize regex after map/grep block (RT #75921) |
15 |
| 6 |
#431 |
minus after ) and ] parsed as negative number |
20 |
| 7 |
#433 |
parse hashref after any operator as Constructor (GH #34) |
21 |
| 8 |
#366 |
scan for fat comma in list-embedded curlies (GH #236) |
21 |
4B: Symbol/Magic variable fixes
| Order |
PR |
Title |
Score |
| 1 |
#384 |
treat @_{} and $_{} as Symbol, not Magic |
9 |
| 2 |
#389 |
stop treating `$:: |
` as a magic variable |
| 3 |
#408 |
remove code duplication in Token::Magic |
9 |
| 4 |
#428 |
parse $$$a as chained dereferences |
10 |
4C: Statement/Structure fixes
| Order |
PR |
Title |
Score |
| 1 |
#407 |
implement module_first_arg for Statement::Include |
7 |
| 2 |
#370 |
detect Statement::Variable in open() without parens |
21 |
| 3 |
#435 |
stop Statement::Variable from consuming sibling args in list context |
21 |
| 4 |
#436 |
remove dead guards for Structure without start brace |
10 |
| 5 |
#413 |
allow programmatic creation of PPI::Structure subclasses |
6 |
| 6 |
#430 |
remove inverted condition in Lexer::_add_element label detection |
21 |
4D: Feature tracking / Lexer scoping
| Order |
PR |
Title |
Score |
| 1 |
#335 |
handle whitespace tokens in feature argument decomposition |
7 |
| 2 |
#351 |
fix feature scoping leak when leaving blocks |
21 |
| 3 |
#361 |
recognize try feature from use experimental 'try' |
7 |
4E: Quote/QuoteLike API consistency
| Order |
PR |
Title |
Score |
| 1 |
#364 |
add get_delimiters() for qw, qx, q, qq |
10 |
| 2 |
#411 |
make methods on Quote subclasses consistent |
7 |
| 3 |
#406 |
add QuoteLike->string (like Quote has) |
10 |
4F: Misc standalone fixes
| PR |
Title |
Score |
| #332 |
add dotted bitwise operators to Operator.pm POD (CI-FAILING — needs fix) |
7 |
| #352 |
support isa infix operator from Perl 5.32 |
10 |
| #374 |
default $word parameter in __current_token_is_forced_word |
20 |
| #371 |
all_tokens() exception message nesting |
20 |
| #358 |
reject all non-string refs in scalar ref input |
20 |
| #394 |
remove unused PPI::Exception::ParserRejection |
20 |
| #425 |
handle NUL and vertical tab characters in source |
17 |
| #382 |
parse [subscript] after ${deref} as Subscript |
21 |
| #372 |
detect readline with variable filehandle after block |
15 |
Phase 5: Feature Additions (higher review burden)
These add new API surface or significant behavior changes. Merge after bugs are clear.
| PR |
Title |
Score |
Notes |
| #424 |
add Word classification methods from PPIx::Utils |
8 |
High value — internalizes PPIx::Utils methods |
| #336 |
add signature() method to Statement::Sub |
8 |
Clean API addition |
| #409 |
parse string interpolations via interpolated_fragments() |
10 |
Large (494 additions), new API |
| #417 |
parse anonymous subs as PPI::Statement::Sub |
22 |
Significant Lexer change |
| #346 |
support Corinna keywords (class, method, field, ADJUST) |
29 |
Large, touches Lexer + Token::Word |
| #352 |
support isa infix operator from Perl 5.32 |
10 |
New operator type |
| #432 |
parse ellipsis ... as PPI::Token::Ellipsis |
35 |
New token class, 9 files |
| #412 |
implement perl -x emulation via perl_x option |
52 |
7 files, new Document option |
| #434 |
encoding-aware constructor APIs |
17 |
Depends on duplicate resolution with #438 |
| #396 |
implement PPI::Document::Strict |
13 |
New subclass |
Phase 6: Documentation PRs
Low risk but touch overlapping doc areas. Merge after code PRs stabilize.
| PR |
Title |
Score |
| #400 |
document why PPI accepts incomplete documents |
13 |
| #397 |
document best-effort parsing of broken code |
17 |
| #367 |
clarify insert_before/insert_after docs for single element |
13 |
| #419 |
cross-link insert method rules and clarify PDOM explanation |
26 |
| #379 |
document filename param for PPI::Document->new |
17 |
Phase 7: Defer or Needs Discussion
Competing designs (pick one per cluster)
CI-Failing (need fixes before merge)
| PR |
Title |
Issue |
| #332 |
dotted bitwise operators POD |
CI fail |
| #333 |
UTF-8 decode (duplicate of #363) |
CI fail — just close |
| #348 |
reparse section metadata after set_content |
CI fail |
| #402 |
parse qw with backslash delimiters |
CI fail |
| #403 |
add modifier_type() and modifier() |
CI fail |
| #405 |
whitespace-only line token concatenation |
CI fail |
| #420 |
auto-invalidate location cache after mutations |
CI fail |
| #438 |
add encoding parameter to Document->new |
CI fail |
Community PRs (old, no CI, need fresh evaluation)
| PR |
Title |
Author |
Recommendation |
| #49 |
cmp_document branch |
moregan |
Close — subsumed by #146 |
| #79 |
Fix insert_{after,before} |
hartzell |
Evaluate against #392 |
| #146 |
Cmp document functions |
moregan |
Large (71 conflicts), evaluate independently |
| #151 |
Allow statements in insert operations |
karenetheridge |
Large (56 conflicts), evaluate against #392 |
| #172 |
Cache directory permissions |
zhurs |
Small fix buried in large diff (71 conflicts) |
| #182 |
actual filename attribute |
van-de-bugger |
Conflicts with #379 |
| #186 |
byte offsets for Tokens |
ksurent |
Conflicts with #415 (character offsets) |
| #190 |
multi-line subroutine attribute params |
edenhochbaum |
Needs rebase (31 conflicts) |
| #250 |
parse format as single token |
? |
20 conflicts, old |
| #306 |
tidy everything |
wchristian |
101 conflicts — do NOT merge until all else is done |
| #307 |
variables with spaces after sigil |
wchristian |
Duplicate of #388 — close |
| #357 |
factor out feature set stack |
mauke |
21 conflicts, related to #351 |
Cross-cutting mega-PRs (merge LAST if at all)
| PR |
Title |
Score |
Files Changed |
| #395 |
add use warnings to all library modules |
102 |
98 |
| #338 |
use dzil Pod::Weaver for POD |
101 |
92 |
| #306 |
tidy everything |
101 |
large |
These three PRs conflict with virtually every other PR. Merge them dead last, after all targeted PRs are in. Even then, they'll need complete rebases. Consider if #395 (use warnings) can be done incrementally per-module instead.
Summary: Recommended Merge Sequence
1. Close 9+ duplicates (Phase 2) → reduces PR count to ~100
2. Merge 5 zero-conflict test-only PRs (Phase 1) → 5 merges, 0 rebases needed
3. Merge 12 low-conflict bug fixes (Phase 3) → 12 merges, minimal rebases
4. Merge medium-conflict fixes by group (Phase 4) → ~30 merges, group-wise rebases
5. Merge features after design review (Phase 5) → ~10 merges
6. Merge docs (Phase 6) → ~5 merges
7. Evaluate community PRs (Phase 7) → close or rebase as needed
8. Cross-cutting changes last (Phase 7) → #395, #338, #306
Estimated merge-to-rebase ratio: By following this order, roughly 50 PRs can merge before any significant rebase is required. The remaining PRs will each need at most 1 rebase, not cascading rebases.
🤖 Generated by Kōan from merge order analysis session
Context
With 111 open PRs (100 from toddr-bot, 11 community), we need a merge strategy that maximizes value while minimizing rebase churn. This issue provides a recommended merge order based on file-level conflict analysis and CI status.
Methodology: Each PR was scored by how many other open PRs touch the same non-test source files. Lower score = fewer conflicts after merging. CI status was verified for all PRs.
See also: #440 (duplicate PR triage)
Phase 1: Zero-Conflict, Test-Only PRs (merge immediately)
These PRs touch only test files or auxiliary files. Zero source-file conflicts with any other PR. All CI-passing.
Value: 5 merges with zero rebase risk to any other PR.
Phase 2: Duplicate Resolution (close losers per #440)
Before merging anything else, close the weaker half of each duplicate cluster. Recommended winners:
use utf8Closing 9+ PRs reduces the open count and eliminates future conflict sources.
Phase 3: Low-Conflict Bug Fixes (1-5 conflict score, CI-passing)
Merge in this order (ascending conflict score):
__DATA__no longer causes incomplete documents<<>>) operator%/as magic variableValue: 12 targeted fixes with minimal rebase ripple.
Phase 4: Medium-Conflict Bug Fixes (5-15 conflict score, CI-passing)
These touch core files but are focused enough to merge cleanly in sequence.
4A: Tokenizer operator/parsing fixes (group — share
Tokenizer.pmandWhitespace.pm)<<as bit shift after numeric tokenss///ee//as regexp match after Perl builtins)and]parsed as negative number4B: Symbol/Magic variable fixes
@_{}and$_{}as Symbol, not Magic$$$aas chained dereferences4C: Statement/Structure fixes
module_first_argfor Statement::Includeopen()without parens4D: Feature tracking / Lexer scoping
tryfeature fromuse experimental 'try'4E: Quote/QuoteLike API consistency
get_delimiters()for qw, qx, q, qq4F: Misc standalone fixes
isainfix operator from Perl 5.32$wordparameter in__current_token_is_forced_wordall_tokens()exception message nesting[subscript]after${deref}as SubscriptPhase 5: Feature Additions (higher review burden)
These add new API surface or significant behavior changes. Merge after bugs are clear.
signature()method to Statement::Subinterpolated_fragments()isainfix operator from Perl 5.32...as PPI::Token::Ellipsisperl -xemulation viaperl_xoptionPhase 6: Documentation PRs
Low risk but touch overlapping doc areas. Merge after code PRs stabilize.
Phase 7: Defer or Needs Discussion
Competing designs (pick one per cluster)
CI-Failing (need fixes before merge)
Community PRs (old, no CI, need fresh evaluation)
Cross-cutting mega-PRs (merge LAST if at all)
use warningsto all library modulesThese three PRs conflict with virtually every other PR. Merge them dead last, after all targeted PRs are in. Even then, they'll need complete rebases. Consider if #395 (use warnings) can be done incrementally per-module instead.
Summary: Recommended Merge Sequence
Estimated merge-to-rebase ratio: By following this order, roughly 50 PRs can merge before any significant rebase is required. The remaining PRs will each need at most 1 rebase, not cascading rebases.
🤖 Generated by Kōan from merge order analysis session