/** * Unified speculative-entry synthesis for `when.happened`'s tool_call- * scope speculative allow. * * Replaces the pre-PR-5 specialized speculative-allow path (a pair of * helpers on the evaluator that matched observers against prior `&&` * refs on a per-call boolean basis). For every bash command * ref in an unconditionally-`&&`-reachable segment, for every observer * writing an event AND matching the ref via the shared * {@link matchesWatch} contract, we produce a synthetic entry that * later `happened` evaluations merge with real entries via timestamp * ordering. * * Pure function of `(refs, observers)`. The evaluator wires the * output into per-ref `walkerState.events` before running predicates. * * ## Timestamp convention * * speculativeTimestamp(ref_j) = SPECULATIVE_BASELINE + 1 + j * * where `SPECULATIVE_BASELINE = 2^52` — a literal chosen far above * any epoch-ms timestamp pi writes on real entries (`Date.now()` * returns < 2^48 for any date through ~year 10,890 AD). The speculative * timestamp is thus strictly greater than ANY real entry's timestamp, * regardless of type or scope. So a speculative `sync-done` at ts * `2^52 + 1` beats a real `upstream-failed` at ts `Date.now()` in * the since-invalidator comparison. * * Two properties follow (see the `unification-reconsider` review's * "Timestamp reframing" section for the full walk-through): * * 1. **Strictly newer than every real entry across all types and * scopes.** The reserved-range literal sidesteps a per-type * max-plus-one approach — which would fail on a two-writes * scenario where the since-invalidator's latest real entry is * newer than the event type's latest real entry. A speculative * entry newer than ALL real entries is newer than any subset. * * 2. **Relative ordering among multiple speculative writes follows * AST order.** Ref at index `j` gets `BASELINE + 1 + j`; a later * ref at `k > j` gets `BASELINE + 1 + k`. So * `when.happened: { event: X, since: Y }` correctly reads X as * stale when Y is written later — the two-speculative-writes- * with-since-invalidator correctness case pinned by the * `A && B && cr` test in this commit pack. * * ## Safety * * **Chain reachability**: only refs with joiner `&&` in an * unconditionally-reached segment qualify as eligible producers. The * `&&` short-circuit guarantees any later ref that runs saw the * producer complete successfully first. * * **Observer eligibility**: observers must declare * `watch.inputMatches.command`. Any-bash-event observers would grant * allow for every `foo && cr` regardless of what `foo` does. Non-bash * `toolName` watches are rejected early (prior `&&` refs always * originate from bash). Other filter fields are delegated to * {@link matchesWatch} against a synthesized success event — the * single-source-of-truth filter contract gates future new `watch` * fields automatically. * * @internal — not part of the public pi-steering surface. */ import type { CommandRef } from "@cad0p/unbash-walker"; import type { Observer } from "../schema.ts"; /** * Speculative baseline timestamp. All synthetic entries carry * `SPECULATIVE_BASELINE + 1 + astIndex` so they order strictly above * any real entry's `timestamp` (real entries are epoch-ms from * `Date.now()`, well under `2^48` for any realistic date). See the * file-level JSDoc's "Timestamp convention" section for the full * rationale and the acknowledged numerical-convention caveat. * * @internal */ export declare const SPECULATIVE_BASELINE: number; /** * Speculative session entry. Structurally a superset of real entries * (`{ data, timestamp }`) plus a `speculative: true` marker so the * built-in `happened` predicate and plugin filters over * `walkerState.events` can distinguish synthetic writes from real * ones. Default direction (include speculative) matches what * `happened` wants; plugins wanting pure historical semantics filter * with `.filter(e => !e.speculative)`. */ export interface SyntheticEntry { readonly data: T; readonly timestamp: number; readonly speculative: true; } /** Per-ref view: `walkerState.events[customType] → SyntheticEntry[]`. */ type SyntheticEventsByType = Readonly>; /** Per-ref output keyed by {@link CommandRef} identity. */ export type SpeculativeEventsByRef = ReadonlyMap; /** * Compute per-ref speculative events. See file-level JSDoc for the * timestamp convention, reachability model, and observer eligibility. */ export declare function synthesizeSpeculativeEntries(refs: readonly CommandRef[], observers: readonly Observer[]): SpeculativeEventsByRef; export {}; //# sourceMappingURL=speculative-synthesis.d.ts.map