/** * Reading a predicate's TOP-LEVEL clauses. * * Structural, not evaluative: these answer "what does this predicate say" from the shape alone, the * same basis `predicateShapeFor` sits here on. Nothing here decides anything about an app. * * It lived beside the replay code until the journal's flow-naming needed it too, and a * `journal -> flows` reach is a file filed in the wrong place rather than a dependency anybody * wanted. The thing both callers want is a reader for a core type, so it lives with the type. * * v1 stored one slot per kind, so "does this step assert state?" was a property read and "drop the * element clause" was a `delete`. A `Predicate` nests, so every one of those questions is a walk. * * The walks here are deliberately SHALLOW, and that is the whole design. A lifted v1 file produces * either a single leaf or one flat `allOf`, so a top-level walk reproduces v1 behaviour exactly. A * hand-written v2 predicate can nest arbitrarily, and going deeper would silently change what an * existing flow asserts: * * - dropping a leaf from an `allOf` removes a conjunct, which is what v1's `delete` did; * - dropping a branch from an `anyOf` removes an ALTERNATIVE, which makes the predicate STRICTER * and can turn a passing flow red; * - dropping anything under a `not` inverts the meaning of the thing you dropped. * * So the composite cases are handled where they mean what v1 meant, and left alone everywhere else. */ import { PredicateKind } from './consequence.js'; import type { Predicate } from './predicate.js'; /** * The plain clause each side of a `compare` reads, so a walker that asks "which endpoints, signals, * stores or elements does this predicate depend on?" answers for a comparison without learning its * shape. They are READERS of the same channel, never claims: a compare's `net` side is not an * assertion that some call succeeded, only that the comparison reads one. */ export declare function compareSourceClauses(predicate: Extract): readonly Predicate[]; /** Every clause at the top level: the predicate itself, or the members of a top-level `allOf`. */ export declare function conjuncts(predicate: Predicate | undefined): readonly Predicate[]; /** The first top-level clause of this kind, or undefined. */ export declare function clauseOfKind(predicate: Predicate | undefined, kind: K): Extract | undefined; /** Does this expectation assert store state at the top level? The drift kind branches on it. */ export declare function assertsState(predicate: Predicate | undefined): boolean; /** * The testid an element clause says must be PRESENT, when the expectation has one at the top level. * * An `absent: true` clause names a testid that must be gone, and asking the replay runner to * require it made a correct dismissal fail. That clause is left to the predicate wait instead. */ export declare function expectedElementTestid(predicate: Predicate | undefined): string | undefined; /** * Rebuild the expectation without the top-level clauses a caller wants gone, collapsing as it goes. * * One clause left is that clause, not an `allOf` of one: a single-member composite grades weaker * than its own member and reads worse in a report, and `combine()` has had to be taught about * zero-branch composites once already. */ export declare function withoutClauses(predicate: Predicate | undefined, drop: (clause: Predicate) => boolean): Predicate | undefined; /** * Name what was asserted, for the drift row's `anchor` column. * * Reports the STRONGEST clause rather than the first, because that is the one a reader is asking * about: an `allOf[settled, net]` is about the request, and answering "settled" names the gate * instead of the claim. */ export declare function expectLabel(predicate: Predicate | undefined): string; /** * An element ref: `e` and a sequence number, minted per session by the SDK's ref table. It is an * address inside ONE session's numbering, not an identity. */ export declare const SESSION_REF: RegExp; /** * The stable part of the refusal for a `ref` Reticle never minted. The server's recovery table keys * on it, so it is one constant rather than two spellings that could drift. */ export declare const UNISSUED_REF_REFUSAL = "is not a ref Reticle issued"; /** * Why an act refused a `ref` that does not have the minted shape. * * The browser's ref table answers a miss with null, and an unknown string and a detached element * reached the same refusal: "that ref is stale: refs are invalidated whenever the DOM re-renders". * For `find:aria-label=Open menu` — never a ref at all — that diagnosis is wrong, and the agent * retried the same mistake. A string that cannot have been minted is answered for what it is, and * pointed at `target`, which is what the caller was reaching for. */ export declare function unissuedRefRefusal(ref: string): string; /** Why a flow refused a predicate holding a ref, naming the field. */ export declare function sessionRefRefusal(field: string): string; /** * The first field anywhere in the tree that holds a session ref, as `kind.field "value"`. * * DEEP, unlike every reader above: those walk the top level because dropping a nested clause would * change what a flow means, while this only asks whether the predicate can mean anything at all in * another session. A ref under a `not` is exactly as meaningless as one at the top. */ export declare function sessionBoundField(predicate: Predicate): string | undefined;