Boundaries
Versioned contracts
Refactor internal facts freely while keeping external promises explicit and reviewable.
Map internal facts deliberately
// The only place where an internal fact becomes a public contract.
public sealed class PaymentChargedPublication : Publication<PaymentCharged, PaymentChargedV1>
{
public override PaymentChargedV1 Map(PaymentCharged e) => new(e.OrderId, e.Amount, "EUR");
}Review the contract as text
Every integration event is captured in contracts.wyrd.txt. Breaking changes fail the build; compatible additions receive an IDE code fix.
# contracts.wyrd.txt (reviewed in PRs)
payments.payment-charged v1 | Amount: decimal; Currency: string; OrderId: string
# If you change Amount from decimal to double:
error WYRD0201: Breaking change in integration event 'payments.payment-charged' v1:
field 'Amount' changed type from decimal to double. Existing subscribers would fail
to read it. Publish it as v2 and keep v1 until subscribers migrate, or revert the change.Analyzer rules
WYRD0001ErrorA type cannot be both a command and an event.
WYRD0002ErrorA command must have a single owning slice.
WYRD0003 / 0004InfoEvents should be past tense; commands should be imperative.
WYRD0011 / 0012WarningProcess rules: every step says how it is undone or .NoCompensation("why") (WYRD0011), every wait has .Within (WYRD0012).
WYRD0014WarningEvery step declares its retry policy, .Retry(...) or .NoRetry("why"). There is no default. Replaces the removed WYRD0010.
WYRD0013WarningThe process syntax a repository picks (wyrd_process_style), with a one-click fluent ⇄ pipe conversion.
WYRD0020ErrorA switch over a [Union] must handle every case; when it does, no discard is needed.
WYRD0101ErrorDomain types cannot leak inside a public integration event contract.
WYRD0200 / 0202WarningNew integration event or compatible optional field added — one-click IDE code fix updates contracts.wyrd.txt.
WYRD0201 / 0203ErrorBreaking field change or deleted contract without retirement.
WYRD0300–0302ErrorKeeps [WyrdJsonContext] complete and collision-free for Native AOT.