Appearance
W2: Policy enforcement
In plain terms. Every customer has spend policies — "no alcohol on client cards", "hotels capped at $200 a night in Asia-Pacific", "receipts required above $50". Today those live in a PDF handbook and finance teams enforce them after the fact, usually too late to do anything about it. This skill checks every card swipe and every bill against the customer's policies in real time and returns one of three answers: allow, flag for review, or deny outright. Crucially there is no language model involved in the live check — it is plain rule-checking, fast enough to be sub-millisecond and clear enough that a controller can read the row and see exactly which rules fired. (Natural-language policy authoring, which is the part that benefits from a model, is a separate authoring-time step that compiles into the same rules — so the engine shipped here is the destination, not a placeholder.)
The brief below is worth a quick open: it sets up why I deliberately did not put a model in the runtime path. The 5% out-of-policy figure, the multi-currency drift, and the PDF-handbook starting point are exactly the conditions that demand deterministic, auditable verdicts.
Assignment brief — Workflow 2
Ingest natural-language spend policies (per-diem caps, vendor restrictions, receipt requirements, hotel star limits, category bans). Evaluate every corporate-card transaction against them. Take graduated action — flag, request receipt, escalate, propose clawback — and close the loop with the employee.
Reap customers write spend policies in plain English in Notion, Slack, or a PDF handbook ("hotels max 4-star, $200/night in APAC; no alcohol on client cards; receipts required >$50"). Finance teams enforce them manually after the fact. ~5% of corporate-card spend ends up out-of-policy and most of it is never recovered. The pain compounds in multi-currency mid-market customers: per-diems vary by country, FX moves the effective cap, and policies drift across versions.
This skill runs on every card authorization and bill event. The enforcement path is deterministic: a typed policy bundle evaluated by a pure rule engine, with no model in the hot path. Natural-language policy authoring compiles to the same rule rows; the compiler is an authoring-time tool, not a runtime dependency.
Two surfaces in the product expose this skill: the policy editor (where rules are authored and simulated) and the card surface (where the rules become controls a controller can inspect before any transaction lands in the queue).


Notice that neither screenshot has a "chat with the policy" affordance. There is no prompt box because there is no model in the path — the editor produces typed rule rows, and the card surface is a window onto those rows.
Verdict model
Every check this skill produces collapses into one of four cells. Three of them are verdicts the controller acts on; the fourth is the version stamp that makes the verdict replayable later.
allow
autoApply at 0.99 when no findings fire, subject to autonomy.flag
suggest at 0.70 for receipt, amount, after-hours, and review-worthy findings.deny
refuse(policy_conflict) for blocked merchant category code, geography, vendor, or hard-cap failures.versionEvery row carries the policy bundle version used at evaluation time.
The version stamp is the one cell most teams forget. Without it, an employee appealing a flagged charge two months later cannot find out which version of the policy they were judged against — and the appeal becomes an argument, not a lookup. With it, the dispute is resolved by reading the row.
Rule map
Six rule types ship in this submission. Each one is colour-coded by the strongest verdict it can produce — red rules can deny, gold rules flag for review, green rules cap or constrain. New rule types slot in alongside these without touching the engine.
amount_capMerchant-category-code-scoped United States dollar cap.
mcc_blockATM, gambling, or blocked category.
geo_blockSanctioned countries.
receipt_requiredEvidence threshold.
after_hoursTime-window check.
vendor_blocklistExplicit vendor denylist.
Three red, two gold, one green is roughly the balance most customer policies end up at — there are more "things we deny" than "things we conditionally cap", and that asymmetry is fine. What matters is that each rule's severity is declared with the rule, so the engine never has to guess how seriously to take a finding.
Decision flow
Here is what happens when one event arrives, end to end. There are four stops and no model anywhere in the chain — that is the point.
Event
FinanceEventCard and bill events carry merchant category code, amount, vendor, receipt link, geography, and timestamp evidence.
↓
Rule
Evaluate typed bundleThe engine runs every active Zod-validated rule and records each finding with rule identifier, severity, and message.
↓
POL
Strongest verdict winsDeny outranks flag, flag outranks allow, and the outcome stays deterministic.
↓
LOG
Autonomy gate + decision logThe decision row carries the policy bundle version so replays do not collide across policy edits.
Step 3 ("strongest verdict wins") is what keeps the engine commutative: a rule firing earlier or later in the bundle never changes the verdict. That property is what makes the engine safe to extend — adding a new rule cannot accidentally weaken an existing deny.
Submission stance
Three deliberate choices shape this skill. Each one trades flexibility for some property the controller needs more — speed, auditability, or tenant isolation.
No hot-path large language modelPolicy enforcement has to be explainable, fast, and replayable. I kept the engine as a pure rule evaluator.Sub-millisecond path.
Compiler-readyNatural-language policies compile into the same rule rows. The shipped engine is the target intermediate representation.Designed seam, not overclaimed.
Tenant-scopedThe engine only sees one tenant bundle per request.No cross-tenant policy contamination.
The compromise this stance makes is that the engine cannot reason about a brand-new rule type until that type exists in the typed bundle — there is no "and just figure it out from this paragraph" fallback. That is the right compromise for a verdict path that has to defend its answers later.
Testing & evals
Two layers — Vitest unit tests on the rule engine, plus a 22-case runtime golden corpus and the 10-case natural-language policy-compiler boundary set — pinned on their own page so each layer can be regressed independently.
- Policy enforcement — evals — runtime corpus, injection on rule inputs, and the authoring-time compiler.
Read next
The worked example walks through a single Singapore Airlines card authorization, S$4,029.50, that the engine flagged for being over the single-trip travel cap and missing a receipt. You see exactly which rules fired, what the controller sees on the queue row, how the policy bundle version is stamped so the verdict can be replayed later, and the design patterns the engine implements.
- Worked example — the Singapore Airlines row, end to end.
Next skill in this section: W3: Accounts Payable agent — where the deterministic discipline of this skill meets a much harder problem (money movement) and the agent answers by refusing to move money on its own, no matter how confident it is.