Skip to content

Audit Logging & Match Trail

Capture every match decision, rule trace, and conflict resolution for regulatory compliance and debugging.

Overview

Identity resolution produces complex decisions: which records matched, which rules fired, what confidence scores were assigned, and how conflicts were resolved. Kanoniv's audit logging captures this full decision trail so you can explain any match after the fact.

Cloud Feature

Audit configuration in the spec requires the Cloud tier. Basic audit events (API actions, overrides) are available on all tiers.

Spec Configuration

Add an audit block to your decision section:

yaml
decision:
  thresholds:
    match: 0.9
    review: 0.7
  conflict_strategy: prefer_high_confidence
  audit:
    log_all_comparisons: true
    log_decisions: true
    log_conflicts: true

Fields

FieldTypeDefaultDescription
log_all_comparisonsboolfalseLog every pairwise comparison, including NoMerge (non-match) decisions. Must be explicitly enabled.
log_decisionsbooltrueLog Merge and Review decisions with scores. Enabled by default; set to false to suppress.
log_conflictsboolfalseLog conflict resolution details when multiple matches compete (survivorship conflicts)

Default Behavior

Even with no audit block in your spec, log_decisions defaults to true, so Merge and Review decisions are always audited out of the box. Only NoMerge decisions require explicit opt-in via log_all_comparisons. When compliance.audit_required is true, all decisions (including NoMerge) are force-audited regardless of these flags.

Verbosity Levels

Choose a verbosity level based on your needs:

Minimal (Decisions Only), Default

This is the default behavior even without an audit block. Merge and Review decisions are logged automatically. If you want to be explicit:

yaml
decision:
  audit:
    log_decisions: true   # default: true (can be omitted)

To disable decision logging entirely:

yaml
decision:
  audit:
    log_decisions: false

Standard (Decisions + Conflicts)

Good for debugging match quality and understanding why certain records were grouped:

yaml
decision:
  audit:
    log_decisions: true
    log_conflicts: true

Full (All Comparisons)

Captures every comparison the engine evaluates. Useful for compliance audits and ML training data, but generates significantly more data:

yaml
decision:
  audit:
    log_all_comparisons: true
    log_decisions: true
    log_conflicts: true

WARNING

Enabling log_all_comparisons can produce large volumes of audit data. For a dataset with 100K records using composite blocking, this could generate millions of comparison logs. Use selectively or pair with a retention policy.

What Gets Logged

Match Decisions

Every match decision includes:

FieldDescription
entity_a_idFirst entity in the comparison
entity_b_idSecond entity in the comparison
decisionmatch, reject, or review
confidenceFinal confidence score (0.0 - 1.0)
rule_traceWhich rules fired and their individual scores
blocking_keyThe blocking key that brought these records together

Rule Traces

Each rule trace entry shows:

json
{
  "rule_name": "email_exact",
  "rule_type": "exact",
  "field": "email",
  "result": true,
  "score": 1.0,
  "weight": 1.0
}

Conflict Logs

When multiple candidate matches compete for the same entity:

json
{
  "entity_id": "ent_001",
  "candidates": [
    { "match_id": "ent_042", "confidence": 0.95 },
    { "match_id": "ent_078", "confidence": 0.91 }
  ],
  "strategy": "prefer_high_confidence",
  "winner": "ent_042"
}

PII-Safe Audit Trail

When compliance is configured, audit logs automatically redact PII:

  • Blocking keys derived from PII fields are hashed
  • Rule traces show field names but not raw values
  • Entity IDs are preserved (they are system-generated, not PII)

This ensures audit logs can be shared with compliance teams and stored in external systems without exposing sensitive data.

Querying Audit Logs

Match Audit Records

python
import httpx

# Query match audit records for a specific batch
resp = httpx.get(
    "https://api.kanoniv.com/v1/audit/matches",
    params={"batch_run_id": "run_abc123", "decision": "match", "limit": 50},
    headers={"X-API-Key": "kn_..."},
)
audits = resp.json()

for audit in audits:
    print(f"{audit['entity_a_id']}{audit['entity_b_id']}: "
          f"{audit['decision']} ({audit['confidence']:.2f})")
    for rule in audit["rule_trace"]:
        print(f"  - {rule['rule_name']}: {rule['score']}")
bash
# Query match audits for a batch run
curl "https://api.kanoniv.com/v1/audit/matches?batch_run_id=run_abc123&decision=match&limit=50" \
  -H "X-API-Key: kn_..."

# Response:
# [
#   {
#     "entity_a_id": "...",
#     "entity_b_id": "...",
#     "decision": "match",
#     "confidence": 0.95,
#     "rule_trace": [...],
#     "blocking_key": "smith|j"
#   }
# ]

General Audit Events

python
import httpx

# Query general audit events (API actions, overrides, etc.)
resp = httpx.get(
    "https://api.kanoniv.com/v1/audit",
    params={"event_type": "override.create", "limit": 100},
    headers={"X-API-Key": "kn_..."},
)
events = resp.json()

for event in events:
    print(f"{event['timestamp']} - {event['action']} by {event['actor_id']}")
bash
curl "https://api.kanoniv.com/v1/audit?event_type=override.create&limit=100" \
  -H "X-API-Key: kn_..."

Full Example

yaml
api_version: kanoniv/v2
identity_version: customer_v3

entity:
  name: customer
  compliance:
    frameworks:
      - soc2
    pii_fields:
      - email
      - phone
    audit_required: true

sources:
  - name: crm
    adapter: postgres
    location: public.contacts
    primary_key: contact_id
    attributes:
      email: email_address
      phone: phone_number
      name: full_name

rules:
  - type: exact
    name: email_match
    field: email
    weight: 1.0
  - type: similarity
    name: name_match
    field: name
    algorithm: jaro_winkler
    threshold: 0.85
    weight: 0.7

decision:
  thresholds:
    match: 0.9
    review: 0.7
  conflict_strategy: prefer_high_confidence
  audit:
    log_all_comparisons: false
    log_decisions: true
    log_conflicts: true

SIEM Integration

Audit events can be streamed to external security monitoring tools in real time. See SIEM Integration for configuring destinations like Splunk, S3, or Kafka.

Next Steps

The identity and delegation layer for AI agents.