VEX Auto-Generation Flow
Implementation status (reconciled against
src/2026-05-30). This document describes an aspirational end-to-end “VEX auto-generation” pipeline. Most of the flow as originally written — an autonomous AdvisoryAI that gathers evidence, decides the VEX status, emits a full OpenVEX statement, routes it through a Console review/approve UI, then signs and stores it in VexLens with a Rekor transparency-log entry — is NOT IMPLEMENTED as a single pipeline. Three real, narrower capabilities exist in code today and are documented inline below:
- AdvisoryAI
/v1/advisory-ai/justifydrafts justification text (not a full VEX document) for a user-proposed status + justification type, returning a confidence score and evidence suggestions. The human chooses the status; the AI does not decide it. Source:src/AdvisoryAI/StellaOps.AdvisoryAI.WebService/Program.cs(HandleJustify) andContracts/JustifyContracts.cs.- VexLens computes deterministic, trust-weighted consensus over VEX statements that were already ingested (via VexHub). It does not generate, author, sign, or store newly-authored VEX statements, and it has no AdvisoryAI integration. Source:
src/VexLens/StellaOps.VexLens/**andsrc/VexLens/StellaOps.VexLens.WebService/Extensions/VexLensEndpointExtensions.cs.- Console source includes a dedicated AI-justify panel (
AiJustifyPanelComponent, task VEX-AI-009) and a VEX create-workflow wizard (VexCreateWorkflowComponent, task VEX-AI-011). The justify panel calls AdvisoryAI/justify, renders the draft, confidence, and a review checklist, and emits a chosen justification; the create-workflow walks vulnerability → status → justification → evidence → review and thenPOSTs to a VexHub create endpoint. Caveat: that create endpoint (POST /api/v1/vex/statements/…/statements/simple, expected bysrc/Web/StellaOps.Web/src/app/core/api/vex-hub.client.ts) does not exist server-side — VexHub’s WebService only exposes read endpoints plus one adminPOST /api/v1/vex/conflicts/resolve. The Console therefore does not expose a Create action:…/vex/createredirects to VEX search until a real, authenticated create endpoint exists. The wizard source remains dormant.Sections that describe non-existent surfaces (the auto-approve YAML, the
VexDraftRequest/VexDraftResponseschemas, thevex_drafts_*metrics, thevex.draft.*log events, signing + Rekor) are flagged NOT IMPLEMENTED where they appear and retained as roadmap intent. The earlier blanket claim that “the Console draft-review UI” does not exist was incorrect and is corrected below (the UI exists; its backend does not).
Overview
The VEX (Vulnerability Exploitability eXchange) Auto-Generation Flow describes how StellaOps assists in creating VEX statements by analyzing reachability data, runtime observations, and historical patterns. This flow combines automated analysis with human review to produce accurate exploitability assessments.
Audience: security analysts reviewing VEX data and engineers integrating with AdvisoryAI and VexLens. Read the implementation-status banner above first — most of the end-to-end pipeline is aspirational; the live surfaces are AdvisoryAI /justify, VexLens consensus, and Console VEX search/read workflows.
Business Value: Reduce false positive burden by automatically identifying vulnerabilities that are not exploitable in the specific deployment context.
Actors
| Actor | Type | Role | Status |
|---|---|---|---|
| Security Analyst | Human | Reviews VEX statements and consensus; may propose status/justification through future authoring | Read workflows implemented; Console authoring is unavailable until the backend create contract exists (see Step 6) |
| AdvisoryAI | Service | AI-assisted justification text drafting via /v1/advisory-ai/justify; does not decide status | Implemented (justification drafting only) |
| ReachGraph | Service | Provides reachability analysis (supplied to AdvisoryAI as a reachabilityScore context field, not auto-queried by a VEX pipeline) | Partial — no auto-wired VEX pipeline |
| Signals | Service | Provides runtime observations (not consumed by any VEX-generation pipeline) | NOT IMPLEMENTED for this flow |
| VexLens | Service | Computes trust-weighted consensus over already-ingested VEX statements; does not author/sign/distribute new VEX | Implemented (consensus only) |
| VexHub | Service | Ingests/normalizes/stores VEX statements and is the intended authoring backend the Console create-workflow targets. No author/create endpoint exists yet — VexHub’s WebService only exposes read endpoints plus one admin POST /api/v1/vex/conflicts/resolve | Partial — read + conflict-resolve only; create endpoint NOT IMPLEMENTED |
| Console (Web UI) | Frontend | Hosts VEX search/read workflows; retains dormant AI-justify and create-workflow source | Read UI implemented; Create is hidden and …/vex/create redirects to search because the VexHub create endpoint does not exist |
| Scanner | Service | Provides SBOM context (supplied to AdvisoryAI as a free-text sbomContext/callGraphSummary field, not auto-queried) | Partial — manual context only |
Prerequisites
- VEX statements already ingested into VexHub (for VexLens consensus). VexLens reads ingested statements via
IVexStatementProvider(VexHubStatementProvider); it does not generate them. - For AI justification drafting: an AdvisoryAI inference profile configured and the caller holding a sufficient scope (see Authorization).
- Image scanned with SBOM generated (optional — passed to AdvisoryAI only as free-text context, not auto-gathered).
- Reachability analysis (optional — passed to AdvisoryAI only as a
reachabilityScore, not auto-queried). - Runtime signals (NOT wired into any VEX-generation pipeline).
VEX Statuses
Source of truth: the VexStatus enum in src/VexLens/StellaOps.VexLens/Models/NormalizedVexModels.cs (and the mirrored enum in Integration/VexSignalEmitter.cs). VexLens carries a fifth status, unknown, with dedicated rationale/provenance-trace handling — it is not optional.
| Status | Description |
|---|---|
not_affected | Vulnerability not exploitable |
affected | Vulnerability is exploitable |
fixed | Vulnerability has been remediated |
under_investigation | Status being determined |
unknown | Unresolved / no usable consensus — surfaces an unknownRationale and unknownProvenanceTrace |
The “Automation Confidence” column from earlier revisions was removed: there is no automated status-decisioning engine in code, so per-status automation confidence has no implementation backing.
Justification Types (OpenVEX)
Matches the VexJustification enum in src/VexLens/StellaOps.VexLens/Models/NormalizedVexModels.cs exactly.
| Justification | Description |
|---|---|
component_not_present | Vulnerable component not in product |
vulnerable_code_not_present | Specific vulnerable code not included |
vulnerable_code_not_in_execute_path | Code present but unreachable |
vulnerable_code_cannot_be_controlled_by_adversary | Attack vector blocked |
inline_mitigations_already_exist | Compensating controls in place |
Authorization
Reconciled against
src/Authority/.../StellaOpsScopes.csand the two serviceProgram.csfiles.
| Surface | Auth requirement (as enforced in code) | Notes |
|---|---|---|
VexLens read endpoints (POST /api/v1/vexlens/consensus*, GET /api/v1/vexlens/projections*, /stats, /conflicts, /deltas/compute, /gating/*) | ASP.NET policy vexlens.read | Registered by VexLens.WebService/Program.cs and canonically declared as StellaOpsScopes.VexLensRead; the shipped Standard Authority profile grants it to the Console and CLI clients, and migration 010 repairs an existing/drifted Console client grant. |
VexLens issuer-directory endpoints (/api/v1/vexlens/issuers*) | ASP.NET policy vexlens.write | Registered by VexLens.WebService/Program.cs, canonically declared as StellaOpsScopes.VexLensWrite, and granted to the first-party Console and CLI clients by the shipped Standard Authority profile. |
AdvisoryAI POST /v1/advisory-ai/justify | Any of advisory:run, advisory:justify, advisory-ai:operate, advisory-ai:admin (handler checks the token’s scope set) | Only advisory-ai:operate and advisory-ai:admin are in the canonical catalog; advisory:run and advisory:justify are accepted by the handler but not defined in StellaOpsScopes.cs. |
Flagged divergence:
advisory:runandadvisory:justifyare enforced in AdvisoryAI service code but remain absent from the canonical scope catalog. Thevexlens.*gap is closed: both strings are canonical Authority scopes and are present in the shipped Standard client grants.
Flow Diagram
NOT IMPLEMENTED as drawn. The sequence below is the target design. In code today there is no service that auto-queries Scanner, ReachGraph, and Signals on the analyst’s behalf, no autonomous status decision, and no VexLens “store + sign” step. What actually exists:
- The analyst (or a calling tool — in the Console, the
AiJustifyPanelComponent) gathers context manually and calls AdvisoryAI/v1/advisory-ai/justifywith the already-chosen status and justification type, plus optional free-text context (sbomContext,callGraphSummary,reachabilityScore,relatedVexStatements). AdvisoryAI returns drafted justification text, asuggestedJustificationType, a confidence score, and evidence suggestions.- The Console retains VEX create-workflow source for vulnerability → status → justification → evidence → review, but does not expose it.
…/vex/createredirects to search because the VexHub create endpoint does not exist server-side yet (see Step 6).- Separately, VexLens computes consensus over VEX statements already ingested from VexHub (
POST /api/v1/vexlens/consensus), with no authoring step.The ASCII sequence is retained as roadmap intent.
┌─────────────────────────────────────────────────────────────────────────────────┐
│ VEX Auto-Generation Flow (TARGET DESIGN — not implemented) │
└─────────────────────────────────────────────────────────────────────────────────┘
┌─────────┐ ┌───────────┐ ┌───────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Analyst │ │AdvisoryAI │ │ ReachGraph│ │ Signals │ │ VexLens │ │ Scanner │
└────┬────┘ └─────┬─────┘ └─────┬─────┘ └────┬────┘ └────┬────┘ └────┬────┘
│ │ │ │ │ │
│ Review │ │ │ │ │
│ finding │ │ │ │ │
│────────────>│ │ │ │ │
│ │ │ │ │ │
│ │ Get SBOM │ │ │ │
│ │ context │ │ │ │
│ │────────────────────────────────────────────────────>│
│ │ │ │ │ │
│ │ SBOM + │ │ │ │
│ │ call graph │ │ │ │
│ │<────────────────────────────────────────────────────│
│ │ │ │ │ │
│ │ Query reach │ │ │ │
│ │─────────────>│ │ │ │
│ │ │ │ │ │
│ │ │ Analyze │ │ │
│ │ │ call paths │ │ │
│ │ │───┐ │ │ │
│ │ │ │ │ │ │
│ │ │<──┘ │ │ │
│ │ │ │ │ │
│ │ K4 state + │ │ │ │
│ │ evidence │ │ │ │
│ │<─────────────│ │ │ │
│ │ │ │ │ │
│ │ Query runtime│ │ │ │
│ │─────────────────────────────> │ │
│ │ │ │ │ │
│ │ │ │ Check │ │
│ │ │ │ invocations│ │
│ │ │ │───┐ │ │
│ │ │ │ │ │ │
│ │ │ │<──┘ │ │
│ │ │ │ │ │
│ │ Runtime │ │ │ │
│ │ evidence │ │ │ │
│ │<───────────────────────────── │ │
│ │ │ │ │ │
│ │ Analyze │ │ │ │
│ │ with LLM │ │ │ │
│ │───┐ │ │ │ │
│ │ │ │ │ │ │
│ │<──┘ │ │ │ │
│ │ │ │ │ │
│ VEX draft │ │ │ │ │
│ + confidence│ │ │ │ │
│<────────────│ │ │ │ │
│ │ │ │ │ │
│ [Review] │ │ │ │ │
│ Approve/ │ │ │ │ │
│ Modify │ │ │ │ │
│───┐ │ │ │ │ │
│ │ │ │ │ │ │
│<──┘ │ │ │ │ │
│ │ │ │ │ │
│ Submit VEX │ │ │ │ │
│────────────────────────────────────────────────────────> │
│ │ │ │ │ │
│ │ │ │ │ Store │
│ │ │ │ │ + sign │
│ │ │ │ │───┐ │
│ │ │ │ │ │ │
│ │ │ │ │<──┘ │
│ │ │ │ │ │
│ VEX ID │ │ │ │ │
│<──────────────────────────────────────────────────────── │
│ │ │ │ │ │
Step-by-Step
1. Finding Review Initiation
Analyst selects finding for VEX assessment:
{
"scan_id": "scan-abc123",
"cve": "CVE-2024-1234",
"package": "pkg:npm/lodash@4.17.20",
"severity": "critical",
"current_status": "affected",
"request": "assess_exploitability"
}
Reconciliation: there is no
assess_exploitabilityrequest type and no endpoint that takes ascan_id+cveand returns a status recommendation. The implemented entry point is AdvisoryAIPOST /v1/advisory-ai/justify(see Step 3), which requires the caller to already supply theProposedStatus.
2. Context Gathering
NOT IMPLEMENTED as auto-gathering. AdvisoryAI does not call Scanner, ReachGraph, or Signals to assemble this context. The
/justifyrequest accepts a small, caller-suppliedcontextDataobject instead (reachabilityScore,codeSearchResults,sbomContext(free text),callGraphSummary(free text),relatedVexStatements(list of strings)). The rich SBOM/reachability/runtime JSON shapes below are illustrative of what a caller might summarize into those fields — they are not the wire format and are not produced by any service automatically.
SBOM Context
{
"component": {
"purl": "pkg:npm/lodash@4.17.20",
"locations": ["/app/node_modules/lodash"],
"dependents": ["express", "webpack"],
"scope": "runtime"
},
"call_graph": {
"entry_points": ["src/api/handler.js", "src/worker/processor.js"],
"functions_imported": ["_.get", "_.merge", "_.template"]
}
}
Reachability Analysis
{
"package": "pkg:npm/lodash@4.17.20",
"k4_state": "StaticallyReachable",
"vulnerable_function": "_.template",
"analysis": {
"function_imported": true,
"call_sites": 3,
"call_paths": [
{
"path": ["src/api/handler.js:45", "lib/renderer.js:12", "_.template"],
"reachable": true
}
]
}
}
Runtime Signals
{
"package": "pkg:npm/lodash@4.17.20",
"observation_period": "30d",
"signals": {
"function_invocations": {
"_.get": 15234,
"_.merge": 892,
"_.template": 0
},
"vulnerable_function_called": false,
"last_check": "2024-12-29T10:00:00Z"
}
}
3. AI-Assisted Analysis
The implemented surface is POST /v1/advisory-ai/justify(handler HandleJustify in AdvisoryAI.WebService/Program.cs; contracts in Contracts/JustifyContracts.cs). The caller supplies the proposed status and justification type; AdvisoryAI drafts the justification text and a confidence score. It does not decide the status, and it does not return an analysis/recommendation object with a status field as shown in earlier revisions.
Actual request (AiJustifyApiRequest):
{
"cveId": "CVE-2024-1234",
"productRef": "pkg:npm/lodash@4.17.20",
"proposedStatus": "not_affected",
"justificationType": "vulnerable_code_not_in_execute_path",
"contextData": {
"reachabilityScore": 0.2,
"codeSearchResults": 3,
"sbomContext": "lodash@4.17.20 present in /app/node_modules",
"callGraphSummary": "_.template imported; 3 call sites appear unused",
"relatedVexStatements": ["upstream not_affected (vendor)"]
},
"correlationId": "corr-abc123"
}
Actual response (AiJustifyApiResponse):
{
"justificationId": "just-789",
"draftJustification": "The vulnerable _.template function is imported but no reachable call path exercises it with adversary-controlled input.",
"suggestedJustificationType": "vulnerable_code_not_in_execute_path",
"confidenceScore": 0.85,
"evidenceSuggestions": [
"Attach the call-graph excerpt showing the unused import",
"Attach runtime telemetry covering the observation window"
],
"modelVersion": "<inference-profile-version>",
"generatedAt": "2024-12-29T10:30:00Z",
"traceId": "trace-..."
}
4. VEX Draft Generation
NOT IMPLEMENTED. No service emits a full OpenVEX document (
@context/@id/statements[...]) as an automated “draft VEX”. The/justifyendpoint returns only the justification text and metadata shown in Step 3. Authoring a complete OpenVEX statement, assigning a draft@id, and therequires_human_reviewflag are roadmap intent. The OpenVEX shape below is retained as the target document format a future authoring step would produce, and matches the OpenVEXv0.2.0schema StellaOps consumes elsewhere.
{
"draft_vex": {
"@context": "https://openvex.dev/ns/v0.2.0",
"@id": "https://stellaops.local/vex/draft/vex-draft-123",
"author": "StellaOps AdvisoryAI",
"timestamp": "2024-12-29T10:30:00Z",
"version": 1,
"statements": [
{
"vulnerability": {
"@id": "https://nvd.nist.gov/vuln/detail/CVE-2024-1234"
},
"products": [
{
"@id": "pkg:oci/myorg/app@sha256:abc123",
"subcomponents": [
{"@id": "pkg:npm/lodash@4.17.20"}
]
}
],
"status": "not_affected",
"justification": "vulnerable_code_not_in_execute_path",
"impact_statement": "The vulnerable _.template function is imported but never invoked. Runtime monitoring over 30 days confirms zero executions."
}
]
},
"confidence": 0.85,
"evidence_refs": [
"reachability:reach-analysis-456",
"signals:runtime-obs-789"
],
"requires_human_review": true
}
5. Human Review
PARTIALLY IMPLEMENTED (corrected). A dedicated review surface does exist in the Console (
src/Web/), contrary to earlier revisions of this doc:
AiJustifyPanelComponent(src/Web/StellaOps.Web/src/app/features/vex-hub/ai-justify-panel.component.ts, task VEX-AI-009) renders a config form (proposed status, justification type, product ref, optional context), calls AdvisoryAI/justify, then shows the drafted text in an editable box, a circular confidence gauge, the suggested justification type, evidence suggestions, and a three-item review checklist (“verified accurate”, “evidence attached”, “reviewed by a team member”). The “Use This Justification” button is disabled until the checklist is complete and emits the chosen justification text + type.VexCreateWorkflowComponent(…/features/vex-hub/vex-create-workflow.component.ts, task VEX-AI-011) implements a 5-step wizard in source (vulnerability → status → justification → evidence → review). It is not reachable from the Console;…/vex/createredirects to search while the required backend create endpoint is absent.What is not implemented is the autonomous “AI Recommendation: status + justification + confidence” decision shown in the mockup — the AI drafts text for a status the human already chose; it does not recommend the status. The final submit also has no live backend (see Step 6). The ASCII mockup below remains illustrative of the broad layout; the real panels are the components named above.
┌─────────────────────────────────────────────────────────────────┐
│ VEX Draft Review │
├─────────────────────────────────────────────────────────────────┤
│ │
│ CVE: CVE-2024-1234 (Critical) │
│ Package: lodash@4.17.20 │
│ Image: docker.io/myorg/app:v1.2.3 │
│ │
│ ┌─ AI Recommendation ──────────────────────────────────────────┐│
│ │ Status: not_affected ││
│ │ Justification: vulnerable_code_not_in_execute_path ││
│ │ Confidence: 85% ││
│ └──────────────────────────────────────────────────────────────┘│
│ │
│ ┌─ Evidence ───────────────────────────────────────────────────┐│
│ │ ✓ Static analysis: 3 potential call sites found ││
│ │ ✓ Runtime (30d): 0 invocations of _.template ││
│ │ ✓ Call graph: paths exist but appear unused ││
│ │ ⚠ Note: Function is imported in production code ││
│ └──────────────────────────────────────────────────────────────┘│
│ │
│ [Approve] [Modify] [Reject] [Request More Analysis] │
│ │
└─────────────────────────────────────────────────────────────────┘
6. VEX Submission
NOT IMPLEMENTED end-to-end. Two distinct facts:
- VexLens is not the authoring backend. It does not sign or “publish” authored VEX statements and emits no Rekor transparency-log entry for them. VexLens verifies signatures and consumes transparency-log proofs on incoming ingested statements (see
StellaOps.VexLens.Core/Signature/—ISignatureVerifier/SignatureVerifier, theTransparencyLogEntrymodel, and the verification metricsvexlens.signature.*), and it stores consensus projections (IConsensusProjectionStore) — not signed authored VEX.- VexHub is the intended authoring backend, but its create endpoint is missing. The Console create-workflow
POSTs toPOST /api/v1/vex/statementsand…/statements/simple(pervex-hub.client.ts), but the VexHub WebService (src/VexHub/StellaOps.VexHub.WebService/Extensions/VexHubEndpointExtensions.cs) exposes only read endpoints (/cve/{id},/package/{purl},/search,/stats,/export, …) plus one admin write —POST /api/v1/vex/conflicts/resolve. There is no server-side handler for creating an authored statement, so the submission round-trip currently has no live backend. To avoid a dead-end workflow, the Console hides the Create action and redirects direct visits to…/vex/createback to VEX search.Signing + transparency anchoring for newly-authored VEX, and the VexHub create endpoint itself, are roadmap intent. The shape below is illustrative only and does not match any implemented response.
{
"vex_id": "vex-789ghi",
"status": "published",
"signed_by": "analyst@acme.com",
"signature": {
"keyid": "sha256:analyst-key-fingerprint",
"sig": "base64:signature..."
},
"transparency_log": {
"rekor_log_index": 12345678,
"log_id": "sha256:rekor-log..."
}
}
Automation Levels
NOT IMPLEMENTED. There is no
vex_automationconfiguration block, auto-approve engine, orreview_timeoutmechanism in code. Confidence thresholds are not used to auto-approve anything. AdvisoryAI returns aconfidenceScoreon/justify, but nothing acts on it automatically. The YAML below is target design, retained for roadmap intent.
Fully Automated (High Confidence)
vex_automation:
auto_approve:
- condition: component_not_present
confidence_threshold: 0.99
- condition: fixed_version_deployed
confidence_threshold: 0.95
Semi-Automated (Human Review)
vex_automation:
require_review:
- condition: runtime_not_observed
confidence_threshold: 0.70
review_timeout: 24h
Manual Only
vex_automation:
manual_only:
- condition: affected
- condition: inline_mitigations
Data Contracts
Reconciliation. The
VexDraftRequest/VexDraftResponseschemas in earlier revisions do not exist in code (noscan_id/recommended_statusrequest, nodraft_id/recommended_status/expires_atresponse). The two contract families that do exist are: the AdvisoryAI justify contract and the VexLens consensus contract. Both are documented below with their source files.
AdvisoryAI Justify Contract (implemented)
Source: src/AdvisoryAI/StellaOps.AdvisoryAI.WebService/Contracts/JustifyContracts.cs.
// POST /v1/advisory-ai/justify (AiJustifyApiRequest)
interface AiJustifyApiRequest {
cveId: string; // required
productRef: string; // required (PURL, artifact digest, etc.)
proposedStatus: string; // required — caller chooses the status
justificationType: string; // required — OpenVEX justification label
contextData?: {
reachabilityScore?: number; // 0..1
codeSearchResults?: number;
sbomContext?: string; // free-text summary
callGraphSummary?: string; // free-text summary
relatedVexStatements?: string[];
};
correlationId?: string;
}
// 200 OK (AiJustifyApiResponse)
interface AiJustifyApiResponse {
justificationId: string;
draftJustification: string; // the AI-drafted justification TEXT
suggestedJustificationType: string;
confidenceScore: number; // 0..1
evidenceSuggestions: string[];
modelVersion: string;
generatedAt: string; // ISO-8601
traceId?: string;
}
VexLens Consensus Contract (implemented)
Source: src/VexLens/StellaOps.VexLens/Api/ConsensusApiModels.cs and StellaOps.VexLens.WebService/Extensions/VexLensEndpointExtensions.cs.
// POST /api/v1/vexlens/consensus (ComputeConsensusRequest)
interface ComputeConsensusRequest {
vulnerabilityId: string;
productKey: string; // PURL or CPE
tenantId?: string; // also accepted via X-StellaOps-TenantId header
mode?: 'HighestWeight' | 'WeightedVote' | 'Lattice' | 'AuthoritativeFirst';
minimumWeightThreshold?: number;
storeResult?: boolean;
emitEvent?: boolean;
}
// 200 OK (ComputeConsensusResponse)
interface ComputeConsensusResponse {
vulnerabilityId: string;
productKey: string;
status: VexStatus; // not_affected | affected | fixed | under_investigation | unknown
justification?: VexJustification;
confidenceScore: number;
outcome: 'Unanimous' | 'Majority' | 'Plurality' | 'ConflictResolved' | 'NoData' | 'Indeterminate';
rationale: { summary: string; factors: string[]; statusWeights: Record<string, number>; };
contributions: Array<{ statementId: string; issuerId?: string; status: VexStatus; justification?: VexJustification; weight: number; contribution: number; isWinner: boolean; }>;
conflicts?: Array<{ statement1Id: string; statement2Id: string; status1: VexStatus; status2: VexStatus; severity: string /* 'Low'|'Medium'|'High'|'Critical' */; resolution: string; }>;
projectionId?: string;
computedAt: string;
}
A
consensus:withProofvariant adds aproofobject (per-issuer verdicts, trust weights, digest, raw proof JSON), and aconsensus:batchvariant evaluates multiple pairs. See the source for the fullProofResponseshape.
Confidence Scoring
NOT IMPLEMENTED as a fixed table. No code uses this evidence-type → base-confidence + modifier lookup. The two real confidence figures are: (1) AdvisoryAI’s
confidenceScorereturned by/justify, produced by the inference profile; and (2) VexLens’sconfidenceScore, computed from trust-weighted consensus (vexlens.consensus.confidencehistogram), not from evidence type. The table below is retained as roadmap intent for a future evidence-weighting model.
| Evidence Type | Base Confidence | Modifiers |
|---|---|---|
| Component not in SBOM | 0.99 | - |
| Fixed version confirmed | 0.95 | - |
| Runtime never invoked (30d+) | 0.85 | +0.05 per additional 30d |
| Static unreachable | 0.70 | +0.10 with runtime confirm |
| AI code analysis | 0.60 | Requires human review |
| Historical pattern match | 0.50 | Requires human review |
Error Handling
Aspirational. The “fall back to static analysis / template-based / queue for retry” behaviors are not wired (there is no auto-gathering pipeline to degrade and no signing step to retry). What is implemented today:
/justifyreturns 400 Bad Request on invalid input (InvalidOperationException) and 403 Forbidden when the caller lacks an accepted scope; VexLens consensus returns 400 on missing/unparseable inputs and evaluates each batch pair independently (a failing pair is counted infailureCountwithout aborting the batch).
| Error | Recovery (target design) |
|---|---|
| Reachability unavailable | Lower confidence, require review |
| Runtime signals missing | Use static analysis only |
| AI analysis timeout | Fall back to template-based |
| Signing failure | Queue for retry |
Observability
Metrics
Reconciled. The
vex_drafts_*/vex_confidence_score/vex_review_duration_secondsmetrics do not exist. The implemented VexLens meter (StellaOps.VexLens, seeObservability/VexLensMetrics.cs) emits the metrics below (selected). AdvisoryAI/justifyis traced via theadvisory_ai.justifyactivity rather than a dedicated metric.
| Metric | Type | Labels |
|---|---|---|
vexlens.consensus.computed_total | Counter | status, outcome |
vexlens.consensus.conflicts_total | Counter | status, outcome |
vexlens.consensus.confidence | Histogram | status, outcome |
vexlens.consensus.status_changes_total | Counter | status, outcome |
vexlens.trust.weights_computed_total / vexlens.trust.weight_value | Counter / Histogram | issuer_category |
vexlens.projection.stored_total / vexlens.projection.queries_total | Counter | status, status_changed / result_count_bucket |
vexlens.signature.verified_total / vexlens.signature.failures_total | Counter | format, valid |
vexlens.issuer.registered_total / vexlens.issuer.revoked_total | Counter | category, trust_tier |
Key Log Events
Reconciled. There are no
vex.draft.*/vex.publishedstructured log event names. VexLens uses numeric event IDs inVexLensLogEvents(Observability/VexLensMetrics.cs); AdvisoryAI justify is observable via theadvisory_ai.justifyactivity span (tags:advisory.cve_id,advisory.product_ref,advisory.proposed_status,advisory.justification_id,advisory.confidence).
| Event (VexLensLogEvents) | ID | Notes |
|---|---|---|
ConsensusCompleted | 5002 | Consensus computed for a vuln/product pair |
ConflictDetected | 5004 | Issuer dispositions disagree |
StatusChanged | 5005 | Consensus status changed vs. prior projection |
NoStatementsAvailable | 5006 | No ingested statements for the pair |
ProjectionStored | 6001 | Consensus projection persisted |
IssuerRegistered / IssuerRevoked | 7001 / 7002 | Issuer-directory mutations |
Related Flows
- Policy Evaluation Flow - VEX consumption
- Advisory Drift Re-scan Flow - VEX updates
- Exception Approval Workflow - Related approval pattern
