Skip to main content

Standard Predicates

Predicates are the building blocks for governing-model transitions and contract rules. The local contract-log validator enforces the predicates below from replayable commit artifacts: the pending commit body, the pending commit signatures, and the already accepted contract state.

Current Local Evidence Matrix

These are the predicate and label facts currently used by the first-contract local validator path.

FactEvidence sourceCurrent-state rule
+POST, +REPOST, +MODEL, and other method labelsPending commit body methodsChecked on the pending commit
signed_by(/path.id)Pending commit signatures plus the public key string at /path.id in accepted stateReads previously committed state, not values written by the same commit
any_signed(/path)Pending commit signatures plus every accepted-state *.id file at /path or descendantsAt least one listed identity must sign
all_signed(/path)Pending commit signatures plus every accepted-state *.id file at /path or descendantsThe path must contain at least one identity, and every listed identity must sign
threshold("n", /path)Pending commit signatures plus every accepted-state *.id file at /path or descendantsAt least n unique listed identities must sign
modifies(/path)Pending commit body pathsMatches /path itself or descendants such as /path/alice.id
post_to_path(/path)Pending commit body methods and pathsMatches a POST action to /path itself or a descendant
has_property(/path, "a.b")Accepted-state JSON at /pathReads previously committed JSON and follows dot-separated object keys
state_exists(/path)Accepted-state path mapChecks that a path was already committed before the pending commit
text_eq(/path, "value") or text_eq(/left, /right)Accepted-state textCompares previously committed string values or a committed string to a literal
text_contains(/path, "needle"), text_starts_with(/path, "prefix"), and text_ends_with(/path, "suffix")Accepted-state textChecks whether a previously committed string contains, starts with, or ends with a literal substring
amount_in_range(/path, "min", "max")Accepted-state numberCompares a previously committed number to inclusive quoted numeric or accepted-state numeric bounds
num_eq, num_gt, num_gte, num_lt, num_lteAccepted-state numberCompares a previously committed number to a literal or accepted-state numeric bound
bool_true(/path) and bool_false(/path)Accepted-state booleanChecks a previously committed boolean value

Other reference predicates below describe the intended standard vocabulary. Treat them as requiring predicate-specific implementation and tests before using them in the local first-contract path.

Implementation Status

Use this table to distinguish the predicate vocabulary from the predicates currently enforced by the local first-contract validator.

Predicate familyLocal first-contract validatorNotes
Method labels such as +POST, +REPOST, and +MODELEnforcedDerived from pending commit body methods
signed_by, any_signed, all_signed, threshold, modifies, post_to_path, has_property, state_exists, text_eq, text_contains, text_starts_with, text_ends_with, amount_in_range, num_eq, num_gt, num_gte, num_lt, num_lte, bool_true, bool_falseEnforcedDerived from pending signatures, accepted state, pending methods, pending paths, accepted-state path existence, accepted-state JSON, accepted-state text, accepted-state numbers, and accepted-state booleans
timestamp_validUnit-tested extension module onlyImplemented in modality-wasm-validation; not yet replay evidence for the local first-contract validator
before, after, other state-value predicates, hash predicates, oracle_attests, and wasmNot first-contract-local yetIntended extension vocabulary; treat as external or future predicate checks unless a validator path explicitly documents support

Checkpoint Review Scope

For first-contract checkpoint review, the local validator evidence surface now covers method labels, pending signatures, accepted-state identity paths, segment-aware pending write paths, accepted-state JSON properties, accepted-state path existence, accepted-state text comparison, contains, prefix, and suffix checks, accepted-state numeric ranges, and accepted-state numeric comparisons plus accepted-state boolean checks. That is enough to review local log conformance for the current onboarding access-control and state-guard examples without depending on clocks, oracles, hash preimages, or custom WASM execution.

Keep deadline, oracle, hash, and broader WASM predicates out of first-contract claims until the validator path documents the replay artifact format, trust root, and negative tests for each evidence source.

Path Predicates

modifies

Checks if the commit writes to a path itself or a descendant path.

+modifies(/members)

Arguments:

  • path — Path or ancestor path to check

Behavior:

  • Returns true if any path in the commit body is the path itself or a descendant
  • Does not match sibling paths that merely share a string prefix
  • Used for path-based access control rules

Example:

// Only allow membership changes if all members sign
always(!<+modifies(/members)> true | <+modifies(/members) +all_signed(/members)> true)

post_to_path

Checks if the pending commit includes a POST action to the path itself or a descendant path.

+post_to_path(/config)

Arguments:

  • path — Path or ancestor path to check

Behavior:

  • Looks only at the pending commit body
  • Ignores non-POST actions, even when they write under the same path
  • Returns true if any POST action targets the path itself or a descendant
  • Does not match sibling paths that merely share a string prefix

Signature Predicates

signed_by

Verifies the commit is signed by a specific ed25519 key.

+signed_by(/users/alice.id)

Arguments:

  • path — Path to the public key in contract state

Behavior:

  • Looks up the public key string at path in the accepted contract state
  • Passes if the pending commit includes a matching signature
  • Does not see identity files written by the same pending commit

any_signed

Verifies at least one member from a path has signed.

+any_signed(/members)

Arguments:

  • path — Path or ancestor path containing member public keys

Behavior:

  • Enumerates all .id files at the path or descendants
  • Does not count identities from sibling paths that merely share a string prefix
  • Passes if ANY member has a valid signature
  • Used for "any member can act" patterns

all_signed

Verifies ALL members from a path have signed.

+all_signed(/members)

Arguments:

  • path — Path or ancestor path containing member public keys

Behavior:

  • Enumerates all .id files at the path or descendants
  • Does not count identities from sibling paths that merely share a string prefix
  • Passes only if EVERY member has a valid signature
  • Fails when the path contains no .id members
  • Used for "unanimous consent" patterns like adding members

threshold

Verifies n-of-m signatures from the accepted identities under a path.

+threshold("2", /treasury/signers)

Arguments:

  • n — Minimum signatures required
  • signers_path — Path or ancestor path containing signer public keys in *.id files

Behavior:

  • Enumerates all .id files at the path or descendants in accepted contract state
  • Does not count identities from sibling paths that merely share a string prefix
  • Counts each authorized public key at most once
  • Ignores commit signatures from keys that are not listed under the path
  • Passes when at least n unique listed identities signed the pending commit
  • Rejection output reports the authorized signature count, accepted member count, missing signature count, and any unauthorized signatures that were ignored

Time Predicates

The timestamp_valid extension module compares an input timestamp with the predicate context timestamp in unit tests. It is still external to the local first-contract path because replay must define where the trusted clock value comes from before deadline predicates can be treated as verifier evidence.

before

Intended predicate for checking that current time is before a deadline.

before(/deadlines/expiry.datetime)

after

Intended predicate for checking that current time is after a timestamp.

after(/deadlines/start.datetime)

State Predicates

The local validator now derives has_property(/path, "a.b") from accepted contract state. It looks up the previously committed JSON value at /path and follows dot-separated object keys such as a.b. It does not see JSON written by the same pending commit.

has_property(/profiles/alice.json, "contact.email")

The local validator now also derives state_exists(/path) from accepted contract state. It checks only whether the exact path already exists before the pending commit; a value written by the same pending commit is not evidence for that commit.

state_exists(/ready.flag)

The local validator also derives text_eq from accepted contract state. It compares the previously committed string at the first path with either a literal string or the previously committed string at a second path. It does not see text written by the same pending commit.

text_eq(/status.text, "approved")
text_eq(/actual/status.text, /expected/status.text)

The modality-wasm-validation crate also has unit-tested state-inspection modules. The has_property, state_exists, text_eq, text_contains, text_starts_with, text_ends_with, amount_in_range, numeric comparison, bool_true, and bool_false bindings above are first-contract-local replay evidence today. They read only accepted state; they do not see JSON, path existence, text, numbers, or booleans written by the same pending commit. Treat other state predicate inputs as explicit JSON predicate-test data until a contract-log validator path documents how the JSON is derived from replayed commits and accepted state.

bool_true / bool_false

Checks accepted-state boolean values. The local validator looks up the previously committed value at the path and requires it to be a JSON boolean. It does not see booleans written by the same pending commit.

bool_true(/status/delivered.bool)
bool_false(/flags/cancelled.bool)

text_eq / text_contains / text_starts_with / text_ends_with

Checks accepted-state text values. text_eq compares the previously committed string at the first path with either a literal string or the previously committed string at a second path. text_contains, text_starts_with, and text_ends_with check whether the previously committed string at the path contains, starts with, or ends with a literal substring. None of these predicates see text written by the same pending commit.

text_eq(/status.text, "approved")
text_contains(/review.text, "approved")
text_starts_with(/status.text, "approved")
text_ends_with(/status.text, "reviewer")

num_eq / num_gt / num_gte / num_lt / num_lte

Checks accepted-state numeric values. The first argument must be a path to a previously committed number. The second argument can be a numeric literal or a path to another previously committed number. Numeric comparisons do not see numbers written by the same pending commit.

num_gte(/balance.num, "100")
num_lt(/deposit.num, /limit.num)

amount_in_range

Checks that an accepted-state numeric value is inside an inclusive range. Bounds can be quoted numeric values or paths to accepted-state numeric values.

amount_in_range(/invoice/amount.num, "10", "100")
amount_in_range(/invoice/amount.num, /limits/min.num, /limits/max.num)

Oracle Predicates

oracle_attests

Intended predicate for checking a signed attestation from a trusted oracle. This is external evidence vocabulary until a validator path documents the attestation format, freshness rule, replay binding, and signature check.

oracle_attests(/oracles/delivery.id, "delivered", "true")

Arguments:

  • oracle_path — Path to oracle's public key
  • claim — The claim type being attested
  • value — Expected value (optional)

Security features:

  • Should verify oracle signatures
  • Should enforce attestation freshness
  • Should bind attestations to a specific contract
  • Should prevent replay attacks

Hash Predicates

hash_matches

Intended predicate for checking a SHA256 hash commitment.

hash_matches(/commitments/secret.hash, /revealed/value.text)

Using Predicates in Rules

Predicates are combined with logical operators in rule formulas:

export default rule {
starting_at $PARENT
formula {
// All commits must be signed by alice OR bob
always(<+signed_by(/users/alice.id)> true | <+signed_by(/users/bob.id)> true)
}
}

export default rule {
starting_at $PARENT
formula {
// After deadline, only buyer can commit
always(!<+after(/deadlines/expiry.datetime)> true | <+signed_by(/users/buyer.id)> true)
}
}

Transition predicates use the same predicate names inside governing models:

pending -> executed [+threshold("2", /treasury/signers)]

Custom WASM Predicates

WASM predicates are intended custom predicate modules. They are not part of the current local first-contract validator evidence matrix unless the predicate is explicitly listed above. The local validator now derives post_to_path(/path) from the pending commit body directly, has_property(/path, "a.b") from accepted-state JSON directly, text_eq, text_contains, text_starts_with, and text_ends_with from accepted-state strings, numeric comparisons from accepted-state numbers, and bool_true/bool_false from accepted-state booleans; other WASM-style predicate-test inputs remain explicit JSON until a validator path documents their replay binding.

modal predicate create --name my_predicate --output ./predicates/

Then reference in contracts:

wasm(/predicates/my_predicate.wasm, arg1, arg2)