Skip to content

feat(utilities): add Delta / SetDelta<T> set-difference for incremental diffing - #148

Merged
ANcpLua merged 1 commit into
mainfrom
claude/delta-set-diff
Jul 1, 2026
Merged

feat(utilities): add Delta / SetDelta<T> set-difference for incremental diffing#148
ANcpLua merged 1 commit into
mainfrom
claude/delta-set-diff

Conversation

@ANcpLua

@ANcpLua ANcpLua commented Jul 1, 2026

Copy link
Copy Markdown
Owner

What

Adds a small, on-theme utility to ANcpLua.Roslyn.Utilities: set difference for incremental "what changed between the previous and current snapshot" logic — the diffing primitive incremental generators/analyzers reach for constantly.

  • Delta.Difference(first, second) → relative complement second \ first, preserving second's order. Filters (does not deduplicate); documented and tested.
  • Delta.Compute(previous, current) → value-equatable SetDelta<T> carrying Added (in current, not previous) and Removed (in previous, not current) — the "call it twice" idiom baked in.
  • Overloads for ImmutableArray<T> and EquatableArray<T>; results are EquatableArray<T> so a delta flows through the generator cache. SetDelta<T> is value-equatable (==, Equals, HashCombiner-based GetHashCode), with IsEmpty / HasChanges.

Follows repo conventions: dual-visibility (ANCPLUA_ROSLYN_PUBLIC), HashCombiner, full XML docs.

Why

Diffing two snapshots is a recurring need in incremental pipelines (added/removed models, usings, symbols, cache keys). This bakes the correct, allocation-conscious, cache-friendly version into the library and fixes the doc/impl drift of the classic single-direction helper.

Verification — complete & verified

  • CI=true dotnet build -c Release (warnings-as-errors) — green.
  • Full test project: 174 passed, 0 failed (14 new DeltaTests: order, duplicates, symmetry, overload agreement, default-array inputs, record models, value equality).

🤖 Generated with Claude Code

…al diffing

Delta.Difference(first, second) returns the relative complement (second \ first),
preserving second's order; Delta.Compute(previous, current) returns a value-equatable
SetDelta<T> carrying Added/Removed so a snapshot diff flows through the incremental
generator cache. Overloads for ImmutableArray<T> and EquatableArray<T>; results are
EquatableArray<T>. Fixes the doc/impl drift of the classic single-direction helper
(documented filter-not-dedup semantics).

14 tests (order, duplicates, symmetry, overload agreement, record models, value equality).
Verified: CI=true Release build (warnings-as-errors) green; 174 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 1, 2026 05:31
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

  • New Features

    • Added snapshot comparison support to detect added and removed items between two collections.
    • Improved handling for empty inputs, ordering, and duplicate entries when comparing value-equatable items.
    • Introduced value-based change summaries that make it easier to determine whether anything changed.
  • Tests

    • Added coverage for comparison behavior, including edge cases, equality checks, and support for record-based values.

Walkthrough

Introduces a Delta static utility providing Difference<T> and Compute<T> methods for computing set-based differences between EquatableArray<T>/ImmutableArray<T> collections, alongside a new SetDelta<T> readonly struct with value equality. Adds a comprehensive DeltaTests suite covering both APIs.

Changes

Delta Utility and Tests

Layer / File(s) Summary
Difference computation core
src/ANcpLua.Roslyn.Utilities/Delta.cs, tests/ANcpLua.Roslyn.Utilities.Testing.Tests/DeltaTests.cs
Difference<T> overloads compute the relative complement between two collections for EquatableArray<T> and ImmutableArray<T>, with fast paths for empty/default inputs and storage reuse when no elements are filtered; tests validate ordering, duplicate handling, disjoint/subset cases, non-symmetry, and overload agreement.
SetDelta type and Compute method
src/ANcpLua.Roslyn.Utilities/Delta.cs, tests/ANcpLua.Roslyn.Utilities.Testing.Tests/DeltaTests.cs
SetDelta<T> readonly struct stores Added/Removed, exposes IsEmpty/HasChanges, and implements full value equality; Compute<T> overloads build a SetDelta<T> from two Difference calls; tests cover added/removed reporting, same-set reordering, equality/hash code semantics, and usage with value-equatable record models.

Estimated code review effort: 2 (Simple) | ~12 minutes

Related PRs: None specified.

Suggested reviewers: None specified.

Note: Difference builds the result by hashing first and filtering second, then reuses second's underlying storage when nothing is filtered out — verify this reuse path doesn't leak mutable aliasing if EquatableArray<T> wraps a mutable backing array elsewhere in the codebase.

🐇 A rabbit hopped between two sets,
found what's new and what one forgets,
Added, Removed, packed up tight,
equal deltas, hashed just right,
no drama here — just diffs, no debts.


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Title check ❌ Error The title is relevant, but it uses an unsupported scope and exceeds the 72-character limit. Use an allowed scope such as feat(mcp): and shorten the summary to 72 characters or fewer.
✅ Passed checks (7 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly matches the added Delta/SetDelta utility and accompanying tests.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Otel Instrumentation Required ✅ Passed Delta adds only a static utility and readonly value type; no injectable service or DI registration was introduced.
No Unbounded Mcp Responses ✅ Passed No files under src/qyl.mcp were added or modified; the PR only touches Delta.cs and DeltaTests.cs.
Duckdb Backpressure On Write Paths ✅ Passed The PR only adds in-memory Delta/SetDelta utilities and tests; no new DuckDB write path exists in the touched code.
Cancellationtoken Threading ✅ Passed PASS: The new src code (Delta.cs) is synchronous; no new public async methods were added, so CancellationToken threading does not apply.

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

Copilot AI 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.

Pull request overview

Adds a small diffing primitive to ANcpLua.Roslyn.Utilities to support incremental analyzer/generator snapshot comparisons, along with tests and a README entry documenting the new API.

Changes:

  • Introduces Delta.Difference(...) to compute the relative complement (second \ first) while preserving second’s order (and intentionally not deduplicating).
  • Introduces Delta.Compute(...) returning a value-equatable SetDelta<T> (Added/Removed) suitable for incremental cache comparisons.
  • Adds xUnit test coverage for ordering, duplicates, default inputs, overload agreement, and SetDelta<T> value equality; documents the utility in README.md.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
src/ANcpLua.Roslyn.Utilities/Delta.cs Adds Delta + SetDelta<T> APIs (ImmutableArray/EquatableArray overloads, XML docs, value equality + hash).
tests/ANcpLua.Roslyn.Utilities.Testing.Tests/DeltaTests.cs Adds unit tests covering Difference/Compute semantics and SetDelta<T> equality/hash behavior.
README.md Documents the new utility in the library feature list.
.claude/TASK.md Adds an internal task/checklist document related to implementing and shipping the feature.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/ANcpLua.Roslyn.Utilities.Testing.Tests/DeltaTests.cs`:
- Around line 12-85: Consolidate the repetitive Delta.Difference tests into a
single [Theory] with [MemberData] (or equivalent shared data source) instead of
multiple [Fact] methods. Keep the same coverage for the existing Difference_*
cases by parameterizing the inputs and expected outputs, and update the test
names/data setup around Delta.Difference, Eq, and AsImmutableArray so the
behavior assertions remain unchanged while removing duplication.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 178f1923-6f96-4e4c-acf6-04235aa0f9d5

📥 Commits

Reviewing files that changed from the base of the PR and between dfece50 and a07e9c7.

⛔ Files ignored due to path filters (2)
  • .claude/TASK.md is excluded by none and included by none
  • README.md is excluded by none and included by none
📒 Files selected for processing (2)
  • src/ANcpLua.Roslyn.Utilities/Delta.cs
  • tests/ANcpLua.Roslyn.Utilities.Testing.Tests/DeltaTests.cs
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: build (windows-latest)
  • GitHub Check: build (ubuntu-latest)
  • GitHub Check: copilot-pull-request-reviewer
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx,cs,py}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Skip files whose first ~3 lines contain // Ported from <upstream>, // Generated, or // Auto-generated — surface a one-line note instead of line-level findings

Files:

  • src/ANcpLua.Roslyn.Utilities/Delta.cs
  • tests/ANcpLua.Roslyn.Utilities.Testing.Tests/DeltaTests.cs
**/*.cs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

.NET code: enable nullable reference types, use central package management via Directory.Packages.props, and treat Version.props as the single owner of versions — never edit <Version> lines directly

Files:

  • src/ANcpLua.Roslyn.Utilities/Delta.cs
  • tests/ANcpLua.Roslyn.Utilities.Testing.Tests/DeltaTests.cs
src/ANcpLua.Roslyn.Utilities/**/*.{cs,csproj}

📄 CodeRabbit inference engine (AGENTS.md)

Keep ANCPLUA_ROSLYN_PUBLIC controlled per-consumer; avoid bleeding API-visibility mode into source-only or internal package surfaces

Files:

  • src/ANcpLua.Roslyn.Utilities/Delta.cs
src/**/*.cs

📄 CodeRabbit inference engine (Custom checks)

src/**/*.cs: In C# public async methods, verify that every async method accepts and forwards a CancellationToken parameter
When adding a new injectable service class registered in dependency injection, verify that it registers an ActivitySource or Meter for OpenTelemetry instrumentation

Files:

  • src/ANcpLua.Roslyn.Utilities/Delta.cs

⚙️ CodeRabbit configuration file

src/**/*.cs: C# 14 / .NET 10 codebase. Review for: idiomatic modern C#, proper async/await (no sync-over-async, no fire-and-forget without justification), correct IDisposable/IAsyncDisposable, null safety (NRTs enabled), and adherence to existing patterns. Flag new public API surface that lacks XML doc comments. Check DI lifetime correctness (scoped vs singleton vs transient).
ARCHITECTURAL INVARIANTS — flag violations as blocking: 1. Every new injectable service must register OpenTelemetry instrumentation
(ActivitySource or Meter).
2. Every new DuckDB write path must handle backpressure (bounded channel or semaphore). 3. No hardcoded connection strings, paths, or magic strings — use IOptions or
IConfiguration.
4. No new dependencies on Sentry-specific types in core/ — Sentry is a comparison
target, not an identity.
5. CancellationToken must be threaded through all async public methods. 6. No sync-over-async (.Result, .GetAwaiter().GetResult()) outside of
well-documented infrastructure code.

Files:

  • src/ANcpLua.Roslyn.Utilities/Delta.cs
src/**/*.{cs,js,ts,py}

📄 CodeRabbit inference engine (Custom checks)

When adding new code paths that write to DuckDB, verify it uses a bounded channel or semaphore for backpressure handling

Files:

  • src/ANcpLua.Roslyn.Utilities/Delta.cs
**

⚙️ CodeRabbit configuration file

**: # ANcpLua.Roslyn.Utilities

Minimal navigation for Claude/Codex agents. Keep policy in AGENTS.md; keep findings in issues, PRs, or tests.

Project Index

  1. AOT reflection generator
  2. AOT reflection attributes
  3. Discriminated union generator
  4. Extensible enum mirror generator
  5. Core Roslyn utilities
  6. Polyfills package
  7. Source-only package
  8. Testing utilities
  9. AOT testing utilities

Nearby Repos

  • ANcpLua.NET.Sdk: shared SDK/version truth for the ANcpLua repos.
  • ANcpLua.Analyzers: analyzer consumer of the source-only utilities.
  • ANcpLua.Agents: successor location for agent workflow/test helpers; do not describe this repo as the MAF runtime home.

**:

999.9.9


10.0.203
latestMinor

<PropertyGroup Label="Roslyn">
    <RoslynVersion>5.3.0</RoslynVersion>
    <RoslynAnalyzersVersion>5.3.0</RoslynAnalyzersVersion>
</PropertyGroup>

<!-- ═══════════════════════════════════════════════════════════════════════
     ROSLYN ANALYZER TESTING
     Used by: Roslyn.Utilities.Testing, Analyzers.Tests
     ════════════════════════════════════════════════════════════════════...

Files:

  • src/ANcpLua.Roslyn.Utilities/Delta.cs
  • tests/ANcpLua.Roslyn.Utilities.Testing.Tests/DeltaTests.cs
src/ANcpLua.Roslyn.Utilities/**

⚙️ CodeRabbit configuration file

src/ANcpLua.Roslyn.Utilities/**: # ANcpLua.Roslyn.Utilities

Core runtime and Roslyn utility package.

  • Project: ANcpLua.Roslyn.Utilities.csproj
  • Runtime helpers should stay usable without Roslyn dependencies where possible.
  • Check existing helper types before adding another abstraction.

Files:

  • src/ANcpLua.Roslyn.Utilities/Delta.cs
tests/**/*.cs

⚙️ CodeRabbit configuration file

xUnit.v3 test projects using xunit.v3.mtp-v2 with AwesomeAssertions and NSubstitute. Follow Arrange-Act-Assert pattern. Use descriptive test names: MethodName_Scenario_ExpectedResult. Test async methods with async Task, not async void. Flag hardcoded test data that should come from the seeded DuckDB file (the single source of truth for demo/test data). Prefer [Theory] with [InlineData] or [MemberData] over duplicated [Fact] methods testing variations of the same behavior. Flag tests that depend on test execution order.

Files:

  • tests/ANcpLua.Roslyn.Utilities.Testing.Tests/DeltaTests.cs
🧠 Learnings (2)
📚 Learning: 2026-06-14T00:13:53.631Z
Learnt from: ANcpLua
Repo: ANcpLua/ANcpLua.Roslyn.Utilities PR: 144
File: tests/ANcpLua.Roslyn.Utilities.DiscriminatedUnion.Tests/IncrementalDiagnosticLocationTests.cs:63-67
Timestamp: 2026-06-14T00:13:53.631Z
Learning: When testing Roslyn incremental generator diagnostics, assert generator execution failures (e.g., CS8785 “generator-failed”) against `GeneratorDriverRunResult.Diagnostics` (use `driver.GetRunResult().Diagnostics`), not against `outputCompilation.GetDiagnostics()`. Checking `outputCompilation` for CS8785 is a silent no-op because that diagnostic is surfaced only in the driver run result.

Applied to files:

  • tests/ANcpLua.Roslyn.Utilities.Testing.Tests/DeltaTests.cs
📚 Learning: 2026-06-14T00:13:53.631Z
Learnt from: ANcpLua
Repo: ANcpLua/ANcpLua.Roslyn.Utilities PR: 144
File: tests/ANcpLua.Roslyn.Utilities.DiscriminatedUnion.Tests/IncrementalDiagnosticLocationTests.cs:63-67
Timestamp: 2026-06-14T00:13:53.631Z
Learning: In this repo’s test suite, the `Test<TGenerator>` harness and `GeneratorTestEngine.RunTwiceAsync` are not suitable for scenarios that require `ReplaceSyntaxTree` shrinking edits between two driver runs. If a test needs to reproduce regressions like dotnet/roslyn#82032 (incremental update with a smaller syntax tree), write the test with a hand-rolled `CSharpGeneratorDriver` and call `RunGenerators` on the modified compilation directly (i.e., don’t rely on `RunTwiceAsync`/`ReplaceSyntaxTree` shrinking across driver runs).

Applied to files:

  • tests/ANcpLua.Roslyn.Utilities.Testing.Tests/DeltaTests.cs
🔇 Additional comments (2)
src/ANcpLua.Roslyn.Utilities/Delta.cs (1)

1-175: LGTM!

tests/ANcpLua.Roslyn.Utilities.Testing.Tests/DeltaTests.cs (1)

87-136: LGTM!

Comment thread tests/ANcpLua.Roslyn.Utilities.Testing.Tests/DeltaTests.cs
@ANcpLua
ANcpLua merged commit b6659f1 into main Jul 1, 2026
9 checks passed
@ANcpLua
ANcpLua deleted the claude/delta-set-diff branch July 1, 2026 05:36
ANcpLua added a commit that referenced this pull request Jul 5, 2026
…l bumped) (#149)

The Delta / SetDelta<T> task is fully complete: merged via #148, published
as 2.2.29 (tagged, indexed on nuget.org), and qyl's global.json pins were
bumped in qyl#456. Removing the task-state file so it is not mistaken for
ongoing work.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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