Runtime error handling is an admission that your design phase failed.
If you catch a "payment processed but order not created" error at runtime, the real bug is that your design tool allowed a payment call outside a transaction boundary. The error handler is treating a symptom. The disease is in the architecture.
Risk Levels
Fascia's Risk Engine classifies every Tool (API endpoint) into three levels based on its flow graph patterns:
Green — Safe to Deploy
All of the following must be true:
- Only Entity Actions (create, update, transition, soft-delete) — no raw writes
- Explicit transaction boundary around all write operations
- No unbounded queries (all reads have pagination or limits)
- No external calls, OR external calls are outside transaction boundaries
Yellow — Warning, Requires Acknowledgment
Any of the following triggers Yellow:
- External call (payment, email, HTTP) inside a state transition
- Missing retry configuration on external nodes
- High row impact (> 100 rows in a single write operation)
- Read without explicit limit
- Missing timeout on external nodes
Red — Blocked, Cannot Deploy
Any of the following triggers Red:
- Raw write (SQL without Entity abstraction)
- Unbounded UPDATE (no WHERE clause or row limit)
- Payment call without rollback/compensation mechanism
- Missing transaction boundary around write operations
- Hard delete (instead of soft delete)
- External call with side effects inside a transaction boundary
- Circular dependency in flow graph (not a DAG)
Red signals cannot be acknowledged or dismissed. They must be resolved.
Why Design-Time, Not Runtime?
The key insight: unsafe patterns are structural, not behavioral. A payment call inside a transaction boundary is always wrong, regardless of the specific data flowing through it. You don't need to wait for runtime to discover this.
By analyzing the flow graph statically:
- Every developer sees the risk before deployment
- Non-technical stakeholders can understand "this endpoint is Yellow because it sends emails during state transitions"
- Audit logs show risk acceptance decisions, not just runtime errors
Auto-Fix Suggestions
When a risk signal is detected, the engine doesn't just flag it — it suggests the fix:
| Signal | Suggested Fix |
|---|---|
| Missing transaction | Wrap write nodes in a Transaction boundary |
| External call in transaction | Move external call outside transaction |
| Missing retry | Add Retry node (max 3 attempts, exponential backoff) |
| Unbounded update | Add WHERE condition or row limit |
| Payment without error edge | Add error edge to recovery flow |
| Hard delete | Convert to soft delete (set deleted_at) |
The Safety Agent (multi-model cross-check) validates these suggestions before presenting them.
The Execution Contract Enforces It
Even if something slips past the Risk Engine, the 9-step execution contract provides defense in depth:
- Step 3 (Policy Check) catches budget/row-limit violations
- Step 6 (Enforce Invariants) catches business rule violations before commit
- Step 7 (Commit/Rollback) ensures all-or-nothing transactions
- Step 8 (Audit Log) records everything unconditionally
But the goal is to catch problems at step 0 — before the code even exists.
Next in this series: BYOC Architecture — Why Your Data Should Stay in Your Cloud.
Top comments (0)