Skip to content

Spec Versioning ​

Every identity spec has two version identifiers: identity_version (a human-readable string you choose) and plan_hash (a SHA-256 of the compiled plan, computed automatically). Together they let you track what changed and whether it affects reconciliation behavior.

identity_version ​

A user-defined string set in the spec YAML. Convention is {entity}-v{n}:

yaml
identity_version: customer-v3
entity: customer

sources:
  # ...

The identity_version is how you reference a specific spec via the API:

bash
curl "https://api.kanoniv.com/v1/identity/specs/customer-v3" \
  -H "X-API-Key: kn_..."

There are no format restrictions — v1, customer-v3, 2026-02-prod, and experiment-A are all valid. Choose a convention that works for your team and stick with it.

plan_hash ​

The plan_hash is a SHA-256 digest of the compiled IdentityPlan. It's computed automatically when you compile a spec:

python
from kanoniv import Spec, plan

spec = Spec.from_file("customer-v3.yaml")
result = plan(spec)
print(result.plan_hash)  # e.g. "a1b2c3d4e5f6..."

The hash captures everything that affects reconciliation behavior: rules, weights, thresholds, blocking configuration, survivorship strategy, and source definitions. Cosmetic changes (description, metadata tags) do not change the hash.

This means:

  • Same hash = identical reconciliation behavior. You can safely skip re-processing.
  • Different hash = something changed that affects how entities are matched, merged, or scored.

What's Included in the Hash ​

The hash is computed from the serialized IdentityPlan, which includes:

IncludedNot Included
Entity typeSpec description
Source definitions and field mappingsMetadata name/owner
Blocking strategy and keysMetadata tags
Match rules, weights, algorithmsComments in YAML
Decision thresholds
Survivorship strategy
Exclusions, compliance, hierarchy

Diffing Specs ​

The diff() function compares two specs and returns a DiffResult with granular change detection across every section.

python
from kanoniv import Spec, diff

old = Spec.from_file("customer-v2.yaml")
new = Spec.from_file("customer-v3.yaml")

changes = diff(old, new)

if not changes.has_changes:
    print("Specs are identical")
else:
    print(changes.summary)

DiffResult Properties ​

PropertyTypeDescription
rules_addedlist[str]Rule names present in new spec but not old
rules_removedlist[str]Rule names present in old spec but not new
rules_modifiedlist[dict]Rules in both specs with changed fields. Each dict: name, field, old_value, new_value
sources_addedlist[str]Source names added
sources_removedlist[str]Source names removed
sources_modifiedlist[dict]Sources with changed fields. Each dict: name, field, old_value, new_value
entity_changedboolWhether the entity definition changed
entity_changeslist[dict]Field-level entity changes. Each dict: path, old_value, new_value
blocking_changedboolWhether blocking strategy or keys changed
blocking_changeslist[dict]Field-level blocking changes
thresholds_changedboolWhether decision thresholds changed
decision_changeslist[dict]Field-level decision changes
survivorship_changedboolWhether survivorship rules changed
survivorship_changeslist[dict]Field-level survivorship changes
scoring_changedboolWhether scoring model configuration changed
scoring_changeslist[dict]Field-level scoring changes
metadata_changedboolWhether spec metadata changed
metadata_changeslist[dict]Field-level metadata changes
version_changedboolWhether identity_version changed
has_changesboolTrue if any part of the spec changed
summarystrHuman-readable summary of all changes

Example: Inspecting a Diff ​

python
from kanoniv import Spec, diff

changes = diff(
    Spec.from_file("customer-v2.yaml"),
    Spec.from_file("customer-v3.yaml"),
)

if changes.rules_added:
    print(f"New rules: {', '.join(changes.rules_added)}")

if changes.thresholds_changed:
    for c in changes.decision_changes:
        print(f"  {c['path']}: {c['old_value']} -> {c['new_value']}")

if changes.survivorship_changed:
    for c in changes.survivorship_changes:
        print(f"  survivorship {c['path']}: {c['old_value']} -> {c['new_value']}")

API Endpoints ​

Upload and Compile a Spec ​

POST /v1/identity/specs
python
import httpx

spec_yaml = open("customer-v3.yaml").read()

resp = httpx.post("https://api.kanoniv.com/v1/identity/specs",
    headers={"X-API-Key": "kn_...", "Content-Type": "application/json"},
    json={"raw_yaml": spec_yaml, "compile": True})

result = resp.json()
if result["valid"]:
    print(f"Compiled. plan_hash: {result['plan_hash']}")
else:
    print(f"Errors: {result['errors']}")
bash
curl -X POST "https://api.kanoniv.com/v1/identity/specs" \
  -H "X-API-Key: kn_..." \
  -H "Content-Type: application/json" \
  -d "{\"raw_yaml\": \"$(cat customer-v3.yaml)\", \"compile\": true}"

Response:

json
{
  "valid": true,
  "warnings": [],
  "errors": [],
  "plan_hash": "a1b2c3d4e5f6..."
}

List All Spec Versions ​

GET /v1/identity/specs
GET /v1/identity/specs?tag=production

Get a Specific Version ​

GET /v1/identity/specs/:version

Returns the full spec detail including raw_yaml, compiled_plan, and metadata. See the Rules & Specs API reference for complete request/response documentation.

Best Practices ​

Use semantic version strings. Name versions after the entity and increment: customer-v1, customer-v2. This makes API lookups and audit trails readable.

Check plan_hash in CI. Before deploying a spec change, compare the new hash against production. If the hash didn't change, the update is cosmetic and doesn't need re-reconciliation. See the CI/CD pipeline example in Spec Evolution.

Use metadata tags for filtering. Tag specs with production, staging, or experiment-* to organize versions:

yaml
metadata:
  name: Customer Resolution
  owner: data-team
  tags: [production, customer]

Then filter via API: GET /v1/identity/specs?tag=production.

Record plan_hash with every dataset. When you export golden records for downstream use (analytics, ML training), save the plan_hash alongside the data. This lets you trace any dataset back to the exact spec logic that produced it. See ML Training Data for the full pattern.

See Also ​

The identity and delegation layer for AI agents.