diff --git a/src/Core/Core.fsproj b/src/Core/Core.fsproj
index e43b4c64..3fc6e80f 100644
--- a/src/Core/Core.fsproj
+++ b/src/Core/Core.fsproj
@@ -41,6 +41,7 @@
+
diff --git a/src/Core/Veridicality.fs b/src/Core/Veridicality.fs
new file mode 100644
index 00000000..8b62832d
--- /dev/null
+++ b/src/Core/Veridicality.fs
@@ -0,0 +1,121 @@
+namespace Zeta.Core
+
+open System
+
+
+/// **Veridicality — provenance-aware claim scoring (foundation).**
+///
+/// This module hosts the primitives for what the bootstrap-era
+/// conversation called the "bullshit detector" and Amara's
+/// subsequent ferries (7th-10th) formalized as veridicality
+/// scoring. The name `Veridicality` (from Latin *veridicus*,
+/// "truth-telling") names the scorable quantity: how true-to-
+/// reality a claim looks given its provenance, falsifiability,
+/// coherence, drift, and compression-gap signals. "Bullshit" is
+/// the informal inverse (`bullshit = 1 - veridicality`).
+///
+/// **First graduation (this file):** `Provenance` + `Claim<'T>`
+/// record types + `validateProvenance`. These are the input
+/// shapes for every downstream scorer. The actual veridicality
+/// scorer (`V(c) = σ(β₀ + β₁(1-P) + β₂(1-F) + β₃(1-K) + …)` from
+/// Amara's 7th ferry, or `BS(c) = σ(w₁·C + w₂·(1-P) + …)` from
+/// the 10th ferry) is a separate graduation that composes over
+/// these types.
+///
+/// **Attribution.**
+/// * **Concept** — the bullshit-detector / provenance-aware-
+/// scoring framing is Aaron's design, present in the bootstrap
+/// conversation (`docs/amara-full-conversation/**`) before
+/// Amara's ferries formalized it. Aaron 2026-04-24 Otto-112:
+/// *"bullshit, it was in our conversation history too, not
+/// just her ferry."*
+/// * **Formalization** — Amara (7th/8th/9th/10th ferries):
+/// veridicality formula, semantic-canonicalization "rainbow
+/// table", oracle-rule specification, 7-feature composite.
+/// * **Implementation** — Otto, under the Otto-105 graduation
+/// cadence. Fifth graduation.
+///
+/// Future graduations add (in priority order): `antiConsensusGate`
+/// (requires `Provenance`); `canonicalizeClaim` (semantic
+/// canonicalization → `CanonicalClaimKey`); `scoreVeridicality`
+/// (the composite function).
+[]
+module Veridicality =
+
+ /// **Provenance** — the evidence trail behind a claim.
+ ///
+ /// Every accepted claim MUST carry provenance with at minimum
+ /// `SourceId`, `RootAuthority`, `ArtifactHash`, and
+ /// `SignatureOk = true`. Empty-string `SourceId` or
+ /// `RootAuthority`, empty `ArtifactHash`, or `SignatureOk =
+ /// false` all indicate unverified or missing evidence.
+ ///
+ /// Fields match Amara's 9th/10th ferry specification verbatim
+ /// (`docs/aurora/2026-04-23-amara-aurora-deep-research-
+ /// report-10th-ferry.md` §ADR-style spec for oracle rules and
+ /// implementation).
+ ///
+ /// `RootAuthority` vs `SourceId`: a single source may speak
+ /// under different authorities (a mailing list, an academic
+ /// publication, a company blog), and consumers of the claim
+ /// need both to distinguish "two sources, same root
+ /// authority" (anti-consensus-gate failure) from "two sources,
+ /// two independent roots" (anti-consensus-gate pass).
+ type Provenance =
+ { SourceId: string
+ RootAuthority: string
+ ArtifactHash: string
+ BuilderId: string option
+ TimestampUtc: DateTimeOffset
+ EvidenceClass: string
+ SignatureOk: bool }
+
+ /// **Claim<'T>** — a piece of information with a payload,
+ /// a weight (matches the Z-set weight model for retraction-
+ /// native semantics), and its provenance.
+ ///
+ /// `Id` is the claim's identity in the claim ledger. `Payload`
+ /// is the domain-specific information being claimed (a string,
+ /// a record, a numeric oracle reading — whatever the caller
+ /// has). `Weight` is a signed multiplicity: positive for
+ /// assertion, negative for retraction. Total net-zero after
+ /// assertion+retraction matches Z-set semantics.
+ type Claim<'T> =
+ { Id: string
+ Payload: 'T
+ Weight: int64
+ Prov: Provenance }
+
+ /// **Validate provenance** — returns `true` when the
+ /// provenance has the minimum fields populated + a valid
+ /// signature. Returns `false` on empty-string `SourceId`,
+ /// `RootAuthority`, or `ArtifactHash`, or when `SignatureOk
+ /// = false`.
+ ///
+ /// Matches Amara's 10th-ferry snippet:
+ ///
+ /// ```
+ /// let validateProvenance c =
+ /// c.Prov.SourceId <> ""
+ /// && c.Prov.RootAuthority <> ""
+ /// && c.Prov.ArtifactHash <> ""
+ /// && c.Prov.SignatureOk
+ /// ```
+ ///
+ /// `BuilderId = None`, `TimestampUtc`, and `EvidenceClass`
+ /// are NOT checked by this predicate — they are evidence
+ /// quality signals that downstream scorers consume, not
+ /// hard validity gates. An unsigned artifact with known
+ /// source/root/hash is still rejected, because cryptographic
+ /// attestation is the minimum trust bar.
+ let validateProvenance (p: Provenance) : bool =
+ p.SourceId <> ""
+ && p.RootAuthority <> ""
+ && p.ArtifactHash <> ""
+ && p.SignatureOk
+
+ /// Convenience alias for `validateProvenance` on a full
+ /// `Claim<'T>`, matching Amara's 10th-ferry snippet which
+ /// takes a claim rather than bare provenance.
+ let validateClaim (c: Claim<'T>) : bool =
+ validateProvenance c.Prov
diff --git a/tests/Tests.FSharp/Algebra/Veridicality.Tests.fs b/tests/Tests.FSharp/Algebra/Veridicality.Tests.fs
new file mode 100644
index 00000000..a9c9ff37
--- /dev/null
+++ b/tests/Tests.FSharp/Algebra/Veridicality.Tests.fs
@@ -0,0 +1,96 @@
+module Zeta.Tests.Algebra.VeridicalityTests
+
+open System
+open FsUnit.Xunit
+open global.Xunit
+open Zeta.Core
+
+
+// ─── Provenance / validateProvenance ─────────
+
+let private goodProv () : Veridicality.Provenance =
+ { SourceId = "repo/amara/ferry-10"
+ RootAuthority = "amara@aurora"
+ ArtifactHash = "blake3:3f8e..."
+ BuilderId = Some "otto-115"
+ TimestampUtc = DateTimeOffset.UtcNow
+ EvidenceClass = "research"
+ SignatureOk = true }
+
+[]
+let ``validateProvenance accepts a fully-populated signed provenance`` () =
+ Veridicality.validateProvenance (goodProv ()) |> should equal true
+
+[]
+let ``validateProvenance rejects empty SourceId`` () =
+ let p = { goodProv () with SourceId = "" }
+ Veridicality.validateProvenance p |> should equal false
+
+[]
+let ``validateProvenance rejects empty RootAuthority`` () =
+ let p = { goodProv () with RootAuthority = "" }
+ Veridicality.validateProvenance p |> should equal false
+
+[]
+let ``validateProvenance rejects empty ArtifactHash`` () =
+ let p = { goodProv () with ArtifactHash = "" }
+ Veridicality.validateProvenance p |> should equal false
+
+[]
+let ``validateProvenance rejects SignatureOk = false`` () =
+ let p = { goodProv () with SignatureOk = false }
+ Veridicality.validateProvenance p |> should equal false
+
+[]
+let ``validateProvenance accepts BuilderId = None (not a hard gate)`` () =
+ // BuilderId is a quality signal, not a validity gate. An
+ // artifact can be legitimately signed without a builder
+ // identity (e.g., a human-authored doc signed with a personal
+ // key).
+ let p = { goodProv () with BuilderId = None }
+ Veridicality.validateProvenance p |> should equal true
+
+
+// ─── Claim<'T> / validateClaim ─────────
+
+[]
+let ``validateClaim wraps validateProvenance on the claim's provenance`` () =
+ let c =
+ { Id = "claim-001"
+ Payload = 42
+ Weight = 1L
+ Prov = goodProv () }
+ Veridicality.validateClaim c |> should equal true
+
+[]
+let ``validateClaim is polymorphic over the Payload type`` () =
+ // Same validation whether payload is int, string, record, etc.
+ // The provenance discipline doesn't depend on payload shape.
+ let c =
+ { Id = "claim-002"
+ Payload = "Zeta is a retraction-native substrate."
+ Weight = 1L
+ Prov = goodProv () }
+ Veridicality.validateClaim c |> should equal true
+
+[]
+let ``validateClaim rejects a claim with invalid provenance`` () =
+ let c =
+ { Id = "claim-003"
+ Payload = ()
+ Weight = 1L
+ Prov = { goodProv () with SignatureOk = false } }
+ Veridicality.validateClaim c |> should equal false
+
+[]
+let ``Claim supports negative Weight for retraction semantics`` () =
+ // Z-set style: negative weight = retraction. validateClaim
+ // does NOT inspect Weight; a retraction claim is valid if its
+ // provenance is valid. Retraction semantics are at the ledger
+ // level, not the claim-validity level.
+ let c =
+ { Id = "claim-004"
+ Payload = 7
+ Weight = -1L
+ Prov = goodProv () }
+ Veridicality.validateClaim c |> should equal true
diff --git a/tests/Tests.FSharp/Tests.FSharp.fsproj b/tests/Tests.FSharp/Tests.FSharp.fsproj
index f9e64744..9c6d4286 100644
--- a/tests/Tests.FSharp/Tests.FSharp.fsproj
+++ b/tests/Tests.FSharp/Tests.FSharp.fsproj
@@ -19,6 +19,7 @@
+