Skip to content

Spec-Driven Governance

Use the YAML spec as the single source of truth for identity resolution policy.

Overview

Every aspect of Kanoniv's reconciliation behavior is controlled by a single YAML specification. This spec-driven approach means your identity resolution policy is version-controlled, reviewable, and auditable, the same way you manage infrastructure as code. No hidden configuration, no imperative API calls that drift from documentation.

Compilation Flow

When you upload a spec, it goes through a multi-stage pipeline:

┌──────────┐    ┌────────────┐    ┌────────────┐    ┌──────────────┐
│  YAML    │───▶│  Parse &   │───▶│  Validate  │───▶│  Compile to  │
│  Spec    │    │  Deserialize│    │  (semantic  │    │  IR (Identity │
│          │    │            │    │  + tier)    │    │   Plan)       │
└──────────┘    └────────────┘    └────────────┘    └──────┬───────┘


                                                    ┌──────────────┐
                                                    │  Store plan  │
                                                    │  + hash      │
                                                    │  (versioned) │
                                                    └──────────────┘
  1. Parse. YAML is deserialized into the IdentitySpec structure.
  2. Validate. Semantic rules check field references, threshold bounds, unique names, safety limits, and tier permissions.
  3. Compile. The validated spec is compiled into an IdentityPlan IR with resolved sources, compiled rules, and a plan hash.
  4. Store. The compiled plan and raw YAML are stored with a SHA-256 hash for versioning.

Spec Metadata

Cloud tier specs support metadata for organization and discoverability:

yaml
api_version: kanoniv/v2
identity_version: customer_v3.1

metadata:
  name: Customer Identity Resolution
  description: Cross-system customer matching for CRM, billing, and support
  owner: data-engineering
  tags:
    - production
    - customer
    - gdpr-compliant

Metadata Fields

FieldTypeDescription
namestringHuman-readable name for the spec
descriptionstringPurpose and scope of this identity resolution
ownerstringTeam or individual responsible for this spec
tagsstring[]Labels for filtering and organizing specs

Governance Policies

The governance block enforces quality gates across all sources:

yaml
governance:
  require_freshness: true
  require_schema: true
  required_tags:
    - production

Governance Fields

FieldTypeDefaultDescription
require_freshnessboolfalseBlock reconciliation if any source exceeds its max_age
require_schemaboolfalseBlock reconciliation if schema drift is detected
required_tagsstring[][]Every source must have all of these tags

Tag Enforcement

When required_tags is set, the validator checks every source in the spec. Sources missing a required tag cause a validation error:

[ERROR] sources[1].tags: Source 'billing' missing required governance tag 'production'

This ensures that only properly labeled and vetted sources are included in production reconciliation runs.

Full Annotated Example

This spec demonstrates all cloud governance features together:

yaml
api_version: kanoniv/v2
identity_version: customer_v5

# Cloud: Spec metadata for discoverability
metadata:
  name: Customer Master Resolution
  description: Golden record construction across CRM, billing, and support
  owner: data-platform-team
  tags:
    - production
    - customer
    - hipaa

# Entity with compliance and hierarchy
entity:
  name: customer
  description: B2B customer identity
  compliance:
    frameworks:
      - hipaa
      - gdpr
    pii_fields:
      - email
      - phone
      - ssn
    audit_required: true
    retention_days: 2555
  hierarchy:
    parent_field: parent_account_id
    depth: 3
    inheritance:
      - industry
      - region

# Sources with freshness, schema, and tags
sources:
  - name: crm
    adapter: postgres
    location: public.contacts
    primary_key: contact_id
    freshness:
      max_age: "24h"
      warn_after: "12h"
    schema:
      email:
        type: string
        pii: true
      phone:
        type: string
        pii: true
      name:
        type: string
        nullable: true
    tags:
      - production
      - crm
    attributes:
      email: email_address
      phone: phone_number
      name: full_name

  - name: billing
    adapter: snowflake
    location: analytics.billing.accounts
    primary_key: account_id
    freshness:
      max_age: "48h"
    tags:
      - production
      - billing
    attributes:
      email: billing_email
      name: account_name

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

# Survivorship
survivorship:
  default: most_recent
  overrides:
    - field: email
      strategy: source_priority
      priority:
        - crm
        - billing

# Exclusions
exclusions:
  - type: cross_tenant
    enabled: true

# Decision with audit trail
decision:
  scoring:
    method: weighted_sum
  thresholds:
    match: 0.9
    review: 0.7
    reject: 0.3
  conflict_strategy: prefer_high_confidence
  review_queue:
    enabled: true
    webhook: "https://hooks.company.com/review"
    sla_hours: 48
  audit:
    log_decisions: true
    log_conflicts: true

# Governance enforcement
governance:
  require_freshness: true
  require_schema: true
  required_tags:
    - production

Uploading Specs

python
import httpx

api_key = "kn_..."

with open("customer.kanoniv.yaml") as f:
    spec_yaml = f.read()

resp = httpx.post(
    "https://api.kanoniv.com/v1/specs",
    headers={"X-API-Key": api_key, "Content-Type": "application/x-yaml"},
    content=spec_yaml,
)
plan = resp.json()
print(f"Plan ID: {plan['id']}")
print(f"Hash: {plan['plan_hash']}")
print(f"Version: {plan['identity_version']}")
bash
curl -X POST "https://api.kanoniv.com/v1/specs" \
  -H "X-API-Key: kn_..." \
  -H "Content-Type: application/x-yaml" \
  --data-binary @customer.kanoniv.yaml

# Response:
# {
#   "id": "plan_abc123",
#   "identity_version": "customer_v5",
#   "plan_hash": "a1b2c3...",
#   "created_at": "2026-02-09T12:00:00Z"
# }

Listing and Filtering Specs

python
import httpx

api_key = "kn_..."
headers = {"X-API-Key": api_key}

# List all specs
specs = httpx.get("https://api.kanoniv.com/v1/specs", headers=headers).json()

# Filter by tag
production_specs = httpx.get(
    "https://api.kanoniv.com/v1/specs", params={"tag": "production"}, headers=headers
).json()
for spec in production_specs:
    print(f"{spec['identity_version']} - {spec.get('metadata', {}).get('name', 'unnamed')}")

# Filter by owner
team_specs = httpx.get(
    "https://api.kanoniv.com/v1/specs", params={"owner": "data-platform-team"}, headers=headers
).json()
bash
# List all specs
curl "https://api.kanoniv.com/v1/specs" \
  -H "X-API-Key: kn_..."

# Filter by tag
curl "https://api.kanoniv.com/v1/specs?tag=production" \
  -H "X-API-Key: kn_..."

# Filter by owner
curl "https://api.kanoniv.com/v1/specs?owner=data-platform-team" \
  -H "X-API-Key: kn_..."

Spec Versioning

Each spec upload creates a new version identified by its identity_version string and a SHA-256 plan_hash computed from the compiled IR. Uploading the same spec twice produces the same hash, making it easy to detect drift.

TIP

Use a versioning scheme like customer_v3.1 in your identity_version field. Bump the version when you change matching rules or thresholds so you can track which version produced each batch run.

Validation Errors

The validator catches issues before compilation. Common errors:

ErrorCause
Field 'phone' not found in any source attributesRule references a field not mapped in any source
Duplicate source name 'crm'Two sources share the same name
Source 'billing' missing required governance tag 'production'Governance requires a tag the source doesn't have
Compliance features require Cloud tierSpec uses Cloud features on a lower tier
Hierarchy depth 15 exceeds maximum of 10depth exceeds the safety limit

Next Steps

The identity and delegation layer for AI agents.