Uncertainty States & Entropy Scoring

Status: Implemented v0 for reachability facts (Signals). Owners: Signals Guild · Policy Guild · UI Guild.

Audience: Signals, Policy, and Console engineers who consume or act on uncertainty data.

Stella Ops treats missing data and untrusted evidence as first-class uncertainty states, not silent false negatives. Signals persists uncertainty state entries alongside reachability facts and derives a deterministic riskScore that increases when entropy is high. Policy gates and the Console then reason over those states explicitly, so a release decision can never quietly rest on an unproven “not affected”.


1. Core states (extensible)

CodeNameMeaning
U1MissingSymbolResolutionUnresolved symbols/edges prevent a complete reachability proof.
U2MissingPurlPackage identity/version is ambiguous (lockfile absent, heuristics only).
U3UntrustedAdvisoryAdvisory source lacks provenance/corroboration.
U4UnknownNo analyzers have processed this subject; baseline uncertainty.

Each state records:


1.1 Uncertainty Tiers (v1 — Sprint 0401)

Uncertainty states are grouped into tiers that determine policy thresholds and UI treatment.

Tier Definitions

TierEntropy RangeStatesRisk ModifierPolicy Implication
T1 (High)0.7 - 1.0U1 (high), U4+50%Block “not_affected”, require human review
T2 (Medium)0.4 - 0.69U1 (medium), U2+25%Warn on “not_affected”, flag for review
T3 (Low)0.1 - 0.39U2 (low), U3+10%Allow “not_affected” with advisory note
T4 (Negligible)0.0 - 0.09U3 (low)+0%Normal processing, no special handling

Tier Assignment Rules

  1. U1 (MissingSymbolResolution):

    • entropy >= 0.7 → T1 (>30% unknowns in callgraph)
    • entropy >= 0.4 → T2 (15-30% unknowns)
    • entropy < 0.4 → T3 (<15% unknowns)
  2. U2 (MissingPurl):

    • entropy >= 0.5 → T2 (>50% packages unresolved)
    • entropy < 0.5 → T3 (<50% packages unresolved)
  3. U3 (UntrustedAdvisory):

    • entropy >= 0.6 → T3 (no corroboration)
    • entropy < 0.6 → T4 (partial corroboration)
  4. U4 (Unknown):

    • Always T1 (no analysis performed = maximum uncertainty)

Aggregate Tier Calculation

When multiple uncertainty states exist, the aggregate tier is the maximum (most severe):

aggregateTier = max(tier(state) for state in uncertainty.states)

2. JSON shape

{
  "uncertainty": {
    "states": [
      {
        "code": "U1",
        "name": "MissingSymbolResolution",
        "entropy": 0.72,
        "timestamp": "2025-11-12T14:12:00Z",
        "evidence": [
          {
            "type": "UnknownsRegistry",
            "sourceId": "signals.unknowns",
            "detail": "unknownsCount=12;unknownsPressure=0.375"
          }
        ]
      }
    ]
  }
}

3. Risk score math (Signals)

Signals computes a riskScore deterministically during reachability recompute:

meanEntropy  = avg(uncertainty.states[].entropy)              // 0 when no states
entropyBoost = clamp(meanEntropy * k, 0 .. boostCeiling)
riskScore    = clamp(baseScore * (1 + entropyBoost), 0 .. 1)

Where:


4. Policy guidance (high level)

Uncertainty should bias decisions away from “not affected” when evidence is missing:

See the reachability lattice guide for the current reachability score model and the Signals reachability contract for the Signals API contract.


5. Tier-Based Risk Score (v1 — Sprint 0401)

Risk Score Formula

Building on §3, the v1 risk score incorporates tier-based modifiers:

tierModifier = {
  T1: 0.50,
  T2: 0.25,
  T3: 0.10,
  T4: 0.00
}[aggregateTier]

riskScore = clamp(baseScore * (1 + tierModifier + entropyBoost), 0 .. 1)

Where:

Example Calculation

Given:
  - baseScore = 0.4 (moderate reachability)
  - uncertainty.states = [
      {code: "U1", entropy: 0.72},  // T1 tier
      {code: "U3", entropy: 0.45}   // T3 tier
    ]
  - aggregateTier = T1 (max of T1, T3)
  - tierModifier = 0.50

  meanEntropy = (0.72 + 0.45) / 2 = 0.585
  entropyBoost = clamp(0.585 * 0.5, 0 .. 0.5) = 0.2925

  riskScore = clamp(0.4 * (1 + 0.50 + 0.2925), 0 .. 1)
            = clamp(0.4 * 1.7925, 0 .. 1)
            = clamp(0.717, 0 .. 1)
            = 0.717

Tier Thresholds for Policy Gates

TierriskScore RangeVEX “not_affected”VEX “affected”Auto-triage
T1>= 0.6❌ blocked⚠️ reviewunder_investigation
T20.4 - 0.59⚠️ warning✅ allowedManual review
T30.2 - 0.39✅ with note✅ allowedNormal
T4< 0.2✅ allowed✅ allowedNormal

6. JSON Schema (v1)

Extended schema with tier information:

{
  "uncertainty": {
    "states": [
      {
        "code": "U1",
        "name": "MissingSymbolResolution",
        "entropy": 0.72,
        "tier": "T1",
        "timestamp": "2025-12-13T10:00:00Z",
        "evidence": [
          {
            "type": "UnknownsRegistry",
            "sourceId": "signals.unknowns",
            "detail": "unknownsCount=45;totalSymbols=125;unknownsPressure=0.36"
          }
        ]
      },
      {
        "code": "U4",
        "name": "Unknown",
        "entropy": 1.0,
        "tier": "T1",
        "timestamp": "2025-12-13T10:00:00Z",
        "evidence": [
          {
            "type": "NoAnalysis",
            "sourceId": "signals.bootstrap",
            "detail": "subject not yet analyzed"
          }
        ]
      }
    ],
    "aggregateTier": "T1",
    "riskScore": 0.717,
    "computedAt": "2025-12-13T10:00:00Z"
  }
}

7. Implementation Pointers


8. Policy Guidance (v1 — Sprint 0401)

Uncertainty gates enforce evidence-quality thresholds in the Policy Engine. When entropy is too high or evidence is missing, policies block or downgrade VEX decisions.

8.1 Gate Mapping

GateUncertainty StateTierPolicy Action
U1MissingSymbolResolutionT1/T2Block not_affected, require review
U2MissingPurlT2/T3Warn on not_affected, add review flag
U3UntrustedAdvisoryT3/T4Advisory caveat, no blocking

8.2 Sample Policy Rules

// Block not_affected when symbol resolution has high entropy
rule u1_gate_high_entropy priority 5 {
  when signals.uncertainty.level == "U1"
       and signals.uncertainty.entropy >= 0.7
  then status := "under_investigation"
       annotate gate := "U1"
       annotate remediation := "Upload symbols or close unknowns registry"
  because "High symbol entropy blocks strong VEX claims";
}

// Tier-based compound gate
rule tier1_block_not_affected priority 3 {
  when signals.uncertainty.aggregateTier == "T1"
       and vex.any(status == "not_affected")
  then status := "under_investigation"
       annotate blocked_reason := "T1 uncertainty requires evidence"
  because "Maximum uncertainty tier blocks all exclusion claims";
}

8.3 YAML Configuration

uncertainty_gates:
  u1_gate:
    entropy_threshold: 0.7
    blocked_statuses: [not_affected]
    fallback_status: under_investigation
    remediation_hint: "Upload symbols or resolve unknowns"
  u2_gate:
    entropy_threshold: 0.4
    blocked_statuses: [not_affected]
    warn_on_block: true
  u3_gate:
    entropy_threshold: 0.1
    annotate_caveat: true

See Policy DSL §12 — Uncertainty Gates for the complete gate rules and tier-aware compound patterns.


9. Remediation Actions

Each uncertainty state has recommended remediation steps:

StateCodeRemediationCLI Command
MissingSymbolResolutionU1Upload debug symbols, resolve unknownsstella symbols ingest --path <symbols>
MissingPurlU2Generate lockfile, verify package coordinatesstella sbom refresh --resolve
UntrustedAdvisoryU3Cross-reference trusted sourcesstella advisory verify --source NVD,GHSA
UnknownU4Run initial analysisstella scan --full

9.1 Automated Remediation Flow

1. Policy blocks decision with U1/U2 gate
   ↓
2. Console/CLI shows remediation hint
   ↓
3. User runs remediation command (e.g., stella symbols ingest)
   ↓
4. Signals recomputes uncertainty states
   ↓
5. Risk score updates, tier may drop
   ↓
6. Policy re-evaluates, decision may proceed

9.2 Remediation Priority

When multiple uncertainty states exist, prioritize by tier:

  1. T1 states first — Block all exclusions until resolved
  2. T2 states — May proceed with warnings if T1 cleared
  3. T3/T4 states — Normal flow with caveats

Last updated: 2025-12-13 (Sprint 0401).