Skip to main content

Forward-Chaining Engine

The ForwardChainEngine is the deterministic core of Quint’s scoring pipeline. It evaluates events against 90 inference rules using agenda-based forward-chaining — a Rete-style pattern matching algorithm that reaches a fixed point in under 1ms.

Algorithm

class ForwardChainEngine:
    def evaluate(
        self,
        initial_facts: list[Fact],
        tenant_frameworks: set[str] | None = None
    ) -> InferenceResult
Execution flow:
1

Initialize working memory

Extract initial facts from the event using extract_facts(event, policies, baseline). This produces ~50+ facts covering action type, target classification, data sensitivity, bulk operations, input patterns, and behavioral signals.
2

Forward-chaining loop

Until fixed point or MAX_ITERATIONS (50):
  1. For each rule (sorted by priority, lower = first):
    • Skip if already fired (single-fire per rule per evaluation)
    • Check framework requirement against tenant subscriptions
    • Check ALL conditions match facts in working memory
    • If conditions met: fire rule
  2. Execute rule actions: assert_fact, add_score, add_violation, add_mitigation
  3. Track newly fired rules
  4. Exit if no new rules fired (fixed point reached)
3

Compute result

Aggregate score deltas, collect violations and mitigations, compute confidence from rule coverage and data completeness.
Complexity: O(R × I × F) where R = rule count, I = iterations, F = fact count

Rule Structure

@dataclass(frozen=True)
class InferenceRule:
    name: str                        # Unique rule ID
    priority: int                    # Execution order (lower = first)
    conditions: tuple[FactPattern]   # ALL must match
    actions: tuple[RuleAction]       # Fire when conditions met
    confidence_decay: float = 0.95   # Applied to derived facts
    explanation_template: str = ""   # Human-readable
    frameworks: tuple[str] = ()      # Related frameworks
    requires_framework: str | None   # Gate on tenant subscription

Example Rule

InferenceRule(
    name="bulk_external_exfiltration",
    priority=10,
    conditions=(
        FactPattern(fact_type="bulk_access"),
        FactPattern(fact_type="targets_external"),
    ),
    actions=(
        RuleAction(action_type="add_score", score_delta=50),
        RuleAction(
            action_type="add_violation",
            text="Bulk data export to external resource",
            articles=("SOC2 CC6.1", "ISO27001 A.13.2"),
            severity="high",
        ),
        RuleAction(
            action_type="assert_fact",
            fact_type="exfiltration_risk",
            predicate="bulk_external",
        ),
        RuleAction(
            action_type="add_mitigation",
            text="Restrict bulk exports to internal resources",
        ),
    ),
    explanation_template="Bulk data access + external target = potential exfiltration",
)

Rule Categories (90 Total)

CategoryCountScope
Common11Universal rules (bulk access, external targets, PII)
GDPR~15Consent, data minimization, cross-border transfer
HIPAA~12PHI exposure, encryption, minimum necessary
SOC2~12Access control, change management, availability
PCI-DSS~8Cardholder data, encryption, network segmentation
PII~6Personal data access patterns
OWASP~8Injection, broken auth, security misconfiguration
ISO27001~5Information security management
OWASP LLM Top 10~8Prompt injection, training data poisoning, excessive agency
OWASP Agentic Top 10~6Tool poisoning, MCP attacks, multi-turn manipulation
Behavioral~5Novel resources, rare actions, off-hours, volume spikes

Fact Extraction

The extract_facts() function transforms raw events into ~50+ initial facts:
  • action_is — canonical action type
  • action_is_read, action_is_write, action_is_delete, action_is_execute
  • targets_external, targets_internal
  • targets_production, targets_public_storage, targets_non_eu
  • accesses_sensitive, accesses_phi, accesses_ssn
  • accesses_pan, accesses_contact_info, accesses_special_category
  • Detected from 51 predefined sensitive field names + custom policies
  • bulk_access — high row count or SELECT * patterns
  • excessive_fields — touching many data fields
  • prompt_injection, system_prompt_extraction
  • agent_code_execution, excessive_autonomy
  • rag_poisoning, mcp_tool_poisoning
  • multi_turn_attack, encoding_evasion
  • novel_resource — resource never accessed before
  • rare_action — action type < 1% of historical
  • unusual_field_access — touching new field types
  • off_hours_activity, volume_spike

Tenant Framework Management

Frameworks are automatically inferred from customer policies:
# Default frameworks for all tenants
defaults = {gdpr, soc2, pii, owasp, owasp_llm, owasp_agentic}

# Auto-detected from policies
if has_phi_policies → add hipaa
if has_payment_policies → add pci_dss
if has_iso_policies → add iso27001
Rules with requires_framework only fire if the tenant subscribes to that framework. Framework subscriptions are cached with a 5-minute TTL per tenant.

Risk Level Mapping

Score RangeRisk Level
1-10none
11-30low
31-55medium
56-80high
81-100critical