Skip to content

Reduce cross-instance private access in merge-tree - #28242

Open
Matt Rakow (ChumpChief) wants to merge 7 commits into
microsoft:mainfrom
ChumpChief:refactor/merge-tree-trivial-private-access
Open

Matt Rakow (ChumpChief) wants to merge 7 commits into
microsoft:mainfrom
ChumpChief:refactor/merge-tree-trivial-private-access

Conversation

@ChumpChief

@ChumpChief Matt Rakow (ChumpChief) commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

Description

Reduce cross-instance private access in merge-tree through small changes that preserve behavior for valid callers:

  • Compare tracking groups through the existing trackingGroups getter and remove unnecessary optional chaining, relying on matches()'s existing non-nullable parameter contract.
  • Replace the private enqueueOnCopy() helper with public enqueue() and the existing previous-properties bookkeeping.
  • Add owner-side methods for reading partial-length counts and baselines and setting the incremental-invalidation marker.
  • Use leafLength() and LocalReferenceCollection.size instead of private access in verification helpers.
  • Simplify child-partial iteration with for...of, removing the cached array length.

This is an incremental cleanup, not a complete elimination of private access. Larger changes to attribution, property-manager copying, reference transfers, and partial-length construction are intentionally deferred.

Test Coverage

The added tests make the existing contracts explicit and guard against accidental behavioral changes while replacing private access:

  • Tracking groups: Verify matching uses group identity and set membership, independent of insertion order, with both ordered and unordered tracking groups.
  • Segment-group copying: Verify copying retains the correct source segment's previous-properties object, including when the source is not the first group member. This protects the bookkeeping previously performed by enqueueOnCopy().
  • Partial-length queries: Cover empty state, child aggregation, and an advanced minimum sequence number. These distinguish the baseline at minSeq from the length after later sequence adjustments.
  • Incremental invalidation: Verify only the latest invalidated sequence triggers rebuilding, that invalidation propagates to ancestors, and that calculated lengths remain unchanged.
  • Local-reference counts: Verify size reflects additions and removals, excludes transient references, and includes references in all three bucket positions. The existing count-validation helper now uses this getter instead of private access.

Reviewer Guidance

The review process is outlined in the pull request guidelines.

The intended scope is straightforward access substitutions, preserving existing calculations, bookkeeping, and operation ordering. No data structures or copying contracts are redesigned.

…ification

Use the trackingGroups getter for comparisons and leafLength for leaf-only partial-length verification. Cover tracking-group identity comparisons with a regression test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use public enqueue and copy the source segment's previous properties directly in copyTo, avoiding a private method call on the destination collection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extract the invalidation setter and segment-count/baseline queries without changing partial-length construction or incremental contribution logic. Adapt coverage to the existing combine and update paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Expose the existing count through a getter for diagnostic validation without changing reference storage, initialization, or transfer behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the cached child count and indexed loops with for-of iteration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings September 17, 2026 04:48
@ChumpChief
Matt Rakow (ChumpChief) requested a review from a team as a code owner September 17, 2026 04:48
@github-actions github-actions Bot added area: tools area: dds Issues related to distributed data structures area: repo Repo related work area: website base: main PRs targeted against main branch labels Sep 17, 2026
@github-actions

github-actions Bot commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

Hi! Thank you for opening this PR. Want me to review it?

Based on the diff (252 lines, 9 files), I've queued these reviewers:

  • Correctness — logic errors, race conditions, lifecycle issues
  • Security — vulnerabilities, secret exposure, injection
  • API Compatibility — breaking changes, release tags, type design
  • Performance — algorithmic regressions, memory leaks
  • Testing — coverage gaps, hollow tests

How this works

  • Adjust the reviewer set by ticking/unticking boxes above. Reviewer toggles alone don't trigger anything.

  • Tick Start review below to dispatch the review fleet.

  • After review finishes, tick Start review again to request another run — it auto-resets after each dispatch.

  • This comment updates as new commits land; your reviewer selections are preserved.

  • Start review

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Fix the possibly undefined trackingGroups dereference causing TS2532 and preventing compilation.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

This pull request replaces private merge-tree access with public APIs while preserving behavior and adding regression tests.

Changes:

  • Updates tracking, segment-group, partial-length, and reference-count access.
  • Adds owner-side partial-length APIs and invalidation coverage.
  • Adds focused regression tests.
File summaries
File Summary
packages/dds/merge-tree/src/test/tracking.spec.ts Tests tracking-group matching.
packages/dds/merge-tree/src/test/testUtils.ts Uses public reference-count access.
packages/dds/merge-tree/src/test/segmentGroupCollection.spec.ts Tests previous-properties preservation.
packages/dds/merge-tree/src/test/partialLength.spec.ts Tests partial-length queries and invalidation.
packages/dds/merge-tree/src/test/localReference.spec.ts Tests local-reference counts.
packages/dds/merge-tree/src/segmentGroupCollection.ts Uses public enqueueing during copies.
packages/dds/merge-tree/src/partialLengths.ts Adds owner-side accessors and simplifies iteration.
packages/dds/merge-tree/src/mergeTreeTracking.ts Uses the tracking-groups getter.
packages/dds/merge-tree/src/localReference.ts Adds the reference-count getter.
Review details
  • Files reviewed: 9/9 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/dds/merge-tree/src/mergeTreeTracking.ts
Remove optional chaining and the unnecessary undefined union from matches, consistent with its non-nullable parameter and getter return type.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

Fleet Review — Clean

No issues found across the reviewer fleet for this run.

View run

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The substitutions preserve existing behavior and are covered by focused tests for the affected invariants.

Review details
  • Files reviewed: 9/9 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

const combined = PartialSequenceLengths.combine(parent, mergeTree.collabWindow);

for (const partials of [mergeTree.root.partialLengths, combined]) {
assert.equal(partials.getSegmentCount(), 3);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I will note -- I don't understand why these numbers are what they are. Just double checking that you are confident in them before we let the LLM reward hack a broken test in

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I checked the expectations at packages/dds/merge-tree/src/test/partialLength.spec.ts:81-83: inserting "more " at offset 5 produces "hello", "more ", and " world!"—three segments. The baseline at minSeq = 0 contains the original 12 characters (5 + 7), while sequence 1 includes the insertion for a total of 17 (12 + 5); wrapping the subtree in a parent does not change those values. I added brief comments explaining these and the other numeric expectations in 992bf1c160f; the assertions are unchanged.

Which is, admittedly, exactly what a reward-hacking LLM would say.

— Copilot, the LLM under investigation

Clarify text segmentation, sequence baselines, reference counts, and property-slot expectations without changing test behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Bundle size comparison

Base commit: f469232c2bc8613a23c68e4edde1914da0d78f88
Head commit: 992bf1c160f53046de87ffa54c3a3ea315c7cea3

Notable changes

No bundles changed by ≥ 500 bytes parsed.

Per-bundle deltas

@fluid-example/bundle-size-tests

  • fluidFrameworkAllAlpha.js: parsed 801533 → 801716 (+183), gzip 220527 → 220633 (+106)
  • azureClient.js: parsed 634336 → 634331 (-5), gzip 169989 → 170074 (+85)
  • odspClient.js: parsed 606600 → 606711 (+111), gzip 163052 → 163198 (+146)
  • aqueduct.js: parsed 533117 → 533255 (+138), gzip 143294 → 143373 (+79)
  • fluidFramework.js: parsed 415378 → 415411 (+33), gzip 117810 → 117845 (+35)
  • sharedTree.js: parsed 404757 → 404783 (+26), gzip 115252 → 115271 (+19)
  • containerRuntime.js: parsed 315027 → 315009 (-18), gzip 86438 → 86439 (+1)
  • sharedString.js: parsed 170105 → 170239 (+134), gzip 48455 → 48478 (+23)
  • experimentalSharedTree.js: parsed 161846 → 161846 (0), gzip 46722 → 46722 (0)
  • matrix.js: parsed 153720 → 153854 (+134), gzip 44381 → 44421 (+40)
  • loader.js: parsed 147328 → 147344 (+16), gzip 40038 → 40049 (+11)
  • odspDriver.js: parsed 106695 → 106753 (+58), gzip 33227 → 33293 (+66)
  • directory.js: parsed 65669 → 65676 (+7), gzip 18493 → 18502 (+9)
  • 578.js: parsed 58686 → 58686 (0), gzip 17657 → 17657 (0)
  • odspPrefetchSnapshot.js: parsed 46463 → 46444 (-19), gzip 15512 → 15522 (+10)
  • map.js: parsed 45820 → 45827 (+7), gzip 14120 → 14127 (+7)
  • 252.js: parsed 44384 → 44384 (0), gzip 13741 → 13741 (0)
  • summarizerDelayLoadedModule.js: parsed 31287 → 31287 (0), gzip 7929 → 7929 (0)
  • socketModule.js: parsed 27108 → 27078 (-30), gzip 8069 → 8103 (+34)
  • createNewModule.js: parsed 12464 → 12464 (0), gzip 4792 → 4805 (+13)
  • summaryModule.js: parsed 3888 → 3888 (0), gzip 1874 → 1874 (0)
  • connectionState.js: parsed 909 → 909 (0), gzip 500 → 500 (0)
  • sharedTreeAttributes.js: parsed 845 → 852 (+7), gzip 496 → 505 (+9)
  • debugAssert.js: parsed 429 → 429 (0), gzip 299 → 299 (0)
  • FluidFramework-HashFallback.js: parsed 419 → 419 (0), gzip 313 → 313 (0)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: dds Issues related to distributed data structures area: repo Repo related work area: tools area: website base: main PRs targeted against main branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants