Skip to content

Fix replace-all matching with reused full-file indexes - #737

Open
morluto wants to merge 9 commits into
repoprompt:mainfrom
morluto:agent/replace-all-index-reuse
Open

Fix replace-all matching with reused full-file indexes#737
morluto wants to merge 9 commits into
repoprompt:mainfrom
morluto:agent/replace-all-index-reuse

Conversation

@morluto

@morluto morluto commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Replace-all now searches one processed full-file representation with an advancing absolute lower bound.

This fixes later matches being skipped when DiffBatchGenerator supplies a full-file index and removes repeated suffix normalization and index construction.

Change

  • Reuse the batch generator's processed lines and full-file index.
  • Build processed lines and the index once when callers do not supply them.
  • Filter matcher candidates using an absolute minimum match index.
  • Preserve ambiguity, indentation, ordering, and original-file chunk coordinates.

Regression coverage

Tests cover a nonzero searchStartLine with a non-nil full-file index, the complete batch diff fallback route with separated matches, and a deterministic fuzzy-probe case with more than 400 distinct keys before minimumMatchIndex. The latter verifies that an eligible fuzzy-only match after the boundary is still found.

For a synthetic 5,000-line/20-match case, source-level operation counting changes normalization from 60,460 processLine calls to 5,000 and index construction from 21 suffix indexes to one full-file index.

Validation

  • Exact branch diff and git diff --check passed.
  • Staged whitespace and secret scans passed.
  • Branch autoreview is clean.
  • Swift/macOS checks are pending on the new head's CI.

Fixes #729

@morluto
morluto marked this pull request as ready for review August 5, 2026 10:08

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 42757299c5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/RepoPromptDomainRuntime/Diffing/DiffGenerationUtility.swift Outdated

@baron baron left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed exact head 4275729 on the current-main synthetic merge, with a curated Fable 5 High second opinion.

The absolute line-coordinate conversion and search advancement are consistent, and downstream exact matching protects the strict-to-loose fallback. No blocking finding.

The only hosted failure is the unrelated CodeMapRootManifestStore atomic-snapshot concurrency test; please rerun to exact-head green before merge.

@baron baron left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-reviewed exact head 9f44d5018326e857f87ff2bcbaa9874a29a30e33 on the current-main synthetic merge 19d222f7d20eee3e9c0f1068bb3e02ca1a9ae643 (base cc9ff8f5901c2d511eef2e52d45cb21df780bace).

The implementation change correctly filters positions before minimumMatchIndex before consuming the fuzzy-probe budget in both the first- and second-line paths. Global coordinates, replace-all advancement, and cumulative offsets also look consistent. The focused DiffGenerationUtilityRoutingTests suite passed (3 tests, 0 failures), and hosted CI is green.

One blocker remains: please add a deterministic regression test for the corrected fuzzy-budget failure. The current tests use exact normalized keys and do not enter the fuzzy path; they also pass on the known-bad prior head 42757299. A focused test should place more than the probe budget of distinct keys only before minimumMatchIndex, then verify an eligible fuzzy-only match after the boundary is still found. This directly guards the false-negative fixed by the latest commit.

@baron baron left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-reviewed exact head e7d7b41960e7bed0d26759c17b89e5c40b72b53d on current-main synthetic merge f70e65bc10593bb34d6f99931db2a0f1b1c4366d. The production fuzzy-budget fix still looks correct, and the new test is aimed at the exact requested regression.

The new test does not compile: DiffGenerationUtilityRoutingTests.swift:45 accesses removedTagsHigh, which is internal to another module and inaccessible from this test target. This makes swift test list fail across all app shards and the Sentry build. Style also fails at line 48 for numeric-literal grouping (1_024).

Please construct the index keys through an API visible to this test target (or place the regression test in the owning module), run the formatter, and get exact-head CI green. I did not find a new blocker in the production change itself.

morluto commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

@baron Addressed in d1fb5c0b: the regression now constructs keys through DiffGenerationUtility.buildLineIndexMapHigh instead of accessing LineData.removedTagsHigh across the module boundary, while retaining the 401 pre-boundary-key setup and fuzzy-only post-boundary match. Also corrected the 1024 literal style issue. Exact-head hosted CI is queued.

@baron baron left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-reviewed exact head 20bd84fa4de5f736a91ca15bbd8fb818c720e100 on the current-main synthetic merge (base 6f31d61ccb83dd9bd3d84421f352e4e04bb819b6).

The prior blocker remains. The revised test now builds the final index through buildLineIndexMapHigh, but lines 51-52 still directly access candidateLine.removedTagsHigh, which is internal to RepoPromptDomainRuntime. The exact-head Sentry build fails with: DiffGenerationUtilityRoutingTests.swift:51:42: error: removedTagsHigh is inaccessible due to internal protection level.

Please avoid reading LineData.removedTagsHigh from this test target entirely (or move the regression to the owning module), then obtain exact-head green CI. The production fuzzy-budget fix itself still looks correct.

Replace inaccessible removedTagsHigh reads with keys derived from
buildLineIndexMapHigh, as requested by review.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@morluto

morluto commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

@baron Follow-up: the test-only compile blocker is corrected on the current head fdb128f. The regression now derives candidate index keys through DiffGenerationUtility.buildLineIndexMapHigh and no longer reads LineData.removedTagsHigh from the test target. Exact-head CI is running: https://github.com/repoprompt/repoprompt-ce/actions/runs/31211681728

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fdb128f711

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +57 to +61
let orderedKeys = Array(candidateIndex.keys)
let positions = candidateKeys.compactMap { key in
orderedKeys.firstIndex(of: key)
}
return !positions.isEmpty && positions.allSatisfy { $0 >= 400 }

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 Badge Make the fuzzy-probe boundary test deterministic

With Swift's randomized per-dictionary iteration order, this checks the candidate's position in a copied candidateIndex, but the matcher later receives a freshly rebuilt lineIndex whose key order can differ. Consequently XCTUnwrap can find no qualifying alias for some hash seeds, and when it does, the candidate may move inside the first 400 entries in the actual index, allowing the pre-fix implementation to pass. Construct and pass the same index whose ordering was inspected, or avoid depending on dictionary enumeration order.

Useful? React with 👍 / 👎.

@morluto

morluto commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

one moment, lookign at this

morluto and others added 2 commits August 8, 2026 04:00
The fuzzy boundary test rebuilt the line index via buildLineIndexMapHigh
after selecting a candidate, which produced a different key ordering than
the index map inspected during selection. Pass the same candidateIndex
into matchSelectorFast so the probe sees the ordering the test validated,
removing the randomized-order mismatch. Apply numeric grouping and
multiline formatting for CI conformance.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@morluto

morluto commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator Author

@baron The test-target visibility issue is resolved on the PR head: it derives the fuzzy probe keys via DiffGenerationUtility.buildLineIndexMapHigh and no longer accesses LineData.removedTagsHigh.

The remaining failed CI run was unrelated to this PR: its synthetic merge picked up a broken transcript signature-cleanup change from main (references to removed globals). That fix is now on main; I merged current main into this branch as b7583426 without rewriting history. The resulting merge tree passes make dev-swift-build PRODUCT=RepoPrompt locally, and exact-head CI is now running: https://github.com/repoprompt/repoprompt-ce/actions/runs/31256215647

@baron

baron commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Re-reviewed exact head b75834268710ed3a910eff10680cd236aaf31e78. The earlier functional and compile findings are addressed: ineligible earlier positions are filtered before consuming the fuzzy budget, and the regression no longer reaches into an inaccessible helper. I found no remaining source blocker. Please rerun/fix the red Style check and refresh current-base CI before integration.

@baron baron left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved on exact head 51f81de255f065d1e3e0da95325272f7aa240662. The prior deterministic regression is addressed by filtering candidates below minimumMatchIndex before charging the fuzzy-probe budget, and the test builds the inspected index through the production API with the valid candidate beyond the 400-key boundary. The two red hosted checks are outside this three-file diff, so they do not justify retaining a stale code-review rejection; they must still be rerun successfully before merge.

morluto commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

Audit disposition — merge candidate after exact-head validation (2026-08-14)

Reusing one processed full-file representation and index while advancing an absolute minimum match position addresses both the skipped-later-match bug and repeated normalization/index construction. The reviewed strict, loose, and fuzzy candidate paths consistently apply the lower bound, and the focused tests cover the important nonzero-start and probe-budget cases.

Please require exact-head CI, the stated large-file benchmark, and an ambiguity/overlapping-match regression on the final head. I did not find a code-level blocker.

morluto commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

Deep-review assessment — 2026-08-14

Disposition: merge candidate after final matcher/property coverage. Reusing one processed full-file representation and index, then advancing an absolute minimumMatchIndex, fixes the coordinate mismatch and removes repeated suffix normalization/index construction. The lower bound is carried into strict/loose/fuzzy candidate discovery, which is the important correctness point.

I did not find a blocker. Please complete exact-head Swift/macOS CI and include regressions for overlapping matches, replacement blocks that change line counts, selectors at the final boundary, fuzzy-only candidates, ambiguity behavior, and guaranteed forward progress/no infinite loop. With those gates, this is a focused correctness and performance fix.

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.

Replace-all misses later matches when batch diffing reuses a full-file line index

2 participants