DEV Community

Fascia
Fascia

Posted on

Design-Time Safety: How Fascia's Risk Engine Blocks Unsafe Patterns Before Deployment

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.

fascia.run

Top comments (0)