Accounts Payable
Accounts Payable is a starter pack: a typed APContext, tuned signal
extractors, and a default rule pack for vendor-payment workflows. It is a fast
start for an AP agent, not a prerequisite for enforcement. You supply the
context as a typed object on each process_invoice write, and the Novarch engine
reasons over the full session, not just the single action, when it applies the AP
rule pack.
If your workflow does not produce signals like domain_similarity_to_canonical,
you do not need this pack to get enforcement. Use
GenericContext and author rules over the evidence you
have. The typed pack is opinionated by design.
from novarch.verticals.ap import APContextAPContext fields
APContext is the typed context for the AP / vendor-payment vertical.
Every field below exists on the Pydantic model; values are validated at
the write boundary.
What this pack expects
The pack is tuned for vendor-payment fraud, so it asks for more than identity:
- Identity (required, shown to the operator as evidence):
vendor_id,vendor_name,invoice_id,amount,payment_method,approval_threshold. - Pack signals (required, because the bundled rules read them):
vendor_in_master_db,domain_similarity_to_canonical,off_cycle,agent_confidence. - Optional enrichment (defaulted; supply more to sharpen which rules fire):
vendor_first_seen_days_ago,vendor_bank_change_days_ago,amount_z_score_vs_vendor_history,exception_ticket,urgency_language_detected,submitted_off_hours.
If you cannot produce the required pack signals, that is the cue to use
GenericContext instead.
Identity (required for evidence display)
| Field | Type | Meaning |
|---|---|---|
vendor_id | str | The vendor’s stable identifier. |
vendor_name | str | Human-readable vendor name. |
invoice_id | str | The invoice this payment settles. |
amount | float (≥ 0.0) | Payment amount. |
payment_method | "ach" | "wire" | "check" | Settlement rail. Validated to one of these three literals. |
approval_threshold | float (> 0.0) | The per-action approval ceiling for this vendor / payment. |
Vendor identity & legitimacy
| Field | Type | Meaning |
|---|---|---|
vendor_in_master_db | bool | Whether the vendor exists in the canonical vendor master. |
vendor_first_seen_days_ago | int | None (≥ 0) | Age of the vendor relationship in days. None means a pre-existing relationship established before the audit window. |
domain_similarity_to_canonical | float (0.0–1.0) | 1.0 is an exact match against the canonical vendor domain or name; lower values indicate a homograph / look-alike. |
Payment instrument integrity
| Field | Type | Meaning |
|---|---|---|
vendor_bank_change_days_ago | int | None (≥ 0) | Days since the vendor’s bank details last changed. None means no recorded bank change in the window (treated as no signal). |
Amount & threshold anomaly
| Field | Type | Meaning |
|---|---|---|
amount_z_score_vs_vendor_history | float | None | How far this amount deviates from the vendor’s historical baseline. None means no baseline (cold-start vendor). |
Timing & cadence
| Field | Type | Meaning |
|---|---|---|
off_cycle | bool | Whether the payment falls outside the vendor’s normal billing cadence. |
exception_ticket | str | None | Finance exception-ticket reference for off-cycle payments. Format EXC-NNNN (literal EXC- + four digits). Missing, empty, or mis-formatted on an off-cycle payment is an AP-4 kill. On-cycle payments leave this None. |
urgency_language_detected | bool (default False) | At least one urgency marker (“wire today”, “pay immediately”, “urgent”, “ASAP”, …) was found in the inbound vendor communication. A behavioral BEC signal. |
submitted_off_hours | bool (default False) | The invoice arrived outside the vendor’s normal business hours (weekend, late evening, very early morning). This is a pure wall-clock timing anomaly, distinct from off_cycle. A behavioral BEC signal. |
Agent reasoning quality
| Field | Type | Meaning |
|---|---|---|
agent_confidence | float (0.0–1.0) | The agent’s own stated confidence in this action. |
Cross-action evidence
| Field | Type | Meaning |
|---|---|---|
referenced_prior_action_ids | list[str] (default []) | Action IDs this action explicitly references. This is relational metadata, not a signal value. |
Wiring it up
You attach the context to a write tool through the context_builder=
argument of @augur.tool. The builder runs when the write fires; it
receives the tool’s call arguments and returns the APContext.
from novarch import augurfrom novarch.verticals.ap import APContext
def build_invoice_context(invoice: dict) -> APContext: return APContext( vendor_id=invoice["vendor_id"], vendor_name=invoice["vendor_name"], invoice_id=invoice["invoice_id"], amount=invoice["amount"], payment_method=invoice["payment_method"], # "ach" | "wire" | "check" approval_threshold=invoice["approval_threshold"], vendor_in_master_db=invoice["vendor_in_master_db"], vendor_first_seen_days_ago=invoice.get("vendor_first_seen_days_ago"), domain_similarity_to_canonical=invoice["domain_similarity_to_canonical"], vendor_bank_change_days_ago=invoice.get("vendor_bank_change_days_ago"), amount_z_score_vs_vendor_history=invoice.get("amount_z_score"), off_cycle=invoice["off_cycle"], exception_ticket=invoice.get("exception_ticket"), urgency_language_detected=invoice.get("urgency_language_detected", False), submitted_off_hours=invoice.get("submitted_off_hours", False), agent_confidence=invoice["agent_confidence"], )
@augur.tool( kind="write", action_type="process_invoice", context_builder=lambda invoice: build_invoice_context(invoice),)def process_invoice(invoice: dict) -> dict: # Reaches here only after the Novarch engine returns a pass verdict. return pay(invoice)Read tools (@augur.tool(kind="read")) buffer into the pending action;
the process_invoice write drains that buffer, materializes the Action
with this APContext, and gates on the Novarch engine’s verdict before the body
runs.
AP rule pack
Three rules ship with the AP vertical. They are plain-English statements the Novarch engine applies to the whole session.
- AP-1 · BEC Pattern (BLOCKED): Blocks payments that fit a business-email-compromise fingerprint: three or more converging behavioral signals (recent bank change, near-threshold amount, off-hours submission, urgency language, off-cycle timing). The sending domain matching, vendor-in-master and high agent confidence do not rescue it: a compromised mailbox produces all three.
- AP-2 · Unverified Bank Change (PAUSED): Pauses a payment when the vendor’s bank details changed inside the last 30 days and nothing in the session evidences a callback confirming the change, so an operator can decide whether the verification happened off the record.
- AP-4 · Off-Cycle Without Exception Ticket (BLOCKED): Blocks any
off-cycle payment that does not reference a Finance exception ticket
(
EXC-NNNN), regardless of vendor identity, amount, or domain match.
Rule bodies are editable in plain English by the workflow owner; these descriptions summarize the shipped defaults.