feat(tree): add SchemaFactoryAlpha.stagedOptional for incremental required→optional field migration#26918
Merged
noencke merged 26 commits intomicrosoft:mainfrom Apr 13, 2026
Merged
Conversation
…uired→optional field migration Adds `SchemaFactoryAlpha.stagedOptional(T)` to enable migrating a required field to optional across multiple deployments without breaking cross-version collaboration. - Required field stays in the stored schema during the rollout period, so old clients are unaffected - New clients using `stagedOptional` see the field as Optional in the view (TypeScript type is `T | undefined`) - Writing `undefined` is blocked at runtime until the stored schema is upgraded to Optional - Migrating to `sf.optional(T)` upgrades the stored schema and enables clearing the field Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new “staged optional” field pattern to the SharedTree Simple Tree alpha schema API to support incremental required → optional migrations without coordinated deployments, by keeping the stored schema required during rollout while exposing optionality in the view schema.
Changes:
- Introduces
SchemaFactoryAlpha.stagedOptional(...)(and supporting plumbing) to represent “optional-in-view, required-in-stored (until fully upgraded)” fields. - Extends stored-schema generation options with
includeStagedOptional(...)and updates view→stored transformation / discrepancy logic to account for staged optional compatibility. - Adds end-to-end and compatibility tests covering the A(required) → B(staged optional) → C(optional) rollout path and unhydrated construction behavior.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts | Adds the stagedOptional schema factory API (static + instance) and docs. |
| packages/dds/tree/src/simple-tree/fieldSchema.ts | Plumbs a staged-optional marker through field props and exposes it via FieldSchemaAlpha.isOptionalStaged. |
| packages/dds/tree/src/simple-tree/simpleSchema.ts | Extends SimpleFieldSchema with isOptionalStaged marker metadata. |
| packages/dds/tree/src/simple-tree/core/toStored.ts | Adds includeStagedOptional to StoredFromViewSchemaGenerationOptions. |
| packages/dds/tree/src/simple-tree/toStoredSchema.ts | Threads includeStagedOptional through restrictive/permissive options and adjusts view→stored conversion to potentially force Required kind for staged optional. |
| packages/dds/tree/src/simple-tree/api/discrepancies.ts | Suppresses kind mismatch when viewing Required stored fields with staged-optional view fields. |
| packages/dds/tree/src/simple-tree/api/storedSchema.ts | Ensures persisted schema extraction does not include staged optional as optional in stored schema. |
| packages/dds/tree/src/test/simple-tree/api/stagedSchemaUpgrade.spec.ts | Adds migration-path tests (user API + compatibility tester + unhydrated construction). |
| packages/dds/tree/src/test/simple-tree/toStoredSchema.spec.ts | Updates tests for new stored-schema generation option shape. |
| packages/dds/tree/src/test/testTrees.ts | Updates test document schema generation options to include includeStagedOptional. |
| packages/dds/tree/api-report/tree.alpha.api.md | Updates alpha API report for new API surface. |
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…clarify docs - filterFieldAllowedTypes now preserves the isOptionalStaged SchemaUpgrade marker when using the Unchanged (view-copy) path, so getSimpleSchema output retains staged optional information. - Clarify SimpleFieldSchema.isOptionalStaged doc comment: false = view, not staged; absent = derived from stored schema. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This reverts commit 2793d4d.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…ce ambiguity SchemaFactoryAlpha.stagedOptional has both a static and instance declaration, making it ambiguous for TSDoc links. Link to SchemaStaticsAlpha.stagedOptional instead, which is unambiguous (interface member). Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…dering SchemaFactoryAlpha.stagedOptional (instance and static) landed with "stagedOptionalUpgrade" | "defaultProvider" while SchemaStaticsAlpha had "defaultProvider" | "stagedOptionalUpgrade". CI compiles fresh TypeScript and produces alphabetical order for both. Align the class members to match. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
noencke
commented
Apr 2, 2026
…Optional to includeStaged Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
jenn-le
reviewed
Apr 2, 2026
packages/dds/tree/src/test/simple-tree/api/stagedSchemaUpgrade.spec.ts
Outdated
Show resolved
Hide resolved
- Rename isOptionalStaged → isStagedOptional to match the stagedOptional factory naming - Fix comment capitalization in discrepancies.ts (optional/required not capitalized) - Rename describe block to "staged allowed type upgrade" (was "staged schema upgrade") - Expand JSDoc on isStagedOptional to explain why false and undefined are distinct Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
undefined for isStagedOptional only means "stored schema" — view schemas are always constructed by the current in-memory package, so there is no "legacy view field" scenario. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
jenn-le
approved these changes
Apr 6, 2026
Josmithr
reviewed
Apr 9, 2026
Josmithr
reviewed
Apr 9, 2026
Josmithr
reviewed
Apr 9, 2026
Josmithr
reviewed
Apr 9, 2026
Josmithr
reviewed
Apr 9, 2026
Josmithr
reviewed
Apr 9, 2026
Josmithr
reviewed
Apr 9, 2026
# Conflicts: # packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts
38d79aa to
4fb38db
Compare
- Remove inline code backticks from changeset title per repo guidelines - Clarify changeset description to lead with required→optional migration - Fix JSDoc in schemaFactoryAlpha.ts step 3 wording (Josh's suggestion) - Reword isStagedOptional JSDoc to "Indicates that..." instead of reading as an action Co-Authored-By: Claude Opus 4.6 <[email protected]>
Aligns with how AllowedTypeMetadata.stagedSchemaUpgrade is documented — no restriction on setting the property by hand. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Swap Omit union member order from "stagedOptionalUpgrade" | "defaultProvider" to "defaultProvider" | "stagedOptionalUpgrade" to match CI's api-extractor output. Co-Authored-By: Claude Opus 4.6 <[email protected]>
The @System tag was removed from the source code but the API report files were not regenerated to match. Co-Authored-By: Claude Opus 4.6 <[email protected]>
The previous ordering fix incorrectly changed all Omit union orderings to "defaultProvider" | "stagedOptionalUpgrade". CI generates different orderings for class members vs interface members: - SchemaFactoryAlpha (class): "stagedOptionalUpgrade" | "defaultProvider" - SchemaStaticsAlpha (interface): "defaultProvider" | "stagedOptionalUpgrade" Reverts the class member ordering to match what CI actually produces, verified against the last passing CI build. Co-Authored-By: Claude Opus 4.6 <[email protected]>
After merging main, api-extractor no longer needs the _2 suffix to disambiguate ITree in the fluid-framework re-export package. Updated configuredSharedTree and SharedTree return types accordingly. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
jenn-le
approved these changes
Apr 13, 2026
# Conflicts: # packages/dds/tree/api-report/tree.alpha.api.md # packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md
jenn-le
approved these changes
Apr 13, 2026
Contributor
|
🔗 No broken links found! ✅ Your attention to detail is admirable. linkcheck output |
Josmithr
approved these changes
Apr 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
SchemaFactoryAlpha.stagedOptional(T)to enable incremental migration of required fields to optional fields without a coordinated deploymentT | undefined) but the stored schema stays Required, so old clients are unaffected and writingundefinedis blocked at runtimeSchemaStaticsBeta.staged(T)pattern for allowed types, but for field optionalityMigration path:
sf.required(T)→sf.stagedOptional(T)→sf.optional(T)