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) │
└──────────────┘- Parse. YAML is deserialized into the
IdentitySpecstructure. - Validate. Semantic rules check field references, threshold bounds, unique names, safety limits, and tier permissions.
- Compile. The validated spec is compiled into an
IdentityPlanIR with resolved sources, compiled rules, and a plan hash. - 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:
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-compliantMetadata Fields
| Field | Type | Description |
|---|---|---|
name | string | Human-readable name for the spec |
description | string | Purpose and scope of this identity resolution |
owner | string | Team or individual responsible for this spec |
tags | string[] | Labels for filtering and organizing specs |
Governance Policies
The governance block enforces quality gates across all sources:
governance:
require_freshness: true
require_schema: true
required_tags:
- productionGovernance Fields
| Field | Type | Default | Description |
|---|---|---|---|
require_freshness | bool | false | Block reconciliation if any source exceeds its max_age |
require_schema | bool | false | Block reconciliation if schema drift is detected |
required_tags | string[] | [] | 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:
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:
- productionUploading Specs
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']}")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
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()# 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:
| Error | Cause |
|---|---|
Field 'phone' not found in any source attributes | Rule 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 tier | Spec uses Cloud features on a lower tier |
Hierarchy depth 15 exceeds maximum of 10 | depth exceeds the safety limit |
Next Steps
- Compliance & PII Masking: Regulatory framework configuration
- Freshness Monitoring: Source staleness detection
- Audit Logs: Match trail configuration
