diff --git a/src/domain/analysisView/environmentCoverageView.test.ts b/src/domain/analysisView/environmentCoverageView.test.ts index 70eb2cd6e9..50bdc6b205 100644 --- a/src/domain/analysisView/environmentCoverageView.test.ts +++ b/src/domain/analysisView/environmentCoverageView.test.ts @@ -169,6 +169,35 @@ it("summarizes the state the environment-state view derives with the same rules" ); }); +it("says an untimed capture learns no clock, and only for an untimed capture", () => { + const untimed = /learns no clock/u; + const scenarioParent = parentOf( + scenarioCaptureEvidence( + scenarioCaptureFixture(SCENARIO_EXCHANGES, { + request_body: true, + response_body: true, + header_values: true, + }), + ), + ); + for (const [parent, timeline] of [ + [parentOf(), "recorded-start-time"], + [scenarioParent, "record-order"], + ] as const) { + const state = project("environment-state", parent); + const coverage = project("environment-coverage", parent); + if ( + state.kind !== "environment-state" || + coverage.kind !== "environment-coverage" + ) + throw new Error("Expected state and coverage views"); + expect(state.timeline).toBe(timeline); + expect(coverage.limitations.some((line) => untimed.test(line))).toBe( + timeline === "record-order", + ); + } +}); + it("refuses a browser scenario without response bodies as the state view does", () => { const evidence = scenarioCaptureEvidence( scenarioCaptureFixture(SCENARIO_EXCHANGES, { diff --git a/src/domain/analysisView/environmentCoverageView.ts b/src/domain/analysisView/environmentCoverageView.ts index e2a836ec6f..63435e3e7a 100644 --- a/src/domain/analysisView/environmentCoverageView.ts +++ b/src/domain/analysisView/environmentCoverageView.ts @@ -172,6 +172,11 @@ export const projectEnvironmentCoverageView = ( limitations: [ ...state.limitations, "Coverage summarizes the environment-state view an environment derives at startup; it does not run the environment. An environment whose served catalog exceeds the discovery budget, or whose state exceeds what data/add loads, serves replay instead, which this view does not check. Hints are advice about what to record next.", + ...(state.timeline === "record-order" + ? [ + "Not every record carries a start time (browser scenario captures carry none), so the state learns no clock: a write whose response changes a timestamp the server sets, such as a modification time, is withheld as unexplained-change however often it is recorded.", + ] + : []), ], unknowns: state.unknowns, origin: state.origin,