Skip to content

fix: count WHOLE_FILE assignments with empty hunk_indices everywhere - #58

Open
vitali87 wants to merge 3 commits into
mainfrom
fix/whole-file-loc-accounting
Open

fix: count WHOLE_FILE assignments with empty hunk_indices everywhere#58
vitali87 wants to merge 3 commits into
mainfrom
fix/whole-file-loc-accounting

Conversation

@vitali87

Copy link
Copy Markdown
Owner

Summary

Commit 1984630 taught validate_coverage and merge_chain_assignments to treat a WHOLE_FILE assignment with an empty hunk_indices list as full coverage, but three other consumers still iterated only hunk_indices:

  • recompute_estimated_loc → such a group got estimated_loc = 0, so the plan passed coverage and then failed validate_loc with Total LOC 0 does not match diff LOC N
  • assign_uncovered_hunks → the file's hunks were seen as unassigned and re-added as PARTIAL_HUNKS
  • validate_no_conflicts → overlaps with a whole-file assignment were invisible

The expansion now lives in one place, GroupAssignment.covered_indices(hunk_count), and all three use it (validate_no_conflicts gains an optional hunk_counts argument, passed from validate_plan).

Also: assign_uncovered_hunks raised a bare ValueError from max([]) when the LLM returned zero groups in chunked mode; it now raises PlanValidationError(COVERAGE_GAP).

Test plan

  • New tests: whole-file LOC recompute, whole-file counts as covered, zero groups raises, whole-file vs partial conflict detected
  • uv run ruff check / ruff format --check clean
  • uv run pytest -q — 448 passed

@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 26 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8fc0520a-858a-49bd-9b70-9370fa926ceb

📥 Commits

Reviewing files that changed from the base of the PR and between e4cc532 and b4f50a3.

📒 Files selected for processing (8)
  • pr_split/diff_ops/reconstructor.py
  • pr_split/planner/chunker.py
  • pr_split/planner/validator.py
  • pr_split/schemas.py
  • tests/test_chunker.py
  • tests/test_reconstructor.py
  • tests/test_schemas.py
  • tests/test_validator.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Aug 30, 2026

Copy link
Copy Markdown

Greptile Summary

This change centralizes whole-file hunk expansion for planning and validation. A reproduced case shows that a WHOLE_FILE assignment can retain an invalid stored hunk index, causing conflict validation to reject a plan whose assignments do not overlap on any parsed hunk. Update the whole-file expansion before merging.

Confidence Score: 4/5

Not safe to merge until WHOLE_FILE coverage excludes nonexistent hunk indices.

A focused executable reproducer exercised the full validation path on a one-hunk diff, observed the false overlap error, and confirmed that limiting whole-file coverage to parsed indices allows the same plan to pass.

Files Needing Attention: pr_split/schemas.py needs the coverage calculation corrected; tests should cover validation with an out-of-range stored hunk index.

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex posted a P1 finding and attached a narrow Python reproducer for the invalid WHOLE_FILE index conflict.
  • T-Rex captured the current validator output showing a false conflict from index 99.
  • T-Rex captured a corrected WHOLE_FILE coverage output without the false conflict.
  • T-Rex captured the source of the executed invalid-index reproducer.
  • A general-contract-validation-proof shows the initial run reported whole covered indices [0, 99] and PlanValidationError, while the corrected run reports [0] and validate_plan passes.

View all artifacts

T-Rex Ran code and verified through T-Rex

Comments Outside Diff (1)

  1. General comment

    P1 WHOLE_FILE retains nonexistent hunk indices and creates a false conflict

    • Bug
      • For a file parsed with one hunk, a WHOLE_FILE assignment with hunk_indices=[99] expands to [0, 99]. An independent partial assignment with [99] then intersects it, so validate_plan rejects the plan even though neither assignment overlaps on a real parsed hunk.
    • Cause
      • GroupAssignment.covered_indices() unions range(hunk_count) with supplied indices for WHOLE_FILE assignments rather than treating WHOLE_FILE coverage as exactly the parsed file's valid indices.
    • Fix
      • At pr_split/schemas.py:22, return only the valid whole-file range, e.g. return list(range(hunk_count)), and add a regression test that verifies validate_plan permits a WHOLE_FILE assignment carrying an out-of-range index alongside a partial assignment of that same nonexistent index.

    T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "fix: count WHOLE_FILE assignments with e..." | Re-trigger Greptile

Comment thread pr_split/schemas.py Outdated
was left empty; PARTIAL_HUNKS covers exactly what it lists.
"""
if self.assignment_type is AssignmentType.WHOLE_FILE:
return sorted(set(range(hunk_count)) | set(self.hunk_indices))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 WHOLE_FILE retains phantom hunk indices

covered_indices() unions every stored hunk_indices value into a WHOLE_FILE assignment, including indices that do not exist in the parsed file. A separate partial assignment containing the same invalid index then intersects it during conflict validation, and the plan is rejected despite sharing no real hunk. Return only the parsed file's index range for WHOLE_FILE assignments.

Artifacts

Narrow Python reproducer for the invalid WHOLE_FILE index conflict

  • This executable source parses a one-hunk diff and invokes the full plan validator before and after substituting corrected WHOLE_FILE coverage semantics, with the takeaway that the scenario directly exercises the claimed path.

Current validator output with a false conflict from index 99

  • Executed with `uv run` from `/home/user/repo`, this capture shows current WHOLE_FILE coverage includes nonexistent index 99 and validation raises an overlap error, with the takeaway that the claim reproduces on the current code.

Corrected WHOLE_FILE coverage output without the false conflict

  • Executed with `uv run` from `/home/user/repo`, this comparison capture limits WHOLE_FILE coverage to parsed indices and validation passes, with the takeaway that ignoring stored invalid indices resolves the false conflict.

Captured source of the executed invalid-index reproducer

  • This command capture contains the exact narrow reproducer source used for both executions, with the takeaway that the proof is traceable to the supplied in-process validation scenario.

View artifacts

T-Rex Ran code and verified through T-Rex

@vitali87
vitali87 force-pushed the fix/whole-file-loc-accounting branch from d25f1f2 to deb147e Compare August 30, 2026 12:25

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile has paused reviews on this repository — it used its 100 free open-source review credits for this billing period. Reviews resume automatically on September 2. To continue before then, an organization admin can keep reviews running past the free credits — those bill as normal usage.

validate_coverage and merge_chain_assignments already treated a
WHOLE_FILE assignment with an empty hunk_indices list as covering every
hunk, but recompute_estimated_loc, assign_uncovered_hunks and
validate_no_conflicts still iterated only hunk_indices. Such a group got
estimated_loc=0 and the plan then failed validate_loc; the conflict
check was blind to it. Centralise the expansion in
GroupAssignment.covered_indices() and use it in all three. Also turn the
zero-groups case in assign_uncovered_hunks into a PlanValidationError
instead of a raw ValueError from max([]).
@vitali87

Copy link
Copy Markdown
Owner Author

Addressed the T-Rex P1 in e7d6223: covered_indices now returns exactly the parsed range for WHOLE_FILE (stale stored indices are ignored), and merge_chain_assignments expands ancestors through the same helper so a stale index can no longer reach materialisation either. Tests: schema-level ([99][0,1,2]), the same-file phantom-conflict scenario from the review, and a reconstructor case with carry_ancestor_files=True. Local review: 5/5.

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.

1 participant