paybondpaybond
Sign in

Harbor predicate DSL

The wire format, clause semantics, fuel limits, and evaluation response shape for Harbor predicate documents.

Harbor predicate DSL (API reference)

This document describes the predicate_dsl field on Harbor intent creation and how evaluation results appear on evidence submission. It is aimed at API consumers, SDK authors, and operators integrating with harbor-intent-escrow.

Normative implementation: paybond-predicate-vm (evaluate, validate_predicate_document). Task context: tasks/PAYBOND-004-predicate-vm-and-safe-mvp-dsl.md.

Managed policy registry (V1-006): Approved templates, tenant versions, preview, and lifecycle APIs are described in the mergeable OpenAPI fragment harbor-policy-openapi.yaml (Harbor /policy/v1/*; gateway adds the /harbor prefix).

Where this appears

HTTPField / bodyRole
POST /intentspredicate_dsl (JSON object, required)Stored on the intent; validated at creation (structure, version, fuel limits). Digested for principal signing (v2).
POST /intents/{id}/evidenceRequest payloadEvaluated as evidence JSON against the intent’s predicate_dsl.
POST /intents/{id}/evidenceResponse predicate_evaluationStructured PredicateReport (passed and trace).

Harbor rejects malformed or oversized predicate documents at intent creation with 400 Bad Request. Some evaluation-time failures (for example schema shape problems) may surface as 422 Unprocessable Entity when they are classified as evaluation errors rather than a simple passed: false.

Tenant isolation

Evaluation uses only data from the current intent row in the authenticated tenant context: submitted evidence payload, intent amount_cents, and intent evidence_schema. It performs no network I/O and does not read other tenants or external systems. See Tenant scoping.

Document envelope

Every predicate document must include:

FieldTypeDescription
versionintegerDSL revision. Only 1 is supported today.
rootobjectRoot clause (see below). Must contain string field op.
{
  "version": 1,
  "root": { "op": "true" }
}

Unsupported version values are rejected.

Clauses (op tag)

All clauses are JSON objects with op in snake_case. Paths are arrays of string keys into the evidence JSON object (nested objects only).

Constants and composition

opFieldsSemantics
trueAlways satisfied.
andclauses: array of clause objectsAll clauses must pass.
orclauses: array of clause objectsAt least one clause must pass.
notclause: single clause objectNegates inner result.

Evidence comparisons

opFieldsSemantics
eqpath: string[], value: anyEvidence at path must equal value (JSON equality).
completionpath: string[], value: anySame as eq; preferred for audit readability (e.g. status completed).
ltepath: string[], limit_source: stringInteger at path must be <= intent budget. Only limit_source "amount_cents" is supported (matches intent amount_cents).
budget_cappath: string[]Shorthand: same as lte with amount_cents.

Schema-aware check

opFieldsSemantics
schema_fieldfield: string (non-empty)Top-level evidence key field must exist, and its JSON value’s type must match the intent’s evidence_schema.properties[field].type.

evidence_schema should follow a minimal JSON Schema style, for example:

{
  "type": "object",
  "properties": {
    "status": { "type": "string" },
    "cost": { "type": "integer" }
  }
}

Supported type strings (same as common JSON Schema usage): null, boolean, string, integer, number, array, object. An array of strings is allowed for multi-type fields.

Limits (abuse prevention)

These limits apply to validation (create) and evaluation (evidence). Exceeding them returns an error and does not run unbounded work.

LimitValueApplies to
Max nesting depth (and / or / not)24Clause tree
Max fuel (AST nodes visited)256Whole document
Max path segments16path on eq, completion, lte, budget_cap
Max clauses length in and / or32Per operator

Evaluation response (predicate_evaluation)

On successful evidence submission, Harbor includes a predicate_evaluation object shaped like:

{
  "passed": true,
  "trace": [
    {
      "kind": "completion",
      "detail": "value matched",
      "data": { "path": "status", "passed": true, "expected": "completed", "observed": "completed" }
    }
  ]
}
FieldDescription
passedIf true, Harbor’s MVP flow treats the predicate as satisfied for release vs refund transitions (see escrow lifecycle).
traceOrdered steps for audits and support (kind, detail, data).

Logical failures (for example eq mismatch) yield passed: false with a trace explaining the failure; the HTTP status may still be 202 Accepted if evidence and signatures were valid.

Principal signing (v2)

Intent creation signing uses bincode v2 payload IntentCreationSignV2 (see signing.rs): it commits to BLAKE3 digests of canonical JSON for budget, evidence_schema, and predicate_dsl, plus amount, currency, deadline, tenant, DIDs, and predicate_ref. When implementing an offline signer, use the same canonical JSON rules as Harbor (json_value_digest / sorted object keys) or call canonical_intent_creation_message from the harbor_intent_escrow crate in tests/tools.

Examples

Always release when evidence is submitted (smoke / tests):

{
  "version": 1,
  "root": { "op": "true" }
}

Completed status and cost under budget:

{
  "version": 1,
  "root": {
    "op": "and",
    "clauses": [
      { "op": "completion", "path": ["status"], "value": "completed" },
      { "op": "budget_cap", "path": ["cost"] }
    ]
  }
}

Evidence might be { "status": "completed", "cost": 5000 } with amount_cents >= 5000.

Require typed field per schema:

{
  "version": 1,
  "root": { "op": "schema_field", "field": "invoice_id" }
}

Evidence must include top-level invoice_id, and evidence_schema.properties.invoice_id.type must describe its JSON type.

Changelog (document-level)

predicate_dsl.versionMeaning
1Current wire format (this page).

Future versions will be introduced with new task/spec entries; clients should treat unknown version as unsupported.