Craig Macomber (Microsoft)
90d · built 2026-08-09
90-day totals
- Commits
- 95
- Grow
- 4.4
- Maintenance
- 7.0
- Fixes
- 1.6
- Total ETV
- 13
Where this dev ranks
Percentile against the global top-100 leaderboard (all-time totals).
- By commits
- Top 44 %
- By Growth share
- Top 85 %
30-day trajectory
Last 30 days vs. the 30 days before. Up arrows on Growth and ETV mean improvement; up arrow on Fixes share means more time on fixes (worse).
↓-3.1 %
vs 32 prior
↑+49.1 pp
recent vs prior
↑+10.0 pp
recent vs prior
Daily performance
Daily ETV, stacked by Growth, Maintenance and Fixes.
Work-mix over time
Share of Growth / Maintenance / Fixes over a rolling 7-day window. Reads as 'where is effort flowing right now'.
Repository spread
Where this developer's commits land. Concentrated work (top1 > 80%) vs polymath spread (top1 < 30%).
| Repo | Commits | ETV |
|---|---|---|
| FluidFramework | 71 | 13.0 |
Most impactful commits
Top 20 by ETV in the 90-day window.
- 2.4ETVIntroduce Unified ServiceClient API for Fluid Client (#27693) ## Description This add a simple API as a cleaner alternative to fluid-static and aquaduct. The implementation details are well encapsulated, making this a viable alternative to the `fluid-static` public API and a viable successor to the existing much larger legacy API surface we do not want to stabilize. This addresses several issues with our existing APIs: 1. non-legacy (fluid-static declarative model) API: 1. No stable way to use local service for testing (Internally or for customers). Forces tests to use alternative patterns (like test-utils, mocks etc. or a separate azure local service process). 2. No way to avoid bundling in SharedDirectory. 3. Defining and using DataStores is not well supported, especially for the root. 4. Dependency layering is such that its disallowed for DDS packages to use the public API surfaces to do collab tests. 5. No abstraction for Services / ServiceClient makes logic portable over services harder to write. 6. Doesn't support lazy loading DDS and DataStore code (at least not clearly/cleanly). 7. No migration path from legacy APIs to this 3. legacy (encapsulated model, including aquaduct): 1. Leak way too many details with too many non-sealed interfaces presenting tons of theoretical extension points we don't want to stabilize. 2. Encourages use of DataObject and its subclassing based extension approach which is limiting (Like how it makes switching to root trees) hard, and makes changing the implementation without introducing breaking changes very difficult. Because this new "unified" API offers value for our own internal testing (for example in tree), it is useful, even as alpha (or internal). Exposing this new API as alpha should be low risk, as it makes no long-term commitments. Since we have first party in-repo use cases, it should be practical to refine and iterate on this API with use in test and examples before we consider promoting it to beta. Requirements for this new API: 1. Testing: 2. Can easily be used for tests including collab and reopening documents. 3. Can be used by DDS (like shared-tree) tests replacing the need for many of our mocks and test utils 4. Can be used by customers (apps and libraries requiring stable APIs when promoted past alpha). When adopted, customers should not have need of any of our legacy test-utils and mocks (so we can migrate our legacy apps off of our test utils and eventually make them internal only). 5. Will be possible to stabilize to public (or at least beta) without depending on or stabilizing legacy APIs. 6. Is easy to use for tests, including collab. 7. Is easy to use for real production apps (should work the same as with tests). 8. Provides a clear and practical incremental migration path from both existing APIs: there can be gaps we need to close for some use-cases but those gaps need to be practical to close.github.com-microsoft-FluidFramework · ee47192d · 2026-07-28
- 1.9ETVFactor out tree identifier compression and healing utils (#27367) ## Description Factor out tree identifier compression and healing utils. Remove the originator id (which is incorrect) that is passed down into the field batch codec, factoring the encode and decode codecs into different types which only take in exactly what they should have. This intentionally changes `IIdCompressor` from `@public` to `@public @sealed`. While in some ways this is a breaking change, custom implementations of `IIdCompressor` didn't actually work due to us already having code which assumes they are our implementation and down casts them. Therefor adding `@sealed` is more of a bug fix than a break.github.com-microsoft-FluidFramework · 4af40944 · 2026-06-25
- 1.3ETVfeat(tree): add alpha Component utilities for open-polymorphic schema (#27628) ## Description Promotes the `Component` composition namespace out of the `openPolymorphism.integration.ts` test file and into `@fluidframework/tree` as a new `@alpha` API (also re-exported from `fluid-framework`). This pattern was previously validated only by the open-polymorphism examples; it's now a supported (alpha) part of the package because an app depends on it. `Component` provides utilities for composing independently authored application "components" that contribute to a shared configuration — useful for "open polymorphism" schema patterns where the set of allowed types for a field or collection can be extended by separate libraries. Each component is a `Component.Factory` that receives a lazy reference to the composed configuration and returns the content it contributes; `Component.composeComponents` combines them into a `Component.ComposedComponents`. Changes: - New `packages/dds/tree/src/simple-tree/api/componentApi.ts` with the `@alpha`-tagged, fully documented `Component` namespace, exporting only what's needed (`Factory`, `LazyArray`, `Configurable`, `composeComponents`, `ComposedComponents`); the `Config` implementation class stays internal. - Exported from `@fluidframework/tree` and (via the alpha entrypoint) `fluid-framework`; API reports updated. - The integration test now imports `Component` instead of defining it locally. - New focused unit tests in `componentApi.spec.ts` supplementing the existing example/integration tests. - Fixed a latent caching bug in `getConfigured` (it previously ran `configure` on every call; now cached via `getOrCreate`). - Changeset added.github.com-microsoft-FluidFramework · 7a56d096 · 2026-07-09
- 0.8ETVFix version utils to get the versions it tries from the set it has installed (#27521) ## Description Avoid trying to test client package versions looked up in the npm registry: instead consult the manifest of versions we have installed locally. This prevents the act of publishing a new package from breaking tests which test against recent versions (using the N-1 style conventions).github.com-microsoft-FluidFramework · 7bf79128 · 2026-06-09
- 0.6ETVInclude final retain in tree deltas (#27809) ## Description Previously our array node deltas were not required to include the final retain. This is now always included. Additionally handling of the extra new line required to make quill more robust, fixing a bug where remote collaborators could end up with extra new lines.github.com-microsoft-FluidFramework · 6af2aba0 · 2026-08-04
- 0.4ETVAdd simpler way to use Component (#27664) ## Description Add overload and default parameters to easy simple case use of Component APIgithub.com-microsoft-FluidFramework · 393ccf34 · 2026-07-15
- 0.4ETVrefactor(tree): split encode/decode contexts for change and field codecs (#27758) ## Description Part of a set of changes for giving SharedTree's change codecs distinct encode-side and decode-side context types. Pure type-level refactor — **no runtime behavior change** — scoped to the change/field codecs. ### What changed 1. **Distinct decode contexts.** Add `ChangeDecodingContext` and `FieldChangeDecodingContext`, and thread `TDecodeContext` through the change/field codec family declarations (`ChangeFamily.codecs`, `ChangeFamilyCodec`, `FieldChangeHandler.codecsFactory`, the sequence/optional/generic field families, modular change, and shared-tree-change families). The codec infrastructure already supported a separate `TDecodeContext` defaulting to `TEncodeContext`, so this is mostly plumbing. 2. **Drop `schema` from `ChangeDecodingContext`** (`Omit<ChangeEncodingContext, "schema">`): it's only used for schema-aware compression on encode. 3. **Split `FieldChangeEncodingContext`/`FieldChangeDecodingContext`** into `encodeNode`-only and `decodeNode`-only interfaces, removing the `fail(...)` stubs `modularChangeCodecV1` previously used to guard against misuse. `ChangeEncodingContext` keeps `healing`/`originatorId` for now because the EditManager/Message codecs still use one context type for both directions; splitting those (and dropping the decode-only fields) is a follow-up. ### Tests - Round-trip contexts typed as `FieldChangeEncodingContext & FieldChangeDecodingContext`; encode-only snapshot contexts drop the unused `decodeNode`. - `makeEncodingTestSuite`/`registerValidationHook` generalized to accept split encode/decode contexts (backward-compatible via `TDecodeContext = TEncodeContext`).github.com-microsoft-FluidFramework · 04aa59d7 · 2026-07-28
- 0.4ETVMisc Formatted Text work (#27770) ## Description Misc work before we want to take text to alpha. 1. Disable expensive asserts outside of text tests. 2. Use javascript private properties where APIs could collide with user subclass properties. 3. Note risk of name coillision for properties of erased types 4. add reformat API 5. Clarify formatRange API with docs and tests. 6. Fill in some lacking docsgithub.com-microsoft-FluidFramework · 6cb32455 · 2026-07-28
- 0.2ETVMake FormattedTextAsTree generic, moving special case to FormattedTextAsTreeDefault (#27609) ## Description Make FormattedTextAsTree generic, moving special case to FormattedTextAsTreeDefault.github.com-microsoft-FluidFramework · 0c5bc752 · 2026-06-30
- 0.2ETVFactor out concrete IdDecodingContext (#27626) ## Description Factor out IdDecodingContext, better encapsulating the ID specific logic and make it possible to reuse in other contexts.github.com-microsoft-FluidFramework · f2fee7f9 · 2026-07-07
- 0.2ETVMake internals of formatted text schema generic (#27596) ## Description Refactor internal formatted text implementation do use a generic schema generator function. This is refactor to get us closer to having support for formatted text with arbitrary user provided format types and embedded object types.github.com-microsoft-FluidFramework · 555a12ce · 2026-06-26
- 0.2ETVrefactor(tree): Compose IdDecodingContext in FieldBatchDecodingContext (#27790) ## Description Refactors `FieldBatchDecodingContext` to **compose** an `IdDecodingContext` (as a public `idDecodingContext` field) instead of **subclassing** it. Previously `FieldBatchDecodingContext extends IdDecodingContext`, so the decode context was passed directly wherever an `IdDecodingContext` was expected. That coupling only mattered at a single boundary (the field-batch codec's `decode`), while the generic `DecoderContext` already composed an `idDecodingContext` separately. Subclassing also meant that reusing an existing `IdDecodingContext` to build a `FieldBatchDecodingContext` would have required copy-constructing the base context. With composition: - `FieldBatchDecodingContext` holds `idDecodingContext` and `incrementalDecoder`; it is no longer an `IdDecodingContext`. - The codec decode boundary passes `context.idDecodingContext` to `decode(...)`. - `IdDecodingContext.hasOriginatorSessionId` is now `public` (consulted by `withIncrementalDecoder`, which previously relied on protected subclass access). - A handful of tests that abused the subclassing to use a `FieldBatchDecodingContext` where an `IdDecodingContext` was wanted now construct an `IdDecodingContext` directly. This is a pure internal refactor with no runtime, wire-format, or public-API change. It unblocks upcoming adoption of `IdDecodingContext` in the change codecs, where an existing `IdDecodingContext` can be reused to build a `FieldBatchDecodingContext` without copying.github.com-microsoft-FluidFramework · e8e5a033 · 2026-08-03
- 0.2ETVRename ClientVersionDispatchingCodecBuilder to VersionDispatchingCodecBuilder (#27328) ## Description Rename ClientVersionDispatchingCodecBuilder to VersionDispatchingCodecBuilder (mostly to have a shorter name) and related cleanup.github.com-microsoft-FluidFramework · d2a46d23 · 2026-05-19
- 0.2ETVBetter output for flub package commands (#27635) ## Description Output from flub package commands was a mess. In at least the cases I tested (mainly errors) I have confirmed this to be much better. \github.com-microsoft-FluidFramework · 63280ff3 · 2026-07-06
- 0.2ETVType erase the details of StringTextAtom to prevent implicit construction with invalid strings (#27807) ## Description Type erase the details of StringTextAtom to prevent implicit construction with invalid strings. This also erases its schema from the API, making schema evolution practical and property key renames non-breaking. ## Breaking Changes These are all internal, so no changeset, and should not break any apps: 1. Users of StringTextAtomNode's constructor have to move to the static factories. 2. Users of instanceof can use Tree.is instead. 3. Users modifiying the content of a StringTextAtom must repalce the whole node now.github.com-microsoft-FluidFramework · f872d5db · 2026-07-31
- 0.2ETVfeat(tree): emit telemetry when healing unresolvable identifiers on decode (#27756) ## Description When `SharedTreeOptionsBeta.healUnresolvableIdentifiersOnDecode` is enabled, SharedTree now records a `HealUnresolvableIdentifierOnDecode` telemetry event (at `LogLevel.info`) each time a non-final identifier is healed while loading a summary. This lets applications relying on the healing workaround observe which documents actually required healing. This is a follow-up to the identifier-healing work: the heal and throw paths only exist because of a prior bug where non-finalized identifiers could be written into summaries. Instrumenting the recovery path makes those occurrences visible in the wild. The error/throw path is intentionally left un-instrumented — the thrown exception already surfaces via the application's own error telemetry and must not be silently swallowed. Changes: - Add an optional `logger` to the internal `IdentifierHealingConfig`; `forceDecodeEncodedIdWithoutSession` sends the event directly via `logger?.send(..., LogLevel.essential)`. - Thread the shared object's logger into the healing config in `SharedTreeKernel` and `SharedTreeCore`. - Document the telemetry event and level on `healUnresolvableIdentifiersOnDecode`. - Add unit tests and a changeset. Because it changes observable behavior for consumers who opted into the healing feature (they now get telemetry), this ships with a changeset.github.com-microsoft-FluidFramework · e5ada10f · 2026-08-05
- 0.2ETVAdd and use ServiceClient.createAttachedContainer (#27789) ## Description Adopt ServiceClient for a couple tests, and add ServiceClient.createAttachedContainer to help out ergonomics of using ServiceClient for common patterns.github.com-microsoft-FluidFramework · 1671447b · 2026-08-05
- 0.2ETVMake Breakable.run special case promises (#27275) ## Description Async methods, like runTransaction, now will break the brekable object if they reject the promise, and will fail if broken while they were running.github.com-microsoft-FluidFramework · 823c1d88 · 2026-05-14
- 0.2ETVCleanup FormattedTextAsTree API surface a bit (#27781) ## Description Cleanup FormattedTextAsTreeDefault API surface a bit, preparing for promotion to alpha. This mostly just combines FormattedTextMembers and Members, and adds the missing optional format parameter to Statics.fromString. Additionally includes some better API tagging, comments minor tweaks.github.com-microsoft-FluidFramework · 45edd3b8 · 2026-07-29
- 0.2ETVfeat(tree): better formatted text insertion APIs (#27800) ## Description Remove `defaultFormat` property from FormattedTextAsTree.Members. Extend `insertAt` so it can insert either strings or typed text atoms with optional formatting. ## Breaking Changes APIs are internal only (so no changeset). Callers using `FormattedTextAsTree.Members.defaultFormat` must pass formatting directly to `insertAt` or `reformat`. References to `FormattedTextAtoms` must use `TextAtomSchemas`.github.com-microsoft-FluidFramework · 0cf4fb38 · 2026-07-31