@e2edev/e2e 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +104 -0
- package/dist/agent/act-validation.d.ts +27 -0
- package/dist/agent/act-validation.d.ts.map +1 -0
- package/dist/agent/act-validation.js +121 -0
- package/dist/agent/act-validation.js.map +1 -0
- package/dist/agent/act.d.ts +27 -0
- package/dist/agent/act.d.ts.map +1 -0
- package/dist/agent/act.js +775 -0
- package/dist/agent/act.js.map +1 -0
- package/dist/agent/actions.d.ts +66 -0
- package/dist/agent/actions.d.ts.map +1 -0
- package/dist/agent/actions.js +82 -0
- package/dist/agent/actions.js.map +1 -0
- package/dist/agent/ai-sdk.d.ts +16 -0
- package/dist/agent/ai-sdk.d.ts.map +1 -0
- package/dist/agent/ai-sdk.js +59 -0
- package/dist/agent/ai-sdk.js.map +1 -0
- package/dist/agent/call-options.d.ts +10 -0
- package/dist/agent/call-options.d.ts.map +1 -0
- package/dist/agent/call-options.js +28 -0
- package/dist/agent/call-options.js.map +1 -0
- package/dist/agent/default-agent.d.ts +22 -0
- package/dist/agent/default-agent.d.ts.map +1 -0
- package/dist/agent/default-agent.js +354 -0
- package/dist/agent/default-agent.js.map +1 -0
- package/dist/agent/error.d.ts +53 -0
- package/dist/agent/error.d.ts.map +1 -0
- package/dist/agent/error.js +94 -0
- package/dist/agent/error.js.map +1 -0
- package/dist/agent/executor.d.ts +238 -0
- package/dist/agent/executor.d.ts.map +1 -0
- package/dist/agent/executor.js +56 -0
- package/dist/agent/executor.js.map +1 -0
- package/dist/agent/index.d.ts +15 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +304 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/invocation.d.ts +194 -0
- package/dist/agent/invocation.d.ts.map +1 -0
- package/dist/agent/invocation.js +389 -0
- package/dist/agent/invocation.js.map +1 -0
- package/dist/agent/ledger.d.ts +24 -0
- package/dist/agent/ledger.d.ts.map +1 -0
- package/dist/agent/ledger.js +48 -0
- package/dist/agent/ledger.js.map +1 -0
- package/dist/agent/loop-guards.d.ts +35 -0
- package/dist/agent/loop-guards.d.ts.map +1 -0
- package/dist/agent/loop-guards.js +110 -0
- package/dist/agent/loop-guards.js.map +1 -0
- package/dist/agent/model/adapter.d.ts +97 -0
- package/dist/agent/model/adapter.d.ts.map +1 -0
- package/dist/agent/model/adapter.js +40 -0
- package/dist/agent/model/adapter.js.map +1 -0
- package/dist/agent/model/router.d.ts +36 -0
- package/dist/agent/model/router.d.ts.map +1 -0
- package/dist/agent/model/router.js +45 -0
- package/dist/agent/model/router.js.map +1 -0
- package/dist/agent/model/schema.d.ts +16 -0
- package/dist/agent/model/schema.d.ts.map +1 -0
- package/dist/agent/model/schema.js +37 -0
- package/dist/agent/model/schema.js.map +1 -0
- package/dist/agent/model/sdk.d.ts +28 -0
- package/dist/agent/model/sdk.d.ts.map +1 -0
- package/dist/agent/model/sdk.js +258 -0
- package/dist/agent/model/sdk.js.map +1 -0
- package/dist/agent/observation.d.ts +70 -0
- package/dist/agent/observation.d.ts.map +1 -0
- package/dist/agent/observation.js +174 -0
- package/dist/agent/observation.js.map +1 -0
- package/dist/agent/phases.d.ts +71 -0
- package/dist/agent/phases.d.ts.map +1 -0
- package/dist/agent/phases.js +124 -0
- package/dist/agent/phases.js.map +1 -0
- package/dist/agent/prompts.d.ts +40 -0
- package/dist/agent/prompts.d.ts.map +1 -0
- package/dist/agent/prompts.js +104 -0
- package/dist/agent/prompts.js.map +1 -0
- package/dist/agent/protocol.d.ts +31 -0
- package/dist/agent/protocol.d.ts.map +1 -0
- package/dist/agent/protocol.js +67 -0
- package/dist/agent/protocol.js.map +1 -0
- package/dist/agent/public.d.ts +12 -0
- package/dist/agent/public.d.ts.map +1 -0
- package/dist/agent/public.js +12 -0
- package/dist/agent/public.js.map +1 -0
- package/dist/agent/replay.d.ts +61 -0
- package/dist/agent/replay.d.ts.map +1 -0
- package/dist/agent/replay.js +185 -0
- package/dist/agent/replay.js.map +1 -0
- package/dist/agent/secrets.d.ts +22 -0
- package/dist/agent/secrets.d.ts.map +1 -0
- package/dist/agent/secrets.js +63 -0
- package/dist/agent/secrets.js.map +1 -0
- package/dist/agent/step-cache.d.ts +156 -0
- package/dist/agent/step-cache.d.ts.map +1 -0
- package/dist/agent/step-cache.js +301 -0
- package/dist/agent/step-cache.js.map +1 -0
- package/dist/agent/tool-loop.d.ts +51 -0
- package/dist/agent/tool-loop.d.ts.map +1 -0
- package/dist/agent/tool-loop.js +331 -0
- package/dist/agent/tool-loop.js.map +1 -0
- package/dist/agent/tool.d.ts +39 -0
- package/dist/agent/tool.d.ts.map +1 -0
- package/dist/agent/tool.js +52 -0
- package/dist/agent/tool.js.map +1 -0
- package/dist/backend/contract.d.ts +186 -0
- package/dist/backend/contract.d.ts.map +1 -0
- package/dist/backend/contract.js +65 -0
- package/dist/backend/contract.js.map +1 -0
- package/dist/backend/index.d.ts +316 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +219 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/session.d.ts +23 -0
- package/dist/backend/session.d.ts.map +1 -0
- package/dist/backend/session.js +213 -0
- package/dist/backend/session.js.map +1 -0
- package/dist/backend/surface.d.ts +83 -0
- package/dist/backend/surface.d.ts.map +1 -0
- package/dist/backend/surface.js +11 -0
- package/dist/backend/surface.js.map +1 -0
- package/dist/cache/anchors.d.ts +37 -0
- package/dist/cache/anchors.d.ts.map +1 -0
- package/dist/cache/anchors.js +89 -0
- package/dist/cache/anchors.js.map +1 -0
- package/dist/cache/context.d.ts +74 -0
- package/dist/cache/context.d.ts.map +1 -0
- package/dist/cache/context.js +82 -0
- package/dist/cache/context.js.map +1 -0
- package/dist/cache/decide.d.ts +42 -0
- package/dist/cache/decide.d.ts.map +1 -0
- package/dist/cache/decide.js +47 -0
- package/dist/cache/decide.js.map +1 -0
- package/dist/cache/identity.d.ts +113 -0
- package/dist/cache/identity.d.ts.map +1 -0
- package/dist/cache/identity.js +109 -0
- package/dist/cache/identity.js.map +1 -0
- package/dist/cache/recorder.d.ts +76 -0
- package/dist/cache/recorder.d.ts.map +1 -0
- package/dist/cache/recorder.js +143 -0
- package/dist/cache/recorder.js.map +1 -0
- package/dist/cache/relocate.d.ts +69 -0
- package/dist/cache/relocate.d.ts.map +1 -0
- package/dist/cache/relocate.js +125 -0
- package/dist/cache/relocate.js.map +1 -0
- package/dist/cache/store.d.ts +68 -0
- package/dist/cache/store.d.ts.map +1 -0
- package/dist/cache/store.js +106 -0
- package/dist/cache/store.js.map +1 -0
- package/dist/cache/trace.d.ts +146 -0
- package/dist/cache/trace.d.ts.map +1 -0
- package/dist/cache/trace.js +249 -0
- package/dist/cache/trace.js.map +1 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +4 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/index.d.ts +4 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +108 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +6 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +101 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/collect/collect.d.ts +44 -0
- package/dist/collect/collect.d.ts.map +1 -0
- package/dist/collect/collect.js +89 -0
- package/dist/collect/collect.js.map +1 -0
- package/dist/collect/registry.d.ts +47 -0
- package/dist/collect/registry.d.ts.map +1 -0
- package/dist/collect/registry.js +262 -0
- package/dist/collect/registry.js.map +1 -0
- package/dist/collect/select.d.ts +54 -0
- package/dist/collect/select.d.ts.map +1 -0
- package/dist/collect/select.js +230 -0
- package/dist/collect/select.js.map +1 -0
- package/dist/config/agent.d.ts +91 -0
- package/dist/config/agent.d.ts.map +1 -0
- package/dist/config/agent.js +232 -0
- package/dist/config/agent.js.map +1 -0
- package/dist/config/load.d.ts +23 -0
- package/dist/config/load.d.ts.map +1 -0
- package/dist/config/load.js +75 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/resolve.d.ts +94 -0
- package/dist/config/resolve.d.ts.map +1 -0
- package/dist/config/resolve.js +500 -0
- package/dist/config/resolve.js.map +1 -0
- package/dist/config/validate.d.ts +6 -0
- package/dist/config/validate.d.ts.map +1 -0
- package/dist/config/validate.js +21 -0
- package/dist/config/validate.js.map +1 -0
- package/dist/credentials.d.ts +7 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +42 -0
- package/dist/credentials.js.map +1 -0
- package/dist/expect/async.d.ts +5 -0
- package/dist/expect/async.d.ts.map +1 -0
- package/dist/expect/async.js +186 -0
- package/dist/expect/async.js.map +1 -0
- package/dist/expect/index.d.ts +7 -0
- package/dist/expect/index.d.ts.map +1 -0
- package/dist/expect/index.js +23 -0
- package/dist/expect/index.js.map +1 -0
- package/dist/expect/values.d.ts +4 -0
- package/dist/expect/values.d.ts.map +1 -0
- package/dist/expect/values.js +108 -0
- package/dist/expect/values.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/ai-trace.d.ts +151 -0
- package/dist/internal/ai-trace.d.ts.map +1 -0
- package/dist/internal/ai-trace.js +360 -0
- package/dist/internal/ai-trace.js.map +1 -0
- package/dist/internal/brands.d.ts +9 -0
- package/dist/internal/brands.d.ts.map +1 -0
- package/dist/internal/brands.js +9 -0
- package/dist/internal/brands.js.map +1 -0
- package/dist/internal/debug.d.ts +43 -0
- package/dist/internal/debug.d.ts.map +1 -0
- package/dist/internal/debug.js +102 -0
- package/dist/internal/debug.js.map +1 -0
- package/dist/internal/errors.d.ts +98 -0
- package/dist/internal/errors.d.ts.map +1 -0
- package/dist/internal/errors.js +212 -0
- package/dist/internal/errors.js.map +1 -0
- package/dist/internal/globs.d.ts +29 -0
- package/dist/internal/globs.d.ts.map +1 -0
- package/dist/internal/globs.js +126 -0
- package/dist/internal/globs.js.map +1 -0
- package/dist/internal/ids.d.ts +32 -0
- package/dist/internal/ids.d.ts.map +1 -0
- package/dist/internal/ids.js +124 -0
- package/dist/internal/ids.js.map +1 -0
- package/dist/internal/json-value.d.ts +15 -0
- package/dist/internal/json-value.d.ts.map +1 -0
- package/dist/internal/json-value.js +61 -0
- package/dist/internal/json-value.js.map +1 -0
- package/dist/internal/package-version.d.ts +6 -0
- package/dist/internal/package-version.d.ts.map +1 -0
- package/dist/internal/package-version.js +14 -0
- package/dist/internal/package-version.js.map +1 -0
- package/dist/internal/realm-slot.d.ts +13 -0
- package/dist/internal/realm-slot.d.ts.map +1 -0
- package/dist/internal/realm-slot.js +23 -0
- package/dist/internal/realm-slot.js.map +1 -0
- package/dist/internal/redact.d.ts +33 -0
- package/dist/internal/redact.d.ts.map +1 -0
- package/dist/internal/redact.js +56 -0
- package/dist/internal/redact.js.map +1 -0
- package/dist/internal/regexp.d.ts +10 -0
- package/dist/internal/regexp.d.ts.map +1 -0
- package/dist/internal/regexp.js +27 -0
- package/dist/internal/regexp.js.map +1 -0
- package/dist/internal/text.d.ts +39 -0
- package/dist/internal/text.d.ts.map +1 -0
- package/dist/internal/text.js +66 -0
- package/dist/internal/text.js.map +1 -0
- package/dist/internal/time.d.ts +37 -0
- package/dist/internal/time.d.ts.map +1 -0
- package/dist/internal/time.js +91 -0
- package/dist/internal/time.js.map +1 -0
- package/dist/internal/trace.d.ts +18 -0
- package/dist/internal/trace.d.ts.map +1 -0
- package/dist/internal/trace.js +46 -0
- package/dist/internal/trace.js.map +1 -0
- package/dist/internal/urls.d.ts +31 -0
- package/dist/internal/urls.d.ts.map +1 -0
- package/dist/internal/urls.js +95 -0
- package/dist/internal/urls.js.map +1 -0
- package/dist/locator/engine.d.ts +65 -0
- package/dist/locator/engine.d.ts.map +1 -0
- package/dist/locator/engine.js +164 -0
- package/dist/locator/engine.js.map +1 -0
- package/dist/locator/expression.d.ts +19 -0
- package/dist/locator/expression.d.ts.map +1 -0
- package/dist/locator/expression.js +85 -0
- package/dist/locator/expression.js.map +1 -0
- package/dist/locator/screen.d.ts +36 -0
- package/dist/locator/screen.d.ts.map +1 -0
- package/dist/locator/screen.js +281 -0
- package/dist/locator/screen.js.map +1 -0
- package/dist/report/build.d.ts +214 -0
- package/dist/report/build.d.ts.map +1 -0
- package/dist/report/build.js +346 -0
- package/dist/report/build.js.map +1 -0
- package/dist/report/code-frame.d.ts +20 -0
- package/dist/report/code-frame.d.ts.map +1 -0
- package/dist/report/code-frame.js +73 -0
- package/dist/report/code-frame.js.map +1 -0
- package/dist/report/debug-steps.d.ts +14 -0
- package/dist/report/debug-steps.d.ts.map +1 -0
- package/dist/report/debug-steps.js +85 -0
- package/dist/report/debug-steps.js.map +1 -0
- package/dist/report/list.d.ts +80 -0
- package/dist/report/list.d.ts.map +1 -0
- package/dist/report/list.js +372 -0
- package/dist/report/list.js.map +1 -0
- package/dist/report/live-status.d.ts +51 -0
- package/dist/report/live-status.d.ts.map +1 -0
- package/dist/report/live-status.js +162 -0
- package/dist/report/live-status.js.map +1 -0
- package/dist/report/write.d.ts +4 -0
- package/dist/report/write.d.ts.map +1 -0
- package/dist/report/write.js +13 -0
- package/dist/report/write.js.map +1 -0
- package/dist/run/app-process.d.ts +18 -0
- package/dist/run/app-process.d.ts.map +1 -0
- package/dist/run/app-process.js +112 -0
- package/dist/run/app-process.js.map +1 -0
- package/dist/run/artifacts.d.ts +51 -0
- package/dist/run/artifacts.d.ts.map +1 -0
- package/dist/run/artifacts.js +114 -0
- package/dist/run/artifacts.js.map +1 -0
- package/dist/run/events.d.ts +100 -0
- package/dist/run/events.d.ts.map +1 -0
- package/dist/run/events.js +59 -0
- package/dist/run/events.js.map +1 -0
- package/dist/run/execute.d.ts +119 -0
- package/dist/run/execute.d.ts.map +1 -0
- package/dist/run/execute.js +555 -0
- package/dist/run/execute.js.map +1 -0
- package/dist/run/fixtures.d.ts +40 -0
- package/dist/run/fixtures.d.ts.map +1 -0
- package/dist/run/fixtures.js +408 -0
- package/dist/run/fixtures.js.map +1 -0
- package/dist/run/in-process.d.ts +24 -0
- package/dist/run/in-process.d.ts.map +1 -0
- package/dist/run/in-process.js +120 -0
- package/dist/run/in-process.js.map +1 -0
- package/dist/run/public.d.ts +19 -0
- package/dist/run/public.d.ts.map +1 -0
- package/dist/run/public.js +11 -0
- package/dist/run/public.js.map +1 -0
- package/dist/run/realm.d.ts +52 -0
- package/dist/run/realm.d.ts.map +1 -0
- package/dist/run/realm.js +101 -0
- package/dist/run/realm.js.map +1 -0
- package/dist/run/records.d.ts +87 -0
- package/dist/run/records.d.ts.map +1 -0
- package/dist/run/records.js +3 -0
- package/dist/run/records.js.map +1 -0
- package/dist/run/retry.d.ts +18 -0
- package/dist/run/retry.d.ts.map +1 -0
- package/dist/run/retry.js +33 -0
- package/dist/run/retry.js.map +1 -0
- package/dist/run/runner.d.ts +49 -0
- package/dist/run/runner.d.ts.map +1 -0
- package/dist/run/runner.js +375 -0
- package/dist/run/runner.js.map +1 -0
- package/dist/run/scheduler.d.ts +45 -0
- package/dist/run/scheduler.d.ts.map +1 -0
- package/dist/run/scheduler.js +512 -0
- package/dist/run/scheduler.js.map +1 -0
- package/dist/run/serial.d.ts +52 -0
- package/dist/run/serial.d.ts.map +1 -0
- package/dist/run/serial.js +247 -0
- package/dist/run/serial.js.map +1 -0
- package/dist/run/sessions.d.ts +54 -0
- package/dist/run/sessions.d.ts.map +1 -0
- package/dist/run/sessions.js +221 -0
- package/dist/run/sessions.js.map +1 -0
- package/dist/run/steps.d.ts +196 -0
- package/dist/run/steps.d.ts.map +1 -0
- package/dist/run/steps.js +151 -0
- package/dist/run/steps.js.map +1 -0
- package/dist/run/unit-runner.d.ts +30 -0
- package/dist/run/unit-runner.d.ts.map +1 -0
- package/dist/run/unit-runner.js +11 -0
- package/dist/run/unit-runner.js.map +1 -0
- package/dist/run/units.d.ts +50 -0
- package/dist/run/units.d.ts.map +1 -0
- package/dist/run/units.js +103 -0
- package/dist/run/units.js.map +1 -0
- package/dist/run/worker/entry.d.ts +8 -0
- package/dist/run/worker/entry.d.ts.map +1 -0
- package/dist/run/worker/entry.js +137 -0
- package/dist/run/worker/entry.js.map +1 -0
- package/dist/run/worker/handle.d.ts +10 -0
- package/dist/run/worker/handle.d.ts.map +1 -0
- package/dist/run/worker/handle.js +74 -0
- package/dist/run/worker/handle.js.map +1 -0
- package/dist/run/worker/protocol.d.ts +129 -0
- package/dist/run/worker/protocol.d.ts.map +1 -0
- package/dist/run/worker/protocol.js +18 -0
- package/dist/run/worker/protocol.js.map +1 -0
- package/dist/run/worker/session.d.ts +69 -0
- package/dist/run/worker/session.d.ts.map +1 -0
- package/dist/run/worker/session.js +123 -0
- package/dist/run/worker/session.js.map +1 -0
- package/dist/types.d.ts +630 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +91 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-step replay decision (RFC0001 layer 3, cache-in decision).
|
|
3
|
+
*
|
|
4
|
+
* Pure and fail-to-miss: every reason a validated entry cannot replay is a
|
|
5
|
+
* miss that dispatches the live executor, never an error and never a step
|
|
6
|
+
* failure. Validation has one owner — the store (`readTraceEntry`) — so this
|
|
7
|
+
* decision takes an already-trusted entry and answers only the questions the
|
|
8
|
+
* entry alone cannot: is it whole, and is the app where the recording began?
|
|
9
|
+
*/
|
|
10
|
+
import type { ActionTrace, TraceEntry } from './trace.ts';
|
|
11
|
+
/**
|
|
12
|
+
* Whether two recorded locations are the same page. Pathname only, at both
|
|
13
|
+
* ends of a trace: a volatile query string (`?utm=…`, a cache-busting stamp)
|
|
14
|
+
* must not break zero-turn, and the relocated targets and end anchors — not
|
|
15
|
+
* the query — are what prove the screen is the one the flow was proven on.
|
|
16
|
+
*/
|
|
17
|
+
export declare function samePathname(a: string, b: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Whether a trace establishes its own starting point by navigating first.
|
|
20
|
+
* Such a trace needs no start-path precondition — and a trace with neither
|
|
21
|
+
* anchor can never replay at all, so it is not worth writing.
|
|
22
|
+
*/
|
|
23
|
+
export declare function opensWithNavigate(trace: ActionTrace): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* The full miss vocabulary of the report. `no-entry` and `invalid-entry` are
|
|
26
|
+
* assigned by the store-read path; this decision produces the other two.
|
|
27
|
+
*/
|
|
28
|
+
export type TraceReplayMissReason = 'no-entry' | 'invalid-entry' | 'truncated' | 'wrong-context';
|
|
29
|
+
export type TraceReplayDecision = {
|
|
30
|
+
readonly action: 'replay';
|
|
31
|
+
} | {
|
|
32
|
+
readonly action: 'miss';
|
|
33
|
+
readonly reason: 'truncated' | 'wrong-context';
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Decides whether one entry replays for the current step. A trace that does
|
|
37
|
+
* not open with a navigate carries a start-path precondition: the app must
|
|
38
|
+
* be on the page where the recording began, or the recorded actions would
|
|
39
|
+
* run against a different screen than they were proven on.
|
|
40
|
+
*/
|
|
41
|
+
export declare function decideTraceReplay(entry: TraceEntry, currentPath: string | undefined): TraceReplayDecision;
|
|
42
|
+
//# sourceMappingURL=decide.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decide.d.ts","sourceRoot":"","sources":["../../src/cache/decide.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAE1D;AAMD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE7D;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,eAAe,GAAG,WAAW,GAAG,eAAe,CAAC;AAEjG,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,GAC7B;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,eAAe,CAAA;CAAE,CAAC;AAEhF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,UAAU,EACjB,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,mBAAmB,CASrB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-step replay decision (RFC0001 layer 3, cache-in decision).
|
|
3
|
+
*
|
|
4
|
+
* Pure and fail-to-miss: every reason a validated entry cannot replay is a
|
|
5
|
+
* miss that dispatches the live executor, never an error and never a step
|
|
6
|
+
* failure. Validation has one owner — the store (`readTraceEntry`) — so this
|
|
7
|
+
* decision takes an already-trusted entry and answers only the questions the
|
|
8
|
+
* entry alone cannot: is it whole, and is the app where the recording began?
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Whether two recorded locations are the same page. Pathname only, at both
|
|
12
|
+
* ends of a trace: a volatile query string (`?utm=…`, a cache-busting stamp)
|
|
13
|
+
* must not break zero-turn, and the relocated targets and end anchors — not
|
|
14
|
+
* the query — are what prove the screen is the one the flow was proven on.
|
|
15
|
+
*/
|
|
16
|
+
export function samePathname(a, b) {
|
|
17
|
+
return pathnameOf(a) === pathnameOf(b);
|
|
18
|
+
}
|
|
19
|
+
function pathnameOf(path) {
|
|
20
|
+
return path.split('?')[0] ?? path;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Whether a trace establishes its own starting point by navigating first.
|
|
24
|
+
* Such a trace needs no start-path precondition — and a trace with neither
|
|
25
|
+
* anchor can never replay at all, so it is not worth writing.
|
|
26
|
+
*/
|
|
27
|
+
export function opensWithNavigate(trace) {
|
|
28
|
+
return trace.actions.find((action) => action.name !== 'tool')?.name === 'navigate';
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Decides whether one entry replays for the current step. A trace that does
|
|
32
|
+
* not open with a navigate carries a start-path precondition: the app must
|
|
33
|
+
* be on the page where the recording began, or the recorded actions would
|
|
34
|
+
* run against a different screen than they were proven on.
|
|
35
|
+
*/
|
|
36
|
+
export function decideTraceReplay(entry, currentPath) {
|
|
37
|
+
if (entry.payload.truncated === true)
|
|
38
|
+
return { action: 'miss', reason: 'truncated' };
|
|
39
|
+
if (!opensWithNavigate(entry.payload)) {
|
|
40
|
+
const startPath = entry.payload.startPath;
|
|
41
|
+
if (startPath === undefined || currentPath === undefined || !samePathname(startPath, currentPath)) {
|
|
42
|
+
return { action: 'miss', reason: 'wrong-context' };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return { action: 'replay' };
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=decide.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decide.js","sourceRoot":"","sources":["../../src/cache/decide.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,CAAS,EAAE,CAAS;IAC/C,OAAO,UAAU,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACpC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAkB;IAClD,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,EAAE,IAAI,KAAK,UAAU,CAAC;AACrF,CAAC;AAYD;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAiB,EACjB,WAA+B;IAE/B,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,KAAK,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IACrF,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;QAC1C,IAAI,SAAS,KAAK,SAAS,IAAI,WAAW,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,WAAW,CAAC,EAAE,CAAC;YAClG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;QACrD,CAAC;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trace cache key identity (RFC0001 layer 3, cache-in decision).
|
|
3
|
+
*
|
|
4
|
+
* A key names the exact context a trace was recorded in. Every field that can
|
|
5
|
+
* change replay behavior is part of the key, so a stale entry can only ever be
|
|
6
|
+
* a miss rather than a wrong answer. Secret values never enter a key: a secret
|
|
7
|
+
* contributes only its stable name and purpose, exactly as the executor sees
|
|
8
|
+
* it in the projected params.
|
|
9
|
+
*
|
|
10
|
+
* Executor identity is deliberately absent (OQ10's conservative default):
|
|
11
|
+
* entries are shared across roster members and carry their producer as
|
|
12
|
+
* provenance on the entry, so a future ReplayPolicy can reject foreign traces
|
|
13
|
+
* without a re-key.
|
|
14
|
+
*/
|
|
15
|
+
import type { JsonValue } from '../types.ts';
|
|
16
|
+
import { TRACE_SCHEMA_VERSION } from './trace.ts';
|
|
17
|
+
/**
|
|
18
|
+
* Step kinds the trace cache admits. Only `act` today: an assert must not
|
|
19
|
+
* change state, so its trace would be action-free, and judgments are made
|
|
20
|
+
* fresh per run by normative rule (spec 10).
|
|
21
|
+
*/
|
|
22
|
+
export type TraceCacheKind = 'act';
|
|
23
|
+
export interface TraceCacheKey {
|
|
24
|
+
readonly specVersion: '0.1';
|
|
25
|
+
readonly cacheSchema: typeof TRACE_SCHEMA_VERSION;
|
|
26
|
+
/** SHA-256 of the resolved `projectId`. */
|
|
27
|
+
readonly project: string;
|
|
28
|
+
readonly testId: string;
|
|
29
|
+
readonly targetId: string;
|
|
30
|
+
readonly platform: string;
|
|
31
|
+
readonly backendName: string;
|
|
32
|
+
readonly backendVersion: string;
|
|
33
|
+
readonly backendSpiVersion: number;
|
|
34
|
+
readonly kind: TraceCacheKind;
|
|
35
|
+
/** Zero-based occurrence of this signature within the attempt. */
|
|
36
|
+
readonly callIndex: number;
|
|
37
|
+
readonly instructionDigest: string;
|
|
38
|
+
readonly paramsDigest: string;
|
|
39
|
+
readonly appIdentity: string;
|
|
40
|
+
readonly policyVersion: string;
|
|
41
|
+
}
|
|
42
|
+
/** Identity of the target/backend/app a trace was recorded against. */
|
|
43
|
+
export interface CacheTargetIdentity {
|
|
44
|
+
readonly targetId: string;
|
|
45
|
+
readonly platform: string;
|
|
46
|
+
readonly backendName: string;
|
|
47
|
+
readonly backendVersion: string;
|
|
48
|
+
readonly spiVersion: number;
|
|
49
|
+
readonly appIdentity: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Reduces a backend version to the part that can change how a semantic node
|
|
53
|
+
* resolves: `1.61.1` becomes `1.61`. Keying on the exact version cold-started
|
|
54
|
+
* every entry on a patch release for no benefit; a minor might change matching,
|
|
55
|
+
* so that part is kept. A version that is not `major.minor[.patch]` is used
|
|
56
|
+
* unchanged rather than guessed at.
|
|
57
|
+
*/
|
|
58
|
+
export declare function backendCompatibilityVersion(version: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Normalizes one instruction before digesting it: CRLF/CR become LF, the text
|
|
61
|
+
* is NFC-normalized, and leading/trailing Unicode whitespace is trimmed.
|
|
62
|
+
* Interior whitespace is preserved, because it can be semantically meaningful.
|
|
63
|
+
*/
|
|
64
|
+
export declare function normalizeInstruction(instruction: string): string;
|
|
65
|
+
/** SHA-256 of the normalized instruction. */
|
|
66
|
+
export declare function instructionDigest(instruction: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* SHA-256/JCS of the projected (secret-free) call parameters. A missing params
|
|
69
|
+
* object digests as the empty object, so `act(x)` and `act(x, {})` share one
|
|
70
|
+
* entry.
|
|
71
|
+
*/
|
|
72
|
+
export declare function paramsDigest(params: Readonly<Record<string, JsonValue>> | undefined): string;
|
|
73
|
+
/** SHA-256 of the resolved project identity. */
|
|
74
|
+
export declare function projectIdentity(projectId: string): string;
|
|
75
|
+
/**
|
|
76
|
+
* What a step asks for, independent of where it sits in the test: the kind
|
|
77
|
+
* plus the digests of its instruction and projected parameters.
|
|
78
|
+
*
|
|
79
|
+
* Two steps sharing a signature are the same request, so this is the scope the
|
|
80
|
+
* occurrence index counts within. Scoping it any wider — counting every agent
|
|
81
|
+
* step in the test — would make an unrelated step appearing or disappearing
|
|
82
|
+
* renumber every entry after it, which is exactly what a conditional flow like
|
|
83
|
+
* an optional cookie dialog does on a real site.
|
|
84
|
+
*/
|
|
85
|
+
export interface TraceCallSignature {
|
|
86
|
+
readonly kind: TraceCacheKind;
|
|
87
|
+
readonly instructionDigest: string;
|
|
88
|
+
readonly paramsDigest: string;
|
|
89
|
+
}
|
|
90
|
+
/** Builds one signature by digesting the instruction and projected parameters. */
|
|
91
|
+
export declare function traceCallSignature(kind: TraceCacheKind, instruction: string, params: Readonly<Record<string, JsonValue>> | undefined): TraceCallSignature;
|
|
92
|
+
/**
|
|
93
|
+
* Counts occurrences of each call signature within one attempt, returning the
|
|
94
|
+
* zero-based index of each step among its own repeats. Per signature rather
|
|
95
|
+
* than per attempt on purpose: only a genuine repeat of the same request
|
|
96
|
+
* advances the number.
|
|
97
|
+
*/
|
|
98
|
+
export declare function createCallIndexer(): (signature: TraceCallSignature) => number;
|
|
99
|
+
/**
|
|
100
|
+
* Assembles one key. Field order is irrelevant to the digest, since JCS sorts
|
|
101
|
+
* keys, but the explicit shape keeps every required field accounted for.
|
|
102
|
+
*/
|
|
103
|
+
export declare function buildTraceCacheKey(parts: {
|
|
104
|
+
readonly project: string;
|
|
105
|
+
readonly testId: string;
|
|
106
|
+
readonly target: CacheTargetIdentity;
|
|
107
|
+
readonly signature: TraceCallSignature;
|
|
108
|
+
readonly callIndex: number;
|
|
109
|
+
readonly policyVersion: string;
|
|
110
|
+
}): TraceCacheKey;
|
|
111
|
+
/** SHA-256/JCS of one key, used as both the entry digest and its file name. */
|
|
112
|
+
export declare function traceCacheKeyHash(key: TraceCacheKey): string;
|
|
113
|
+
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/cache/identity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trace cache key identity (RFC0001 layer 3, cache-in decision).
|
|
3
|
+
*
|
|
4
|
+
* A key names the exact context a trace was recorded in. Every field that can
|
|
5
|
+
* change replay behavior is part of the key, so a stale entry can only ever be
|
|
6
|
+
* a miss rather than a wrong answer. Secret values never enter a key: a secret
|
|
7
|
+
* contributes only its stable name and purpose, exactly as the executor sees
|
|
8
|
+
* it in the projected params.
|
|
9
|
+
*
|
|
10
|
+
* Executor identity is deliberately absent (OQ10's conservative default):
|
|
11
|
+
* entries are shared across roster members and carry their producer as
|
|
12
|
+
* provenance on the entry, so a future ReplayPolicy can reject foreign traces
|
|
13
|
+
* without a re-key.
|
|
14
|
+
*/
|
|
15
|
+
import { canonicalDigest, sha256Hex } from '../internal/ids.js';
|
|
16
|
+
import { TRACE_SCHEMA_VERSION } from './trace.js';
|
|
17
|
+
/**
|
|
18
|
+
* Reduces a backend version to the part that can change how a semantic node
|
|
19
|
+
* resolves: `1.61.1` becomes `1.61`. Keying on the exact version cold-started
|
|
20
|
+
* every entry on a patch release for no benefit; a minor might change matching,
|
|
21
|
+
* so that part is kept. A version that is not `major.minor[.patch]` is used
|
|
22
|
+
* unchanged rather than guessed at.
|
|
23
|
+
*/
|
|
24
|
+
export function backendCompatibilityVersion(version) {
|
|
25
|
+
const match = /^(\d+)\.(\d+)(?:[.\-+].*)?$/u.exec(version);
|
|
26
|
+
return match === null ? version : `${match[1]}.${match[2]}`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Normalizes one instruction before digesting it: CRLF/CR become LF, the text
|
|
30
|
+
* is NFC-normalized, and leading/trailing Unicode whitespace is trimmed.
|
|
31
|
+
* Interior whitespace is preserved, because it can be semantically meaningful.
|
|
32
|
+
*/
|
|
33
|
+
export function normalizeInstruction(instruction) {
|
|
34
|
+
return instruction.replace(/\r\n?/gu, '\n').normalize('NFC').trim();
|
|
35
|
+
}
|
|
36
|
+
/** SHA-256 of the normalized instruction. */
|
|
37
|
+
export function instructionDigest(instruction) {
|
|
38
|
+
return sha256Hex(normalizeInstruction(instruction));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* SHA-256/JCS of the projected (secret-free) call parameters. A missing params
|
|
42
|
+
* object digests as the empty object, so `act(x)` and `act(x, {})` share one
|
|
43
|
+
* entry.
|
|
44
|
+
*/
|
|
45
|
+
export function paramsDigest(params) {
|
|
46
|
+
return canonicalDigest(params ?? {});
|
|
47
|
+
}
|
|
48
|
+
/** SHA-256 of the resolved project identity. */
|
|
49
|
+
export function projectIdentity(projectId) {
|
|
50
|
+
return sha256Hex(projectId);
|
|
51
|
+
}
|
|
52
|
+
/** Builds one signature by digesting the instruction and projected parameters. */
|
|
53
|
+
export function traceCallSignature(kind, instruction, params) {
|
|
54
|
+
return {
|
|
55
|
+
kind,
|
|
56
|
+
instructionDigest: instructionDigest(instruction),
|
|
57
|
+
paramsDigest: paramsDigest(params),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Map key for one signature. Both digests are hex, so a colon cannot appear
|
|
62
|
+
* inside either and the join is unambiguous.
|
|
63
|
+
*/
|
|
64
|
+
function traceCallSignatureKey(signature) {
|
|
65
|
+
return `${signature.kind}:${signature.instructionDigest}:${signature.paramsDigest}`;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Counts occurrences of each call signature within one attempt, returning the
|
|
69
|
+
* zero-based index of each step among its own repeats. Per signature rather
|
|
70
|
+
* than per attempt on purpose: only a genuine repeat of the same request
|
|
71
|
+
* advances the number.
|
|
72
|
+
*/
|
|
73
|
+
export function createCallIndexer() {
|
|
74
|
+
const seen = new Map();
|
|
75
|
+
return (signature) => {
|
|
76
|
+
const mapKey = traceCallSignatureKey(signature);
|
|
77
|
+
const count = seen.get(mapKey) ?? 0;
|
|
78
|
+
seen.set(mapKey, count + 1);
|
|
79
|
+
return count;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Assembles one key. Field order is irrelevant to the digest, since JCS sorts
|
|
84
|
+
* keys, but the explicit shape keeps every required field accounted for.
|
|
85
|
+
*/
|
|
86
|
+
export function buildTraceCacheKey(parts) {
|
|
87
|
+
return {
|
|
88
|
+
specVersion: '0.1',
|
|
89
|
+
cacheSchema: TRACE_SCHEMA_VERSION,
|
|
90
|
+
project: parts.project,
|
|
91
|
+
testId: parts.testId,
|
|
92
|
+
targetId: parts.target.targetId,
|
|
93
|
+
platform: parts.target.platform,
|
|
94
|
+
backendName: parts.target.backendName,
|
|
95
|
+
backendVersion: backendCompatibilityVersion(parts.target.backendVersion),
|
|
96
|
+
backendSpiVersion: parts.target.spiVersion,
|
|
97
|
+
kind: parts.signature.kind,
|
|
98
|
+
callIndex: parts.callIndex,
|
|
99
|
+
instructionDigest: parts.signature.instructionDigest,
|
|
100
|
+
paramsDigest: parts.signature.paramsDigest,
|
|
101
|
+
appIdentity: parts.target.appIdentity,
|
|
102
|
+
policyVersion: parts.policyVersion,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** SHA-256/JCS of one key, used as both the entry digest and its file name. */
|
|
106
|
+
export function traceCacheKeyHash(key) {
|
|
107
|
+
return canonicalDigest(key);
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/cache/identity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Step trace recording (RFC0001 layer 3, cache-in decision).
|
|
3
|
+
*
|
|
4
|
+
* Records every grammar action a step commits, capturing a durable target
|
|
5
|
+
* descriptor at commit time — the moment the harness resolved the node — so
|
|
6
|
+
* replay can re-find it against a fresh observation. Recording is
|
|
7
|
+
* defense-in-depth on secrets: callers already hand secret-free input
|
|
8
|
+
* (`typeSecret` contributes only the secret's stable name), and every string
|
|
9
|
+
* that could carry screen content is additionally passed through the run's
|
|
10
|
+
* redactor before it can reach disk.
|
|
11
|
+
*
|
|
12
|
+
* Replay inputs are verbatim or nothing. A value the redactor would alter, or
|
|
13
|
+
* one over the input cap, poisons the trace (`truncated`) instead of being
|
|
14
|
+
* bent to fit: a trimmed URL or half a typed value would replay a different
|
|
15
|
+
* action than the one recorded, and could self-finalize a step on the wrong
|
|
16
|
+
* state. A poisoned trace still documents what happened; it never replays.
|
|
17
|
+
*/
|
|
18
|
+
import { type RecordableAction } from '../agent/actions.ts';
|
|
19
|
+
import { type ActionTrace, type TraceTargetDescriptor } from './trace.ts';
|
|
20
|
+
export interface TraceRecorderOptions {
|
|
21
|
+
/** The run's secret redactor; applied to every recorded string. */
|
|
22
|
+
readonly redact: (text: string) => string;
|
|
23
|
+
readonly testIdAttribute: string;
|
|
24
|
+
readonly maxActions?: number;
|
|
25
|
+
}
|
|
26
|
+
export declare class TraceRecorder {
|
|
27
|
+
private readonly actions;
|
|
28
|
+
private truncated;
|
|
29
|
+
private readonly redact;
|
|
30
|
+
private readonly testIdAttribute;
|
|
31
|
+
private readonly maxActions;
|
|
32
|
+
constructor(options: TraceRecorderOptions);
|
|
33
|
+
/** Number of actions recorded so far, gaps included. */
|
|
34
|
+
get recordedCount(): number;
|
|
35
|
+
/** Records one committed grammar action. */
|
|
36
|
+
record(action: RecordableAction): void;
|
|
37
|
+
/**
|
|
38
|
+
* Records one mutating project-tool call as a gap. Replay ends here rather
|
|
39
|
+
* than skipping it: the grammar cannot reproduce the mutation, and a replay
|
|
40
|
+
* that silently dropped a state change would prove nothing.
|
|
41
|
+
*/
|
|
42
|
+
recordGap(toolName: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* Concludes recording into a trace, or undefined when nothing was recorded —
|
|
45
|
+
* a step that committed no actions has no flow worth replaying.
|
|
46
|
+
*/
|
|
47
|
+
finalize(conclusion: {
|
|
48
|
+
readonly executor: {
|
|
49
|
+
readonly name: string;
|
|
50
|
+
readonly version?: string;
|
|
51
|
+
};
|
|
52
|
+
readonly summary: string;
|
|
53
|
+
readonly startPath?: string;
|
|
54
|
+
readonly endPath?: string;
|
|
55
|
+
/** Already projected and capped by `describeAnchors`; recorded as given. */
|
|
56
|
+
readonly endAnchors?: readonly TraceTargetDescriptor[];
|
|
57
|
+
}): ActionTrace | undefined;
|
|
58
|
+
private anchorPath;
|
|
59
|
+
/**
|
|
60
|
+
* Builds the stored variant for one action. The descriptor and the prose
|
|
61
|
+
* come from `describeAction` — already redacted and bounded, and the same
|
|
62
|
+
* text the live event carried. Stored inputs still go through `verbatim`,
|
|
63
|
+
* whose poisoning marks the trace non-replayable when a value cannot be
|
|
64
|
+
* kept whole.
|
|
65
|
+
*/
|
|
66
|
+
private toRecorded;
|
|
67
|
+
/**
|
|
68
|
+
* A replay input, verbatim or poisoned. A value the redactor alters carried
|
|
69
|
+
* a registered secret; an oversized one cannot be stored whole. Either way
|
|
70
|
+
* the trace is marked non-replayable and a redacted, bounded copy is kept
|
|
71
|
+
* for documentation only.
|
|
72
|
+
*/
|
|
73
|
+
private verbatim;
|
|
74
|
+
private push;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=recorder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/cache/recorder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAML,KAAK,WAAW,EAEhB,KAAK,qBAAqB,EAC3B,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,oBAAoB;IACnC,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2B;IAClD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,YAAY,OAAO,EAAE,oBAAoB,EAIxC;IAED,wDAAwD;IACxD,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,4CAA4C;IAC5C,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAGrC;IAED;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAEhC;IAED;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE;QACnB,QAAQ,CAAC,QAAQ,EAAE;YAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QACxE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAC1B,4EAA4E;QAC5E,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;KACxD,GAAG,WAAW,GAAG,SAAS,CAsB1B;IAED,OAAO,CAAC,UAAU;IAOlB;;;;;;OAMG;IACH,OAAO,CAAC,UAAU;IAmClB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,IAAI;CAOb"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Step trace recording (RFC0001 layer 3, cache-in decision).
|
|
3
|
+
*
|
|
4
|
+
* Records every grammar action a step commits, capturing a durable target
|
|
5
|
+
* descriptor at commit time — the moment the harness resolved the node — so
|
|
6
|
+
* replay can re-find it against a fresh observation. Recording is
|
|
7
|
+
* defense-in-depth on secrets: callers already hand secret-free input
|
|
8
|
+
* (`typeSecret` contributes only the secret's stable name), and every string
|
|
9
|
+
* that could carry screen content is additionally passed through the run's
|
|
10
|
+
* redactor before it can reach disk.
|
|
11
|
+
*
|
|
12
|
+
* Replay inputs are verbatim or nothing. A value the redactor would alter, or
|
|
13
|
+
* one over the input cap, poisons the trace (`truncated`) instead of being
|
|
14
|
+
* bent to fit: a trimmed URL or half a typed value would replay a different
|
|
15
|
+
* action than the one recorded, and could self-finalize a step on the wrong
|
|
16
|
+
* state. A poisoned trace still documents what happened; it never replays.
|
|
17
|
+
*/
|
|
18
|
+
import { describeAction } from '../agent/actions.js';
|
|
19
|
+
import { bound, MAX_TRACE_ACTIONS, MAX_TRACE_DESCRIPTOR_CHARS, MAX_TRACE_INPUT_CHARS, MAX_TRACE_SUMMARY_CHARS, } from './trace.js';
|
|
20
|
+
export class TraceRecorder {
|
|
21
|
+
actions = [];
|
|
22
|
+
truncated = false;
|
|
23
|
+
redact;
|
|
24
|
+
testIdAttribute;
|
|
25
|
+
maxActions;
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.redact = options.redact;
|
|
28
|
+
this.testIdAttribute = options.testIdAttribute;
|
|
29
|
+
this.maxActions = Math.min(options.maxActions ?? MAX_TRACE_ACTIONS, MAX_TRACE_ACTIONS);
|
|
30
|
+
}
|
|
31
|
+
/** Number of actions recorded so far, gaps included. */
|
|
32
|
+
get recordedCount() {
|
|
33
|
+
return this.actions.length;
|
|
34
|
+
}
|
|
35
|
+
/** Records one committed grammar action. */
|
|
36
|
+
record(action) {
|
|
37
|
+
const { target, summary } = describeAction(action, this.redact, this.testIdAttribute);
|
|
38
|
+
this.push(this.toRecorded(action, target, summary));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Records one mutating project-tool call as a gap. Replay ends here rather
|
|
42
|
+
* than skipping it: the grammar cannot reproduce the mutation, and a replay
|
|
43
|
+
* that silently dropped a state change would prove nothing.
|
|
44
|
+
*/
|
|
45
|
+
recordGap(toolName) {
|
|
46
|
+
this.push({ name: 'tool', summary: bound(`tool ${this.redact(toolName)}`, MAX_TRACE_SUMMARY_CHARS) });
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Concludes recording into a trace, or undefined when nothing was recorded —
|
|
50
|
+
* a step that committed no actions has no flow worth replaying.
|
|
51
|
+
*/
|
|
52
|
+
finalize(conclusion) {
|
|
53
|
+
if (this.actions.length === 0)
|
|
54
|
+
return undefined;
|
|
55
|
+
const summary = bound(this.redact(conclusion.summary), MAX_TRACE_SUMMARY_CHARS);
|
|
56
|
+
// Anchors are replay preconditions, so they follow the input rule: a path
|
|
57
|
+
// the redactor alters carried a secret (a token in a query string) and
|
|
58
|
+
// the trace is marked non-replayable rather than storing it verbatim.
|
|
59
|
+
const startPath = this.anchorPath(conclusion.startPath);
|
|
60
|
+
const endPath = this.anchorPath(conclusion.endPath);
|
|
61
|
+
return {
|
|
62
|
+
actions: [...this.actions],
|
|
63
|
+
executor: {
|
|
64
|
+
name: conclusion.executor.name,
|
|
65
|
+
...(conclusion.executor.version === undefined ? {} : { version: conclusion.executor.version }),
|
|
66
|
+
},
|
|
67
|
+
summary: summary.trim() === '' ? 'step passed' : summary,
|
|
68
|
+
...(startPath === undefined ? {} : { startPath }),
|
|
69
|
+
...(endPath === undefined ? {} : { endPath }),
|
|
70
|
+
...(conclusion.endAnchors === undefined || conclusion.endAnchors.length === 0
|
|
71
|
+
? {}
|
|
72
|
+
: { endAnchors: conclusion.endAnchors }),
|
|
73
|
+
...(this.truncated ? { truncated: true } : {}),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
anchorPath(value) {
|
|
77
|
+
if (value === undefined || value === '')
|
|
78
|
+
return undefined;
|
|
79
|
+
const redacted = this.redact(value);
|
|
80
|
+
if (redacted !== value)
|
|
81
|
+
this.truncated = true;
|
|
82
|
+
return bound(redacted, MAX_TRACE_DESCRIPTOR_CHARS);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Builds the stored variant for one action. The descriptor and the prose
|
|
86
|
+
* come from `describeAction` — already redacted and bounded, and the same
|
|
87
|
+
* text the live event carried. Stored inputs still go through `verbatim`,
|
|
88
|
+
* whose poisoning marks the trace non-replayable when a value cannot be
|
|
89
|
+
* kept whole.
|
|
90
|
+
*/
|
|
91
|
+
toRecorded(action, target, summary) {
|
|
92
|
+
// A targeted commit whose node yields no durable descriptor cannot be
|
|
93
|
+
// re-found; the trace stays honest by poisoning instead of guessing.
|
|
94
|
+
const requireTarget = () => {
|
|
95
|
+
if (target !== undefined)
|
|
96
|
+
return target;
|
|
97
|
+
this.truncated = true;
|
|
98
|
+
return { role: 'unknown' };
|
|
99
|
+
};
|
|
100
|
+
switch (action.name) {
|
|
101
|
+
case 'tap':
|
|
102
|
+
return { name: 'tap', summary, target: requireTarget() };
|
|
103
|
+
case 'type':
|
|
104
|
+
return { name: 'type', summary, target: requireTarget(), value: this.verbatim(action.value) };
|
|
105
|
+
case 'typeSecret':
|
|
106
|
+
return { name: 'typeSecret', summary, target: requireTarget(), secret: action.secret };
|
|
107
|
+
case 'press':
|
|
108
|
+
return { name: 'press', summary, target: requireTarget(), key: this.verbatim(action.key) };
|
|
109
|
+
case 'select':
|
|
110
|
+
return { name: 'select', summary, target: requireTarget(), value: this.verbatim(action.value) };
|
|
111
|
+
case 'scroll':
|
|
112
|
+
return {
|
|
113
|
+
name: 'scroll',
|
|
114
|
+
summary,
|
|
115
|
+
direction: action.direction,
|
|
116
|
+
...(target === undefined ? {} : { target }),
|
|
117
|
+
};
|
|
118
|
+
case 'navigate':
|
|
119
|
+
return { name: 'navigate', summary, url: this.verbatim(action.url) };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* A replay input, verbatim or poisoned. A value the redactor alters carried
|
|
124
|
+
* a registered secret; an oversized one cannot be stored whole. Either way
|
|
125
|
+
* the trace is marked non-replayable and a redacted, bounded copy is kept
|
|
126
|
+
* for documentation only.
|
|
127
|
+
*/
|
|
128
|
+
verbatim(value) {
|
|
129
|
+
const redacted = this.redact(value);
|
|
130
|
+
if (redacted === value && value.length <= MAX_TRACE_INPUT_CHARS)
|
|
131
|
+
return value;
|
|
132
|
+
this.truncated = true;
|
|
133
|
+
return bound(redacted, MAX_TRACE_INPUT_CHARS);
|
|
134
|
+
}
|
|
135
|
+
push(action) {
|
|
136
|
+
if (this.actions.length >= this.maxActions) {
|
|
137
|
+
this.truncated = true;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
this.actions.push(action);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=recorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.js","sourceRoot":"","sources":["../../src/cache/recorder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,cAAc,EAAyB,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EACL,KAAK,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,qBAAqB,EACrB,uBAAuB,GAIxB,MAAM,YAAY,CAAC;AASpB,MAAM,OAAO,aAAa;IACP,OAAO,GAAqB,EAAE,CAAC;IACxC,SAAS,GAAG,KAAK,CAAC;IACT,MAAM,CAA2B;IACjC,eAAe,CAAS;IACxB,UAAU,CAAS;IAEpC,YAAY,OAA6B;QACvC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;QAC/C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,IAAI,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;IACzF,CAAC;IAED,wDAAwD;IACxD,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IAC7B,CAAC;IAED,4CAA4C;IAC5C,MAAM,CAAC,MAAwB;QAC7B,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;QACtF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtD,CAAC;IAED;;;;OAIG;IACH,SAAS,CAAC,QAAgB;QACxB,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,uBAAuB,CAAC,EAAE,CAAC,CAAC;IACxG,CAAC;IAED;;;OAGG;IACH,QAAQ,CAAC,UAOR;QACC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAChD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,uBAAuB,CAAC,CAAC;QAChF,0EAA0E;QAC1E,uEAAuE;QACvE,sEAAsE;QACtE,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACpD,OAAO;YACL,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;YAC1B,QAAQ,EAAE;gBACR,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,IAAI;gBAC9B,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;aAC/F;YACD,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO;YACxD,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;YACjD,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;YAC7C,GAAG,CAAC,UAAU,CAAC,UAAU,KAAK,SAAS,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;gBAC3E,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,UAAU,EAAE,CAAC;YAC1C,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/C,CAAC;IACJ,CAAC;IAEO,UAAU,CAAC,KAAyB;QAC1C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;YAAE,OAAO,SAAS,CAAC;QAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,QAAQ,KAAK,KAAK;YAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QAC9C,OAAO,KAAK,CAAC,QAAQ,EAAE,0BAA0B,CAAC,CAAC;IACrD,CAAC;IAED;;;;;;OAMG;IACK,UAAU,CAChB,MAAwB,EACxB,MAAyC,EACzC,OAAe;QAEf,sEAAsE;QACtE,qEAAqE;QACrE,MAAM,aAAa,GAAG,GAA0B,EAAE;YAChD,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,MAAM,CAAC;YACxC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC7B,CAAC,CAAC;QACF,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,KAAK,KAAK;gBACR,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,CAAC;YAC3D,KAAK,MAAM;gBACT,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YAChG,KAAK,YAAY;gBACf,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;YACzF,KAAK,OAAO;gBACV,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7F,KAAK,QAAQ;gBACX,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YAClG,KAAK,QAAQ;gBACX,OAAO;oBACL,IAAI,EAAE,QAAQ;oBACd,OAAO;oBACP,SAAS,EAAE,MAAM,CAAC,SAAS;oBAC3B,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;iBAC5C,CAAC;YACJ,KAAK,UAAU;gBACb,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACzE,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACK,QAAQ,CAAC,KAAa;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,QAAQ,KAAK,KAAK,IAAI,KAAK,CAAC,MAAM,IAAI,qBAAqB;YAAE,OAAO,KAAK,CAAC;QAC9E,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,OAAO,KAAK,CAAC,QAAQ,EAAE,qBAAqB,CAAC,CAAC;IAChD,CAAC;IAEO,IAAI,CAAC,MAAsB;QACjC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC3C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;CACF"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic target relocation (RFC0001 layer 3, cache-in decision).
|
|
3
|
+
*
|
|
4
|
+
* Re-finds a recorded target descriptor in a fresh observation: exactly one
|
|
5
|
+
* node must match, or replay diverges. This is the conservative public
|
|
6
|
+
* ReplayPolicy — no scoring, no fuzzy matching, no vision. A tuned policy may
|
|
7
|
+
* replace it behind the same seam; the fail-closed contract (one match or
|
|
8
|
+
* hand off) is not tunable.
|
|
9
|
+
*
|
|
10
|
+
* Candidates are compared through the same `describeTarget` projection the
|
|
11
|
+
* recorder used, so redaction, whitespace collapsing, and bounding cannot
|
|
12
|
+
* make a node unequal to its own recording. The matching vocabulary — which
|
|
13
|
+
* tiers a descriptor is tried in, and what "equal on the recorded fields"
|
|
14
|
+
* means — is exported so end anchors (`anchors.ts`) are checked by the same
|
|
15
|
+
* rules and can never drift from relocation.
|
|
16
|
+
*/
|
|
17
|
+
import type { SemanticNode } from '../backend/surface.ts';
|
|
18
|
+
import type { TraceTargetDescriptor } from './trace.ts';
|
|
19
|
+
/**
|
|
20
|
+
* Version of the replay/relocation policy, part of every cache key. Bumping
|
|
21
|
+
* it cold-starts the cache — which is exactly right when the matching rules
|
|
22
|
+
* change, because an entry recorded under different rules could relocate to a
|
|
23
|
+
* different node.
|
|
24
|
+
*/
|
|
25
|
+
export declare const REPLAY_POLICY_VERSION = "conservative/3";
|
|
26
|
+
export type RelocationFailure = 'target-not-found' | 'target-ambiguous';
|
|
27
|
+
export type RelocationResult = {
|
|
28
|
+
readonly kind: 'found';
|
|
29
|
+
readonly id: string;
|
|
30
|
+
} | {
|
|
31
|
+
readonly kind: 'failed';
|
|
32
|
+
readonly failure: RelocationFailure;
|
|
33
|
+
};
|
|
34
|
+
export type DescriptorField = keyof TraceTargetDescriptor;
|
|
35
|
+
export interface DescriptorMatchOptions {
|
|
36
|
+
readonly redact: (text: string) => string;
|
|
37
|
+
readonly testIdAttribute: string;
|
|
38
|
+
}
|
|
39
|
+
/** A node's descriptor projection alongside its per-observation id. */
|
|
40
|
+
export interface DescribedNode {
|
|
41
|
+
readonly id: string;
|
|
42
|
+
readonly descriptor: TraceTargetDescriptor;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The tiers a recorded descriptor is matched in, strictest first:
|
|
46
|
+
*
|
|
47
|
+
* 1. **Strict** — every identity field the recording captured must match.
|
|
48
|
+
* 2. **Semantic** — only when a `testId` was recorded and the remaining
|
|
49
|
+
* fields still identify the node: the same descriptor without it. Test
|
|
50
|
+
* ids are the strongest discriminator when stable, but some apps mint
|
|
51
|
+
* them per render; a node the semantic fields still identify has not
|
|
52
|
+
* moved, its label has not changed, and refusing it would fail on
|
|
53
|
+
* cosmetics.
|
|
54
|
+
*
|
|
55
|
+
* Empty for a descriptor that identifies nothing.
|
|
56
|
+
*/
|
|
57
|
+
export declare function descriptorTiers(descriptor: TraceTargetDescriptor): readonly TraceTargetDescriptor[];
|
|
58
|
+
/** Every listed field the recording captured must be present and equal on the candidate. */
|
|
59
|
+
export declare function fieldsEqual(recorded: TraceTargetDescriptor, candidate: TraceTargetDescriptor, fields: readonly DescriptorField[]): boolean;
|
|
60
|
+
/** Projects every node of an observation the way the recorder described its targets. */
|
|
61
|
+
export declare function describeNodes(nodes: ReadonlyMap<string, SemanticNode>, options: DescriptorMatchOptions): readonly DescribedNode[];
|
|
62
|
+
/**
|
|
63
|
+
* Relocates one descriptor against the nodes of a fresh observation, tier by
|
|
64
|
+
* tier (`descriptorTiers`), each exactly-one-or-diverge. Ambiguity at any
|
|
65
|
+
* tier diverges immediately: two candidates sharing the matched identity
|
|
66
|
+
* cannot be told apart by waiting, and acting on either would be a guess.
|
|
67
|
+
*/
|
|
68
|
+
export declare function relocateDescriptor(descriptor: TraceTargetDescriptor, nodes: ReadonlyMap<string, SemanticNode>, options: DescriptorMatchOptions): RelocationResult;
|
|
69
|
+
//# sourceMappingURL=relocate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relocate.d.ts","sourceRoot":"","sources":["../../src/cache/relocate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AAEtD,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;AAExE,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAErE,MAAM,MAAM,eAAe,GAAG,MAAM,qBAAqB,CAAC;AAE1D,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;CAC5C;AA4BD;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,qBAAqB,GAAG,SAAS,qBAAqB,EAAE,CAKnG;AAED,4FAA4F;AAC5F,wBAAgB,WAAW,CACzB,QAAQ,EAAE,qBAAqB,EAC/B,SAAS,EAAE,qBAAqB,EAChC,MAAM,EAAE,SAAS,eAAe,EAAE,GACjC,OAAO,CAET;AAeD,wFAAwF;AACxF,wBAAgB,aAAa,CAC3B,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,EACxC,OAAO,EAAE,sBAAsB,GAC9B,SAAS,aAAa,EAAE,CAgB1B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,qBAAqB,EACjC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,EACxC,OAAO,EAAE,sBAAsB,GAC9B,gBAAgB,CAOlB"}
|