10 KiB
Unified Trust Score Architecture
Ownership: Policy Guild • Signals Guild Services:
StellaOps.Signals.UnifiedScore(facade),StellaOps.Signals.EvidenceWeightedScore(core),StellaOps.Policy.Determinization(entropy) Related docs: Policy architecture, EWS migration, Score Proofs API
This document describes the unified trust score facade that provides a single API for accessing risk scores, uncertainty metrics, and evidence from the underlying EWS and Determinization systems.
1 · Design Principle: Facade Over Rewrite
Stella Ops has mature, battle-tested scoring systems:
| System | Purpose | Maturity |
|---|---|---|
| EWS | 6-dimension risk scoring with guardrails | Production (1000+ determinism tests) |
| Determinization | Entropy, confidence decay, conflict detection | Production |
| RiskEngine | Signal-specific providers (CVSS/KEV/EPSS) | Production |
The unified score facade does not replace these systems. Instead, it:
- Combines EWS scores with Determinization entropy in a single result
- Externalizes EWS weights to versioned manifest files for auditing
- Exposes the unknowns fraction (U) as a first-class metric
2 · Architecture
┌─────────────────────────────────────────────────────────────┐
│ IUnifiedScoreService │
│ (Facade) │
├─────────────────────────────────────────────────────────────┤
│ • ComputeAsync(request) → UnifiedScoreResult │
│ • Combines EWS + Determinization + ConflictDetector │
│ • Loads weights from versioned manifests │
└─────────────┬───────────────────────┬───────────────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ EvidenceWeightedScore │ │ Determinization │
│ Calculator │ │ │
├─────────────────────────┤ ├─────────────────────────┤
│ • 6-dimension scoring │ │ • Entropy calculation │
│ • Guardrails (caps/ │ │ • Confidence decay │
│ floors) │ │ • Signal gap tracking │
│ • Anchor metadata │ │ • Fingerprinting │
│ • Policy digest │ │ • Conflict detection │
└─────────────────────────┘ └─────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ etc/weights/*.json │
│ (Versioned Weight Manifests) │
└─────────────────────────────────────────────────────────────┘
3 · What the Facade Provides
3.1 · Unified Score Result
public sealed record UnifiedScoreResult
{
// From EWS
public int Score { get; } // 0-100
public string Bucket { get; } // ActNow, ScheduleNext, Investigate, Watchlist
public IReadOnlyList<DimensionContribution> Breakdown { get; }
public AppliedGuardrails Guardrails { get; }
public string EwsDigest { get; } // SHA-256 of EWS result
// From Determinization
public double UnknownsFraction { get; } // U metric (0.0 = complete, 1.0 = no data)
public UnknownsBand UnknownsBand { get; } // Complete, Adequate, Sparse, Insufficient
public IReadOnlyList<SignalGap> Gaps { get; }
public IReadOnlyList<SignalConflict> Conflicts { get; }
public string DeterminizationFingerprint { get; }
// Combined
public IReadOnlyList<SignalDelta> DeltaIfPresent { get; } // Impact if missing signals arrive
public string WeightManifestRef { get; } // version + hash
public DateTimeOffset ComputedAt { get; }
}
3.2 · Unknowns Fraction (U)
The UnknownsFraction directly exposes Determinization's entropy calculation:
U = 1 - (weighted_present_signals / total_weight)
| U Range | Band | Meaning | Action |
|---|---|---|---|
| 0.0 – 0.2 | Complete | All signals present | Automated decisions |
| 0.2 – 0.4 | Adequate | Sufficient for evaluation | Automated decisions |
| 0.4 – 0.6 | Sparse | Signal gaps exist | Manual review recommended |
| 0.6 – 1.0 | Insufficient | Critical data missing | Block pending more signals |
Thresholds align with existing Determinization config:
RefreshEntropyThreshold: 0.40→ triggers signal refreshManualReviewEntropyThreshold: 0.60→ requires human review
3.3 · Delta-If-Present
When signals are missing, the facade calculates potential score impact:
{
"delta_if_present": [
{
"signal": "reachability",
"min_impact": -15,
"max_impact": +8,
"description": "If reachability confirmed as not-reachable, score decreases by up to 15"
},
{
"signal": "runtime",
"min_impact": 0,
"max_impact": +25,
"description": "If runtime execution observed, score increases by up to 25"
}
]
}
4 · Weight Manifests
4.1 · Location
Weight manifests are stored in etc/weights/ with versioned filenames:
etc/weights/
├── v2026-01-22.weights.json
├── v2026-02-01.weights.json
└── ...
4.2 · Schema
{
"version": "v2026-01-22",
"effective_from": "2026-01-22T00:00:00Z",
"description": "EWS default weights",
"weights": {
"rch": 0.30,
"rts": 0.25,
"bkp": 0.15,
"xpl": 0.15,
"src": 0.10,
"mit": 0.10
},
"hash": "sha256:..."
}
4.3 · Versioning Rules
- Immutable once published – Manifest content never changes after creation
- Hash verification – SHA-256 of canonical JSON ensures integrity
- Policy pinning – Policies can specify
weights_refto lock a version - Fallback – If manifest missing, EWS uses compiled defaults
5 · Existing Systems (Unchanged)
5.1 · EWS Formula (Preserved)
The EWS formula remains unchanged:
rawScore = (RCH × w_rch) + (RTS × w_rts) + (BKP × w_bkp) +
(XPL × w_xpl) + (SRC × w_src) - (MIT × w_mit)
finalScore = clamp(rawScore, 0, 1) × 100
With guardrails:
- Speculative cap (45): RCH=0 and RTS=0
- Not-affected cap (15): BKP≥1.0, VEX=not_affected, RTS<0.6
- Runtime floor (60): RTS≥0.8
5.2 · Determinization (Preserved)
Entropy and decay calculations remain unchanged:
entropy = 1 - (present_weight / total_weight)
decay = max(floor, exp(-ln(2) × age_days / half_life_days))
With conflict detection:
- VEX vs Reachability contradiction
- Static vs Runtime contradiction
- Multiple VEX status conflict
- Backport vs Status conflict
6 · Integration Points
6.1 · CLI Commands
# Existing (enhanced)
stella gate score evaluate --finding-id CVE-2024-1234@pkg:npm/lodash \
--cvss 7.5 --epss 0.15 --reachability function \
--show-unknowns --show-deltas
# New
stella score compute --finding-id CVE-2024-1234@pkg:npm/lodash \
--cvss 7.5 --epss 0.15
stella score explain CVE-2024-1234@pkg:npm/lodash
stella gate score weights list
stella gate score weights show v2026-01-22
stella gate score weights diff v2026-01-22 v2026-02-01
6.2 · API Endpoints
POST /api/v1/score/evaluate # Compute unified score
GET /api/v1/score/{id}/replay # Fetch signed replay proof
GET /api/v1/score/weights # List weight manifests
GET /api/v1/score/weights/{v} # Get specific manifest
Replay Endpoint Response
The /score/{id}/replay endpoint returns a DSSE-signed attestation with payload type application/vnd.stella.score+json:
{
"signed_replay_log_dsse": "BASE64",
"rekor_inclusion": {"logIndex": 12345, "rootHash": "…"},
"canonical_inputs": [
{"name": "sbom.json", "sha256": "…"},
{"name": "vex.json", "sha256": "…"}
],
"transforms": [
{"name": "canonicalize_spdx", "version": "1.1"},
{"name": "age_decay", "params": {"lambda": 0.02}}
],
"algebra_steps": [
{"signal": "rch", "w": 0.30, "value": 0.78, "term": 0.234}
],
"final_score": 85
}
Replay proofs are stored as OCI referrers ("StellaBundle" pattern) attached to the scored artifact.
6.3 · Console UI
Finding detail views show:
- Score with bucket (existing)
- Unknowns fraction (U) with color-coded band
- Delta-if-present for missing signals
- Weight manifest version
7 · Determinism Guarantees
The facade inherits determinism from underlying systems:
| Aspect | Guarantee |
|---|---|
| EWS score | Identical inputs → identical score (1000+ iteration tests) |
| Entropy | Identical signal presence → identical U |
| Fingerprint | Content-addressed SHA-256 |
| Weight manifest | Immutable after creation |
The facade adds no additional sources of non-determinism.
8 · What We're NOT Doing
- ❌ Replacing EWS formula
- ❌ Replacing Determinization entropy calculation
- ❌ Changing guardrail logic
- ❌ Changing conflict detection
- ❌ Breaking existing CLI commands
- ❌ Breaking existing API contracts
The facade is additive – existing functionality continues to work unchanged.