requisite puts a few data-handling requirements in OCaml types:
Trustseparates input from values that passed an application policy.Confidencevalidates probabilities, selects an action tier, and issues an abstractcertaintoken at the highest tier.Freshchecks a per-value TTL against a monotonic clock.
The library is small by design. It depends only on
mtime for portable monotonic time.
opam install requisiteThe package requires OCaml 4.14 or later.
Code that names Mtime.t or Mtime.span should declare mtime directly:
(libraries requisite mtime)requisite depends on mtime.clock internally, but Dune projects should not
rely on transitive libraries for names used in their own source.
open Requisite
let load_customer (id : (int, Trust.trusted) Trust.t) =
database_lookup (Trust.trusted_value id)
let raw = Trust.from_input request_body
let id =
Trust.try_sanitize raw (fun text ->
match int_of_string_opt (String.trim text) with
| Some id -> Ok id
| None -> Error `Bad_customer_id)Trust.t and its state markers are abstract. A trusted sink states its
requirement in its argument type. sanitize and try_sanitize are the safe
promotion paths; widen lowers a trusted value when an API asks for untrusted
input.
The policy function defines “trusted” for the destination. Requisite records that the function succeeded, not that its policy was sufficient.
let act (_ : Confidence.certain) decision =
commit decision
match Confidence.create ~probability:0.98 predicted_decision with
| Error invalid -> report_bad_score invalid.Confidence.value
| Ok scored ->
match Confidence.gate scored with
| Confidence.High_confidence (proof, decision) -> act proof decision
| Confidence.Likely decision -> queue_review decision
| Confidence.Unsure decision -> record decisionProbabilities must be finite and lie in [0, 1]. The default likely and certain
boundaries are 0.60 and 0.95. Custom thresholds may raise the certain
boundary, but cannot lower it:
let thresholds =
Confidence.Thresholds.create ~likely:0.75 ~certain:0.99The certain constructor is hidden. The token proves that some qualifying gate
issued it; it is not tied to the score or payload that produced it. Ordinary
OCaml code may store it, reuse it, or construct a new High_confidence value
that pairs it with another payload. Keep the gate and authorized action close
when that distinction matters.
let ttl = Mtime.Span.( * ) 30 Mtime.Span.s
let quote = Fresh.fetch ~ttl price
match Fresh.read_with_stale quote with
| Ok price -> charge price
| Error expired ->
audit_expired_quote expired.Fresh.value;
Format.eprintf "%a@." Fresh.pp_stale expired.Fresh.staleFresh stores a monotonic timestamp for each value. read returns stale timing
metadata; read_with_stale also returns the payload for an explicit recovery
path. remaining saturates at zero. fetched_at accepts an existing Mtime.t
and rejects timestamps ahead of the current clock.
A freshness result describes the instant of the check. OCaml does not make the returned payload expire later, so this is not a lease.
Mtime 2.x counts system suspend on Linux and supported modern macOS. Older macOS releases and other clock backends may differ; applications that require suspend to expire TTLs should verify their deployment platform.
Fresh wrappers are immutable and can be shared between threads or domains. Concurrent checks do not mutate the wrapper. This does not make a mutable payload safe for concurrent access.
The Rust library uses a higher-ranked lifetime to keep Live<'id, _> inside a
closure. Standard OCaml has no equivalent lifetime or locality constraint for
heap values. A rank-2 phantom brand blocks a direct return, but a caller can
package the branded value in an existential GADT and use a polymorphic accessor
after the callback. A generative first-class module has the same escape.
This port therefore omits Live rather than presenting that pattern as a
compile-time scope guarantee. A revocable runtime handle is possible, but it is
a different contract.
The abstractions hold for safe code using the public interfaces. Obj.magic,
unsafe unmarshalling, or deliberately discarding wrappers can bypass them.
Freshness and confidence thresholds are runtime checks. Trust policies remain
application responsibilities.
dune exec examples/trust_flow.exe
dune exec examples/confidence_gate.exe
dune exec examples/fresh_cache.exe
dune fmt
dune build @all
dune runtest
dune build @doc
dune build --profile=ci @all @runtest @doc @installRuntime tests cover validation and boundary behavior. Compile-negative tests
typecheck small programs against the public Trust and Confidence
interfaces and require the compiler to reject attempts to forge or skip state
transitions. Each case asserts diagnostic patterns so an unrelated typo cannot
count as success. These tests use POSIX sh and are skipped on Windows; the
portable runtime suite still runs there.
See CONTRIBUTING.md for the layout and release checks, and CHANGES.md for notable changes.
Licensed under either Apache-2.0 or MIT, at your option.