@@ -88,17 +88,134 @@ The mechanism differs:
8888- The deployment is governed by an environment contract: enforcement is only as
8989 sound as the facts the environment promises to publish.
9090
91- ` clauz3 ` currently proves a single Python program before execution. FORGE
92- enforces individual decisions during execution. Those designs are not
93- substitutes. A static contract proof gives the user a concise permission
94- artifact and avoids partial side effects; runtime enforcement gives defense in
95- depth when execution drifts from the proved model.
91+ ` clauz3 ` proves a single Python program before execution; that * static* proof
92+ is its distinctive layer. FORGE-style policy enforcement decides individual
93+ actions during execution. Those designs are not substitutes. A static contract
94+ proof gives the user a concise permission artifact and avoids partial side
95+ effects; policy-monitor runtime enforcement gives defense in depth when
96+ execution drifts from the proved model.
97+
98+ Note this comparison is about * policy* enforcement, not about whether clauz3 has
99+ any runtime checks at all — it does. The trusted layer's deal preconditions and
100+ effect markers are enforced at runtime regardless of the proof (see
101+ [ Concepts: static proof vs runtime] ( concepts.md#static-proof-vs-runtime ) ). What
102+ clauz3 lacks, relative to FORGE, is a reference monitor evaluating a policy over
103+ the agent's actions as they happen.
104+
105+ ## Guardians
106+
107+ Meijer, * Guardians of the Agents: Formal verification of AI workflows*
108+ ([ ACM Queue 23(4), July–August 2025] ( https://queue.acm.org/detail.cfm?id=3762990 ) ;
109+ Communications of the ACM, January 2026;
110+ [ doi:10.1145/3777544] ( https://doi.org/10.1145/3777544 ) ), proposes a
111+ ** generate → verify → execute** discipline for agents, with an open-source
112+ implementation at
113+ [ ` metareflection/guardians ` ] ( https://github.com/metareflection/guardians ) .
114+ Meijer frames it as "a safety paradigm rooted in mathematical proof
115+ verification" and an extension of Java/.NET ** bytecode verification** to agentic
116+ computation — the same "complexity in production, verification stays simple"
117+ asymmetry that motivates proof-carrying code above.
118+
119+ The core argument is that prompt injection has the same root cause as SQL
120+ injection: code (instructions) and data (content) are not separated, so the fix
121+ is the same. Instead of letting the model call one tool, read the result, and
122+ then decide the next side-effecting action, the model emits a complete
123+ structured ** workflow** * up front* — a JSON AST of steps whose arguments are
124+ ** symbolic references** (string result bindings such as ` "emails_fetched" ` ,
125+ rendered ` @emails_fetched ` in the literate explanation; modeled as ` SymRef ` in
126+ the implementation) rather than concrete values. The plan is authored from the
127+ goal and tool specs alone, before any concrete (possibly attacker-controlled)
128+ data exists, then verified against a security policy, and only then executed.
129+ Because the code is fixed before the data arrives, malicious content in inbox
130+ data, tool results, * or tool descriptions* cannot introduce a new
131+ side-effecting step; anything unexpected is caught at verification and the
132+ workflow is rejected.
133+
134+ The paper's running example is an email exfiltration: a malicious inbox message
135+ instructs the agent to silently forward a summary to ` it@othercorp.com ` .
136+ Verification draws on:
137+
138+ - ** Source-sink / taint analysis** — a policy forbidding data flow from
139+ ` fetch_email ` 's result to ` send_email ` 's ` body ` when the ` to ` argument is
140+ outside an allowlist. Meijer suggests a CodeQL path query or SemGrep; the
141+ implementation carries this as its own ` TaintRule ` with provenance labels and
142+ sanitizers.
143+ - ** Security automata** — a finite state machine over the tool-call sequence
144+ that rejects on reaching an error state (the paper's figure 2 forbids sending
145+ to external domains). Meijer introduces this as a * runtime* monitor; the
146+ implementation also evaluates it at verification time.
147+ - ** Z3 / Dafny over pre/post/frame conditions** — including a careful treatment
148+ of the ** frame problem** (McCarthy & Hayes, 1969): a naive postcondition for
149+ "delete foo.txt and bar.txt" is also satisfied by ` delete_file("*.txt") ` , so a
150+ ** frame condition** ("files not matching the pattern are unchanged") is needed
151+ before the over-broad plan fails to verify.
152+
153+ Meijer gives three reasons to verify first: prevention rather than detection,
154+ ** eliminating the need for rollbacks** (only verified workflows run, so there is
155+ no partial side effect to undo), and automation. The middle reason is the same
156+ transactional argument ` clauz3 ` makes for static proof over runtime monitors
157+ (see [ static proof vs runtime] ( concepts.md#static-proof-vs-runtime ) ).
158+
159+ The shared ground with ` clauz3 ` is substantial: both reject unsafe behavior
160+ * before* side effects run, both make the tool/effect trust boundary explicit,
161+ both compile to Z3, and both replace ad-hoc natural-language promises with a
162+ checkable artifact. The mechanism differs:
163+
164+ - Guardians verifies a structured ** workflow AST** against an operator-defined
165+ policy, with the plan fixed before data arrives.
166+ - ` clauz3 ` proves an agent-authored ** Python program** satisfies
167+ agent-stated guarantees over trusted effect facts derived by symbolic
168+ execution, and treats the proved contract as the user-facing consent artifact.
169+
170+ Where Guardians is ahead, and ` clauz3 ` is not yet:
171+
172+ - a first-class symbolic workflow representation, with the clean code/data
173+ separation that gives the prompt-injection story;
174+ - built-in taint/provenance tracking for source-to-sink data flow;
175+ - built-in security automata for tool-call * sequences* .
176+
177+ One difference cuts the other way. Meijer needs explicit frame conditions
178+ because his Z3 obligations describe world state (` fileSystem ` ), and a model will
179+ satisfy an under-specified postcondition the cheapest way it can. ` clauz3 `
180+ reasons instead over a * closed-world finite trace* of effect facts — an effect
181+ not in the trace provably does not happen — so contracts like
182+ ` filesystem.only_write_under ` or ` emails.only ` bound the entire effect set
183+ directly, giving the frame guarantee implicitly for the effects the prover
184+ tracks (see
185+ [ effect-IR] ( ../todos/effect-ir.md#what-level-fol-datalog-or-the-z3-lisp-syntax ) ).
186+
187+ ` clauz3 ` does already reason about data it has not seen — its symbolic
188+ iteration over a trusted query's ` list[Row] ` return, with ` UserRow.email `
189+ column-binding contracts (see
190+ [ symbolic iteration] ( symbolic-iteration.md ) ), is the closest existing analog to
191+ "plan before the data." What it lacks is the provenance layer needed to say "a
192+ value that came from ` fetch_mail ` must not reach ` send_email.body ` ," and any
193+ notion of effect * order* on which an automaton could run; today the effect facts
194+ are an unordered set carrying only path conditions.
195+
196+ Where ` clauz3 ` is distinct:
197+
198+ - ordinary Python as the agent-authored surface, rather than a bespoke workflow
199+ AST;
200+ - effect facts inferred from trusted function signatures, rather than
201+ hand-declared ` ToolSpec ` s;
202+ - a user-facing contract vocabulary (allowlists, absence, uniqueness, counts,
203+ sums, filtered counts, joins) and an approval service built around proved
204+ guarantees and coverage, not pass/fail policy enforcement;
205+ - contract * abduction* — the agent proposes the permission artifact (see
206+ "Operator Policy Versus Agent-Abduced Contracts" below).
207+
208+ These projects look more like complementary halves than alternatives. The
209+ concrete synergy tracks — taint/provenance in the fact layer, security automata
210+ over effect traces, a workflow front-end that lowers into the effect IR, a
211+ combined approval surface, and a shared email-exfiltration benchmark — are
212+ collected in [ Guardians synergies] ( ../todos/guardians-synergies.md ) .
96213
97214## Operator Policy Versus Agent-Abduced Contracts
98215
99- FORGE assumes policies are written by humans up front and applied to agents.
100- That is the right shape for organizational rules the agent should not be able
101- to weaken.
216+ FORGE and Guardians both assume policies are written by humans up front and
217+ applied to agents. That is the right shape for organizational rules the agent
218+ should not be able to weaken.
102219
103220` clauz3 ` explores the opposite surface: the agent proposes a contract for a
104221specific program, the prover checks that program against that contract, and the
@@ -172,13 +289,18 @@ Provenance facts:
172289The current prover records trusted calls as independent effect facts. It cannot
173290yet express policies like "this URL must have come from a literal allowlist or
174291from a trusted database table." A provenance relation in the fact layer would
175- unlock that class of policy.
292+ unlock that class of policy. Guardians' source-sink taint model is the sharpest
293+ articulation of this idea; see
294+ [ Guardians synergies] ( ../todos/guardians-synergies.md ) for how it could attach
295+ to the ` FactInfo ` layer.
176296
177297Benchmarks:
178298
179299The repo has examples by proof shape. It does not yet have an adversarial
180300benchmark. Even a small corpus of plausible agent-authored programs that try to
181- violate contracts would make prover coverage more measurable.
301+ violate contracts would make prover coverage more measurable. The Guardians
302+ email-exfiltration scenario is a natural first adversarial case; see
303+ [ Guardians synergies] ( ../todos/guardians-synergies.md#track-5-shared-examples-benchmark ) .
182304
183305## What Is Distinct Here
184306
0 commit comments