Skip to content

feat(tree): add SchemaFactoryAlpha.stagedOptional for incremental required→optional field migration#26918

Merged
noencke merged 26 commits intomicrosoft:mainfrom
noencke:noencke/staged-optional
Apr 13, 2026
Merged

feat(tree): add SchemaFactoryAlpha.stagedOptional for incremental required→optional field migration#26918
noencke merged 26 commits intomicrosoft:mainfrom
noencke:noencke/staged-optional

Conversation

@noencke
Copy link
Copy Markdown
Contributor

@noencke noencke commented Apr 1, 2026

Summary

  • Adds SchemaFactoryAlpha.stagedOptional(T) to enable incremental migration of required fields to optional fields without a coordinated deployment
  • During the staged rollout period, the field is Optional in the view schema (TypeScript type T | undefined) but the stored schema stays Required, so old clients are unaffected and writing undefined is blocked at runtime
  • Mirrors the existing SchemaStaticsBeta.staged(T) pattern for allowed types, but for field optionality

Migration path: sf.required(T)sf.stagedOptional(T)sf.optional(T)

…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]>
@noencke noencke requested a review from a team as a code owner April 1, 2026 19:52
Copilot AI review requested due to automatic review settings April 1, 2026 19:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

noencke and others added 9 commits April 1, 2026 20:14
…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]>
…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]>
@noencke noencke requested a review from jenn-le April 2, 2026 18:45
noencke and others added 2 commits April 2, 2026 19:16
…Optional to includeStaged

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
noencke and others added 2 commits April 3, 2026 04:09
- 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]>
@noencke noencke requested a review from a team as a code owner April 3, 2026 04:10
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]>
@noencke noencke requested a review from a team as a code owner April 3, 2026 15:36
# Conflicts:
#	packages/dds/tree/src/simple-tree/api/schemaFactoryAlpha.ts
@noencke noencke force-pushed the noencke/staged-optional branch from 38d79aa to 4fb38db Compare April 10, 2026 16:39
noencke and others added 8 commits April 10, 2026 16:52
- 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]>
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]>
noencke added 2 commits April 13, 2026 20:43
# Conflicts:
#	packages/dds/tree/api-report/tree.alpha.api.md
#	packages/framework/fluid-framework/api-report/fluid-framework.alpha.api.md
@github-actions
Copy link
Copy Markdown
Contributor

🔗 No broken links found! ✅

Your attention to detail is admirable.

linkcheck output


> [email protected] ci:check-links /home/runner/work/FluidFramework/FluidFramework/docs
> start-server-and-test "npm run serve -- --no-open" 3000 check-links

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"


> [email protected] serve
> docusaurus serve --no-open

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

> [email protected] check-links
> linkcheck http://localhost:3000 --skip-file skipped-urls.txt

Crawling...

Stats:
  279037 links
    1880 destination URLs
    2126 URLs ignored
       0 warnings
       0 errors


@noencke noencke merged commit fb808eb into microsoft:main Apr 13, 2026
35 checks passed
@noencke noencke deleted the noencke/staged-optional branch April 13, 2026 21:52
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.

4 participants