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 @@ +