feat(container-runtime): expose versionMarkResolver on IContainerRuntime - #28168
feat(container-runtime): expose versionMarkResolver on IContainerRuntime#28168lindsnguyen wants to merge 3 commits into
Conversation
|
Hi! Thank you for opening this PR. Want me to review it? Based on the diff (398 lines, 14 files), I've queued these reviewers:
How this works
|
There was a problem hiding this comment.
🟡 Changes recommended
@fluidframework/container-runtime currently re-exports the version-mark types from @fluidframework/container-runtime-definitions/internal, which conflicts with the stated intent to re-export from /legacy and may leak an internal module specifier into the public .d.ts surface.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR graduates the version mark resolver to a supported host-facing access point by adding versionMarkResolver to the @legacy @beta IContainerRuntime interface, moving the related public types into @fluidframework/container-runtime-definitions, and extending ResolveResult with an optional diagnostic reason?: string for pending/unresolvable.
Changes:
- Move
IVersionMarkResolver,ResolveResult, andVersionMarkCaptureinto@fluidframework/container-runtime-definitionsand export them from the package entrypoint. - Add
versionMarkResolver: IVersionMarkResolvertoIContainerRuntimeso hosts no longer need to cast toContainerRuntime. - Add an optional
reason?: stringtoResolveResult’spending/unresolvableoutcomes and update runtime + tests/docs accordingly.
File summaries
| File | Description |
|---|---|
| packages/runtime/container-runtime/src/versionMarks/versionMarkResolver.ts | Switches to imported shared public types and adds reason when returning pending/unresolvable. |
| packages/runtime/container-runtime/src/versionMarks/index.ts | Re-exports version mark public types from container-runtime-definitions and continues exporting the implementation. |
| packages/runtime/container-runtime/src/versionMarks/DEV.md | Updates design notes to document the reason?: string policy and improves formatting. |
| packages/runtime/container-runtime/src/test/versionMarks/versionMarkResolver.spec.ts | Updates expected ResolveResult shapes to include reason where applicable. |
| packages/runtime/container-runtime/src/test/containerRuntime.spec.ts | Updates the loader-compat regression test to expect reason: "historicalOpsUnavailable". |
| packages/runtime/container-runtime/api-report/container-runtime.legacy.beta.api.md | Updates legacy beta API report for ResolveResult.reason?: string. |
| packages/runtime/container-runtime/api-report/container-runtime.legacy.alpha.api.md | Updates legacy alpha API report for ResolveResult.reason?: string. |
| packages/runtime/container-runtime-definitions/src/versionMarks.ts | Introduces the new shared @legacy @beta version mark API types and docs. |
| packages/runtime/container-runtime-definitions/src/test/types/validateContainerRuntimeDefinitionsPrevious.generated.ts | Updates type-test baseline to acknowledge expected forward-compat break for the deprecated interface. |
| packages/runtime/container-runtime-definitions/src/index.ts | Re-exports the new version mark types from the package root. |
| packages/runtime/container-runtime-definitions/src/containerRuntime.ts | Adds versionMarkResolver to IContainerRuntime. |
| packages/runtime/container-runtime-definitions/package.json | Marks the known forward-compat break for the deprecated interface in typeValidation.broken. |
| packages/runtime/container-runtime-definitions/api-report/container-runtime-definitions.legacy.beta.api.md | Adds the new IVersionMarkResolver/ResolveResult/VersionMarkCapture exports and IContainerRuntime.versionMarkResolver. |
| .changeset/version-mark-resolver-access-point.md | Adds changeset for the API surface move and ResolveResult.reason. |
Review details
- Files reviewed: 14/14 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Deep Review: The diagnostic Consequence: the runtime never logs why a mark did not resolve — every host must forward the field itself. The value is low-cardinality and PII-free, so add it to the payload under the same "diagnostic-only, unstable, log-only" rule already applied to the returned field, and update the shape assertion in the spec. If the omission is intentional (cardinality/PII), document it as a non-goal instead — and state the supported way for the runtime, not each host, to log the non-resolution cause. |
|
Deep Review: This PR adds Rewrite the "Host exposure" paragraph (lines 92-95) to state the resolver is now exposed on the |
Daniel Madrid (dannimad)
left a comment
There was a problem hiding this comment.
Do not merge until bump PR is merged first
Move the version mark resolver public types (IVersionMarkResolver, ResolveResult, VersionMarkCapture) into container-runtime-definitions and expose `versionMarkResolver` on the `@legacy @beta` IContainerRuntime interface, so hosts obtain the resolver from a supported interface rather than the concrete `@internal` ContainerRuntime class. container-runtime re-exports the types for back-compat; its API surface is unchanged.
…nding/unresolvable ResolveResult - `reason` is an opaque, log-only diagnostic string, not a typed union. The runtime currently sets `awaitingSequence` / `historicalOpsUnavailable` on `pending` and `historyTrimmed` on `unresolvable`. - Hosts drive all behavior from `kind` and must not branch on `reason`. A plain string keeps additions non-breaking and avoids a second de facto discriminator; a future state needing different behavior should be a new `kind`, not a new `reason`. - `reason` is transient operational context, not persisted. office-bohemia will log it when moving to the supported access point but makes no behavioral change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
42ca62f to
dd89cdc
Compare
|
🔗 No broken links found! ✅ Your attention to detail is admirable. linkcheck output |
| * Copyright (c) Microsoft Corporation and contributors. All rights reserved. | ||
| * Licensed under the MIT License. | ||
| */ | ||
|
|
There was a problem hiding this comment.
Should these types be @sealed?
There was a problem hiding this comment.
Deep Review: Good question. IVersionMarkResolver should be @sealed. It's runtime-owned ("Runtime-owned resolver for app-stored version mark locators") and implemented only by Fluid. The same forward-compat argument this PR relies on for adding a required member to the @sealed IContainerRuntime applies here: without @sealed, a future member addition to IVersionMarkResolver would be a forward-compat break for any host implementer/deriver, whereas @sealed documents that only Fluid implements it. Adding it and regenerating the api-reports is the safe, consistent call.
For ResolveResult and VersionMarkCapture, @sealed doesn't apply the same way — they're type-alias unions, not interfaces, so there's no implementer to seal against.
One thing to confirm: if hosts are only ever expected to consume IVersionMarkResolver (never implement it), seal it; if some host implementation is intended, that changes the call — worth stating either way.
| --- | ||
| Expose the version mark resolver on IContainerRuntime | ||
|
|
||
| `IContainerRuntime` now exposes `versionMarkResolver: IVersionMarkResolver`, the supported access point for the version mark resolver APIs (`IVersionMarkResolver`, `ResolveResult`, `VersionMarkCapture`), which move to `@fluidframework/container-runtime-definitions`. Hosts obtain the resolver from the runtime instead of the concrete `ContainerRuntime` class. |
There was a problem hiding this comment.
Nit: can we link to the API docs for the existing APIs here?
Joshua Smithrud (Josmithr)
left a comment
There was a problem hiding this comment.
Approving docs changes. I didn't review the code or API changes in much detail (I see that Tony has already been reviewing those).
Deep ReviewReviewed commit Readiness: 9/10 — ALMOST READY Ready for human review — no blocking defects. This completes the planned graduation of the version-mark resolver onto the Path to Ready
Context for Reviewers
For human reviewer
Review history (1 prior review)
|
Bundle size comparisonBase commit: Pending — |
Description
Expose the version mark resolver as a supported access point on the
@legacy @betaIContainerRuntimeinterface, so hosts obtain it from a supported interface instead ofcasting to the concrete
@internalContainerRuntimeclass. Fixes AB#82258.IVersionMarkResolver,ResolveResult,VersionMarkCapture) into@fluidframework/container-runtime-definitionsand addsversionMarkResolver: IVersionMarkResolvertoIContainerRuntime.@fluidframework/container-runtimere-exports the types (its barrel imports them fromthe definitions package's
/internalentrypoint, the standard cross-package importdoor). api-extractor inlines the type declarations into container-runtime's own rolled-up
.d.ts, so existing consumers still import them unchanged from@fluidframework/container-runtime/legacyand no internal module specifier is exposed.reason?: stringto thependingandunresolvablevariants ofResolveResult. It is an opaque, log-only diagnostic string (the runtime currentlysets
awaitingSequence/historicalOpsUnavailableonpendingandhistoryTrimmedon
unresolvable). Hosts drive behavior fromkindand must not branch onreason.A plain string keeps additions non-breaking and avoids a second discriminator; a state
that needs different host behavior should become a new
kind.The three existing
kindvalues are unchanged.Reviewer Guidance
versionMarkResolverto the@sealedIContainerRuntimeis backCompat-safe;the forward-compat break is only on the non-sealed
IContainerRuntimeWithResolveHandle_Deprecatedand is acknowledged viatypeValidation.brokenplus the regenerated type-test.reason?: stringis deliberately a plain string, not a string-literal union, so it isdiagnostic-only and additions never break exhaustive
kindconsumers./internalentrypoint,matching how production packages (
fluid-framework,container-definitions) re-exportsibling types. api-extractor inlines them into the consumer-facing rollup, so the
/internalspecifier does not leak into the published.d.ts.