Skip to content

refactor(conflict)!: key path overlap by file or by directory - #575

Merged
behinddwalls merged 1 commit into
mainfrom
preetam/conflict
Aug 12, 2026
Merged

refactor(conflict)!: key path overlap by file or by directory#575
behinddwalls merged 1 commit into
mainfrom
preetam/conflict

Conversation

@behinddwalls

@behinddwalls behinddwalls commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Why?

fileoverlap serialized two batches only when they changed the exact same file. That is the narrowest useful reading of target overlap, and for a queue whose directories are tightly coupled it is too narrow: two changes to sibling files in one package can break each other without either one touching the path the other did, and the analyzer will happily speculate them in parallel.

The right granularity is not a property of the analyzer. It follows from how tightly coupled a directory's contents are in the repository behind the queue, which is something only the integrator wiring that queue up can know. So it belongs at construction, next to the resolver, rather than baked into the package.

What?

Overlap is measured on a key projected from each changed path. PathKey is that projection, chosen at construction and applied to every path before the two batches' sets are intersected; Analyze is otherwise unchanged.

Two projections ship with the package. ByFile keys on the whole path and reproduces the previous behaviour. ByDirectory keys on the immediate parent, so batches touching sibling files conflict too — strictly coarser, since every file overlap is also a directory overlap. It buys protection against semantic conflicts between neighbouring files and pays for it in parallelism, which is the trade the integrator is choosing between.

Paths at the repository root key on . under ByDirectory, so a batch touching README.md conflicts with one touching go.mod. Root files are usually build configuration and usually do interact, so this is deliberate rather than incidental.

The package is renamed fileoverlappathoverlap, because the unit of overlap is now a path-derived key rather than a file. New takes the key as a third argument and panics on nil, mirroring heuristic.New. conflict.Analyzer, conflict.Config and ConflictTypeTargetOverlap are untouched — a folder is a coarser target, not a different kind of one. The only caller, file-overlap-queue in the orchestrator profiles, passes ByFile and keeps its behaviour and its name.

One incidental behaviour change: ByFile runs path.Clean, where paths were previously compared verbatim. A provider emitting an unclean path used to produce a missed conflict.

Test Plan

make test — 98 pass
make lint, make check-gazelle, make check-tidy

New coverage in pathoverlap_test.go:

  • TestPathKey — both projections over a nested path, a repository-root file, and an unclean path.
  • Sibling files in one directory: no conflict under ByFile, conflict under ByDirectory; files in sibling directories conflict under neither; the same file still conflicts under both.
  • Two root-level files conflict under ByDirectory while a nested file in the same batch set does not.
  • New panics when the key is nil.

## Summary

### Why?

`fileoverlap` serialized two batches only when they changed the exact same file. That is the narrowest useful reading of target overlap, and for a queue whose directories are tightly coupled it is too narrow: two changes to sibling files in one package can break each other without either one touching the path the other did, and the analyzer will happily speculate them in parallel.

The right granularity is not a property of the analyzer. It follows from how tightly coupled a directory's contents are in the repository behind the queue, which is something only the integrator wiring that queue up can know. So it belongs at construction, next to the resolver, rather than baked into the package.

### What?

Overlap is measured on a key projected from each changed path. `PathKey` is that projection, chosen at construction and applied to every path before the two batches' sets are intersected; `Analyze` is otherwise unchanged.

Two projections ship with the package. `ByFile` keys on the whole path and reproduces the previous behaviour. `ByDirectory` keys on the immediate parent, so batches touching sibling files conflict too — strictly coarser, since every file overlap is also a directory overlap. It buys protection against semantic conflicts between neighbouring files and pays for it in parallelism, which is the trade the integrator is choosing between.

Paths at the repository root key on `.` under `ByDirectory`, so a batch touching `README.md` conflicts with one touching `go.mod`. Root files are usually build configuration and usually do interact, so this is deliberate rather than incidental.

The package is renamed `fileoverlap` → `pathoverlap`, because the unit of overlap is now a path-derived key rather than a file. `New` takes the key as a third argument and panics on nil, mirroring `heuristic.New`. `conflict.Analyzer`, `conflict.Config` and `ConflictTypeTargetOverlap` are untouched — a folder is a coarser target, not a different kind of one. The only caller, `file-overlap-queue` in the orchestrator profiles, passes `ByFile` and keeps its behaviour and its name.

One incidental behaviour change: `ByFile` runs `path.Clean`, where paths were previously compared verbatim. A provider emitting an unclean path used to produce a missed conflict.

## Test Plan

✅ `make test` — 98 pass
✅ `make lint`, `make check-gazelle`, `make check-tidy`

New coverage in `pathoverlap_test.go`:

- `TestPathKey` — both projections over a nested path, a repository-root file, and an unclean path.
- Sibling files in one directory: no conflict under `ByFile`, conflict under `ByDirectory`; files in sibling directories conflict under neither; the same file still conflicts under both.
- Two root-level files conflict under `ByDirectory` while a nested file in the same batch set does not.
- `New` panics when the key is nil.
@behinddwalls
behinddwalls marked this pull request as ready for review August 12, 2026 03:15
@behinddwalls
behinddwalls requested review from a team and sbalabanov as code owners August 12, 2026 03:15
@behinddwalls
behinddwalls added this pull request to the merge queue Aug 12, 2026
Merged via the queue into main with commit 910680c Aug 12, 2026
27 checks passed
@behinddwalls
behinddwalls deployed to stack-rebase August 12, 2026 18:05 — with GitHub Actions Active
@behinddwalls
behinddwalls deleted the preetam/conflict branch August 12, 2026 18:05
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.

2 participants