Example — mailguard.glith
The glither.mail (mailguard) ruleset is the canonical worked example for the
Glither compiler. It is the degenerate,
flat-verdict dialect (fold first-match, no ladders): a message settles into
delivered/dropped or rests in quarantine.
Source: roux/tests/fixtures/mailguard.glith in the glither repo.
Source Ruleset
#pragma dialect glither.mail ; fold first-match
/// # Mailguard policy — glither.mail
/// Flat-verdict dialect (spec §7, §11.3): a message settles into `delivered`
/// or `dropped`, or rests in `quarantine : Pending<{delivered, dropped}>`
/// awaiting an admin release or its deadline.
rule drop_dmarc_reject =
msg | from.domain != dkim.domain
| not sender.allowlisted
| dmarc.policy == reject
=> into dropped (reason = dmarc_reject)
rule quarantine_spoof =
msg | from.domain != dkim.domain
| not sender.allowlisted
=> hold into quarantine
on admin.release into delivered
after 72h into dropped (reason = quarantine_timeout)
rule quarantine_executable =
msg | attachment.ext ~ /^(?:exe|scr|js|vbs|bat)$/
| not sender.allowlisted
=> hold into quarantine
on admin.release into delivered
after 24h into dropped (reason = unscanned_executable)
rule tag_external =
msg | from.org != recipient.org
=> tag (label = "EXTERNAL"),
route to inbox,
into delivered
rule route_newsletters =
msg | list.unsubscribe
| sender.allowlisted
=> route to newsletters,
into delivered
rule deliver_allowlisted =
msg | sender.allowlisted
=> route to inbox,
into delivered
Six rules in first-match cascade. Each predicate is ⟨select⟩ (no crossing phase —
mail is the degenerate case). The quarantine_* rules use suspended dispositions
with after deadlines for liveness.
Compiler Pipeline
The tangle compiler processes the ruleset through five stages:
mailguard.glith
│ tangle: pest parse → lower to typed IR
▼
Typed Core IR
│ infer crossing phases → run structural checks
│ derive
├───► tangle gleam → Gleam source (auditable oracle)
├───► tangle rust → Rust source (production, verified with cargo check)
├───► tangle wit → WIT contract (membrane / component-model boundary)
└───► tangle snapshot → JSON/CBOR snapshot (introspection / BAZ.Weave)
Generated Gleam (first-match oracle)
The Gleam target emits a readable, total-function oracle suitable for audit and differential conformance verification:
// Generated by tangle (Glither compiler)
// Dialect: glither.mail
// Fold: first-match
import gleam/regexp
pub type Msg {
Msg(
from_domain: String,
sender_allowlisted: Bool,
dmarc_policy: String,
attachment_ext: String,
from_org: String,
list_unsubscribe: Bool,
dkim_domain: String,
recipient_org: String,
)
}
pub type Outcome {
Delivered(reason: String)
Dropped(reason: String)
Quarantine(reason: String)
}
pub type Receipt {
Receipt(outcome: Outcome, rule: String, reason: String)
}
pub fn dispose(msg: Msg) -> Receipt {
let assert Ok(re_0) = regexp.from_string("^(?:exe|scr|js|vbs|bat)$")
// drop_dmarc_reject
case msg.from_domain != msg.dkim_domain
&& !msg.sender_allowlisted
&& msg.dmarc_policy == "reject" {
True ->
Receipt(Dropped("dmarc_reject"), "drop_dmarc_reject", "")
False ->
// quarantine_spoof
case msg.from_domain != msg.dkim_domain && !msg.sender_allowlisted {
True ->
Receipt(Quarantine("quarantine_spoof"), "quarantine_spoof", "")
False ->
// quarantine_executable
case string.contains(msg.attachment_ext, re_0)
&& !msg.sender_allowlisted {
True ->
Receipt(Quarantine("quarantine_executable"),
"quarantine_executable", "")
False ->
// tag_external
case msg.from_org != msg.recipient_org {
True ->
Receipt(Delivered(""), "tag_external", "")
False ->
// route_newsletters
case msg.list_unsubscribe && msg.sender_allowlisted {
True ->
Receipt(Delivered(""), "route_newsletters", "")
False ->
case msg.sender_allowlisted {
True ->
Receipt(Delivered(""), "deliver_allowlisted", "")
False ->
Receipt(Dropped("no_rule"), "default",
"no matching rule")
}
}
}
}
}
}
}
Key features:
- Regex predicates compiled to
regexp.from_string()withstring.contains() - First-match cascade via nested
case/True ->/False ->expressions - Side-effect dispositions (
tag,route) emitted as comments Receipt(Dropped("no_rule"), "default", "no matching rule")fallback at the innermost level
Generated Rust (production target)
The Rust target emits a production-ready crate with the same logic, verified
to compile via cargo check in the test suite:
// Generated by tangle (Glither compiler)
// Dialect: glither.mail
// Fold: first-match
use regex;
#[derive(Debug, Clone, PartialEq)]
pub struct Msg {
pub attachment_ext: String,
pub dkim_domain: String,
pub dmarc_policy: String,
pub from_domain: String,
pub from_org: String,
pub list_unsubscribe: bool,
pub recipient_org: String,
pub sender_allowlisted: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Outcome {
Delivered(String),
Dropped(String),
Quarantine(String),
}
#[derive(Debug, Clone, PartialEq)]
pub struct Receipt {
pub outcome: Outcome,
pub rule: String,
pub reason: String,
}
impl Receipt {
fn dropped(rule: &str, reason: &str) -> Self {
Self {
outcome: Outcome::Dropped(reason.to_string()),
rule: rule.to_string(),
reason: String::new(),
}
}
}
pub fn dispose(msg: Msg) -> Receipt {
let re_0 = regex::Regex::new(r#"^(?:exe|scr|js|vbs|bat)$"#).unwrap();
// drop_dmarc_reject
if msg.from_domain.as_str() != msg.dkim_domain.as_str()
&& !msg.sender_allowlisted
&& msg.dmarc_policy.as_str() == "reject"
{
Receipt { outcome: Outcome::Dropped("dmarc_reject".to_string()),
rule: "drop_dmarc_reject".to_string(), reason: String::new() }
} else if msg.from_domain.as_str() != msg.dkim_domain.as_str()
&& !msg.sender_allowlisted
{
Receipt { outcome: Outcome::Quarantine("quarantine_spoof".to_string()),
rule: "quarantine_spoof".to_string(), reason: String::new() }
} else if re_0.is_match(msg.attachment_ext.as_str())
&& !msg.sender_allowlisted
{
Receipt { outcome: Outcome::Quarantine(
"quarantine_executable".to_string()),
rule: "quarantine_executable".to_string(), reason: String::new() }
} else if msg.from_org.as_str() != msg.recipient_org.as_str() {
Receipt { outcome: Outcome::Delivered("".to_string()),
rule: "tag_external".to_string(), reason: String::new() }
} else if msg.list_unsubscribe && msg.sender_allowlisted {
Receipt { outcome: Outcome::Delivered("".to_string()),
rule: "route_newsletters".to_string(), reason: String::new() }
} else if msg.sender_allowlisted {
Receipt { outcome: Outcome::Delivered("".to_string()),
rule: "deliver_allowlisted".to_string(), reason: String::new() }
} else {
Receipt::dropped("default", "no matching rule")
}
}
Key features:
regex::Regex::newwith raw-string patterns for regex predicatesif/elsecascade for first-match semanticsReceipt::dropped()convenience constructor for the fallback case#[derive]for all types (Debug, Clone, PartialEq)
Generated WIT (membrane contract)
The WIT target derives the component-model interface — the membrane contract:
package glither:mail;
interface types {
/// The artifact being disposed.
record msg {
attachment-ext: string,
dkim-domain: string,
dmarc-policy: string,
from-domain: string,
from-org: string,
list-unsubscribe: bool,
recipient-org: string,
sender-allowlisted: bool,
}
/// Disposition outcomes.
enum outcome {
delivered,
dropped,
quarantine,
}
/// A signed disposition receipt.
record receipt {
outcome: outcome,
rule: string,
reason: string,
}
}
/// Membrane contract for glither.mail.
world msg {
use types.{msg, receipt};
export dispose: func(msg: msg) -> receipt;
}
Key features:
- Kebab-case field names (
attachment-ext,dkim-domain) - Record types for the artifact (
msg) and receipt - Enum for disposition outcomes with camelCase variants
world msgdeclaration with thedisposeexport
Pipeline Verification
Each fixture's Rust output is verified through end-to-end compilation:
- Generate Rust source from the
.glithruleset - Create a temporary Cargo project with
regexas a dependency - Run
cargo checkon the generated code - Assert compilation succeeds
This is done for all 5 fixtures (mailguard, accumulate, segment, decision, articles) as part of the test suite.
Test Suite
The Glither compiler's test suite for mailguard coverage:
| Test Group | Count | What It Covers |
|---|---|---|
| roux unit tests | 18 | Parse, lower, infer, check (dead rules), codegen (gleam/rust/wit per fixture) |
| Compilation tests | 5 | Rust cargo check for each fixture |
| Mailguard integration | 11 | Roundtrip, snapshot, inference, check diagnostics |
| CLI integration | 17 | tangle check/gleam/wit/rust/snapshot for all fixtures |
51 tests total, zero clippy warnings.