/** * The §5 soundness validator — `claimAllowed`, the PURE function that decides * whether a single claim is `VALIDATED` (SDD §E; v1.1 §5; SDD §J.1). This is THE * soundness heart of the claims runtime: a claim may reach the renderer (P1) * **iff** every §5 conjunct holds against the per-turn Evidence Ledger. * * The predicate is transcribed VERBATIM from SDD §E / v1.1 §5 — each conjunct is * one §5 line, derived not re-invented (SDD zero-drift contract; §P misreadings * refused). It is **NOT** `Owner==Verified AND age<=TruthBudget` (the §P * misreading): ownership is ONE conjunct (C1), freshness is PER-EVIDENCE per * `e.freshnessPolicy` (not the turn-level Truth Budget — that is §L, a different * mechanism), and integrity/provenance/presence/non-emptiness/(action) outcome * are independent conjuncts. * * Kernel-abstract & PURE: every repo-specific capability is INJECTED via `deps` * (ownership resolution, action-outcome confirmation). This module implements no * repo ownership and no clock — `now` is injected so `fresh(e)` over a cacheable * ttl stays deterministic. No kernel-downstream import (SDD §R kernel purity: * `adjudicate → claustrum → ibatexas`, never backward); no clock/RNG/IO. * * The full registry claim TYPES (the 37-row vocabulary, registry §6) are OUT of * scope here (deferred — SDD §Q scope guard): this validator operates on a * MINIMAL kernel claim shape sufficient for the §5 predicate. */ import type { EvidenceLedger } from "./evidence-ledger.js"; import type { EvidenceRequirement, FalsifierDeclaration, SourceIntegrity } from "./evidence-requirement.js"; import type { ClaimVerdict } from "./verdict.js"; /** * The kind of claim the §5 predicate is validating (SDD §E C4; v1.1 §5): * * - `"read_claim"` — a statement backed by READ evidence; C4 does not apply. * - `"action_claim"` — a statement that an ACTION happened; C4 (outcome * confirmed) is an ADDITIONAL required conjunct. * * This is the kernel-abstract `c.kind` of §5, not a registry type name. */ export type ClaimKind = "read_claim" | "action_claim"; /** * A binding of one `EvidenceRequirement.key` to the concrete RESOURCE that * requirement's ownership check is about (SDD §E C1: `owns(actor, e.resource)`). * The §5 predicate is kernel-abstract — it does NOT know what a "resource" is; * it only passes `(actor, resource)` to the injected `deps.owns`. The claim * supplies the per-key resource via this map so that `ownershipPolicy: * "required"` evidence can be owner-checked without this module knowing any * repo's resource model. * * A `required`-ownership requirement whose key has NO binding here (an absent or * `undefined` resource) is the §J.2 "no owner attribution" case: it must NOT * validate — "no owner" ≠ "any owner" → `REFUSED` (Inv 2). It is NOT silently * treated as ownerless/public. */ export type ResourceBindings = Readonly>; /** * C6 VALUE-BINDING (SDD §5 C6; Theorem S precondition (a-value)) — the optional * declaration that a claim's RENDERED `value` is bound to a specific evidence * entry's value, so the number/string the customer eventually sees cannot be a * model confabulation that merely rode the surplus channel through a claim that * validated on present∧fresh∧owned∧integrity∧provenance. * * - `key` — the `EvidenceRequirement.key` whose ledger value licenses this * claim's `value`. It MUST be one of the claim's `requiredEvidence` * keys so presence/freshness/provenance/integrity are already gated * by the §5 ∀ before C6 compares the value (the binding only adds the * value-equality conjunct on top of an already-validated key). * - `path` — OPTIONAL projection into BOTH the claim's `value` and the bound * entry's `value` before comparison (e.g. `["open"]` to bind the * `open` field of a STORE_OPEN_NOW value object to the schedule * entry's `open` field). Absent ⟹ compare the whole values. * * Additive + OPTIONAL on `MinimalClaim`: a claim that declares no `valueBinding` * is unaffected by C6 (fail-safe no-op — §5 is value-agnostic for it, exactly as * before W6). W5 declares bindings per registry type. */ export interface ValueBinding { readonly key: string; readonly path?: readonly (string | number)[]; } /** * The minimal kernel claim the §5 predicate quantifies over (SDD §E; v1.1 §5). * The full registry claim types (registry §6) are deferred (SDD §Q scope guard); * this carries EXACTLY the fields §5 reads: * * - `requiredEvidence` — the `∀ e ∈ c.requiredEvidence` set (C0 demands it be * non-empty AND impose a real check). * - `minSourceIntegrity`— the C2 floor each evidence's `sourceIntegrity` must * meet-or-exceed. * - `kind` — `read_claim | action_claim` (drives C4). * - `actor` — the subject of `owns(actor, e.resource)` (C1). Kept * `unknown` (kernel-abstract — the injected `deps.owns` * interprets it; this module never inspects it). * - `resources` — per-key `EvidenceRequirement.key → resource` bindings * for C1 (see `ResourceBindings`). Optional; an absent * binding for a `required` key is "no owner" → REFUSED. */ export interface MinimalClaim extends FalsifierDeclaration { readonly requiredEvidence: readonly EvidenceRequirement[]; readonly minSourceIntegrity: SourceIntegrity; readonly kind: ClaimKind; readonly actor: unknown; readonly resources?: ResourceBindings; /** * C6 — the RENDERED value carried by this claim (the proposition the renderer * would fill). OPTIONAL: only inspected when `valueBinding` is declared (the * value-binding conjunct compares this against the bound evidence's value). When * `valueBinding` is absent, §5 stays value-agnostic and never reads this field. */ readonly value?: unknown; /** * C6 value-binding (SDD §5 C6) — see {@link ValueBinding}. OPTIONAL; absent ⟹ * C6 is a no-op for this claim (fail-safe default; W5 declares bindings). */ readonly valueBinding?: ValueBinding; } /** * The PURE capabilities the §5 predicate injects (SDD §E). Implementing these is * the DOWNSTREAM packages' job (repo ownership models, action-outcome wiring); * this kernel module only CALLS them. Both must be pure (deterministic, no IO) so * `claimAllowed` stays a pure function. */ export interface SoundnessDeps { /** * The ownership VALIDATION predicate (SDD §E C1; Inv 2): does `actor` own * `resource`? Kernel-abstract — the repo (OrderProjection-join, owner-scoped * `getById`, …) decides; "ownership is a validation predicate, not read-auth" * (Inv 2). `claimAllowed` calls this ONLY when a requirement's * `ownershipPolicy === "required"` AND a concrete `resource` binding exists; a * `required` key with no binding is "no owner" and is REFUSED WITHOUT calling * `owns` (Inv 2: "no owner" ≠ "any owner"). */ readonly owns: (actor: unknown, resource: unknown) => boolean; /** * The action-outcome accessor (SDD §E C4; Inv 4): for an `action_claim`, did * the action's outcome CONFIRM — `EXECUTE ∧ dispatched=ok ∧ result.success ∧ * (settlement, for money)`? Kernel-abstract — the repo derives it from this * turn's Action verdict + dispatch (NOT a read). Success ≠ session (Inv 4). * Called for ANY claim asserting an action outcome — `kind === "action_claim"` * OR any requirement with `freshnessPolicy === "action_outcome"` (C4's * broadened trigger; see `assertsActionOutcome` in `claimAllowed`). NOT called * for a pure read claim that carries no `action_outcome` requirement. */ readonly outcomeConfirmed: (claim: MinimalClaim) => boolean; /** * The current time, epoch-millis, for the `cacheable` ttl staleness window * (`fresh(e)`). INJECTED (not read from a wall clock) so the predicate is pure and * `fresh(e)` is deterministic in tests. Required because `fresh(e)` for the * cacheable tier compares `now - entry.fetchedAt` against the ttl. */ readonly now: number; } /** * The ATTESTED-CLOCK seam (W6): a `now` epoch-millis paired with an OPTIONAL * `attestation` token identifying the time SOURCE (e.g. a signed NTP/HSM stamp). * `fresh(e)` over a `cacheable` ttl compares `now - fetchedAt`; if `now` is an * un-attested wall clock, staleness can be defeated by clock skew (the negative-age * lower bound already rejects future stamps, but a SOURCE attestation lets a * caller PROVE the clock itself is trustworthy). * * W6 ships the SEAM only: `SoundnessDeps.now` stays a bare `number` (kernel-pure, * deterministic in tests). A caller may source it from {@link readAttestedNow}, * which is where W5 wires a real attested source. The kernel does not itself verify * the attestation — it provides the typed slot so the trust upgrade can land later. */ export interface AttestedClock { readonly now: number; readonly attestation?: string; } /** * Read the `now` value from an {@link AttestedClock} for `SoundnessDeps.now` (W6). * Pure pass-through today; the seam where W5 enforces attestation presence/validity * before trusting the time. Keeping it a function (not a field read) gives W5 one * place to harden without touching `claimAllowed`. */ export declare function readAttestedNow(clock: AttestedClock): number; /** * `CLAIM_ALLOWED(c)` — the §5 soundness predicate (SDD §E; v1.1 §5; §J.1), * returning the three-valued `ClaimVerdict`. A PURE function: same inputs ⟹ same * verdict; all repo specifics are injected via `deps`. * * A claim is `VALIDATED` **iff** ALL of these hold (each = one §E conjunct): * * - **C0** `requiredEvidence ≠ ∅` — else `REFUSED` (no-backing; the ∀-over-∅ * vacuous-true bug is structurally impossible to VALIDATE). * - **∀ e ∈ requiredEvidence:** `present(e) ∧ fresh(e) ∧ (ownershipPolicy === * "required" ⟹ owns(actor, e.resource)) ∧ sourceIntegrity(e) ≥ * minSourceIntegrity ∧ provenanceOK(e)`. * - **C4** `assertsActionOutcome(claim) ⟹ outcomeConfirmed(claim)` — else * REFUSED (asserting a non-happening is a contradiction; the confabulation * guard). `assertsActionOutcome` is `kind === "action_claim"` OR any * requirement with `freshnessPolicy === "action_outcome"` (a claim whose * evidence IS this turn's Action verdict+dispatch asserts an action outcome * regardless of `kind`). * - **C6** `valueBinding ⟹ sameValue(value, evidence value)` — when the claim * declares a value-binding, its RENDERED value must equal the bound evidence * entry's value (the SAME canonical `sameValue` P2/H3 use). An in-grammar * mismatch → REFUSED (an over-claim contradicting its licensing evidence — * the round-2 (a-value) confabulation catch); an unprovable binding (bound key * absent, or a value outside the closed scalar grammar) → UNKNOWN (abstain). * OPTIONAL: a claim with no `valueBinding` is unaffected (fail-safe no-op). * - **Falsifier-completeness** `falsifierComplete ∧ falsifiers ≠ ∅` — else the * all-pass path is CAPPED to `UNKNOWN` (honest ignorance: we cannot prove no * falsifier exists). A type defaults to UNKNOWN-only until W5 enumerates its * falsifiers (fail-safe, demote-only). A `falsifierComplete: true` type with * an empty `falsifiers[]` is the inconsistent lying case → §R hard THROW. * * The verdict is the SAFEST (most-restrictive) over all evidences: * - any evidence REFUSED, OR a C0/C4 REFUSED → `REFUSED` * - else any evidence UNKNOWN → `UNKNOWN` * - else (every conjunct PASSes) → `VALIDATED` * * The HARD invariant (SDD §J.1 / §R): a FAILED conjunct NEVER yields VALIDATED — * `VALIDATED` is returned ONLY on the all-pass path. Mapping of WHICH failure → * REFUSED vs UNKNOWN is per registry §5 (documented on the three-valued mapping * block above and on each branch). */ export declare function claimAllowed(claim: MinimalClaim, ledger: EvidenceLedger, deps: SoundnessDeps): ClaimVerdict; //# sourceMappingURL=soundness.d.ts.map