/** * Per-step outcome capture: derive the grounded post-condition (`expect`) a step is frozen with, * so a step that runs but doesn't reach its outcome is caught at replay (and healed). Expects are * decided RETROACTIVELY at freeze time from the completed evidence (#81) — never from a mid-run * snapshot that races the step's own in-flight request. See spec/core/surgical-heal.md. */ import type { Driver } from "../ports.js"; import type { Evidence, NetworkRequest, Step, WaitUntil } from "../types.js"; /** host + path of a url (query/hash dropped) — a stable, meaningful destination to assert. */ export declare function destinationKey(url: string): string; /** What the loop records before each executed step: the page URL and the request-log length. The * log is append-only within a run (statuses update in place), so `[mark.requestCount, next mark)` * is exactly the tail of requests that step fired. */ export interface OutcomeMark { url: string | undefined; requestCount: number; } /** Observe the freeze-time evidence, waiting (bounded) while a mutation fired during the run is * still in flight — so retroactive expect/assertion grounding sees resolved statuses, not a race. */ export declare function observeOutcomes(driver: Driver, firstRequestCount: number): Promise; /** Retroactively attach each step's grounded post-condition from the completed evidence. * Navigation → expect that destination (the URL at the NEXT executed step, or the final URL — * nothing acts in between, so it is the page this step reached). Navigation is judged at * `destinationKey` granularity — the same granularity the expect is frozen at (#96): a query/hash-only * move would freeze a URL expect the PRE-navigation page already satisfies, so replay's idempotency * pre-check would silently skip the step; such a move falls through to the mutation expect (the fired * request is stronger evidence anyway). Else, a fresh successful mutation in the step's own request * tail → expect that request. A step that changed nothing stays unchecked — a weak expect would * trigger false divergence. `marks[i] === null` skips a step the loop doesn't verify (the baseUrl * goto). */ export declare function assignStepExpects(steps: Step[], marks: readonly (OutcomeMark | null)[], evidence: Evidence): void; /** A `requestStatus` post-condition for a mutation request the step itself fired and that succeeded — * the request that proves the action, so replay can wait for it. Benign noise is excluded, the method * is frozen for exact matching (a same-path GET must not satisfy a submit), and the frozen path stops * before a run-specific id segment (which would never match on a later replay). A repeated identical * mutation (a second add-to-cart) still counts — the tail is positional, not a seen-set. */ export declare function freshMutationExpect(tail: NetworkRequest[]): WaitUntil | undefined;