Skip to main content

Coherence Rules

Define cross-field quality rules on a Spec. List, create, update, delete, and auto-propose coherence rules that penalize confidence on violating cells.

Coherence rules are cross-field quality rules attached to a Spec (a user_schema). Where a validation stage gates the pipeline at a position, a coherence rule expresses a relationship that should hold between fields in a record, for example "field A must not equal field B" or "if field A has a value then field B must be non-zero". When a rule is violated, the platform applies a confidence_penalty to the affected cells so they surface for review.

A rule has a rule_type (such as not_equal, implies_value, non_zero_when_sibling_filled, value_range, or custom) and a config object that names the fields and thresholds for that type. The service stores config verbatim and infers sane defaults for omitted fields: rule_type defaults to custom, confidence_penalty to 0.4, and description to an empty string. Rules carry a status of proposed, active, or rejected plus a proposed_by marker (user for rules you create, system for auto-proposed ones).

You can have Claude auto-propose rules from the Spec fields via the propose endpoint. Proposed rules land with status proposed and take no effect on runs. Approve one by updating it to status: active, or dismiss it with status: rejected. This keeps the human in the loop while letting the model surface candidate relationships you might not have hand-written. The propose call is synchronous and returns the created rules; a Spec whose fields yield no viable candidates returns an empty array.

Status behaves differently on the two write paths: a rule you create directly with POST .../coherence-rules is always saved active — the status field in the create body is accepted but ignored, since a hand-written rule is presumed intentional. Only the update endpoint changes status, which is how proposals get approved or rejected. Deleting a rule returns { "deleted": true }.

GET/v1/schemas/{id}/coherence-rules
POST/v1/schemas/{id}/coherence-rules

Body parameters

rule_typestringOne of not_equal, implies_value, non_zero_when_sibling_filled, value_range, custom (max 50 characters).
configobjectRule parameters: field names and thresholds keyed by rule_type.
descriptionstringHuman-readable description of the rule.
confidence_penaltynumberConfidence reduction applied to violating cells (0 to 1). Defaults to 0.4.
statusstringAccepted but ignored on create: a directly created rule is always saved active. Change status via PATCH.

Create a rule

curl -X POST https://api.talonic.com/v1/schemas/a1b2c3d4-e5f6-7890-abcd-ef1234567890/coherence-rules \
  -H "Authorization: Bearer tlnc_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "rule_type": "non_zero_when_sibling_filled",
    "config": { "trigger_field": "tax_rate", "required_field": "tax_amount" },
    "description": "If a tax rate is present, tax amount must be non-zero.",
    "confidence_penalty": 0.3
  }'
POST/v1/schemas/{id}/coherence-rules/propose
PATCH/v1/schemas/{id}/coherence-rules/{ruleId}

Body parameters

rule_typestringRule type (max 50 characters).
configobjectRule parameters keyed by rule_type.
descriptionstringHuman-readable description.
confidence_penaltynumberConfidence reduction applied to violating cells (0 to 1).
statusstringOne of proposed, active, rejected. Set to active to approve a proposal.
DELETE/v1/schemas/{id}/coherence-rules/{ruleId}

Response

Rule fields

idstringCoherence rule UUID.
rule_typestringThe rule type identifier.
configobjectRule parameters keyed by rule_type.
descriptionstring | nullHuman-readable description.
confidence_penaltynumberConfidence reduction applied to violating cells (0 to 1).
statusstringOne of proposed, active, rejected.
proposed_bystringuser for directly created rules, system for auto-proposed ones.
created_atstringISO 8601 creation timestamp.
updated_atstringISO 8601 update timestamp.

Response

[
  {
    "id": "c0ffee00-1111-2222-3333-444455556666",
    "user_schema_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "rule_type": "non_zero_when_sibling_filled",
    "config": {
      "trigger_field": "tax_rate",
      "required_field": "tax_amount"
    },
    "description": "If a tax rate is present, tax amount must be non-zero.",
    "confidence_penalty": 0.3,
    "status": "active",
    "proposed_by": "user",
    "created_at": "2024-09-14T10:32:00.000Z",
    "updated_at": "2024-09-14T10:32:00.000Z"
  }
]
Use the propose endpoint to seed a Spec with candidate rules, then review each one. Proposals never affect a run until you set their status to active.

Errors

Error responses

400validation_errorInvalid body, or an unrecognized rule_type or status value.
401unauthorizedMissing or invalid API key.
404not_foundNo Spec (schema) or rule with this ID exists for your organization.
429rate_limitedToo many requests. Retry after the period indicated in the Retry-After header.

Frequently asked questions

How is a coherence rule different from a validation stage?+
A validation stage is a positional checkpoint that gates the pipeline at a rail position. A coherence rule is a cross-field relationship that, when violated, lowers the confidence of the affected cells so they surface for review. They are complementary.
What happens to a proposed rule?+
Proposals from `POST .../propose` land with status `proposed` and have no effect on runs. PATCH the rule to `status: active` to enforce it, or `status: rejected` to dismiss it.
What does confidence_penalty do?+
When a rule is violated on a record, the platform subtracts the penalty (0 to 1) from the confidence of the affected cells, pushing them below review thresholds so a human inspects them. Omitted, it defaults to 0.4; auto-proposed rules typically land between 0.2 and 0.5.
Why is my created rule active when I sent status: proposed?+
The create endpoint always saves directly created rules as active — the status field in the create body is ignored, on the assumption that a hand-written rule is intentional. Only PATCH changes status; if you want a staged review flow, create via the propose endpoint instead, whose rules land as proposed.