# How to Enforce Policy Compliance with check_decision_rules() for Decision Categories

> Enforce policy compliance with check_decision_rules() to validate decision payloads against configurable rules. Get a structured report on confidence, outcomes, metadata, and reasoning.

- Repository: [Semantica /semantica](https://github.com/semantica-agi/semantica)
- Tags: how-to-guide
- Published: 2026-08-17

---

**The `check_decision_rules()` method serves as a convenience wrapper that validates decision payloads against configurable policy rules, returning a structured compliance report indicating whether the decision violates constraints on confidence levels, outcomes, metadata, or reasoning length.**

Enforcing governance policies on AI-driven decisions requires tight integration between your validation logic and knowledge graph. In the semantica-agi/semantica open-source framework, the `check_decision_rules()` function provides the primary entry point for enforcing policy compliance with `check_decision_rules()` on decision categories before they are persisted to the `ContextGraph`.

## Understanding the check_decision_rules() Architecture

The `check_decision_rules()` method is implemented as a thin public wrapper in [`semantica/context/context_graph.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/context/context_graph.py) (lines 4083–4099). Internally, it forwards all validation work to `enforce_decision_policy()` (lines 3600–3652), which performs the actual rule checks against either default constraints or a user-supplied rule set.

This architecture separates the public API from the evaluation engine. While `check_decision_rules()` accepts the decision payload and optional custom rules, `enforce_decision_policy()` handles the heavy lifting of verifying confidence thresholds, mandatory metadata fields, allowed outcomes, and reasoning length limits. The method returns a dictionary containing `compliant`, `violations`, `warnings`, and the exact `policy_rules` applied during validation.

## How Decision Categories Structure Policy Enforcement

Decision categories are treated as first-class citizens within the graph topology. When a decision is added to the `ContextGraph` via `_add_decision_to_graph` (lines 2928–2942), the system automatically creates a category node with the identifier `category_{decision['category']}` and links it to the decision node via a `belongs_to` edge.

This graph-native approach makes categories queryable for downstream compliance analysis. Because the category exists as a distinct node connected to its decisions, you can traverse the graph to audit all decisions within a specific category, enabling batch compliance checks and historical trend analysis across decision types.

## Enforcing Policy Compliance: Implementation Guide

### Required Decision Payload Structure

To validate a decision, `check_decision_rules()` expects a dictionary containing specific fields. At minimum, provide `category`, `outcome`, `confidence`, and `reasoning`. Optional but recommended fields include `decision_maker`, `scenario`, `entities`, and `timestamp`.

The method uses these fields to validate against your policy constraints. Missing required metadata fields or values falling outside allowed ranges trigger violations that mark the decision as non-compliant.

### Default Policy Constraints

By default, `enforce_decision_policy()` applies a baseline governance standard:

- **Confidence threshold**: Minimum score of 0.7
- **Allowed outcomes**: Predefined list of valid decision results
- **Mandatory metadata**: Required fields such as reasoning and decision maker
- **Reasoning length**: Maximum character limit to enforce concise explanations

These defaults ensure that only high-confidence, well-documented decisions enter the knowledge graph unless explicitly overridden by custom configuration.

### Custom Rules for Category-Specific Validation

To enforce policy compliance with `check_decision_rules()` for specific decision categories, pass a custom `rules` dictionary that overrides defaults or adds new constraints. While the wrapper does not automatically validate the `category` field against an allow-list, you can extend the logic by including an `allowed_categories` array in your rules and performing a manual check against the decision payload.

This pattern allows you to implement tiered governance where loan decisions, for example, require higher confidence thresholds (0.95) and stricter metadata requirements than general classification decisions.

## Practical Code Examples

### Basic Compliance Check with Default Policy

```python
from semantica.context.context_graph import ContextGraph

graph = ContextGraph()
decision = {
    "id": "dec_001",
    "category": "loan",
    "scenario": "Approve loan for Alice",
    "reasoning": "Credit score above threshold.",
    "outcome": "approved",
    "confidence": 0.92,
    "decision_maker": "underwriter_ai_v5",
    "entities": ["customer_alice_001", "product_loan_001"],
    "timestamp": "2024-05-01T12:00:00Z",
}

result = graph.check_decision_rules(decision)   # uses default rules

print(result)

# → {'compliant': True, 'violations': [], 'warnings': [], 'policy_rules': {...}}

```

### Enforcing Category-Specific Constraints with Custom Rules

```python
custom_rules = {
    "min_confidence": 0.95,
    "required_outcomes": ["approved", "rejected"],
    "required_metadata": ["decision_maker", "scenario"],
    "max_reasoning_length": 800,
    "allowed_categories": ["loan", "credit"],   # <-- custom field

}

result = graph.check_decision_rules(decision, rules=custom_rules)

# Manual category validation (enforce_decision_policy does not check this automatically)

if decision["category"] not in custom_rules["allowed_categories"]:
    result["violations"].append(f"Disallowed category: {decision['category']}")
    result["compliant"] = False

print(result)

```

### Recording and Querying Validated Decisions by Category

```python

# After validation, persist the decision and its category node

graph.record_decision(decision)   # adds node + category edge

# Query all decisions in the loan category

loan_decisions = graph.find_by_category("loan", limit=100)
print(f"Found {len(loan_decisions)} loan decisions.")

```

## Key Source Files and Implementation Details

Understanding the module structure helps when extending or debugging the compliance pipeline:

- **[`semantica/context/context_graph.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/context/context_graph.py)** – Contains the core `ContextGraph` class with `check_decision_rules()` (lines 4083–4099) and `enforce_decision_policy()` (lines 3600–3652), plus category node creation logic (lines 2928–2942).

- **[`semantica/context/decision_methods.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/context/decision_methods.py)** – Provides higher-level helpers such as `check_decision_compliance()` for policy-ID-based validation workflows.

- **[`semantica/context/policy_engine.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/context/policy_engine.py)** – Manages storage and versioning of reusable policy definitions consumed by `enforce_decision_policy()`.

- **[`semantica/context/decision_recorder.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/context/decision_recorder.py)** – Handles streaming decisions into the graph, including the automatic creation of `belongs_to` edges linking decisions to their category nodes.

## Summary

- **`check_decision_rules()`** acts as a public wrapper around `enforce_decision_policy()` in the `ContextGraph` class, providing a clean API for compliance validation.
- Default policies enforce confidence ≥ 0.7, required metadata fields, allowed outcomes, and reasoning length limits unless overridden.
- Decision categories are graph nodes created with the pattern `category_{decision['category']}` and linked via `belongs_to` edges, enabling categorical queries.
- Custom `rules` dictionaries allow runtime extension of constraints for category-specific governance without modifying source code.
- The method returns a structured report with `compliant`, `violations`, and `warnings` to drive downstream approval or rejection logic.

## Frequently Asked Questions

### What is the difference between `check_decision_rules()` and `enforce_decision_policy()`?

`check_decision_rules()` is a thin convenience wrapper located at lines 4083–4099 of [`context_graph.py`](https://github.com/semantica-agi/semantica/blob/main/context_graph.py) that provides a public-facing API. It immediately delegates to `enforce_decision_policy()` (lines 3600–3652), which contains the core validation logic for evaluating confidence scores, metadata completeness, and reasoning constraints. The wrapper simply formats inputs and returns the compliance report generated by the internal method.

### How do I validate that a decision belongs to an allowed category?

While `check_decision_rules()` does not automatically validate category membership, you can pass an `allowed_categories` list within your custom `rules` dictionary. After calling the method, manually verify that `decision["category"]` exists in your allowed list, and if not, append a violation string to `result["violations"]` and set `result["compliant"]` to `False`.

### Where are decision categories stored in the graph structure?

According to the source code at lines 2928–2942 of [`context_graph.py`](https://github.com/semantica-agi/semantica/blob/main/context_graph.py), when decisions are recorded, the system creates a category node with an ID formatted as `category_{decision['category']}` and establishes a `belongs_to` edge connecting the decision node to this category node. This structure makes categories traversable for compliance audits and batch analysis.

### Can I extend the default policy rules without modifying the source code?

Yes. Pass a custom `rules` dictionary to `check_decision_rules()` containing fields such as `min_confidence`, `required_outcomes`, `required_metadata`, and `max_reasoning_length`. The `enforce_decision_policy()` method applies these values at runtime, overriding the defaults (confidence ≥ 0.7, etc.) without requiring changes to the semantica source files.