Signal Plurality

epistemic

Signal Plurality

Definition and Overview

Signal Plurality is a hard-enforced axiom within the NABLA Infinity epistemic framework requiring a minimum of two independent signals before any belief can be formed, any claim accepted, or any decision made. Single-source claims are insufficient regardless of source credibility, urgency, or authority level. This axiom prevents single points of epistemic failure and ensures all platform knowledge has corroborating evidence from genuinely independent origins.

The axiom addresses a fundamental vulnerability in knowledge systems: dependence on single sources creates catastrophic failure modes. A single compromised source, a single biased assessment, or a single misconfigured sensor can propagate incorrect beliefs throughout the system if there is no requirement for independent corroboration. Signal Plurality transforms this single-point-of-failure pattern into a distributed verification model where every belief requires at least two independent supporting signals.

Signal Plurality is more rigorous than simple "second opinion" requirements found in traditional decision-making frameworks. The axiom requires not just multiple signals but genuinely independent signals -- signals from sources that do not share common upstream dependencies, methodologies, or data feeds. Two signals derived from the same underlying data source count as one signal, regardless of how differently they are presented. This independence requirement prevents the illusion of plurality where multiple nominally different sources all trace back to a single origin.

Within the Prismatic Platform, Signal Plurality is enforced at the E2 level (block and rejection). Violations are not warnings -- they are hard blocks that prevent the violating claim from entering the belief system. This enforcement applies across all platform systems: OSINT intelligence fusion, EASM security ratings, Color Team assessments, and quality evaluations.

Historical Context and Motivation

The Signal Plurality axiom draws from multiple intellectual traditions. In intelligence analysis, the principle of "multi-source intelligence" (MULTI-INT) has been practiced since at least World War II, where signals intelligence (SIGINT), human intelligence (HUMINT), and imagery intelligence (IMINT) were cross-referenced to validate assessments. The failure to enforce this principle has led to documented intelligence failures, most notably the reliance on single-source intelligence in the lead-up to the Iraq War (2003), where the "Curveball" source provided uncorroborated information that shaped policy.

In scientific methodology, the requirement for independent replication serves the same function. A scientific claim is not accepted based on a single experiment; it requires independent replication by separate researchers using different methodologies. The replication crisis in social science (2010s) demonstrated what happens when this standard is relaxed.

In distributed systems engineering, the concept of quorum consensus (requiring agreement from multiple nodes before accepting a write) is the technical analog of Signal Plurality. Systems like Raft and Paxos require majority agreement precisely because individual nodes can fail, be partitioned, or return stale data.

The Prismatic Platform's adoption of Signal Plurality as a hard axiom reflects a recognition that automated systems face the same epistemic risks as human intelligence analysts and distributed databases. When the platform assesses a security posture, classifies a threat, or evaluates code quality, the assessment is only as reliable as the evidence supporting it. Single-source evidence, no matter how authoritative it appears, leaves the assessment vulnerable to source failure.

Technical Deep Dive

Axiom Specification

Signal Plurality is one of seven non-negotiable axioms in the NABLA Infinity framework:

PropertyValue
Axiom Number1 (Signal Plurality)
EnforcementHARD -- cannot be bypassed or overridden
Minimum Signals2 independent sources
Violation ResponseE2 BLOCK -- immediate rejection
Override AuthorityNone -- no authority level can bypass
ScopeAll beliefs, claims, and decisions platform-wide

Independence Verification

Determining signal independence requires analysis of source provenance. Two signals are independent if and only if they have different origins, no shared upstream sources, and different collection methodologies:

defmodule Prismatic.Epistemic.SignalPlurality do
  @moduledoc """
  Enforces the Signal Plurality axiom: minimum 2 independent signals
  for any belief. Hard enforcement with E2 block on violation.

  ## Independence Criteria

  Two signals are considered independent when:
  1. They originate from different sources
  2. They share no upstream data dependencies
  3. They use different collection methodologies
  4. They belong to different independence classes

  ## Enforcement

  Violations result in immediate E2 BLOCK. No authority level
  can bypass this axiom. Claims that fail plurality checking
  are rejected and cannot enter the belief system.
  """

  @type signal :: %{
    source: String.t(),
    content: term(),
    timestamp: DateTime.t(),
    confidence: float(),
    provenance: provenance()
  }

  @type provenance :: %{
    origin: String.t(),
    methodology: String.t(),
    upstream_sources: [String.t()],
    collection_method: atom(),
    independence_class: String.t()
  }

  @type plurality_result ::
    {:ok, :plural, [signal()]}
    | {:error, :insufficient_plurality, String.t()}

  @spec verify_plurality([signal()]) :: plurality_result()
  def verify_plurality(signals) when length(signals) < 2 do
    {:error, :insufficient_plurality,
     "Only #{length(signals)} signal(s) provided. Minimum 2 independent signals required."}
  end

  def verify_plurality(signals) do
    independent_groups = group_by_independence(signals)

    if map_size(independent_groups) >= 2 do
      {:ok, :plural, signals}
    else
      {:error, :insufficient_plurality,
       "#{length(signals)} signals found but only #{map_size(independent_groups)} " <>
       "independent source(s). Signals share upstream dependencies."}
    end
  end

  @spec are_independent?(signal(), signal()) :: boolean()
  def are_independent?(signal_a, signal_b) do
    prov_a = signal_a.provenance
    prov_b = signal_b.provenance

    # Different origins
    prov_a.origin != prov_b.origin and
      # No shared upstream sources
      MapSet.disjoint?(
        MapSet.new(prov_a.upstream_sources),
        MapSet.new(prov_b.upstream_sources)
      ) and
      # Different collection methodologies
      prov_a.methodology != prov_b.methodology
  end

  defp group_by_independence(signals) do
    signals
    |> Enum.group_by(fn signal ->
      signal.provenance.independence_class
    end)
  end
end

Enforcement Architecture

Platform-Wide Enforcement Points

Signal Plurality is enforced at every point where beliefs or claims are formed:

SystemEnforcement PointSignals Required
Intelligence FusionOSINT assessment formation2+ OSINT providers
Security RatingsPer-dimension scoring2+ evidence sources per dimension
Color TeamsRed Team finding validation2+ attack vector confirmations
Blue TeamDefensive posture assessment2+ monitoring signals
Quality AssessmentQuality domain scoring2+ verification tools
Threat IntelligenceThreat indicator acceptance2+ threat feeds
Compliance AssessmentCompliance finding validation2+ compliance checks

Axiom Enforcer Integration

Signal Plurality enforcement integrates with the broader NABLA axiom checking system:

defmodule Prismatic.Epistemic.AxiomEnforcer do
  @moduledoc """
  Enforces all NABLA Infinity axioms with appropriate violation levels.
  Signal Plurality is Axiom 1 with E2 (hard block) enforcement.

  ## Enforcement Levels

  - E1: Warning + correction request (soft axioms)
  - E2: BLOCK + rejection (hard axioms including Signal Plurality)
  - E3: HALT + review required (Trinity Gate failures)
  - E4: Investigation + audit (multiple axiom violations)
  """

  require Logger

  @type enforcement_level :: :e1_warning | :e2_block | :e3_halt | :e4_investigation

  @axioms [
    {:signal_plurality, :hard, :e2_block},
    {:contradiction_preservation, :hard, :e2_block},
    {:absence_informative, :soft, :e1_warning},
    {:time_decay, :hard, :e2_block},
    {:unknown_valid, :hard, :e2_block},
    {:source_independence, :soft, :e1_warning},
    {:provenance_mandatory, :hard, :e2_block}
  ]

  @spec enforce_all([signal()], map()) :: {:ok, map()} | {:error, enforcement_level(), String.t()}
  def enforce_all(signals, claim) do
    Enum.reduce_while(@axioms, {:ok, claim}, fn {axiom, _hardness, level}, {:ok, acc} ->
      case check_axiom(axiom, signals, acc) do
        :ok ->
          {:cont, {:ok, acc}}

        {:violation, reason} ->
          Logger.error("NABLA Axiom violation: #{axiom} - #{reason}")

          :telemetry.execute(
            [:prismatic, :epistemic, :axiom_violation],
            %{count: 1},
            %{axiom: axiom, level: level}
          )

          {:halt, {:error, level, "#{axiom}: #{reason}"}}
      end
    end)
  end

  defp check_axiom(:signal_plurality, signals, _claim) do
    case Prismatic.Epistemic.SignalPlurality.verify_plurality(signals) do
      {:ok, :plural, _} -> :ok
      {:error, :insufficient_plurality, reason} -> {:violation, reason}
    end
  end

  defp check_axiom(:provenance_mandatory, signals, _claim) do
    missing = Enum.filter(signals, fn s -> is_nil(s.provenance) end)
    if Enum.empty?(missing), do: :ok, else: {:violation, "#{length(missing)} signals lack provenance"}
  end

  defp check_axiom(:contradiction_preservation, signals, _claim) do
    # Contradictions between signals must be preserved, not resolved
    :ok
  end

  defp check_axiom(:time_decay, signals, _claim) do
    missing_timestamps = Enum.filter(signals, fn s -> is_nil(s.timestamp) end)
    if Enum.empty?(missing_timestamps), do: :ok, else: {:violation, "Signals missing timestamps"}
  end

  defp check_axiom(:unknown_valid, _signals, _claim), do: :ok
  defp check_axiom(:absence_informative, _signals, _claim), do: :ok
  defp check_axiom(:source_independence, _signals, _claim), do: :ok
end

Security Rating Enforcement

The EASM Security Rating system enforces signal plurality at the dimension level. No dimension score is accepted without at least two independent evidence sources:

defmodule PrismaticPerimeter.Rating.PluralityEnforcer do
  @moduledoc """
  Enforces signal plurality for each security rating dimension.
  No dimension score is accepted without at least 2 independent
  evidence sources. This prevents single-tool bias from distorting
  security ratings.

  ## Rating Dimensions

  Each dimension (network security, application security, DNS health,
  TLS configuration, etc.) must have evidence from at least two
  independent sources before a score can be assigned.
  """

  @type dimension :: atom()
  @type dimension_score :: %{
    value: float(),
    evidence: [evidence()],
    confidence: float()
  }
  @type evidence :: %{source: String.t(), data: term(), timestamp: DateTime.t()}

  @spec enforce_dimension_plurality(%{dimension() => dimension_score()}) ::
    {:ok, %{dimension() => dimension_score()}} | {:error, [dimension()]}
  def enforce_dimension_plurality(dimension_scores) do
    insufficient =
      dimension_scores
      |> Enum.filter(fn {_dim, score} ->
        independent_sources = count_independent_sources(score.evidence)
        independent_sources < 2
      end)
      |> Enum.map(fn {dim, _} -> dim end)

    case insufficient do
      [] -> {:ok, dimension_scores}
      dims -> {:error, dims}
    end
  end

  @spec count_independent_sources([evidence()]) :: non_neg_integer()
  defp count_independent_sources(evidence) do
    evidence
    |> Enum.map(& &1.source)
    |> Enum.uniq()
    |> length()
  end
end

Signal Quality Weighting

Not all signals carry equal weight. While plurality requires at least two signals, the system weights signals based on quality factors. This ensures that while the minimum of two independent signals is always enforced, the resulting belief confidence reflects the quality of the contributing signals:

defmodule Prismatic.Epistemic.SignalWeighting do
  @moduledoc """
  Weights signals based on quality factors while maintaining
  the hard minimum of 2 independent signals for plurality.

  ## Weighting Factors

  - Freshness: Recent signals carry more weight (time decay)
  - Source reliability: Historically accurate sources weight higher
  - Methodology rigor: Formal verification > heuristic analysis
  - Corroboration count: More corroborating signals increase confidence
  """

  @type quality_factors :: %{
    freshness: float(),
    source_reliability: float(),
    methodology_rigor: float(),
    corroboration_count: non_neg_integer()
  }

  @spec weighted_confidence([signal()]) :: float()
  def weighted_confidence(signals) do
    total_weight =
      signals
      |> Enum.map(&signal_weight/1)
      |> Enum.sum()

    weighted_sum =
      signals
      |> Enum.map(fn s -> s.confidence * signal_weight(s) end)
      |> Enum.sum()

    weighted_sum / max(total_weight, 1.0)
  end

  @spec signal_weight(signal()) :: float()
  defp signal_weight(signal) do
    freshness = calculate_freshness(signal.timestamp)
    reliability = signal.provenance |> Map.get(:source_reliability, 0.5)

    freshness * 0.4 + reliability * 0.6
  end

  @spec calculate_freshness(DateTime.t()) :: float()
  defp calculate_freshness(timestamp) do
    age_hours = DateTime.diff(DateTime.utc_now(), timestamp, :hour)

    cond do
      age_hours < 1 -> 1.0
      age_hours < 24 -> 0.9
      age_hours < 168 -> 0.7
      age_hours < 720 -> 0.4
      true -> 0.1
    end
  end
end

Contradiction Handling with Plural Signals

When plural signals contradict each other, the Contradiction Preservation axiom takes precedence. Contradictions between valid signals are preserved as informative data points rather than being resolved by discarding one signal:

defmodule Prismatic.Epistemic.ContradictionHandler do
  @moduledoc """
  Handles contradictions between plural signals.
  Contradictions are preserved, not resolved by discarding one signal.
  The existence of a contradiction is itself a signal that
  warrants investigation.
  """

  @type contradiction :: %{
    signal_a: signal(),
    signal_b: signal(),
    description: String.t(),
    detected_at: DateTime.t()
  }

  @spec detect_contradictions([signal()]) :: {:ok, :no_contradictions} | {:contradiction, [contradiction()]}
  def detect_contradictions(signals) do
    pairs = for a <- signals, b <- signals, a.source != b.source, do: {a, b}

    contradictions =
      pairs
      |> Enum.filter(fn {a, b} -> contradicts?(a.content, b.content) end)
      |> Enum.map(fn {a, b} ->
        %{
          signal_a: a,
          signal_b: b,
          description:
            "Signals from #{a.provenance.origin} and #{b.provenance.origin} contradict. " <>
            "Both preserved per Contradiction Preservation axiom.",
          detected_at: DateTime.utc_now()
        }
      end)
      |> Enum.uniq_by(fn c -> {c.signal_a.source, c.signal_b.source} end)

    case contradictions do
      [] -> {:ok, :no_contradictions}
      found -> {:contradiction, found}
    end
  end

  defp contradicts?(content_a, content_b) do
    # Domain-specific contradiction detection
    # For example, one source says port 443 is open, another says it's closed
    content_a != content_b and covers_same_domain?(content_a, content_b)
  end

  defp covers_same_domain?(a, b) do
    Map.keys(a) -- Map.keys(b) == [] or Map.keys(b) -- Map.keys(a) == []
  end
end

Usage Examples

Checking Signal Plurality

# Verify plurality before forming a belief about a domain's security posture
signals = [
  %{
    source: "shodan",
    content: %{ports: [80, 443]},
    timestamp: DateTime.utc_now(),
    confidence: 0.9,
    provenance: %{
      origin: "shodan",
      methodology: "active_scanning",
      upstream_sources: ["shodan_crawl_db"],
      collection_method: :active_scan,
      independence_class: "shodan"
    }
  },
  %{
    source: "censys",
    content: %{ports: [80, 443, 8080]},
    timestamp: DateTime.utc_now(),
    confidence: 0.85,
    provenance: %{
      origin: "censys",
      methodology: "zmap_scanning",
      upstream_sources: ["censys_universal_dataset"],
      collection_method: :active_scan,
      independence_class: "censys"
    }
  }
]

case Prismatic.Epistemic.SignalPlurality.verify_plurality(signals) do
  {:ok, :plural, verified_signals} ->
    # Safe to form belief - plurality satisfied
    form_belief(verified_signals)

  {:error, :insufficient_plurality, reason} ->
    # BLOCKED - cannot proceed
    Logger.error("Signal Plurality violation: #{reason}")
end

Common Integration Patterns

PatternImplementationExample
OSINT FusionMultiple provider queriesShodan + Censys for port scanning
Certificate ValidationMultiple CT log queriesCT transparency + direct SSL scan
DNS VerificationMultiple resolver queriesPublic DNS + authoritative nameserver
Reputation CheckMultiple reputation databasesGreyNoise + AbuseIPDB
Compliance AssessmentMultiple compliance checksNIS2 + ZKB independent assessments

Relationship to Other NABLA Axioms

Signal Plurality does not operate in isolation. It interacts with the other six NABLA axioms in specific ways:

AxiomRelationship to Signal Plurality
Contradiction PreservationWhen plural signals contradict, both are preserved
Absence InformativeMissing second signal is itself data -- investigated as potential gap
Time DecayPlural signals must be temporally current; aged signals lose weight
Unknown Valid"Insufficient signals" is a valid state; do not fabricate plurality
Source IndependenceWeighting favors independent sources; shared upstream degrades confidence
Provenance MandatoryIndependence verification requires provenance; signals without it are rejected

Best Practices

Design Data Collection for Plurality from the Start: Do not build single-source systems and try to add plurality later. Multiple independent sources should be the default collection pattern.

Verify Independence Rigorously: Two APIs from the same vendor are not independent. Two analyses of the same dataset are not independent. Independence requires genuinely separate data origins.

Document Provenance for All Signals: Without provenance, independence cannot be verified. Every signal entering the system must carry its origin, methodology, and upstream dependencies.

Handle the Cost of Plurality Explicitly: Querying multiple sources takes more time and resources. Design systems with appropriate concurrency and timeout handling for plural collection.

Do Not Weaken Plurality Requirements Under Pressure: The axiom is hard-enforced precisely because pressure situations are when single-source errors are most dangerous.

Common Pitfalls

  • Confusing quantity with plurality: Ten signals from the same source still count as one independent signal. Plurality requires independent origins, not high volume.

  • Assuming API independence: Different API endpoints from the same provider share the same underlying data. They do not constitute independent signals.

  • Relaxing plurality for "trusted" sources: No source is trusted enough to bypass plurality. Even the most reliable source can be compromised, misconfigured, or outdated.

  • Treating plurality as sufficient for truth: Plurality is necessary but not sufficient. Two independent signals can both be wrong. Plurality reduces but does not eliminate epistemic risk.

  • Fabricating signals to satisfy the axiom: Generating artificial signals to meet the minimum of two violates the spirit and purpose of the axiom. The "Unknown Valid" axiom explicitly permits acknowledging insufficient evidence rather than fabricating it.

  • NABLA Infinity -- Parent epistemic framework defining this axiom
  • Intelligence Fusion -- Multi-source correlation requiring signal plurality
  • Blue Team -- Signal aggregation with plurality enforcement
  • Trinity Gate -- Verification gate complementing plurality requirements
  • Confidence Threshold -- Scoring system for evaluating plural signals
  • Contradiction Preservation -- Handling contradictions between plural signals
  • Provenance Mandatory -- Traceability requirement enabling independence verification
  • Time Decay -- Temporal weighting applied to plural signals
  • Shodan -- Primary discovery signal source in EASM
  • Censys -- Secondary discovery signal source in EASM
  • GreyNoise -- Threat context signal source complementing discovery signals
  • EASM -- Security domain enforcing signal plurality per rating dimension

See Also


Connect & Contribute

Created by Tomáš Korcak (korczis) | Open Source under GHL