Skip to main content

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() with string.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::new with raw-string patterns for regex predicates
  • if/else cascade for first-match semantics
  • Receipt::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 msg declaration with the dispose export

Pipeline Verification

Each fixture's Rust output is verified through end-to-end compilation:

  1. Generate Rust source from the .glith ruleset
  2. Create a temporary Cargo project with regex as a dependency
  3. Run cargo check on the generated code
  4. 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 GroupCountWhat It Covers
roux unit tests18Parse, lower, infer, check (dead rules), codegen (gleam/rust/wit per fixture)
Compilation tests5Rust cargo check for each fixture
Mailguard integration11Roundtrip, snapshot, inference, check diagnostics
CLI integration17tangle check/gleam/wit/rust/snapshot for all fixtures

51 tests total, zero clippy warnings.