Skip to main content

Decision Engine

The Decision Engine (IDecisionEngine) is the central orchestrator of Vectra's governance logic. It combines policy evaluation, risk scoring, and semantic analysis into a single, ordered pipeline that produces an Allow, Deny, or Hitl decision for every proxied request.


Evaluation Pipeline

RequestContext


┌─────────────────────────────────┐
│ 1. Policy Evaluation │ ← Checks assigned policy rules
│ → Deny / Hitl = short-circuit│
└────────────────┬────────────────┘
│ (no match or Allow)

┌─────────────────────────────────┐
│ 2. Risk Scoring │ ← Computes weighted risk score
│ → score > threshold = Hitl │
└────────────────┬────────────────┘
│ (score ≤ threshold)

┌─────────────────────────────────┐
│ 3. Semantic Analysis │ ← LLM/ONNX intent classification
│ → negative verdict = Deny/Hitl│
└────────────────┬────────────────┘
│ (no concern)

Allow (with risk score as trust)

Each stage short-circuits — if a stage produces a Deny or Hitl, subsequent stages are skipped.


Stage 1: Policy Evaluation

Runs only if Policy.Enabled = true.

  1. Builds a Dictionary<string, object> input from the RequestContext.
  2. Calls IPolicyProvider.EvaluateAsync(policyName, input).
  3. If the provider returns Deny → engine returns DecisionResult.Deny(reason).
  4. If the provider returns Hitl → engine returns DecisionResult.Hitl(reason).
  5. Otherwise, evaluation continues.

If no policy is assigned to the agent (PolicyName == null), this stage is effectively a no-op and returns null (continue).


Stage 2: Risk Scoring

  1. Calls IRiskScoringService.ComputeRiskScoreAsync(context).
  2. Compares score against HumanInTheLoop.Threshold (default: 0.8).
  3. If score exceeds threshold → DecisionResult.Hitl($"High risk score: {score:F2}", score).
  4. Otherwise, the score is passed to the final Allow result.

Stage 3: Semantic Analysis

Runs only if Semantic.Enabled = true.

  1. The ISemanticProvider converts the request to intent text (via JsonToIntentText) and classifies it.
  2. If the classification returns a negative / malicious verdict with confidence ≥ ConfidenceThreshold → Deny or Hitl.
  3. If confidence is below threshold and AllowLowConfidence = false → Deny.

Decision Finalisation

After every decision (including Allow), the engine calls the private FinalizeAsync method which:

  1. Updates the agent's TrustScore in the repository based on the decision outcome.
  2. Writes an AuditTrail record to the audit repository.
  3. Returns the DecisionResult.

DecisionResult

public record DecisionResult
{
public DecisionType Type { get; init; } // Allow | Deny | Hitl
public string? Reason { get; init; }
public double TrustScore { get; set; }

public bool IsAllowed => Type == DecisionType.Allow;
public bool IsHitl => Type == DecisionType.Hitl;
public bool IsDenied => Type == DecisionType.Deny;

// Factory methods
public static DecisionResult Allow(double trustScore = 1.0);
public static DecisionResult Deny(string reason, double trustScore = 0.0);
public static DecisionResult Hitl(string reason, double trustScore = 0.5);
}

Audit Trail

Every decision (Allow, Deny, Hitl) is persisted as an AuditTrail record containing:

  • Agent ID
  • Decision type and reason
  • Target URL, method, path
  • Risk score
  • Timestamp