← All specifications

Ponens Policy Language

Version: 0.2 · companion to POLICY_SPEC_v0_2

A policy is a machine-checkable rule over a trace. Each policy carries a formula written in this language and is evaluated over a trace as a conformance check — the trace either satisfies the formula (pass), violates it (fail), or contains nothing the policy applies to (not_applicable).

The language is LTLf — linear temporal logic over finite traces — extended with scoped-past operators and first-order structural predicates over the typed artifact graph. Formulas that use only standard temporal operators and action-type propositions are plain propositional LTLf; formulas that use quantifiers, set comprehensions, or lineage predicates require a richer evaluation engine. Every policy declares which fragment it uses in its language_level field (see §3).

This is the reader-friendly operator reference. The canonical, typed definition of the language lives in POLICY_SPEC_v0_2 §9–13 (the OCaml / IML form); this companion presents the same operators as tables and worked examples — the two are kept in lock-step at the same version.

Notation. Policy formula fields in the gallery use the unicode surface shown here (, , , ¬, P_target); POLICY_SPEC §10 gives the equivalent ASCII / OCaml form (->, /\, \/, not, typed constructors like PTarget). They denote the same language.


1. Design rationale

Why LTL as the foundation

A bespoke JSON DSL (must_have_prior_action, must_derive_from_artifact_type, …) encodes temporal meaning implicitly. Every rule type becomes a one-off encoding of a temporal pattern, which leads to:

LTL supplies the temporal foundation instead:

Beyond plain LTL

Not every trace policy is a purely propositional temporal property. Some need:

The policy language is therefore LTL extended with scoped operators and first-order predicates over traces.

Specification-level notation

The formula field holds a specification-level formula with precise semantics — it is not the concrete input syntax of any one tool. Compilation to a model checker’s language or to a runtime monitor is a separate implementation step. ponens ships a reference evaluator that runs the check offline.


2. Operators

2.1 Future-time operators

OperatorNameMeaning
G φGloballyφ holds at every position in the trace
F φFinallyφ holds at some future position
X φNextφ holds at the next position
φ U ψUntilφ holds at every position until ψ holds

2.2 Past-time operators

Past-time LTL (PLTL) is especially natural for trace policies, since most rules look backwards from a triggering event.

OperatorNameMeaning
P φPreviouslyφ held at some earlier position
H φHistoricallyφ held at every earlier position
φ S ψSinceφ has held at every position since ψ last held
φ S_last ψSince lastφ held at some point since the most recent ψ (or trace start if no ψ)

2.3 Scoped past-time operators

Plain P φ means “at some earlier position.” That is often too weak. For policies that require relevant prior work — not just any prior work — scoped operators restrict the search:

OperatorNameMeaning
P_target φPreviously (same target)φ held at some earlier position targeting the same file, module, or artifact
P_chain φPreviously (dependency chain)φ held at some earlier position in the artifact lineage of the current action
H_target φHistorically (same target)φ held at every earlier same-target position
H_chain φHistorically (dependency chain)φ held at every earlier position in the dependency chain

Choosing the right scope:

2.4 Boolean connectives

OperatorName
¬φNegation
φ ∧ ψConjunction
φ ∨ ψDisjunction
φ → ψImplication

2.5 Atomic propositions

Atomic propositions are evaluated at each position (action) in the trace:

2.6 Structural predicates

These go beyond propositional LTL — they read the typed artifact graph and require a richer evaluation engine.

2.7 Quantifiers

Used in structural policies that reason over collections:

2.8 Interpretation over traces

A trace τ = a₀, a₁, …, aₙ is a finite sequence of actions over an artifact graph. A formula φ is evaluated at position i:

Scoped operators restrict the witnessing position j to those sharing the current action’s target (P_target, H_target) or lying in its derived_from lineage (P_chain, H_chain).


3. Language levels

Every policy declares the fragment it uses in its language_level field. This tells the evaluator (and the reviewer) how much machinery a check needs.

language_levelUsesExample
pure_temporalfuture/past operators + atomic propositions onlytests_before_commit
scoped_temporaladds scoped-past operators (P_target, P_chain, …)research_before_edit
structuraladds quantifiers, set comprehensions, and lineage predicatesdata_flow_integrity

4. Standard encodings

Real policies from the gallery, with their language_level:

tests_before_commitpure temporal

G(GitCommit → P(RunTests ∧ completed))

Every commit is preceded by a test run that completed.

research_before_editscoped temporal

G(EditFile → P_target(ReadFile ∨ ReadDocumentation ∨ SearchCode ∨ AnalyzeCode))

No edit without first reading or searching the relevant code (same target).

reasoning_required_for_high_stakesscoped temporal

G(EditFile ∧ high_stakes_path → P_chain(VerificationResult(proved ∨ sat) ∨ Decomposition))

On a high-stakes path, an edit must be backed — somewhere in its lineage — by a proof, a SAT result, or a decomposition.

data_flow_integritystructural

G(∀ input ∈ inputs(a) → ∃! b . b < a ∧ input ∈ outputs(b))

Every input an action consumes was produced by exactly one earlier action — the lineage DAG has no dangling or ambiguous edges.

no_open_critical_residualsstructural

¬∃ r ∈ residuals . r.severity = Critical ∧ r.status = Open

The trace cannot ship with an unresolved critical gap on its residual surface.


5. Evaluation semantics

Evaluating a policy against a trace yields one of three results:

Evaluation may occur:

For runtime monitoring, past-time formulas are evaluated incrementally: each new action requires only local computation against the current state and a finite set of accumulated obligations. This makes PLTL well suited to online policy enforcement during agent execution — blocking an action before it violates a policy.


6. Relationship to other work

Conformance checking of finite execution traces against temporal-logic constraints is the foundation of DECLARE / declarative process mining and of runtime verification. The Ponens Policy Language applies that established machinery to the traces produced by AI coding agents, and extends it with the scoped-past and structural operators needed to talk about a typed artifact graph (files, models, verification results, lineage) rather than a flat event log.

See also the Policy Specification (the policy object, selectors, and evaluation records) and the Trace Specification (the actions and artifacts these formulas range over).