Jason Hartman
90d · built 2026-09-08
Performance
What Jason Hartman shipped in the selected window, measured in ETV, and how it compares with the 90 days before it.
Effective capacity
+0.6engineers
delivers like 1.6 (1.6x pre-AI)
Output (ETV)
9.6ETV
+125.2% vs 4.3 prior
Features share
9.4%
−2.3 pp vs prior window
Fixes share
18.5%
+15.0 pp vs prior window
Work mix
9.4% Features35.9% Maintenance32.5% Tests3.7% Docs18.5% Fixes
60 commits over 90 days, ending 2026-09-08.
Daily performance
Daily ETV, stacked by Features, Maintenance, Tests, Docs and Fixes.
Repository spread
Where this developer's commits land. Concentrated work (top1 > 80%) vs polymath spread (top1 < 30%).
| Repo | Commits | ETV |
|---|---|---|
| FluidFramework | 52 | 9.7 |
Most impactful commits
Top 10 by ETV in the last 90 days.
- 1.2ETVbuild(client-PropertyDDS): Node16 and module support (#27820) Before this change property-properties and property-common only supported CommonJS. property-dds ESM would load CommonJS and ESM versions of property-changeset. ts2esm was used to update sources within property-properties and property-common. Those were then further revised to handle destructuring that was not possible using "import". (The prior ESM output was mostly just another version of CommonJS where there were some dynamic "import"s that probably didn't work.) For tests, converted in body `require` calls to static imports making ESM tests viable. property-properties CommonJS type interface src/index.d.ts has been rewritten for ESM as src/api.ts.github.com-microsoft-FluidFramework · 4fc14eb5 · 2026-08-03
- 1.1ETVfix(client): update TypeScript 6 compatibility (#27815) In TypeScript 6, `Uint8Array` is generic over `ArrayBufferLike` which currently may be either `ArrayBuffer` or `SharedArrayBuffer`. And `ArrayBuffer` is refined to disallow using `Uint8Array` as it implicitly. Supporting changes: - Remove unused `@types/base64-js` - Add helpers for careful, optimal extraction of `ArrayBuffer` or `ArrayBufferLike` from `ArrayBufferLike` or `Uint8Array`. - `Uint8ArrayToArrayBuffer` is split to 1. `AnyUint8ArrayToArrayBuffer` and explicitly produces an `ArrayBuffer` that some cases expect (they don't handle `SharedArrayBuffer`) 2. `Uint8ArrayToArrayBufferLike` that preserves the underlying buffer type (identical execution as before) If `ArrayBufferLike` was expected and `UInt8Array` was provided, now `Uint8ArrayToArrayBufferLike` wraps the use and handles any offsets that the view may have had. (TS 5.4 was unsound for `ArrayBufferLike` allowing `Uint8Array` to satisfy that constraint. In common use of wrapping `ArrayBuferLike` with `Uint8Array` there would be no issue as `Uint8Array` constructor accepts either as single arguments. Other uses like given to `DataView` would compile fine but throw.) If `ArrayBuffer` was expected and `ArrayBufferLike` was provided, now `ArrayBufferLikeToArrayBuffer` wraps the use and will convert from `SharedArrayBuffer` if that was the case. In the future: - some helpers could be removed if `ArrayBuffer` expectations were related to `ArrayBufferLike` or `Uint8Array`. - under actual TypeScript 6 use: - further optimization of `AnyUint8ArrayToArrayBuffer` is possible without type check error. - `Uint8ArrayToArrayBufferLike` and `IsoBuffer` can be made generic. - Blob APIs should be reviewed for ability to support `SharedArrayBuffer` and use more views (`Uint8Array`) that allow segmented references without cloning data. [AB#46433](https://dev.azure.com/fluidframework/235294da-091d-4c29-84fc-cdfc3d90890b/_workitems/edit/46433) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 62172399-447d-4b34-a88c-1fbb53b94268 --------- Copilot-Session: 62172399-447d-4b34-a88c-1fbb53b94268github.com-microsoft-FluidFramework · 2318b8ca · 2026-08-19
- 0.9ETVimprovement(client-tree): pipe ChangeFamily context to transaction post-processors (#27785) Transaction post-processors previously received only the squashed change to process. Some post-processing (e.g. minimization) needs access to change-family–specific helpers such as the `ModularChangeFamily`, which were not reachable from the processor callback. This change threads a new `TChangeProcessingContext` type parameter through the change-processing pipeline so a `ChangeFamily` can supply a context to its related processors: - `ChangeFamily` gains a `buildProcessor` method and a `ProcessChangeFn<TChange, TChangeProcessingContext>` helper type. When `TChangeProcessingContext` is `never` (default), the processor keeps its original `(change) => change` shape; otherwise, it receives `(change, context)`. - `ChangeProcessor`, `SquashingTransactionOptions`, `SquashingTransactionStack`, `SharedTreeBranch`, `EditManager`, and the transaction plumbing are parameterized on `TChangeProcessingContext` and pass the context through. - `SharedTreeChangeFamily` implements `buildProcessor` and exposes a context with `ModularChangeFamily` now available to post-processors. - `DefaultChangeFamily`, `ModularChangeFamily`, and `mitigatedChangeFamily` are updated to the new signatures. - `EditManager`'s `TChangeFamily` parameter that allowed concrete `ChangeFamily` to be read from public `changeFamily` has been removed as no callers required the concrete type. `TChangeProcessingContext` with a default of `never` appears in its place. The context is now piped end-to-end so transaction post-processors (such as the minimizer) can access the change family that produced the change.github.com-microsoft-FluidFramework · 9daa7d13 · 2026-07-30
- 0.6ETVbuild(client): update to module=node20 (#28062) to enable require-esm support. - Add node20 base config - Separate test base config from test.node16 config - Tests select module config and test config independently - Add node20 import resolution testing to `import-testing` [AB#81440](https://dev.azure.com/fluidframework/235294da-091d-4c29-84fc-cdfc3d90890b/_workitems/edit/81440)github.com-microsoft-FluidFramework · 261559ff · 2026-08-25
- 0.6ETVbuild(client): update to TypeScript 6 [BREAKING CHANGE] (#28052) # 1. build: update to typescript 6 Update typescript to v6 and devDep packages to versions supporting v6. - ts-jest from ^29.1.1 to ^29.4.12 - eslint-plugin-jest from ~29.5.0 to ~29.16.0 # 2. build: update TypeScript 6 compatibility baselines Update compiler-focused tests for TypeScript 6 behavior, including recursive schema patterns that no longer require expected errors, stricter Tree view predicate mocks, relocated error expectations, and improved control-flow narrowing. Regenerate the affected Tree, fluid-framework, tree-agent, and test-package API reports so their declaration baselines match the new compiler output. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> # 3. refactor: convert byte arrays directly to strings Replace `IsoBuffer.from(...).toString(...)` conversion chains with `Uint8ArrayToString` when the source value is already a `Uint8Array`. Apply the direct conversion in PropertyDDS summary encoding and container-runtime compression paths, including their legacy and decompression test helpers. This avoids constructing an intermediate Buffer solely to encode existing byte arrays. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> # 4. refactor(client-utils): define typed `IsoBuffer` contract Introduce a shared minimal `IsoBuffer` interface and constructor contract that models generic typed-array backing stores without exposing the full Node.js `Buffer` API. Align the browser implementation and native Node.js `Buffer` declaration, implement browser isBuffer behavior, and centralize the supported utf8 and base64 encoding types. Preserve `ArrayBuffer` information through conversion and hashing helpers, copy `Uint8Array` inputs consistently with Node behavior, and tighten type validation and tests around the new constructor overloads. Update driver consumers to use the typed encoding APIs and narrow git blob encodings to the formats supported across runtimes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> # 5. Update build compatibility (option/feature flexibility) Retire TypeScript <5.7 from `typescript-versions-host`. Adjust and document build test cases in `import-testing`. --- [AB#79314](https://dev.azure.com/fluidframework/235294da-091d-4c29-84fc-cdfc3d90890b/_workitems/edit/79314)github.com-microsoft-FluidFramework · 7ab015c4 · 2026-08-24
- 0.6ETVbuild(client-drivers): enable `exactOptionalPropertyTypes` in most packages (#27551) `odsp-driver` is notably left with `exactOptionalPropertyTypes` disabled as 47 errors are flagged when enabled. common corrections: - use `...(cond ? {} { prop: value })` to only define properties with defined values. - delete optional properties instead of setting to `undefined`. special cases: - `packages/drivers/driver-web-cache`: disable back compat for `FluidCacheConfig` as `ITelemetryBaseLogger.minLogLevel` recently changed and that change is not detecatble via `exactOptionalPropertyTypes` enablement. - `packages/drivers/odsp-driver/src/zipItDataRepresentationUtils.ts`: explicit `false` instead of possibly `undefined`. - `packages/drivers/odsp-driver/src/contractsPublic.ts`: updated to explicitly allow `undefined` for optional properties as is done by `decodeOdspFluidDataStoreLocator`. - `packages/drivers/routerlicious-driver/src/documentServiceFactory.ts`: capture optional property instead of getter that might have to evaluate to `undefined`. - `packages/test/test-drivers`: only set optional members when defined by callergithub.com-microsoft-FluidFramework · 6a323dbb · 2026-06-19
- 0.6ETVfeat(client-tree): transaction post-processing option infrastructure (#27610) `RunTransactionParams` now accepts an optional `postProcessor` (used by `runTransaction` and `runTransactionAsync`). When specified, the post-processor is invoked when the transaction is committed, allowing for additional processing of the transaction's edits. The option is supplied when the transaction starts and is opt-in: when it is omitted the existing behavior is preserved. Note: a minimization post-processor will be added in a future change. New test cases: ```text sharedTreeView Transactions ✔ converts a post-processor and injects it as the post-processor at transaction start ✔ injects no post-processor when no params are provided to runTransaction ✔ injects the post-processor at start for the outermost transaction only ✔ converts and injects a post-processor through runTransactionAsync ✔ does not commit (and so does not apply the post-processor) when rolled back SquashingTransactionStacks transaction post-processing ✔ is invoked with the squashed change when started with a post-processor ✔ is not invoked when the transaction is empty ✔ is not invoked when the transaction is aborted ✔ invokes an "outermost" post-processor once for the outermost transaction started ✔ invokes the "outermost" post-processor for an inner transaction when the outer has no post-processor ✔ invokes the "outermost" post-processor for an inner transaction when the outer has different post-processor ✔ invokes an "always" post-processor at every transaction commit that supplied it ✔ invokes an "always" post-processor only where it was supplied ✔ invokes an "outermost" post-processor once per sibling nested transaction that supplied it ✔ invokes an "outermost" post-processor once when the outer and both sibling nested transactions supply it ✔ invokes a mix of "outermost" and "always" post-processors in the expected order ✔ applies the change returned by the post-processor to the branch ```github.com-microsoft-FluidFramework · ee981100 · 2026-07-01
- 0.5ETVtest(client-tree): unimplemented "minimize" post-processor (#27633) 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 ✔ 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.github.com-microsoft-FluidFramework · 76735bab · 2026-07-14
- 0.4ETVbuild(client-devtools-view): workaround @fluentui misauthoring (#28086) Route Fluent UI runtime imports through a CommonJS wrapper so their misauthored module entrypoints are not loaded by Jest's ESM runtime. Update Jest and axe interop for ESM, and make the ESM suite the default test target. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Copilot-Session: 91d7652d-1289-4bb9-9a45-7ab52d432196github.com-microsoft-FluidFramework · 3474993f · 2026-08-26
- 0.3ETVtest(client-tree): add cross-field move cases for minimize (#27750) new PalletArray added to use array range moves across sibling arrays of boxed values ```text transaction minimize post-processor preserves the observable result and new content appears in change ✔ reflects surviving boxes of boxes inserted and one moved to sibling that is then removed ✔ reflects surviving boxes of boxes inserted and one moved to sibling when the original parent is then removed ✔ reflects surviving boxes of boxes inserted in a new pallet and one moved to sibling when the new pallet is then removed ✔ reflects the remaining box when a box is moved into a new pallet that is then removed produces a consistent view and the same observable result as not minimized ✔ for boxes inserted then some moved to sibling Pallet that is then removed ✔ for boxes inserted then some moved to sibling Pallet and original parent Pallet is then removed ✔ for boxes inserted in new Pallet then one moved to sibling Pallet and new Pallet is then removed ✔ for boxes moved into new Pallet then new Pallet is then removed for double cross-field move remaining under destination ✔ from self inserted to origin ⌚❤️ thru interim ⌚☠️ to dest ⌚☠️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣☠️ to dest ⌚☠️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣❤️ to dest ⌚☠️ ✔ from self inserted to origin ⌚❤️ thru interim ⌚❤️ to dest ⌚☠️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚☠️ to dest ⌚☠️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣☠️ to dest ⌚☠️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣❤️ to dest ⌚☠️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚❤️ to dest ⌚☠️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚☠️ to dest ⌚☠️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣☠️ to dest ⌚☠️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣❤️ to dest ⌚☠️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚❤️ to dest ⌚☠️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚☠️ to dest ⌚☠️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣☠️ to dest ⌚☠️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣❤️ to dest ⌚☠️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚❤️ to dest ⌚☠️ ✔ from self inserted to origin ⌚❤️ thru interim ⌚☠️ to dest 🐣☠️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣☠️ to dest 🐣☠️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣❤️ to dest 🐣☠️ ✔ from self inserted to origin ⌚❤️ thru interim ⌚❤️ to dest 🐣☠️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚☠️ to dest 🐣☠️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣☠️ to dest 🐣☠️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣❤️ to dest 🐣☠️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚❤️ to dest 🐣☠️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚☠️ to dest 🐣☠️ (38ms) ✔ from self inserted to origin 🐣☠️ thru interim 🐣☠️ to dest 🐣☠️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣❤️ to dest 🐣☠️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚❤️ to dest 🐣☠️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚☠️ to dest 🐣☠️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣☠️ to dest 🐣☠️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣❤️ to dest 🐣☠️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚❤️ to dest 🐣☠️ ✔ from self inserted to origin ⌚❤️ thru interim ⌚☠️ to dest 🐣❤️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣☠️ to dest 🐣❤️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣❤️ to dest 🐣❤️ ✔ from self inserted to origin ⌚❤️ thru interim ⌚❤️ to dest 🐣❤️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚☠️ to dest 🐣❤️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣☠️ to dest 🐣❤️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣❤️ to dest 🐣❤️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚❤️ to dest 🐣❤️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚☠️ to dest 🐣❤️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣☠️ to dest 🐣❤️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣❤️ to dest 🐣❤️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚❤️ to dest 🐣❤️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚☠️ to dest 🐣❤️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣☠️ to dest 🐣❤️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣❤️ to dest 🐣❤️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚❤️ to dest 🐣❤️ ✔ from self inserted to origin ⌚❤️ thru interim ⌚☠️ to dest ⌚❤️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣☠️ to dest ⌚❤️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣❤️ to dest ⌚❤️ ✔ from self inserted to origin ⌚❤️ thru interim ⌚❤️ to dest ⌚❤️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚☠️ to dest ⌚❤️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣☠️ to dest ⌚❤️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣❤️ to dest ⌚❤️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚❤️ to dest ⌚❤️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚☠️ to dest ⌚❤️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣☠️ to dest ⌚❤️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣❤️ to dest ⌚❤️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚❤️ to dest ⌚❤️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚☠️ to dest ⌚❤️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣☠️ to dest ⌚❤️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣❤️ to dest ⌚❤️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚❤️ to dest ⌚❤️ ✔ from origin 🐣☠️ thru interim ⌚☠️ to dest ⌚☠️ ✔ from origin 🐣☠️ thru interim 🐣☠️ to dest ⌚☠️ ✔ from origin 🐣☠️ thru interim 🐣❤️ to dest ⌚☠️ ✔ from origin 🐣☠️ thru interim ⌚❤️ to dest ⌚☠️ ✔ from origin 🐣❤️ thru interim ⌚☠️ to dest ⌚☠️ ✔ from origin 🐣❤️ thru interim 🐣☠️ to dest ⌚☠️ ✔ from origin 🐣❤️ thru interim 🐣❤️ to dest ⌚☠️ ✔ from origin 🐣❤️ thru interim ⌚❤️ to dest ⌚☠️ ✔ from origin 🐣☠️ thru interim ⌚☠️ to dest 🐣☠️ ✔ from origin 🐣☠️ thru interim 🐣☠️ to dest 🐣☠️ ✔ from origin 🐣☠️ thru interim 🐣❤️ to dest 🐣☠️ ✔ from origin 🐣☠️ thru interim ⌚❤️ to dest 🐣☠️ ✔ from origin 🐣❤️ thru interim ⌚☠️ to dest 🐣☠️ ✔ from origin 🐣❤️ thru interim 🐣☠️ to dest 🐣☠️ ✔ from origin 🐣❤️ thru interim 🐣❤️ to dest 🐣☠️ ✔ from origin 🐣❤️ thru interim ⌚❤️ to dest 🐣☠️ ✔ from origin 🐣☠️ thru interim ⌚☠️ to dest 🐣❤️ ✔ from origin 🐣☠️ thru interim 🐣☠️ to dest 🐣❤️ ✔ from origin 🐣☠️ thru interim 🐣❤️ to dest 🐣❤️ ✔ from origin 🐣☠️ thru interim ⌚❤️ to dest 🐣❤️ ✔ from origin 🐣❤️ thru interim ⌚☠️ to dest 🐣❤️ ✔ from origin 🐣❤️ thru interim 🐣☠️ to dest 🐣❤️ ✔ from origin 🐣❤️ thru interim 🐣❤️ to dest 🐣❤️ ✔ from origin 🐣❤️ thru interim ⌚❤️ to dest 🐣❤️ ✔ from origin 🐣☠️ thru interim ⌚☠️ to dest ⌚❤️ ✔ from origin 🐣☠️ thru interim 🐣☠️ to dest ⌚❤️ ✔ from origin 🐣☠️ thru interim 🐣❤️ to dest ⌚❤️ ✔ from origin 🐣☠️ thru interim ⌚❤️ to dest ⌚❤️ ✔ from origin 🐣❤️ thru interim ⌚☠️ to dest ⌚❤️ ✔ from origin 🐣❤️ thru interim 🐣☠️ to dest ⌚❤️ ✔ from origin 🐣❤️ thru interim 🐣❤️ to dest ⌚❤️ ✔ from origin 🐣❤️ thru interim ⌚❤️ to dest ⌚❤️ with self removed from destination ✔ from self inserted to origin ⌚❤️ thru interim ⌚☠️ to dest ⌚☠️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣☠️ to dest ⌚☠️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣❤️ to dest ⌚☠️ ✔ from self inserted to origin ⌚❤️ thru interim ⌚❤️ to dest ⌚☠️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚☠️ to dest ⌚☠️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣☠️ to dest ⌚☠️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣❤️ to dest ⌚☠️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚❤️ to dest ⌚☠️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚☠️ to dest ⌚☠️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣☠️ to dest ⌚☠️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣❤️ to dest ⌚☠️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚❤️ to dest ⌚☠️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚☠️ to dest ⌚☠️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣☠️ to dest ⌚☠️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣❤️ to dest ⌚☠️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚❤️ to dest ⌚☠️ ✔ from self inserted to origin ⌚❤️ thru interim ⌚☠️ to dest 🐣☠️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣☠️ to dest 🐣☠️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣❤️ to dest 🐣☠️ ✔ from self inserted to origin ⌚❤️ thru interim ⌚❤️ to dest 🐣☠️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚☠️ to dest 🐣☠️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣☠️ to dest 🐣☠️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣❤️ to dest 🐣☠️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚❤️ to dest 🐣☠️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚☠️ to dest 🐣☠️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣☠️ to dest 🐣☠️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣❤️ to dest 🐣☠️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚❤️ to dest 🐣☠️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚☠️ to dest 🐣☠️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣☠️ to dest 🐣☠️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣❤️ to dest 🐣☠️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚❤️ to dest 🐣☠️ ✔ from self inserted to origin ⌚❤️ thru interim ⌚☠️ to dest 🐣❤️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣☠️ to dest 🐣❤️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣❤️ to dest 🐣❤️ ✔ from self inserted to origin ⌚❤️ thru interim ⌚❤️ to dest 🐣❤️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚☠️ to dest 🐣❤️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣☠️ to dest 🐣❤️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣❤️ to dest 🐣❤️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚❤️ to dest 🐣❤️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚☠️ to dest 🐣❤️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣☠️ to dest 🐣❤️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣❤️ to dest 🐣❤️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚❤️ to dest 🐣❤️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚☠️ to dest 🐣❤️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣☠️ to dest 🐣❤️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣❤️ to dest 🐣❤️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚❤️ to dest 🐣❤️ ✔ from self inserted to origin ⌚❤️ thru interim ⌚☠️ to dest ⌚❤️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣☠️ to dest ⌚❤️ ✔ from self inserted to origin ⌚❤️ thru interim 🐣❤️ to dest ⌚❤️ ✔ from self inserted to origin ⌚❤️ thru interim ⌚❤️ to dest ⌚❤️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚☠️ to dest ⌚❤️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣☠️ to dest ⌚❤️ ✔ from self inserted to origin ⌚☠️ thru interim 🐣❤️ to dest ⌚❤️ ✔ from self inserted to origin ⌚☠️ thru interim ⌚❤️ to dest ⌚❤️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚☠️ to dest ⌚❤️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣☠️ to dest ⌚❤️ ✔ from self inserted to origin 🐣☠️ thru interim 🐣❤️ to dest ⌚❤️ ✔ from self inserted to origin 🐣☠️ thru interim ⌚❤️ to dest ⌚❤️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚☠️ to dest ⌚❤️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣☠️ to dest ⌚❤️ ✔ from self inserted to origin 🐣❤️ thru interim 🐣❤️ to dest ⌚❤️ ✔ from self inserted to origin 🐣❤️ thru interim ⌚❤️ to dest ⌚❤️ ✔ from origin 🐣☠️ thru interim ⌚☠️ to dest ⌚☠️ ✔ from origin 🐣☠️ thru interim 🐣☠️ to dest ⌚☠️ ✔ from origin 🐣☠️ thru interim 🐣❤️ to dest ⌚☠️ ✔ from origin 🐣☠️ thru interim ⌚❤️ to dest ⌚☠️ ✔ from origin 🐣❤️ thru interim ⌚☠️ to dest ⌚☠️ ✔ from origin 🐣❤️ thru interim 🐣☠️ to dest ⌚☠️ ✔ from origin 🐣❤️ thru interim 🐣❤️ to dest ⌚☠️ ✔ from origin 🐣❤️ thru interim ⌚❤️ to dest ⌚☠️ ✔ from origin 🐣☠️ thru interim ⌚☠️ to dest 🐣☠️ ✔ from origin 🐣☠️ thru interim 🐣☠️ to dest 🐣☠️ ✔ from origin 🐣☠️ thru interim 🐣❤️ to dest 🐣☠️ ✔ from origin 🐣☠️ thru interim ⌚❤️ to dest 🐣☠️ ✔ from origin 🐣❤️ thru interim ⌚☠️ to dest 🐣☠️ ✔ from origin 🐣❤️ thru interim 🐣☠️ to dest 🐣☠️ ✔ from origin 🐣❤️ thru interim 🐣❤️ to dest 🐣☠️ ✔ from origin 🐣❤️ thru interim ⌚❤️ to dest 🐣☠️ ✔ from origin 🐣☠️ thru interim ⌚☠️ to dest 🐣❤️ ✔ from origin 🐣☠️ thru interim 🐣☠️ to dest 🐣❤️ ✔ from origin 🐣☠️ thru interim 🐣❤️ to dest 🐣❤️ ✔ from origin 🐣☠️ thru interim ⌚❤️ to dest 🐣❤️ ✔ from origin 🐣❤️ thru interim ⌚☠️ to dest 🐣❤️ ✔ from origin 🐣❤️ thru interim 🐣☠️ to dest 🐣❤️ ✔ from origin 🐣❤️ thru interim 🐣❤️ to dest 🐣❤️ ✔ from origin 🐣❤️ thru interim ⌚❤️ to dest 🐣❤️ ✔ from origin 🐣☠️ thru interim ⌚☠️ to dest ⌚❤️ ✔ from origin 🐣☠️ thru interim 🐣☠️ to dest ⌚❤️ ✔ from origin 🐣☠️ thru interim 🐣❤️ to dest ⌚❤️ ✔ from origin 🐣☠️ thru interim ⌚❤️ to dest ⌚❤️ ✔ from origin 🐣❤️ thru interim ⌚☠️ to dest ⌚❤️ ✔ from origin 🐣❤️ thru interim 🐣☠️ to dest ⌚❤️ ✔ from origin 🐣❤️ thru interim 🐣❤️ to dest ⌚❤️ ✔ from origin 🐣❤️ thru interim ⌚❤️ to dest ⌚❤️ removes extraneous data from the squashed changes (expected to fail until minimize is implemented) - keeps the surviving box's build when boxes are inserted and one moved to sibling that is then removed - keeps the surviving box's build when boxes are inserted and one moved to sibling when the original parent is then removed - keeps the surviving box's build when boxes are inserted in a new pallet and one moved to sibling when the new pallet is then removed - carries no build when a box is moved into a new pallet that is then removed ```github.com-microsoft-FluidFramework · f9f20072 · 2026-07-25