From a9bf87c8733397bf88b30652cc1f2c68409c74a0 Mon Sep 17 00:00:00 2001 From: Mark Fields Date: Fri, 5 Jun 2026 12:39:22 -0700 Subject: [PATCH 1/7] Initial sketch and notes and AI-written tests --- .../container-runtime/src/dataStoreContext.ts | 1 + .../runtime/datastore/src/dataStoreRuntime.ts | 7 +- .../datastore/src/localChannelContext.ts | 26 +++- .../datastore/src/remoteChannelContext.ts | 92 +++++++----- .../src/test/localChannelContext.spec.ts | 118 ++++++++++++++- .../src/test/remoteChannelContext.spec.ts | 138 ++++++++++++++++++ 6 files changed, 342 insertions(+), 40 deletions(-) diff --git a/packages/runtime/container-runtime/src/dataStoreContext.ts b/packages/runtime/container-runtime/src/dataStoreContext.ts index 6b46a9ac9537..a496bf4a2c84 100644 --- a/packages/runtime/container-runtime/src/dataStoreContext.ts +++ b/packages/runtime/container-runtime/src/dataStoreContext.ts @@ -272,6 +272,7 @@ export abstract class FluidDataStoreContext } public get baseLogger(): ITelemetryBaseLogger { + //* This should say DataStoreContext and have public props like ID and PKG return this.parentContext.baseLogger; } diff --git a/packages/runtime/datastore/src/dataStoreRuntime.ts b/packages/runtime/datastore/src/dataStoreRuntime.ts index 0c34a36c6f3e..6cda7bc50b9e 100644 --- a/packages/runtime/datastore/src/dataStoreRuntime.ts +++ b/packages/runtime/datastore/src/dataStoreRuntime.ts @@ -423,7 +423,12 @@ export class FluidDataStoreRuntime logger: dataStoreContext.baseLogger, namespace: "FluidDataStoreRuntime", properties: { - all: { dataStoreId: uuid(), dataStoreVersion: pkgVersion }, + //* COPILOT: Make this shape match EntryPointInitializationFailure props + all: { + dataStoreId: dataStoreContext.id, + dataStoreVersion: pkgVersion, + fullPackagePath: dataStoreContext.packagePath.join("/"), + }, error: { inStagingMode: () => this.inStagingMode, isDirty: () => this.isDirty, diff --git a/packages/runtime/datastore/src/localChannelContext.ts b/packages/runtime/datastore/src/localChannelContext.ts index 641a96b49a65..3f8ebe2716ec 100644 --- a/packages/runtime/datastore/src/localChannelContext.ts +++ b/packages/runtime/datastore/src/localChannelContext.ts @@ -19,9 +19,12 @@ import type { IRuntimeMessageCollection, IRuntimeStorageService, } from "@fluidframework/runtime-definitions/internal"; +import { dataStoreLoadTelemetryProps } from "@fluidframework/runtime-utils/internal"; import { type ITelemetryLoggerExt, DataProcessingError, + createChildLogger, + tagCodeArtifacts, } from "@fluidframework/telemetry-utils/internal"; import { @@ -221,6 +224,19 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase { private readonly snapshotTree: ISnapshotTree, extraBlob?: Map, ) { + const subLogger = createChildLogger({ + logger, + namespace: "RehydratedLocalChannelContext", + properties: { + all: { + ...dataStoreLoadTelemetryProps({ + id: dataStoreContext.id, + packagePath: dataStoreContext.packagePath, + }), + ...tagCodeArtifacts({ channelId: id }), + }, + }, + }); super( id, runtime, @@ -241,7 +257,7 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase { this.dirtyFn, () => this.isGloballyVisible, storageService, - logger, + subLogger, clonedSnapshotTree, blobMap, ); @@ -259,7 +275,7 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase { attributes, factory, this.services.value, - logger, + subLogger, this.id, ); // Send all pending messages to the channel @@ -268,11 +284,13 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase { } return channel; } catch (error) { - throw DataProcessingError.wrapIfUnrecognized( + const errorWrapped = DataProcessingError.wrapIfUnrecognized( error, - "rehydratedLocalChannelContextFailedToLoadChannel", + "rehydratedLocalChannelContextChannelLoad", undefined, ); + subLogger.sendErrorEvent({ eventName: "ChannelLoadFailure" }, errorWrapped); + throw errorWrapped; } }), ); diff --git a/packages/runtime/datastore/src/remoteChannelContext.ts b/packages/runtime/datastore/src/remoteChannelContext.ts index 3b4c1931c82f..ee94490d91a5 100644 --- a/packages/runtime/datastore/src/remoteChannelContext.ts +++ b/packages/runtime/datastore/src/remoteChannelContext.ts @@ -23,10 +23,13 @@ import type { IRuntimeMessageCollection, IRuntimeStorageService, } from "@fluidframework/runtime-definitions/internal"; +import { dataStoreLoadTelemetryProps } from "@fluidframework/runtime-utils/internal"; import { + DataProcessingError, type ITelemetryLoggerExt, ThresholdCounter, createChildLogger, + tagCodeArtifacts, } from "@fluidframework/telemetry-utils/internal"; import { @@ -58,6 +61,7 @@ export class RemoteChannelContext implements IChannelContext { constructor( runtime: IFluidDataStoreRuntime, + //* Replace with property bag with only the needed props dataStoreContext: IFluidDataStoreContext, storageService: IRuntimeStorageService, submitFn: (content: unknown, localOpMetadata: unknown) => void, @@ -74,6 +78,16 @@ export class RemoteChannelContext implements IChannelContext { this.subLogger = createChildLogger({ logger: runtime.logger, namespace: "RemoteChannelContext", + //* Don't need to do this since runtime.logger already adds them + properties: { + all: { + ...dataStoreLoadTelemetryProps({ + id: dataStoreContext.id, + packagePath: dataStoreContext.packagePath, + }), + ...tagCodeArtifacts({ channelId: this.id }), + }, + }, }); this.services = createChannelServiceEndpoints( @@ -88,44 +102,54 @@ export class RemoteChannelContext implements IChannelContext { ); this.channelP = new LazyPromise(async () => { - const { attributes, factory } = await loadChannelFactoryAndAttributes( - dataStoreContext, - this.services, - this.id, - registry, - attachMessageType, - ); + try { + const { attributes, factory } = await loadChannelFactoryAndAttributes( + dataStoreContext, + this.services, + this.id, + registry, + attachMessageType, + ); - const channel = await loadChannel( - runtime, - attributes, - factory, - this.services, - this.subLogger, - this.id, - ); + const channel = await loadChannel( + runtime, + attributes, + factory, + this.services, + this.subLogger, + this.id, + ); - assert( - this.pendingMessagesState !== undefined, - 0xa6c /* pending messages state is undefined */, - ); - for (const messageCollection of this.pendingMessagesState.messageCollections) { - this.services.deltaConnection.processMessages(messageCollection); - } - this.thresholdOpsCounter.send( - "ProcessPendingOps", - this.pendingMessagesState.pendingCount, - ); + assert( + this.pendingMessagesState !== undefined, + 0xa6c /* pending messages state is undefined */, + ); + for (const messageCollection of this.pendingMessagesState.messageCollections) { + this.services.deltaConnection.processMessages(messageCollection); + } + this.thresholdOpsCounter.send( + "ProcessPendingOps", + this.pendingMessagesState.pendingCount, + ); - // Commit changes. - this.channel = channel; - this.pendingMessagesState = undefined; - this.isLoaded = true; + // Commit changes. + this.channel = channel; + this.pendingMessagesState = undefined; + this.isLoaded = true; - // Because have some await between we created the service and here, the connection state might have changed - // and we don't propagate the connection state when we are not loaded. So we have to set it again here. - this.services.deltaConnection.setConnectionState(dataStoreContext.connected); - return this.channel; + // Because have some await between we created the service and here, the connection state might have changed + // and we don't propagate the connection state when we are not loaded. So we have to set it again here. + this.services.deltaConnection.setConnectionState(dataStoreContext.connected); + return this.channel; + } catch (error) { + //* Decorate the error with ID and PKG + const errorWrapped = DataProcessingError.wrapIfUnrecognized( + error, + "remoteChannelContextChannelLoad", + ); + this.subLogger.sendErrorEvent({ eventName: "ChannelLoadFailure" }, errorWrapped); + throw errorWrapped; + } }); this.summarizerNode = createSummarizerNode( diff --git a/packages/runtime/datastore/src/test/localChannelContext.spec.ts b/packages/runtime/datastore/src/test/localChannelContext.spec.ts index d81d2468f7ed..f7a7ff95450a 100644 --- a/packages/runtime/datastore/src/test/localChannelContext.spec.ts +++ b/packages/runtime/datastore/src/test/localChannelContext.spec.ts @@ -5,10 +5,17 @@ import { strict as assert } from "node:assert"; +import { ContainerErrorTypes } from "@fluidframework/container-definitions/internal"; +import type { IErrorBase } from "@fluidframework/core-interfaces"; import type { IChannel } from "@fluidframework/datastore-definitions/internal"; import type { ISnapshotTree } from "@fluidframework/driver-definitions/internal"; import type { IFluidDataStoreContext } from "@fluidframework/runtime-definitions/internal"; -import { extractTelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal"; +import { + extractTelemetryLoggerExt, + isFluidError, + MockLogger, + TelemetryDataTag, +} from "@fluidframework/telemetry-utils/internal"; import { MockFluidDataStoreContext, validateAssertionError, @@ -83,4 +90,113 @@ describe("LocalChannelContext Tests", () => { "Expected exception was not thrown", ); }); + + it("RehydratedLocalChannelContext first await on getChannel() logs ChannelLoadFailure with tagged props when load fails", async () => { + const channelId = "ddsId"; + const mockLogger = new MockLogger(); + const contextWithMockLogger = new MockFluidDataStoreContext( + "testDataStoreId", + false, + mockLogger.toTelemetryLogger(), + ); + contextWithMockLogger.packagePath = ["pkgA", "pkgB"]; + const dataStoreRuntime = loadRuntime(contextWithMockLogger, sharedObjectRegistry); + + // Registry returns undefined so loadChannelFactoryAndAttributes throws + // inside the LazyPromise body. With an empty snapshot tree and no + // attachMessageType, this throws `channelTypeNotAvailable`. + const failingRegistry: ISharedObjectRegistry = { + get: () => undefined, + }; + + const rehydratedChannelContext = new RehydratedLocalChannelContext( + channelId, + failingRegistry, + dataStoreRuntime, + contextWithMockLogger, + contextWithMockLogger.storage, + extractTelemetryLoggerExt(contextWithMockLogger.baseLogger), + () => {}, + () => {}, + { trees: {}, blobs: {} } as unknown as ISnapshotTree, + ); + + await assert.rejects( + async () => rehydratedChannelContext.getChannel(), + (error: IErrorBase) => { + assert.strictEqual( + error.errorType, + ContainerErrorTypes.dataProcessingError, + "thrown error should be a DataProcessingError", + ); + assert(isFluidError(error), "thrown error should be a Fluid error"); + return true; + }, + ); + + const failureEvents = mockLogger.events.filter( + (event) => + typeof event.eventName === "string" && event.eventName.endsWith("ChannelLoadFailure"), + ); + assert.strictEqual( + failureEvents.length, + 1, + "ChannelLoadFailure should be logged exactly once", + ); + const failureEvent = failureEvents[0]; + assert(failureEvent !== undefined); + assert.deepStrictEqual( + failureEvent.fluidDataStoreId, + { value: "testDataStoreId", tag: TelemetryDataTag.CodeArtifact }, + "event should include tagged fluidDataStoreId", + ); + assert.deepStrictEqual( + failureEvent.fullPackageName, + { value: "pkgA/pkgB", tag: TelemetryDataTag.CodeArtifact }, + "event should include tagged fullPackageName", + ); + assert.deepStrictEqual( + failureEvent.channelId, + { value: channelId, tag: TelemetryDataTag.CodeArtifact }, + "event should include tagged channelId", + ); + }); + + it("RehydratedLocalChannelContext subsequent awaits do not re-log ChannelLoadFailure", async () => { + const channelId = "ddsId"; + const mockLogger = new MockLogger(); + const contextWithMockLogger = new MockFluidDataStoreContext( + "testDataStoreId", + false, + mockLogger.toTelemetryLogger(), + ); + contextWithMockLogger.packagePath = ["pkgA", "pkgB"]; + const dataStoreRuntime = loadRuntime(contextWithMockLogger, sharedObjectRegistry); + const failingRegistry: ISharedObjectRegistry = { get: () => undefined }; + + const rehydratedChannelContext = new RehydratedLocalChannelContext( + channelId, + failingRegistry, + dataStoreRuntime, + contextWithMockLogger, + contextWithMockLogger.storage, + extractTelemetryLoggerExt(contextWithMockLogger.baseLogger), + () => {}, + () => {}, + { trees: {}, blobs: {} } as unknown as ISnapshotTree, + ); + + await assert.rejects(async () => rehydratedChannelContext.getChannel()); + await assert.rejects(async () => rehydratedChannelContext.getChannel()); + + const failureEvents = mockLogger.events.filter( + (event) => + typeof event.eventName === "string" && event.eventName.endsWith("ChannelLoadFailure"), + ); + assert.strictEqual( + failureEvents.length, + 1, + "ChannelLoadFailure should only be logged once even across multiple awaits", + ); + }); }); diff --git a/packages/runtime/datastore/src/test/remoteChannelContext.spec.ts b/packages/runtime/datastore/src/test/remoteChannelContext.spec.ts index 4615f706dcdf..b3ba1dbd695e 100644 --- a/packages/runtime/datastore/src/test/remoteChannelContext.spec.ts +++ b/packages/runtime/datastore/src/test/remoteChannelContext.spec.ts @@ -5,12 +5,20 @@ import { strict as assert } from "node:assert"; +import { ContainerErrorTypes } from "@fluidframework/container-definitions/internal"; +import type { IErrorBase } from "@fluidframework/core-interfaces"; import type { ISnapshotTree } from "@fluidframework/driver-definitions/internal"; import type { CreateChildSummarizerNodeFn, IContainerRuntimeBase, IFluidDataStoreContext, + ISummarizerNodeWithGC, } from "@fluidframework/runtime-definitions/internal"; +import { + isFluidError, + MockLogger, + TelemetryDataTag, +} from "@fluidframework/telemetry-utils/internal"; import { MockFluidDataStoreContext, validateAssertionError, @@ -65,4 +73,134 @@ describe("RemoteChannelContext Tests", () => { "Expected exception was not thrown", ); }); + + it("first await on getChannel() logs ChannelLoadFailure with tagged props when load fails", async () => { + const channelId = "ddsId"; + const mockLogger = new MockLogger(); + const contextWithMockLogger = new MockFluidDataStoreContext( + "testDataStoreId", + false, + mockLogger.toTelemetryLogger(), + ); + contextWithMockLogger.containerRuntime = {} as unknown as IContainerRuntimeBase; + contextWithMockLogger.packagePath = ["pkgA", "pkgB"]; + + const dataStoreRuntime = loadRuntime(contextWithMockLogger, sharedObjectRegistry); + + // Registry returns undefined so loadChannelFactoryAndAttributes throws + // `channelFactoryNotRegisteredForGivenType` inside the LazyPromise body. + const failingRegistry: ISharedObjectRegistry = { + get: () => undefined, + }; + + const noopSummarizerNode = { + invalidate: () => {}, + summarize: async () => ({ summary: {}, stats: {} }), + getGCData: async () => ({ gcNodes: {} }), + updateUsedRoutes: () => {}, + } as unknown as ISummarizerNodeWithGC; + const createSummarizerNode: CreateChildSummarizerNodeFn = () => noopSummarizerNode; + + const remoteChannelContext = new RemoteChannelContext( + dataStoreRuntime, + contextWithMockLogger, + contextWithMockLogger.storage, + () => {}, + () => {}, + channelId, + { trees: {}, blobs: {} } as unknown as ISnapshotTree, + failingRegistry, + undefined /* extraBlobs */, + createSummarizerNode, + "SomeAttachMessageType", + ); + + await assert.rejects( + async () => remoteChannelContext.getChannel(), + (error: IErrorBase) => { + assert.strictEqual( + error.errorType, + ContainerErrorTypes.dataProcessingError, + "thrown error should be a DataProcessingError", + ); + assert(isFluidError(error), "thrown error should be a Fluid error"); + return true; + }, + ); + + const failureEvents = mockLogger.events.filter( + (event) => + typeof event.eventName === "string" && event.eventName.endsWith("ChannelLoadFailure"), + ); + assert.strictEqual( + failureEvents.length, + 1, + "ChannelLoadFailure should be logged exactly once", + ); + const failureEvent = failureEvents[0]; + assert(failureEvent !== undefined); + assert.deepStrictEqual( + failureEvent.fluidDataStoreId, + { value: "testDataStoreId", tag: TelemetryDataTag.CodeArtifact }, + "event should include tagged fluidDataStoreId", + ); + assert.deepStrictEqual( + failureEvent.fullPackageName, + { value: "pkgA/pkgB", tag: TelemetryDataTag.CodeArtifact }, + "event should include tagged fullPackageName", + ); + assert.deepStrictEqual( + failureEvent.channelId, + { value: channelId, tag: TelemetryDataTag.CodeArtifact }, + "event should include tagged channelId", + ); + }); + + it("subsequent awaits on getChannel() do not re-log ChannelLoadFailure", async () => { + const channelId = "ddsId"; + const mockLogger = new MockLogger(); + const contextWithMockLogger = new MockFluidDataStoreContext( + "testDataStoreId", + false, + mockLogger.toTelemetryLogger(), + ); + contextWithMockLogger.containerRuntime = {} as unknown as IContainerRuntimeBase; + contextWithMockLogger.packagePath = ["pkgA", "pkgB"]; + + const dataStoreRuntime = loadRuntime(contextWithMockLogger, sharedObjectRegistry); + const failingRegistry: ISharedObjectRegistry = { get: () => undefined }; + const noopSummarizerNode = { + invalidate: () => {}, + summarize: async () => ({ summary: {}, stats: {} }), + getGCData: async () => ({ gcNodes: {} }), + updateUsedRoutes: () => {}, + } as unknown as ISummarizerNodeWithGC; + + const remoteChannelContext = new RemoteChannelContext( + dataStoreRuntime, + contextWithMockLogger, + contextWithMockLogger.storage, + () => {}, + () => {}, + channelId, + { trees: {}, blobs: {} } as unknown as ISnapshotTree, + failingRegistry, + undefined, + () => noopSummarizerNode, + "SomeAttachMessageType", + ); + + await assert.rejects(async () => remoteChannelContext.getChannel()); + await assert.rejects(async () => remoteChannelContext.getChannel()); + + const failureEvents = mockLogger.events.filter( + (event) => + typeof event.eventName === "string" && event.eventName.endsWith("ChannelLoadFailure"), + ); + assert.strictEqual( + failureEvents.length, + 1, + "ChannelLoadFailure should only be logged once even across multiple awaits", + ); + }); }); From 52459164a413553712bf9e87af0d00f907daf4e6 Mon Sep 17 00:00:00 2001 From: Mark Fields Date: Fri, 5 Jun 2026 13:35:13 -0700 Subject: [PATCH 2/7] Clean up --- .../container-runtime/src/dataStoreContext.ts | 2 +- .../runtime/datastore/src/dataStoreRuntime.ts | 8 +------- .../datastore/src/localChannelContext.ts | 15 +++++++++------ .../datastore/src/remoteChannelContext.ts | 18 ++++++++++-------- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/packages/runtime/container-runtime/src/dataStoreContext.ts b/packages/runtime/container-runtime/src/dataStoreContext.ts index a496bf4a2c84..62376ee5d0e4 100644 --- a/packages/runtime/container-runtime/src/dataStoreContext.ts +++ b/packages/runtime/container-runtime/src/dataStoreContext.ts @@ -272,7 +272,7 @@ export abstract class FluidDataStoreContext } public get baseLogger(): ITelemetryBaseLogger { - //* This should say DataStoreContext and have public props like ID and PKG + //* FUTURE: This should say DataStoreContext and have public props like ID and PKG return this.parentContext.baseLogger; } diff --git a/packages/runtime/datastore/src/dataStoreRuntime.ts b/packages/runtime/datastore/src/dataStoreRuntime.ts index 6cda7bc50b9e..1ea909d48ff2 100644 --- a/packages/runtime/datastore/src/dataStoreRuntime.ts +++ b/packages/runtime/datastore/src/dataStoreRuntime.ts @@ -423,13 +423,9 @@ export class FluidDataStoreRuntime logger: dataStoreContext.baseLogger, namespace: "FluidDataStoreRuntime", properties: { - //* COPILOT: Make this shape match EntryPointInitializationFailure props all: { - dataStoreId: dataStoreContext.id, dataStoreVersion: pkgVersion, - fullPackagePath: dataStoreContext.packagePath.join("/"), - }, - error: { + ...dataStoreLoadTelemetryProps(dataStoreContext), inStagingMode: () => this.inStagingMode, isDirty: () => this.isDirty, }, @@ -1579,8 +1575,6 @@ export class FluidDataStoreRuntime ...tagCodeArtifacts({ channelType, channelId, - fluidDataStoreId: this.id, - fluidDataStorePackagePath: this.dataStoreContext.packagePath.join("/"), }), stack: generateStack(30), }); diff --git a/packages/runtime/datastore/src/localChannelContext.ts b/packages/runtime/datastore/src/localChannelContext.ts index 3f8ebe2716ec..51a8bb86b504 100644 --- a/packages/runtime/datastore/src/localChannelContext.ts +++ b/packages/runtime/datastore/src/localChannelContext.ts @@ -229,10 +229,6 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase { namespace: "RehydratedLocalChannelContext", properties: { all: { - ...dataStoreLoadTelemetryProps({ - id: dataStoreContext.id, - packagePath: dataStoreContext.packagePath, - }), ...tagCodeArtifacts({ channelId: id }), }, }, @@ -286,9 +282,16 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase { } catch (error) { const errorWrapped = DataProcessingError.wrapIfUnrecognized( error, - "rehydratedLocalChannelContextChannelLoad", - undefined, + "rehydratedLocalChannelContextFailedToLoadChannel", ); + errorWrapped.addTelemetryProperties({ + ...dataStoreLoadTelemetryProps({ + id: dataStoreContext.id, + packagePath: dataStoreContext.packagePath, + }), + ...tagCodeArtifacts({ channelId: id }), + }); + subLogger.sendErrorEvent({ eventName: "ChannelLoadFailure" }, errorWrapped); throw errorWrapped; } diff --git a/packages/runtime/datastore/src/remoteChannelContext.ts b/packages/runtime/datastore/src/remoteChannelContext.ts index ee94490d91a5..9e421bfb29a0 100644 --- a/packages/runtime/datastore/src/remoteChannelContext.ts +++ b/packages/runtime/datastore/src/remoteChannelContext.ts @@ -61,7 +61,7 @@ export class RemoteChannelContext implements IChannelContext { constructor( runtime: IFluidDataStoreRuntime, - //* Replace with property bag with only the needed props + //* FUTURE: Replace with property bag with only the needed props dataStoreContext: IFluidDataStoreContext, storageService: IRuntimeStorageService, submitFn: (content: unknown, localOpMetadata: unknown) => void, @@ -78,13 +78,8 @@ export class RemoteChannelContext implements IChannelContext { this.subLogger = createChildLogger({ logger: runtime.logger, namespace: "RemoteChannelContext", - //* Don't need to do this since runtime.logger already adds them properties: { all: { - ...dataStoreLoadTelemetryProps({ - id: dataStoreContext.id, - packagePath: dataStoreContext.packagePath, - }), ...tagCodeArtifacts({ channelId: this.id }), }, }, @@ -142,11 +137,18 @@ export class RemoteChannelContext implements IChannelContext { this.services.deltaConnection.setConnectionState(dataStoreContext.connected); return this.channel; } catch (error) { - //* Decorate the error with ID and PKG const errorWrapped = DataProcessingError.wrapIfUnrecognized( error, - "remoteChannelContextChannelLoad", + "remoteChannelContextFailedToLoadChannel", ); + errorWrapped.addTelemetryProperties({ + ...dataStoreLoadTelemetryProps({ + id: dataStoreContext.id, + packagePath: dataStoreContext.packagePath, + }), + ...tagCodeArtifacts({ channelId: id }), + }); + this.subLogger.sendErrorEvent({ eventName: "ChannelLoadFailure" }, errorWrapped); throw errorWrapped; } From ef62bccea300ba4f90ca923baa5cefa7949dd3b3 Mon Sep 17 00:00:00 2001 From: Mark Fields Date: Fri, 5 Jun 2026 16:40:02 -0700 Subject: [PATCH 3/7] PR review notes --- .../container-runtime/src/containerRuntime.ts | 1 + .../container-runtime/src/dataStoreContext.ts | 3 +- .../datastore/src/localChannelContext.ts | 7 +-- .../datastore/src/remoteChannelContext.ts | 14 +++-- .../src/test/localChannelContext.spec.ts | 38 -------------- .../src/test/remoteChannelContext.spec.ts | 51 +------------------ .../runtime-utils/src/dataStoreHelpers.ts | 4 +- 7 files changed, 22 insertions(+), 96 deletions(-) diff --git a/packages/runtime/container-runtime/src/containerRuntime.ts b/packages/runtime/container-runtime/src/containerRuntime.ts index 3c13325457e4..3559d6520a4c 100644 --- a/packages/runtime/container-runtime/src/containerRuntime.ts +++ b/packages/runtime/container-runtime/src/containerRuntime.ts @@ -974,6 +974,7 @@ export class ContainerRuntime logger: passLogger, properties: { all: { + //* FUTURE: Any other props here? Like inStagingMode runtimeVersion: pkgVersion, }, }, diff --git a/packages/runtime/container-runtime/src/dataStoreContext.ts b/packages/runtime/container-runtime/src/dataStoreContext.ts index 62376ee5d0e4..131231876d86 100644 --- a/packages/runtime/container-runtime/src/dataStoreContext.ts +++ b/packages/runtime/container-runtime/src/dataStoreContext.ts @@ -272,7 +272,7 @@ export abstract class FluidDataStoreContext } public get baseLogger(): ITelemetryBaseLogger { - //* FUTURE: This should say DataStoreContext and have public props like ID and PKG + //* FUTURE: This should have public props like ID and PKG return this.parentContext.baseLogger; } @@ -592,6 +592,7 @@ export abstract class FluidDataStoreContext errorWrapped.addTelemetryProperties( dataStoreLoadTelemetryProps({ id: this.id, packagePath: this.pkg ?? [] }), ); + //* FUTURE: Rename this to ChannelLoadError to match DDS. this.mc.logger.sendErrorEvent({ eventName: "RealizeError" }, errorWrapped); throw errorWrapped; }); diff --git a/packages/runtime/datastore/src/localChannelContext.ts b/packages/runtime/datastore/src/localChannelContext.ts index 51a8bb86b504..5e365a92d30b 100644 --- a/packages/runtime/datastore/src/localChannelContext.ts +++ b/packages/runtime/datastore/src/localChannelContext.ts @@ -229,7 +229,7 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase { namespace: "RehydratedLocalChannelContext", properties: { all: { - ...tagCodeArtifacts({ channelId: id }), + ...tagCodeArtifacts({ channelId: id }), //* CPLT: Add channelType similar to remoteChannelContext }, }, }); @@ -289,10 +289,11 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase { id: dataStoreContext.id, packagePath: dataStoreContext.packagePath, }), - ...tagCodeArtifacts({ channelId: id }), + ...tagCodeArtifacts({ channelId: id }), //* CPLT: include channelType too }); - subLogger.sendErrorEvent({ eventName: "ChannelLoadFailure" }, errorWrapped); + //* CPLT Add similar comment to other class + subLogger.sendErrorEvent({ eventName: "RealizeError" }, errorWrapped); throw errorWrapped; } }), diff --git a/packages/runtime/datastore/src/remoteChannelContext.ts b/packages/runtime/datastore/src/remoteChannelContext.ts index 9e421bfb29a0..fd1c4daa9bb4 100644 --- a/packages/runtime/datastore/src/remoteChannelContext.ts +++ b/packages/runtime/datastore/src/remoteChannelContext.ts @@ -80,7 +80,11 @@ export class RemoteChannelContext implements IChannelContext { namespace: "RemoteChannelContext", properties: { all: { - ...tagCodeArtifacts({ channelId: this.id }), + ...tagCodeArtifacts({ + channelId: this.id, + //* CPLT pull this into a local let variable and then set it below once we get attributes in the LazyPromise callback + channelType: undefined, + }), }, }, }); @@ -98,6 +102,7 @@ export class RemoteChannelContext implements IChannelContext { this.channelP = new LazyPromise(async () => { try { + //* FUTURE: factor this into a realize fn simiklar to DataStoreContext const { attributes, factory } = await loadChannelFactoryAndAttributes( dataStoreContext, this.services, @@ -106,6 +111,7 @@ export class RemoteChannelContext implements IChannelContext { attachMessageType, ); + //* FUTURE: Move the error handling into loadChannel? Rationalize with the idea to do a realize fn const channel = await loadChannel( runtime, attributes, @@ -141,15 +147,17 @@ export class RemoteChannelContext implements IChannelContext { error, "remoteChannelContextFailedToLoadChannel", ); + //* FUTURE: Let telemetry props be pulled wholesale off a given logger errorWrapped.addTelemetryProperties({ ...dataStoreLoadTelemetryProps({ id: dataStoreContext.id, packagePath: dataStoreContext.packagePath, }), - ...tagCodeArtifacts({ channelId: id }), + ...tagCodeArtifacts({ channelId: id }), //* CPLT include channelType too }); - this.subLogger.sendErrorEvent({ eventName: "ChannelLoadFailure" }, errorWrapped); + // "Realize" is another name for instantiating the channel for a context + this.subLogger.sendErrorEvent({ eventName: "RealizeError" }, errorWrapped); throw errorWrapped; } }); diff --git a/packages/runtime/datastore/src/test/localChannelContext.spec.ts b/packages/runtime/datastore/src/test/localChannelContext.spec.ts index f7a7ff95450a..d5e2dbf3c357 100644 --- a/packages/runtime/datastore/src/test/localChannelContext.spec.ts +++ b/packages/runtime/datastore/src/test/localChannelContext.spec.ts @@ -161,42 +161,4 @@ describe("LocalChannelContext Tests", () => { "event should include tagged channelId", ); }); - - it("RehydratedLocalChannelContext subsequent awaits do not re-log ChannelLoadFailure", async () => { - const channelId = "ddsId"; - const mockLogger = new MockLogger(); - const contextWithMockLogger = new MockFluidDataStoreContext( - "testDataStoreId", - false, - mockLogger.toTelemetryLogger(), - ); - contextWithMockLogger.packagePath = ["pkgA", "pkgB"]; - const dataStoreRuntime = loadRuntime(contextWithMockLogger, sharedObjectRegistry); - const failingRegistry: ISharedObjectRegistry = { get: () => undefined }; - - const rehydratedChannelContext = new RehydratedLocalChannelContext( - channelId, - failingRegistry, - dataStoreRuntime, - contextWithMockLogger, - contextWithMockLogger.storage, - extractTelemetryLoggerExt(contextWithMockLogger.baseLogger), - () => {}, - () => {}, - { trees: {}, blobs: {} } as unknown as ISnapshotTree, - ); - - await assert.rejects(async () => rehydratedChannelContext.getChannel()); - await assert.rejects(async () => rehydratedChannelContext.getChannel()); - - const failureEvents = mockLogger.events.filter( - (event) => - typeof event.eventName === "string" && event.eventName.endsWith("ChannelLoadFailure"), - ); - assert.strictEqual( - failureEvents.length, - 1, - "ChannelLoadFailure should only be logged once even across multiple awaits", - ); - }); }); diff --git a/packages/runtime/datastore/src/test/remoteChannelContext.spec.ts b/packages/runtime/datastore/src/test/remoteChannelContext.spec.ts index b3ba1dbd695e..bc8a9abe3abd 100644 --- a/packages/runtime/datastore/src/test/remoteChannelContext.spec.ts +++ b/packages/runtime/datastore/src/test/remoteChannelContext.spec.ts @@ -111,7 +111,7 @@ describe("RemoteChannelContext Tests", () => { { trees: {}, blobs: {} } as unknown as ISnapshotTree, failingRegistry, undefined /* extraBlobs */, - createSummarizerNode, + createSummarizerNode, //* CPLT can we mock this more simply? "SomeAttachMessageType", ); @@ -128,6 +128,7 @@ describe("RemoteChannelContext Tests", () => { }, ); + //* CPLT can't this be more concise with MockLogger's capabilities? const failureEvents = mockLogger.events.filter( (event) => typeof event.eventName === "string" && event.eventName.endsWith("ChannelLoadFailure"), @@ -155,52 +156,4 @@ describe("RemoteChannelContext Tests", () => { "event should include tagged channelId", ); }); - - it("subsequent awaits on getChannel() do not re-log ChannelLoadFailure", async () => { - const channelId = "ddsId"; - const mockLogger = new MockLogger(); - const contextWithMockLogger = new MockFluidDataStoreContext( - "testDataStoreId", - false, - mockLogger.toTelemetryLogger(), - ); - contextWithMockLogger.containerRuntime = {} as unknown as IContainerRuntimeBase; - contextWithMockLogger.packagePath = ["pkgA", "pkgB"]; - - const dataStoreRuntime = loadRuntime(contextWithMockLogger, sharedObjectRegistry); - const failingRegistry: ISharedObjectRegistry = { get: () => undefined }; - const noopSummarizerNode = { - invalidate: () => {}, - summarize: async () => ({ summary: {}, stats: {} }), - getGCData: async () => ({ gcNodes: {} }), - updateUsedRoutes: () => {}, - } as unknown as ISummarizerNodeWithGC; - - const remoteChannelContext = new RemoteChannelContext( - dataStoreRuntime, - contextWithMockLogger, - contextWithMockLogger.storage, - () => {}, - () => {}, - channelId, - { trees: {}, blobs: {} } as unknown as ISnapshotTree, - failingRegistry, - undefined, - () => noopSummarizerNode, - "SomeAttachMessageType", - ); - - await assert.rejects(async () => remoteChannelContext.getChannel()); - await assert.rejects(async () => remoteChannelContext.getChannel()); - - const failureEvents = mockLogger.events.filter( - (event) => - typeof event.eventName === "string" && event.eventName.endsWith("ChannelLoadFailure"), - ); - assert.strictEqual( - failureEvents.length, - 1, - "ChannelLoadFailure should only be logged once even across multiple awaits", - ); - }); }); diff --git a/packages/runtime/runtime-utils/src/dataStoreHelpers.ts b/packages/runtime/runtime-utils/src/dataStoreHelpers.ts index bbc8f95c7ff6..d50d43dc3e96 100644 --- a/packages/runtime/runtime-utils/src/dataStoreHelpers.ts +++ b/packages/runtime/runtime-utils/src/dataStoreHelpers.ts @@ -157,8 +157,8 @@ export function dataStoreLoadTelemetryProps(props: { const { id, packagePath } = props; const fullPackageName = packagePath.length > 0 ? packagePath.join("/") : undefined; return tagCodeArtifacts({ - fullPackageName, - fluidDataStoreId: id, + fullPackageName, //* dataStorePackagePath + fluidDataStoreId: id, //* dataStoreId }); } From a980195d977382e6d498b928a14ce734d5dc74ab Mon Sep 17 00:00:00 2001 From: Mark Fields Date: Fri, 5 Jun 2026 16:45:52 -0700 Subject: [PATCH 4/7] Revert "FUTURE" notes --- packages/runtime/container-runtime/src/containerRuntime.ts | 1 - packages/runtime/container-runtime/src/dataStoreContext.ts | 2 -- packages/runtime/datastore/src/remoteChannelContext.ts | 4 ---- 3 files changed, 7 deletions(-) diff --git a/packages/runtime/container-runtime/src/containerRuntime.ts b/packages/runtime/container-runtime/src/containerRuntime.ts index 3559d6520a4c..3c13325457e4 100644 --- a/packages/runtime/container-runtime/src/containerRuntime.ts +++ b/packages/runtime/container-runtime/src/containerRuntime.ts @@ -974,7 +974,6 @@ export class ContainerRuntime logger: passLogger, properties: { all: { - //* FUTURE: Any other props here? Like inStagingMode runtimeVersion: pkgVersion, }, }, diff --git a/packages/runtime/container-runtime/src/dataStoreContext.ts b/packages/runtime/container-runtime/src/dataStoreContext.ts index 131231876d86..6b46a9ac9537 100644 --- a/packages/runtime/container-runtime/src/dataStoreContext.ts +++ b/packages/runtime/container-runtime/src/dataStoreContext.ts @@ -272,7 +272,6 @@ export abstract class FluidDataStoreContext } public get baseLogger(): ITelemetryBaseLogger { - //* FUTURE: This should have public props like ID and PKG return this.parentContext.baseLogger; } @@ -592,7 +591,6 @@ export abstract class FluidDataStoreContext errorWrapped.addTelemetryProperties( dataStoreLoadTelemetryProps({ id: this.id, packagePath: this.pkg ?? [] }), ); - //* FUTURE: Rename this to ChannelLoadError to match DDS. this.mc.logger.sendErrorEvent({ eventName: "RealizeError" }, errorWrapped); throw errorWrapped; }); diff --git a/packages/runtime/datastore/src/remoteChannelContext.ts b/packages/runtime/datastore/src/remoteChannelContext.ts index fd1c4daa9bb4..f9c743928347 100644 --- a/packages/runtime/datastore/src/remoteChannelContext.ts +++ b/packages/runtime/datastore/src/remoteChannelContext.ts @@ -61,7 +61,6 @@ export class RemoteChannelContext implements IChannelContext { constructor( runtime: IFluidDataStoreRuntime, - //* FUTURE: Replace with property bag with only the needed props dataStoreContext: IFluidDataStoreContext, storageService: IRuntimeStorageService, submitFn: (content: unknown, localOpMetadata: unknown) => void, @@ -102,7 +101,6 @@ export class RemoteChannelContext implements IChannelContext { this.channelP = new LazyPromise(async () => { try { - //* FUTURE: factor this into a realize fn simiklar to DataStoreContext const { attributes, factory } = await loadChannelFactoryAndAttributes( dataStoreContext, this.services, @@ -111,7 +109,6 @@ export class RemoteChannelContext implements IChannelContext { attachMessageType, ); - //* FUTURE: Move the error handling into loadChannel? Rationalize with the idea to do a realize fn const channel = await loadChannel( runtime, attributes, @@ -147,7 +144,6 @@ export class RemoteChannelContext implements IChannelContext { error, "remoteChannelContextFailedToLoadChannel", ); - //* FUTURE: Let telemetry props be pulled wholesale off a given logger errorWrapped.addTelemetryProperties({ ...dataStoreLoadTelemetryProps({ id: dataStoreContext.id, From ee1b3b1e6cde925963dc9d64dfd39c3b7af4e639 Mon Sep 17 00:00:00 2001 From: Mark Fields Date: Fri, 5 Jun 2026 18:01:57 -0700 Subject: [PATCH 5/7] Addressing todo's --- .../datastore/src/localChannelContext.ts | 11 ++-- .../datastore/src/remoteChannelContext.ts | 10 ++-- .../src/test/localChannelContext.spec.ts | 35 ++++--------- .../src/test/remoteChannelContext.spec.ts | 52 +++++++------------ 4 files changed, 43 insertions(+), 65 deletions(-) diff --git a/packages/runtime/datastore/src/localChannelContext.ts b/packages/runtime/datastore/src/localChannelContext.ts index 5e365a92d30b..82517dfa44b7 100644 --- a/packages/runtime/datastore/src/localChannelContext.ts +++ b/packages/runtime/datastore/src/localChannelContext.ts @@ -224,12 +224,16 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase { private readonly snapshotTree: ISnapshotTree, extraBlob?: Map, ) { + // `channelType` is not known until the LazyPromise body runs `loadChannelFactoryAndAttributes`. + // Pass a getter to `tagCodeArtifacts` so events log the type as soon as it's available. + let channelType: string | undefined; + const subLogger = createChildLogger({ logger, namespace: "RehydratedLocalChannelContext", properties: { all: { - ...tagCodeArtifacts({ channelId: id }), //* CPLT: Add channelType similar to remoteChannelContext + ...tagCodeArtifacts({ channelId: id, channelType: () => channelType }), }, }, }); @@ -266,6 +270,7 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase { this.id, registry, ); + channelType = attributes.type; const channel = await loadChannel( runtime, attributes, @@ -289,10 +294,10 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase { id: dataStoreContext.id, packagePath: dataStoreContext.packagePath, }), - ...tagCodeArtifacts({ channelId: id }), //* CPLT: include channelType too + ...tagCodeArtifacts({ channelId: id, channelType }), }); - //* CPLT Add similar comment to other class + // "Realize" is another name for instantiating the channel for a context subLogger.sendErrorEvent({ eventName: "RealizeError" }, errorWrapped); throw errorWrapped; } diff --git a/packages/runtime/datastore/src/remoteChannelContext.ts b/packages/runtime/datastore/src/remoteChannelContext.ts index f9c743928347..bc5bc4ec5803 100644 --- a/packages/runtime/datastore/src/remoteChannelContext.ts +++ b/packages/runtime/datastore/src/remoteChannelContext.ts @@ -74,6 +74,10 @@ export class RemoteChannelContext implements IChannelContext { ) { assert(!this.id.includes("/"), 0x310 /* Channel context ID cannot contain slashes */); + // `channelType` is not known until the LazyPromise body runs `loadChannelFactoryAndAttributes`. + // Pass a getter to `tagCodeArtifacts` so events log the type as soon as it's available. + let channelType: string | undefined; + this.subLogger = createChildLogger({ logger: runtime.logger, namespace: "RemoteChannelContext", @@ -81,8 +85,7 @@ export class RemoteChannelContext implements IChannelContext { all: { ...tagCodeArtifacts({ channelId: this.id, - //* CPLT pull this into a local let variable and then set it below once we get attributes in the LazyPromise callback - channelType: undefined, + channelType: () => channelType, }), }, }, @@ -108,6 +111,7 @@ export class RemoteChannelContext implements IChannelContext { registry, attachMessageType, ); + channelType = attributes.type; const channel = await loadChannel( runtime, @@ -149,7 +153,7 @@ export class RemoteChannelContext implements IChannelContext { id: dataStoreContext.id, packagePath: dataStoreContext.packagePath, }), - ...tagCodeArtifacts({ channelId: id }), //* CPLT include channelType too + ...tagCodeArtifacts({ channelId: id, channelType }), }); // "Realize" is another name for instantiating the channel for a context diff --git a/packages/runtime/datastore/src/test/localChannelContext.spec.ts b/packages/runtime/datastore/src/test/localChannelContext.spec.ts index d5e2dbf3c357..53fa769112dc 100644 --- a/packages/runtime/datastore/src/test/localChannelContext.spec.ts +++ b/packages/runtime/datastore/src/test/localChannelContext.spec.ts @@ -134,31 +134,16 @@ describe("LocalChannelContext Tests", () => { }, ); - const failureEvents = mockLogger.events.filter( - (event) => - typeof event.eventName === "string" && event.eventName.endsWith("ChannelLoadFailure"), - ); - assert.strictEqual( - failureEvents.length, - 1, - "ChannelLoadFailure should be logged exactly once", - ); - const failureEvent = failureEvents[0]; - assert(failureEvent !== undefined); - assert.deepStrictEqual( - failureEvent.fluidDataStoreId, - { value: "testDataStoreId", tag: TelemetryDataTag.CodeArtifact }, - "event should include tagged fluidDataStoreId", - ); - assert.deepStrictEqual( - failureEvent.fullPackageName, - { value: "pkgA/pkgB", tag: TelemetryDataTag.CodeArtifact }, - "event should include tagged fullPackageName", - ); - assert.deepStrictEqual( - failureEvent.channelId, - { value: channelId, tag: TelemetryDataTag.CodeArtifact }, - "event should include tagged channelId", + mockLogger.assertMatchAny( + [ + { + eventName: "RehydratedLocalChannelContext:RealizeError", + fluidDataStoreId: { value: "testDataStoreId", tag: TelemetryDataTag.CodeArtifact }, + fullPackageName: { value: "pkgA/pkgB", tag: TelemetryDataTag.CodeArtifact }, + channelId: { value: channelId, tag: TelemetryDataTag.CodeArtifact }, + }, + ], + "Expected one RealizeError event with tagged data-store and channel props", ); }); }); diff --git a/packages/runtime/datastore/src/test/remoteChannelContext.spec.ts b/packages/runtime/datastore/src/test/remoteChannelContext.spec.ts index bc8a9abe3abd..d2aacd9cce08 100644 --- a/packages/runtime/datastore/src/test/remoteChannelContext.spec.ts +++ b/packages/runtime/datastore/src/test/remoteChannelContext.spec.ts @@ -93,13 +93,13 @@ describe("RemoteChannelContext Tests", () => { get: () => undefined, }; - const noopSummarizerNode = { - invalidate: () => {}, - summarize: async () => ({ summary: {}, stats: {} }), - getGCData: async () => ({ gcNodes: {} }), - updateUsedRoutes: () => {}, - } as unknown as ISummarizerNodeWithGC; - const createSummarizerNode: CreateChildSummarizerNodeFn = () => noopSummarizerNode; + const createSummarizerNode: CreateChildSummarizerNodeFn = () => + ({ + invalidate: () => {}, + summarize: async () => ({ summary: {}, stats: {} }), + getGCData: async () => ({ gcNodes: {} }), + updateUsedRoutes: () => {}, + }) as unknown as ISummarizerNodeWithGC; const remoteChannelContext = new RemoteChannelContext( dataStoreRuntime, @@ -111,7 +111,7 @@ describe("RemoteChannelContext Tests", () => { { trees: {}, blobs: {} } as unknown as ISnapshotTree, failingRegistry, undefined /* extraBlobs */, - createSummarizerNode, //* CPLT can we mock this more simply? + createSummarizerNode, "SomeAttachMessageType", ); @@ -128,32 +128,16 @@ describe("RemoteChannelContext Tests", () => { }, ); - //* CPLT can't this be more concise with MockLogger's capabilities? - const failureEvents = mockLogger.events.filter( - (event) => - typeof event.eventName === "string" && event.eventName.endsWith("ChannelLoadFailure"), - ); - assert.strictEqual( - failureEvents.length, - 1, - "ChannelLoadFailure should be logged exactly once", - ); - const failureEvent = failureEvents[0]; - assert(failureEvent !== undefined); - assert.deepStrictEqual( - failureEvent.fluidDataStoreId, - { value: "testDataStoreId", tag: TelemetryDataTag.CodeArtifact }, - "event should include tagged fluidDataStoreId", - ); - assert.deepStrictEqual( - failureEvent.fullPackageName, - { value: "pkgA/pkgB", tag: TelemetryDataTag.CodeArtifact }, - "event should include tagged fullPackageName", - ); - assert.deepStrictEqual( - failureEvent.channelId, - { value: channelId, tag: TelemetryDataTag.CodeArtifact }, - "event should include tagged channelId", + mockLogger.assertMatchAny( + [ + { + eventName: "RemoteChannelContext:RealizeError", + fluidDataStoreId: { value: "testDataStoreId", tag: TelemetryDataTag.CodeArtifact }, + fullPackageName: { value: "pkgA/pkgB", tag: TelemetryDataTag.CodeArtifact }, + channelId: { value: channelId, tag: TelemetryDataTag.CodeArtifact }, + }, + ], + "Expected one RealizeError event with tagged data-store and channel props", ); }); }); From 7a85a771617c694970d8513506785d1f1d55de7e Mon Sep 17 00:00:00 2001 From: Mark Fields Date: Fri, 5 Jun 2026 18:15:35 -0700 Subject: [PATCH 6/7] Rename props --- packages/runtime/runtime-utils/src/dataStoreHelpers.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/runtime/runtime-utils/src/dataStoreHelpers.ts b/packages/runtime/runtime-utils/src/dataStoreHelpers.ts index d50d43dc3e96..915a9d721746 100644 --- a/packages/runtime/runtime-utils/src/dataStoreHelpers.ts +++ b/packages/runtime/runtime-utils/src/dataStoreHelpers.ts @@ -155,10 +155,10 @@ export function dataStoreLoadTelemetryProps(props: { packagePath: readonly string[]; }): ITelemetryPropertiesExt { const { id, packagePath } = props; - const fullPackageName = packagePath.length > 0 ? packagePath.join("/") : undefined; + const dataStorePackagePath = packagePath.length > 0 ? packagePath.join("/") : undefined; return tagCodeArtifacts({ - fullPackageName, //* dataStorePackagePath - fluidDataStoreId: id, //* dataStoreId + dataStorePackagePath, // aka fullPackageName, before 2.103.0 + dataStoreId: id, // aka fluidDataStoreId, before 2.103.0 }); } From 504da48ba086eb700e10368be20dbe9f8ca12866 Mon Sep 17 00:00:00 2001 From: Mark Fields Date: Fri, 5 Jun 2026 18:24:41 -0700 Subject: [PATCH 7/7] nits --- packages/runtime/datastore/src/dataStoreRuntime.ts | 3 +++ packages/runtime/datastore/src/localChannelContext.ts | 5 +---- packages/runtime/datastore/src/remoteChannelContext.ts | 5 +---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/runtime/datastore/src/dataStoreRuntime.ts b/packages/runtime/datastore/src/dataStoreRuntime.ts index 1ea909d48ff2..0e0ccfe3dd88 100644 --- a/packages/runtime/datastore/src/dataStoreRuntime.ts +++ b/packages/runtime/datastore/src/dataStoreRuntime.ts @@ -1575,6 +1575,9 @@ export class FluidDataStoreRuntime ...tagCodeArtifacts({ channelType, channelId, + // Properties renamed in 2.103.0 (present via logger common props): + // fluidDataStoreId -> dataStoreId + // fluidDataStorePackagePath -> dataStorePackagePath }), stack: generateStack(30), }); diff --git a/packages/runtime/datastore/src/localChannelContext.ts b/packages/runtime/datastore/src/localChannelContext.ts index 1a019baac5ba..db3ac43f5076 100644 --- a/packages/runtime/datastore/src/localChannelContext.ts +++ b/packages/runtime/datastore/src/localChannelContext.ts @@ -290,10 +290,7 @@ export class RehydratedLocalChannelContext extends LocalChannelContextBase { "rehydratedLocalChannelContextFailedToLoadChannel", ); errorWrapped.addTelemetryProperties({ - ...dataStoreLoadTelemetryProps({ - id: dataStoreContext.id, - packagePath: dataStoreContext.packagePath, - }), + ...dataStoreLoadTelemetryProps(dataStoreContext), ...tagCodeArtifacts({ channelId: id, channelType }), }); diff --git a/packages/runtime/datastore/src/remoteChannelContext.ts b/packages/runtime/datastore/src/remoteChannelContext.ts index 65b56ce3e80a..38cb80ed6bcd 100644 --- a/packages/runtime/datastore/src/remoteChannelContext.ts +++ b/packages/runtime/datastore/src/remoteChannelContext.ts @@ -149,10 +149,7 @@ export class RemoteChannelContext implements IChannelContext { "remoteChannelContextFailedToLoadChannel", ); errorWrapped.addTelemetryProperties({ - ...dataStoreLoadTelemetryProps({ - id: dataStoreContext.id, - packagePath: dataStoreContext.packagePath, - }), + ...dataStoreLoadTelemetryProps(dataStoreContext), ...tagCodeArtifacts({ channelId: id, channelType }), });