Files
rea/src/application/BrowserScenarioEvidence.ts
T
gensokyo-devandEdgar Arakelyan 3fcbabe593 feat(browser): reuse saved response values across scenario steps (#7267)
Save typed response fields and reuse generated IDs or authentication values across browser scenario requests, UI observations and navigation through the shared CLI/MCP workflow.

Preserve exact numbers, retained Evidence, explicit source/coverage limits and prospective page-value semantics. Bound response decoding, retained spellings and request serialization before allocation, and protect marked response values across source records, follow-up text and planned screenshots.

Integrates Edgar Arakelyan's #7162, including follow-ups through 9f5191ab0. Final local validation: 560 feature-branch tests and 561 current-main integration tests, static/build/docs checks and real PocketBase CLI/MCP privacy workflows. Whole-task comparison and verification limits are recorded in docs/verification/browser-saved-values-2026-10-26.md.

Co-authored-by: Edgar Arakelyan <edgar.arakelyan@scale.com>
2026-10-27 08:15:52 +08:00

61 lines
2.0 KiB
TypeScript

import { digestCanonicalValue } from "../domain/canonicalDigest.js";
import type { ProviderIdentity } from "./AnalysisProvider.js";
import type { BrowserScenario } from "../domain/browserScenario.js";
import type { BrowserScenarioCapture } from "../domain/browserScenarioCapture.js";
import {
createEvidence,
type Evidence,
type EvidenceObservation,
} from "../domain/evidence.js";
import { jsonObjectSchema } from "../domain/jsonValue.js";
/** A step as Evidence records it: a request step leaves out an empty `save`, so a scenario that saves nothing records and hashes as it did before saved values existed. */
const recordedAction = (
action: BrowserScenario["actions"][number],
): Record<string, unknown> => {
if (action.action !== "request" || action.save.length > 0) return action;
const { save, ...rest } = action;
return rest;
};
const browserScenarioParameters = (
scenario: BrowserScenario,
): EvidenceObservation["parameters"] => {
const recorded = {
...scenario,
actions: scenario.actions.map(recordedAction),
};
return {
...jsonObjectSchema.parse(recorded),
scenario_sha256: digestCanonicalValue(recorded, "Browser scenario"),
};
};
/** Create Evidence without retaining resolved scenario secret values. */
export const createBrowserScenarioEvidence = (
scenario: BrowserScenario,
capture: BrowserScenarioCapture,
provider: ProviderIdentity,
): Evidence =>
createEvidence(undefined, provider, {
predicateType: "rea.browser-scenario-capture",
operation: "capture_browser_scenario",
parameters: browserScenarioParameters(scenario),
result: capture,
confidence: "observed",
authority: "controlled-replay",
environment: {
id: `${capture.browser.product}@${capture.browser.version}`,
platform: "unknown",
architecture: "unknown",
isolation:
capture.browser.process_ownership === "provider-owned"
? "process"
: "none",
},
limitations: [
...capture.limitations,
"Browser host platform and architecture were not observed.",
],
});