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.
| Fact | Evidence source | Current-state rule |
|---|---|---|
+POST, +REPOST, +MODEL, and other method labels | Pending commit body methods | Checked on the pending commit |
signed_by(/path.id) | Pending commit signatures plus the public key string at /path.id in accepted state | Reads 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 descendants | At least one listed identity must sign |
all_signed(/path) | Pending commit signatures plus every accepted-state *.id file at /path or descendants | The 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 descendants | At least n unique listed identities must sign |
modifies(/path) | Pending commit body paths | Matches /path itself or descendants such as /path/alice.id |
post_to_path(/path) | Pending commit body methods and paths | Matches a POST action to /path itself or a descendant |
has_property(/path, "a.b") | Accepted-state JSON at /path | Reads previously committed JSON and follows dot-separated object keys |
state_exists(/path) | Accepted-state path map | Checks that a path was already committed before the pending commit |
text_eq(/path, "value") or text_eq(/left, /right) | Accepted-state text | Compares 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 text | Checks whether a previously committed string contains, starts with, or ends with a literal substring |
amount_in_range(/path, "min", "max") | Accepted-state number | Compares a previously committed number to inclusive quoted numeric or accepted-state numeric bounds |
num_eq, num_gt, num_gte, num_lt, num_lte | Accepted-state number | Compares a previously committed number to a literal or accepted-state numeric bound |
bool_true(/path) and bool_false(/path) | Accepted-state boolean | Checks 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 family | Local first-contract validator | Notes |
|---|---|---|
Method labels such as +POST, +REPOST, and +MODEL | Enforced | Derived 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_false | Enforced | Derived 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_valid | Unit-tested extension module only | Implemented 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 wasm | Not first-contract-local yet | Intended 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-
POSTactions, even when they write under the same path - Returns true if any
POSTaction 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
pathin 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
.idfiles 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
.idfiles 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
.idmembers - 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 requiredsigners_path— Path or ancestor path containing signer public keys in*.idfiles
Behavior:
- Enumerates all
.idfiles 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
nunique 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 keyclaim— The claim type being attestedvalue— 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)