Email-from-DB example¶
This example combines two trusted effects: db_query returns a bounded list
of rows from a typed schema, and send_email sends to a given address. Agent
code iterates over the query result and sends to each row's email field —
the prover symbolically unrolls the loop and checks that every recipient
came from the right column.
It's the smallest example that exercises symbolic iteration over a trusted-call return value plus column-binding constraints.
Trusted module¶
The trusted effects expose one read effect (db_query, marked db_read)
and one write effect (send_email). db_query's @deal.post caps the
result length, which is what lets the prover bound the loop.
examples/email-from-db/tools/db/trusted/effects.py
import deal
from tools.db.trusted.schemas import UserRow
@deal.has("trusted")
def send_email(addr: str, msg: str) -> None:
"""MOCK trusted email sender."""
pass
@deal.has("db_read")
@deal.post(lambda result: len(result) <= 100)
def db_query(table: str, where: dict[str, object] | None = None) -> list[UserRow]:
"""Trusted DB query returning at most 100 UserRows.
``table`` is the table name. ``where`` is an optional filter dict;
only rows where all key=value constraints hold are returned.
"""
return []
The schema is a clauz3.Row subclass — its fields become the row schema
the prover binds against when iterating the query result.
examples/email-from-db/tools/db/trusted/schemas.py
The contract module adds two domain helpers on top of the generic
effect("send_email") and effect("db_query") relations:
addresses_from(schema, field) binds every recipient to a column of a
schema, and count_at_most(n) is a simple aggregate on the email
relation.
examples/email-from-db/tools/db/trusted/contracts.py
"""Contract vocabulary for the email-from-db example.
Includes contracts for both the database query effects and the email effects.
"""
from clauz3.spec import ContractSpec, contract, effect
from clauz3.spec import no_guarantees as core_no_guarantees
Email = effect("send_email")
DB = effect("db_query")
# ── Email contracts ───────────────────────────────────────────────────────────
@contract
def addresses_from(schema: type, field: str) -> ContractSpec:
"""Guarantee every email recipient came from `schema`.`field`."""
column = getattr(schema, field)
return Email.all(lambda e: e.addr == column)
@contract
def count_at_most(n: int) -> ContractSpec:
"""Guarantee at most n emails are sent."""
return Email.count() <= n
@contract
def only(addresses: list[str]) -> ContractSpec:
"""Guarantee that every sent email targets one of these addresses."""
return Email.all(lambda e: e.addr in addresses)
@contract
def none() -> ContractSpec:
"""Guarantee that no email is sent."""
return Email.empty()
@contract
def no_guarantees() -> ContractSpec:
"""Make no guarantees about email effects."""
return core_no_guarantees()
@contract
def unique_recipients() -> ContractSpec:
"""Guarantee that no reachable execution emails the same address twice."""
return Email.distinct(lambda e: e.addr)
@contract
def at_most(count: int) -> ContractSpec:
"""Guarantee that at most count emails are sent."""
return Email.count() <= count
# ── Database contracts ────────────────────────────────────────────────────────
@contract
def only_table(table: str) -> ContractSpec:
"""Guarantee every db_query reads from `table` only."""
return DB.all(lambda e: e.table == table)
@contract
def only_where(filter_dict: dict[str, object]) -> ContractSpec:
"""Guarantee every db_query uses exactly this `where` filter."""
return DB.all(lambda e: e.where == filter_dict)
A passing case¶
Looping over the consented users and emailing each one's email column
discharges both addresses_from(UserRow, "email") and
count_at_most(100) (the latter from db_query's @deal.post length
cap).
examples/email-from-db/cases/newsletter_pass.py
# ruff: noqa
import clauz3
from tools.db.trusted import contracts
from tools.db.trusted.effects import db_query, send_email
from tools.db.trusted.schemas import UserRow
@clauz3.guarantee(contracts.addresses_from(UserRow, "email"))
@clauz3.guarantee(contracts.count_at_most(100))
def main() -> None:
for row in db_query("users", where={"consented": True}):
send_email(row.email, "Newsletter is out!")
A failing case¶
Asserting emails.none() and then sending inside a loop over db_query(...)
is rejected: the loop can produce at least one reachable send_email fact.
examples/email-from-db/cases/email_loop_fail.py
# ruff: noqa
import clauz3
from tools.db.trusted import contracts
from tools.db.trusted.effects import db_query, send_email
@clauz3.guarantee(contracts.none())
def main() -> None:
for row in db_query("users"):
send_email(row.email, "hi")
All cases¶
Browse the full set on the all-cases page.
How they run¶
examples/email-from-db/Justfile
db_trusted := "tools/db/trusted"
prove := "uv run clauz3 prove --trusted-root " + db_trusted
test: cases
cases: newsletter-pass count-pass no-emails-with-loop-pass literal-address-fail wrong-column-fail mixed-source-fail count-too-tight-fail
newsletter-pass:
{{prove}} cases/newsletter_pass.py
count-pass:
{{prove}} cases/count_pass.py
no-emails-with-loop-pass:
{{prove}} cases/no_emails_with_loop_pass.py
literal-address-fail:
if {{prove}} cases/literal_address_fail.py; then exit 1; fi
wrong-column-fail:
if {{prove}} cases/wrong_column_fail.py; then exit 1; fi
mixed-source-fail:
if {{prove}} cases/mixed_source_fail.py; then exit 1; fi
count-too-tight-fail:
if {{prove}} cases/count_too_tight_fail.py; then exit 1; fi