Skip to content

test(client-tree): unimplemented "minimize" post-processor#27633

Merged
jason-ha merged 26 commits into
mainfrom
tree/transaction-minimizer-tests
Jul 14, 2026
Merged

test(client-tree): unimplemented "minimize" post-processor#27633
jason-ha merged 26 commits into
mainfrom
tree/transaction-minimizer-tests

Conversation

@jason-ha

@jason-ha jason-ha commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Creates a "minimize" placeholder for transaction post-process functionality.

Unit tests are added to cover the intended new functionality with unsupported tests disabled. (Since implementation is not expected to change observable result tests for observable result can be enabled with the simple do-nothing implementation that is the placeholder.)

  transaction minimize post-processor
    ✔ can be supplied as a transaction post-processor without error
    ✔ throws when edits are made before and after a schema change
    ✔ preserves the observable result across an async transaction and new content appears in change
    ✔ temporary schema change throws restoring schema
    self-tests - no minimization applicable
      ✔ embeds surviving markers but not transient marker for a purely additive scenario
      ✔ result carries no build when pre-existing content is only rearranged
      ✔ result carries no build when pre-existing content is only removed
      ✔ reflects the order of only-rearranged inserted nodes and keeps every build
    preserves the observable result and new content appears in change
      ✔ keeps inserted nodes
      ✔ nets a create-then-remove to no change
      ✔ keeps only the persisted node when a transient node is also created
      ✔ reflects only the final value of a node replaced within the transaction
      ✔ reflects only the surviving node when inserted content is relocated then removed
      ✔ keeps the surrounding nodes when a node in the middle of an inserted run is removed
      ✔ keeps the surrounding nodes when an inserted node is moved then removed
      ✔ keeps only the trailing node when a moved node and its successor from leading node are removed
      ✔ keeps only the leading node when a moved node and its insertion companion are removed
      ✔ leaves pre-existing content unchanged when a transient node is inserted then removed
      ✔ keeps pre-existing content and the surviving inserted node
      ✔ reflects only the final value of a root object field set multiple times
      ✔ reflects only the final undefined root when only item's value of a field is set and then the item is removed
      ✔ reflects only the final value of a field of newly inserted root object when it is replaced
      ✔ reflects only the final value of a nested field set multiple times
      ✔ reflects an undefined root when a nested field is set and then the root object is removed
      ✔ reflects an empty root object when a nested field is set and then the nested field is removed
      ✔ reflects an empty root when a nested object with a value is added and then the root object is removed
      ✔ reflects only the final value of a field of a newly inserted nested object when nested field value is replaced
      ✔ reflects only the final value of a newly inserted nested object when nested object is replaced
      ✔ reflects only the final value of a newly inserted nested object whose value was set before it was replaced
      ✔ reflects the surviving object when a newly inserted object's nested object is removed
      ✔ reflects edits made before a schema change
      ✔ reflects edits made after a schema change
    produces a consistent view and the same observable result as not minimized
      ✔ for A inserted
      ✔ for A then B inserted
      ✔ for A added then removed
      ✔ for A kept and B transient
      ✔ for A replaced by B
      ✔ for B inserted before A then A removed
      ✔ for A,B,C inserted then B removed
      ✔ for A then B,C inserted then rearranged
      ✔ for A,B,C inserted then B moved then removed
      ✔ for A,B,C inserted then B moved then B and A removed
      ✔ for A,B,C inserted then B moved then C and B removed
      ✔ for preexisting content and transient insert
      ✔ for preexisting content and surviving insert
      ✔ for preexisting content rearranged
      ✔ for preexisting content removed
      ✔ for root Box value set twice
      ✔ for nested Box value set twice
      ✔ for root Box value set then root Box removed
      ✔ for nested Box value set then root Box removed
      ✔ for nested Box value set then nested Box removed
      ✔ for nest Box with value then root Box removed
      ✔ for add root Box then replace value
      ✔ for add nested Box then replace value
      ✔ for add nested Box then replace nested Box
      ✔ for add nested Box set value then replace nested Box
      ✔ for add Box with nested Box then remove nested Box
      ✔ for edit before schema change
      ✔ for edit after schema change
    removes extraneous data from the squashed changes (expected to fail until minimize is implemented)
      - drops the build and destroy for a create-then-remove
      - keeps only the persisted node's build when a transient node is also created
      - keeps only the final node's build when a node is replaced
      - keeps only the surviving node's build when inserted content is relocated then removed
      - keeps the surrounding builds when a node in the middle of an inserted run is removed
      - drops the build for an inserted node that is moved then removed
      - keeps only the trailing node's [modified] build when a moved node and its successor from leading node build are removed
      - keeps only the leading node's build when a moved node and its insertion companion are removed
      - carries no build for a transient insert over pre-existing content
      - keeps only the surviving inserted node's build over pre-existing content
      - keeps only the final value's build when a field is set multiple times
      - carries no build when root's value of a field is set and then the root is removed
      - keeps only the final value's builds when a field of newly inserted object is replaced
      - keeps only the final value's build when a nested field is set multiple times
      - carries no build when a nested field is set and then the root object is removed
      - keeps one build when a nested field is set and then the nested object is removed
      - carries no build when a nested object with a value is added and then the root object is removed
      - keeps only the final value's builds when a field of a newly inserted nested object is replaced
      - keeps only the final value's builds when a newly inserted nested object is replaced
      - keeps only the final value's builds when a newly inserted nested object's value is set before the nested object is replaced
      - keeps only the surviving object's build when a newly inserted object's nested object is removed
      - keeps only edits' surviving builds made before a schema change
      - keeps only edits' surviving builds made after a schema change

Additionally bumps tree test lib to ES2022 so that String.replaceAll is available.

Creates a "minimize" placeholder for transaction post-process functionality.

Unit tests are added to cover the intended new functionality with unsupported tests disabled. (Since implementation is not expected to change observable result tests for observable result can be enabled with the simple do-nothing implementation that is the placeholder.)

```text
  transaction minimize post-processor
    ✔ can be supplied as a transaction post-processor without error
    ✔ preserves the observable result across an async transaction
    self-tests - no minimization applicable
      ✔ embeds surviving markers but not transient marker for a purely additive scenario
      ✔ result carries no build when pre-existing content is only rearranged
      ✔ result carries no build when pre-existing content is only removed
      ✔ reflects the order of only-rearranged inserted nodes and keeps every build
    preserves the observable result
      ✔ keeps inserted nodes
      ✔ nets a create-then-remove to no change
      ✔ keeps only the persisted node when a transient node is also created
      ✔ reflects only the final value of a node replaced within the transaction
      ✔ reflects only the surviving node when inserted content is relocated then removed
      ✔ keeps the surrounding nodes when a node in the middle of an inserted run is removed
      ✔ keeps the surrounding nodes when an inserted node is moved then removed
      ✔ keeps only the trailing node when a moved node and its successor from leading node are removed
      ✔ keeps only the leading node when a moved node and its insertion companion are removed
      ✔ leaves pre-existing content unchanged when a transient node is inserted then removed
      ✔ keeps pre-existing content and the surviving inserted node
      ✔ reflects only the final value of a field set multiple times
      ✔ reflects only the final empty array when only item's value of a field is set and then the item is removed
    removes extraneous data from the squashed change (expected to fail until minimize is implemented)
      - drops the build and destroy for a create-then-remove
      - keeps only the persisted node's build when a transient node is also created
      - keeps only the final node's build when a node is replaced
      - keeps only the surviving node's build when inserted content is relocated then removed
      - keeps the surrounding builds when a node in the middle of an inserted run is removed
      - drops the build for an inserted node that is moved then removed
      - keeps only the trailing node's [modified] build when a moved node and its successor from leading node build are removed
      - keeps only the leading node's build when a moved node and its insertion companion are removed
      - carries no build for a transient insert over pre-existing content
      - keeps only the surviving inserted node's build over pre-existing content
      - keeps only the final value's build when a field is set multiple times
      - carries no build when only item's value of a field is set and then the item is removed
```
@jason-ha jason-ha requested a review from a team as a code owner July 1, 2026 21:46
Copilot AI review requested due to automatic review settings July 1, 2026 21:46
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

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

Based on the diff (1808 lines, 12 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.

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

Comment thread packages/dds/tree/src/feature-libraries/modular-schema/minimizeModularChange.ts Outdated
Comment thread packages/dds/tree/src/shared-tree/transactionMinimize.ts Outdated
Comment thread packages/dds/tree/src/shared-tree/transactionMinimize.ts
Comment thread packages/dds/tree/src/test/shared-tree/transactionMinimize.spec.ts
Comment thread packages/dds/tree/src/test/shared-tree/transactionMinimize.spec.ts
Comment thread packages/dds/tree/src/test/shared-tree/transactionMinimize.spec.ts
Comment thread packages/dds/tree/src/test/shared-tree/transactionMinimize.spec.ts
Comment thread packages/dds/tree/src/test/shared-tree/transactionMinimize.spec.ts
Comment thread packages/dds/tree/src/test/shared-tree/transactionMinimize.spec.ts
Comment thread packages/dds/tree/src/test/shared-tree/transactionMinimize.spec.ts
@jason-ha jason-ha requested a review from yann-achard-MS July 7, 2026 10:21
Comment thread packages/dds/tree/src/shared-tree/transactionMinimize.ts Outdated
Comment thread packages/dds/tree/src/test/shared-tree/transactionMinimize.spec.ts Outdated
Comment thread packages/dds/tree/src/test/shared-tree/transactionMinimize.spec.ts
Comment thread packages/dds/tree/src/test/shared-tree/transactionMinimize.spec.ts Outdated
Comment thread packages/dds/tree/src/test/shared-tree/transactionMinimize.spec.ts Outdated
});
});

// These tests only assert the observable end state of the document. Minimization must never change the

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.

This comment is out of date. I think that sentence is unnecessary TBH.

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.

Seems appropriate still. It is odd to be able to have any passing tests for an implementation that doesn't provide value.

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 agree the explanation ("Minimization must never change...") is good. I just meant the first sentence which seems redundant with the describe block title (plus it's not hard to see the pattern in the tests themselves). Re being out of date, I meant that the test do more than assert the observable end state of the document.

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.

Hmm. I think that is really all this describe block currently does. The current view is checked (to have specific content/structure) and the op is partially checked. Other describe blocks do more.

Comment thread packages/dds/tree/src/test/shared-tree/transactionMinimize.spec.ts Outdated
@github-actions

Copy link
Copy Markdown
Contributor

🔗 No broken links found! ✅

Your attention to detail is admirable.

linkcheck output

1: starting server using command "npm run serve -- --no-open"
and when url "[ 'http://127.0.0.1:3000' ]" is responding with HTTP status code 200
running tests using command "npm run check-links"


> fluid-framework-website@0.0.0 serve
> docusaurus serve --no-open

[SUCCESS] Serving "build" directory at: http://localhost:3000/

> fluid-framework-website@0.0.0 check-links
> linkcheck http://localhost:3000 --skip-file skipped-urls.txt

Crawling...

Stats:
  294296 links
    1937 destination URLs
    2187 URLs ignored
       0 warnings
       0 errors


@github-actions

Copy link
Copy Markdown
Contributor

Bundle size comparison

Base commit: ba99c6256f67650704fb174c9ab23780bdf908b6
Head commit: 94d8417abec2a3c7a04d3352dceba4d68a6e8aa1

Notable changes

No bundles changed by ≥ 500 bytes parsed.

Per-bundle deltas

@fluid-example/bundle-size-tests

  • azureClient.js: parsed 619911 → 619967 (+56), gzip 164958 → 165003 (+45)
  • odspClient.js: parsed 592637 → 592693 (+56), gzip 159070 → 159113 (+43)
  • aqueduct.js: parsed 526400 → 526435 (+35), gzip 140839 → 140870 (+31)
  • fluidFramework.js: parsed 394142 → 394163 (+21), gzip 111926 → 111943 (+17)
  • sharedTree.js: parsed 383529 → 383543 (+14), gzip 109311 → 109322 (+11)
  • containerRuntime.js: parsed 304750 → 304764 (+14), gzip 83332 → 83340 (+8)
  • sharedString.js: parsed 175984 → 175991 (+7), gzip 49445 → 49453 (+8)
  • experimentalSharedTree.js: parsed 160798 → 160798 (0), gzip 45804 → 45804 (0)
  • matrix.js: parsed 159845 → 159852 (+7), gzip 45411 → 45418 (+7)
  • loader.js: parsed 145256 → 145270 (+14), gzip 39063 → 39076 (+13)
  • odspDriver.js: parsed 104329 → 104350 (+21), gzip 32625 → 32635 (+10)
  • directory.js: parsed 66616 → 66623 (+7), gzip 18532 → 18540 (+8)
  • 748.js: parsed 58793 → 58793 (0), gzip 17827 → 17827 (0)
  • map.js: parsed 46709 → 46716 (+7), gzip 14310 → 14317 (+7)
  • odspPrefetchSnapshot.js: parsed 45642 → 45656 (+14), gzip 15277 → 15285 (+8)
  • 985.js: parsed 44491 → 44491 (0), gzip 13726 → 13726 (0)
  • summarizerDelayLoadedModule.js: parsed 30749 → 30749 (0), gzip 7753 → 7753 (0)
  • socketModule.js: parsed 26476 → 26483 (+7), gzip 7887 → 7894 (+7)
  • createNewModule.js: parsed 12480 → 12480 (0), gzip 4786 → 4786 (0)
  • summaryModule.js: parsed 3797 → 3797 (0), gzip 1860 → 1860 (0)
  • connectionState.js: parsed 724 → 724 (0), gzip 429 → 429 (0)
  • sharedTreeAttributes.js: parsed 666 → 673 (+7), gzip 432 → 441 (+9)
  • debugAssert.js: parsed 429 → 429 (0), gzip 299 → 299 (0)
  • FluidFramework-HashFallback.js: parsed 422 → 422 (0), gzip 316 → 316 (0)

@jason-ha jason-ha requested a review from yann-achard-MS July 14, 2026 15:35
@jason-ha jason-ha merged commit 76735ba into main Jul 14, 2026
38 checks passed
@jason-ha jason-ha deleted the tree/transaction-minimizer-tests branch July 14, 2026 18:29
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.

3 participants