fix: validate Kafka refresh delivery in web probe
This commit is contained in:
@@ -192,6 +192,15 @@ export interface HwlabRuntimeWebProbeRealtimeFanoutProfileSpec {
|
||||
readonly navigationMaxAttempts: number;
|
||||
readonly navigationRetryDelayMs: number;
|
||||
readonly reconnectQuietMs: number;
|
||||
readonly expectedProductSse: Readonly<{
|
||||
deliverySemantics: string;
|
||||
liveOnly: boolean;
|
||||
replay: boolean;
|
||||
replaySupported: boolean;
|
||||
lossPossible: boolean;
|
||||
refreshHandoff: boolean;
|
||||
replayPriorTraceOnReconnect: boolean;
|
||||
}>;
|
||||
readonly forbiddenRequestPaths: readonly string[];
|
||||
readonly requiredEventTypes: Readonly<{
|
||||
agentrun: readonly string[];
|
||||
@@ -1435,7 +1444,23 @@ function webProbeRealtimeFanoutProfileConfig(value: unknown, path: string): Hwla
|
||||
throw new Error(`${path}.debugStreams must contain stdio, agentrun, and hwlab exactly once`);
|
||||
}
|
||||
const fromBeginning = booleanField(raw, "fromBeginning", path);
|
||||
if (fromBeginning !== false) throw new Error(`${path}.fromBeginning must be false for live-only validation`);
|
||||
if (fromBeginning !== false) throw new Error(`${path}.fromBeginning must be false for turn-scoped debug streams`);
|
||||
const expectedProductSseRaw = asRecord(raw.expectedProductSse, `${path}.expectedProductSse`);
|
||||
const expectedProductSse = {
|
||||
deliverySemantics: stringField(expectedProductSseRaw, "deliverySemantics", `${path}.expectedProductSse`),
|
||||
liveOnly: booleanField(expectedProductSseRaw, "liveOnly", `${path}.expectedProductSse`),
|
||||
replay: booleanField(expectedProductSseRaw, "replay", `${path}.expectedProductSse`),
|
||||
replaySupported: booleanField(expectedProductSseRaw, "replaySupported", `${path}.expectedProductSse`),
|
||||
lossPossible: booleanField(expectedProductSseRaw, "lossPossible", `${path}.expectedProductSse`),
|
||||
refreshHandoff: booleanField(expectedProductSseRaw, "refreshHandoff", `${path}.expectedProductSse`),
|
||||
replayPriorTraceOnReconnect: booleanField(expectedProductSseRaw, "replayPriorTraceOnReconnect", `${path}.expectedProductSse`),
|
||||
};
|
||||
if (expectedProductSse.refreshHandoff && (!expectedProductSse.replay || !expectedProductSse.replaySupported || expectedProductSse.liveOnly)) {
|
||||
throw new Error(`${path}.expectedProductSse refresh handoff requires replay=true, replaySupported=true, and liveOnly=false`);
|
||||
}
|
||||
if (expectedProductSse.replayPriorTraceOnReconnect && !expectedProductSse.replay) {
|
||||
throw new Error(`${path}.expectedProductSse replayPriorTraceOnReconnect requires replay=true`);
|
||||
}
|
||||
const requiredEventTypes = asRecord(raw.requiredEventTypes, `${path}.requiredEventTypes`);
|
||||
const forbiddenRequestPaths = nonEmptyStringArrayField(raw, "forbiddenRequestPaths", path);
|
||||
if (new Set(forbiddenRequestPaths).size !== forbiddenRequestPaths.length) throw new Error(`${path}.forbiddenRequestPaths must not contain duplicates`);
|
||||
@@ -1466,6 +1491,7 @@ function webProbeRealtimeFanoutProfileConfig(value: unknown, path: string): Hwla
|
||||
navigationMaxAttempts: boundedIntegerField(raw, "navigationMaxAttempts", path, 1, 10),
|
||||
navigationRetryDelayMs: boundedIntegerField(raw, "navigationRetryDelayMs", path, 100, 10_000),
|
||||
reconnectQuietMs: boundedIntegerField(raw, "reconnectQuietMs", path, 250, 30_000),
|
||||
expectedProductSse,
|
||||
forbiddenRequestPaths,
|
||||
requiredEventTypes: {
|
||||
agentrun: agentrunEventTypes,
|
||||
|
||||
Reference in New Issue
Block a user