|
| 1 | +# Runtime Facts And Policy Proofs |
| 2 | + |
| 3 | +Status: 1.6 planning policy |
| 4 | + |
| 5 | +Fluxheim should understand its own runtime decisions without becoming a |
| 6 | +database. The goal is a small, typed, bounded model for operational evidence: |
| 7 | +what happened, which policy made the decision, and which public/redacted reason |
| 8 | +can be shown to an operator. |
| 9 | + |
| 10 | +This is inspired by two internal design patterns: |
| 11 | + |
| 12 | +- Aesynx: no ambient authority, typed handles, explicit capability movement, |
| 13 | + bounded telemetry, fail-closed admission gates. |
| 14 | +- Skrifheim: canonical facts, worlds, policy decisions, redacted debug output, |
| 15 | + and deterministic proof objects. |
| 16 | + |
| 17 | +Fluxheim should adopt the discipline, not the database engine. |
| 18 | + |
| 19 | +## Non-Goals |
| 20 | + |
| 21 | +This work must not put a database, graph engine, AI system, or unbounded audit |
| 22 | +store in the request hot path. |
| 23 | + |
| 24 | +Runtime facts are not a replacement for logs, metrics, traces, or admin status. |
| 25 | +They are a typed internal shape that those systems can export safely. |
| 26 | + |
| 27 | +## Core Concepts |
| 28 | + |
| 29 | +### Runtime Fact |
| 30 | + |
| 31 | +A runtime fact is a bounded statement about Fluxheim state or behavior. |
| 32 | + |
| 33 | +Examples: |
| 34 | + |
| 35 | +- config candidate loaded; |
| 36 | +- config reload promoted; |
| 37 | +- route matched; |
| 38 | +- route access policy denied; |
| 39 | +- GeoIP context unavailable; |
| 40 | +- auth-request allowed or denied; |
| 41 | +- rate limit delayed or rejected; |
| 42 | +- load-balancer backend selected; |
| 43 | +- backend ejected or restored; |
| 44 | +- cache object admitted, bypassed, purged, or served stale; |
| 45 | +- ACME certificate installed or rollback attempted; |
| 46 | +- admin mutation accepted or rejected. |
| 47 | + |
| 48 | +Facts should carry enough metadata for diagnostics without leaking secrets: |
| 49 | + |
| 50 | +- fact kind; |
| 51 | +- config or policy epoch; |
| 52 | +- vhost and route identifier where safe; |
| 53 | +- bounded decision reason; |
| 54 | +- source subsystem; |
| 55 | +- monotonic event id or timestamp; |
| 56 | +- redacted subject identifiers; |
| 57 | +- optional causal parent or request correlation id; |
| 58 | +- public classification of whether it is safe for logs, metrics, traces, or |
| 59 | + admin status. |
| 60 | + |
| 61 | +### Policy Proof |
| 62 | + |
| 63 | +Security-relevant decisions should move toward small proof objects: |
| 64 | + |
| 65 | +```text |
| 66 | +decision = allow | deny | redact | defer |
| 67 | +reason = bounded enum |
| 68 | +policy_epoch = current config/runtime policy epoch |
| 69 | +input_count = bounded count |
| 70 | +output_classification = public | sensitive | secret-internal |
| 71 | +``` |
| 72 | + |
| 73 | +The proof is not verbose per-request logging. It is a typed result that keeps |
| 74 | +policy decisions consistent across access control, cache admission, |
| 75 | +load-balancer selection, admin mutation, auth-request, GeoIP, rate limiting, |
| 76 | +Wasm hooks, and future WAF behavior. |
| 77 | + |
| 78 | +### Runtime World |
| 79 | + |
| 80 | +Fluxheim already has implicit worlds: |
| 81 | + |
| 82 | +- current running config; |
| 83 | +- reload candidate; |
| 84 | +- known-good snapshot; |
| 85 | +- rollback target; |
| 86 | +- runtime load-balancer state; |
| 87 | +- cache status; |
| 88 | +- admin-visible status. |
| 89 | + |
| 90 | +The 1.6 line should start treating those as explicit versioned views with |
| 91 | +epochs and clear promotion rules. A candidate config should not become current |
| 92 | +state without validation evidence. Runtime mutations should record the policy |
| 93 | +epoch they were made under. |
| 94 | + |
| 95 | +## 1.6 Adoption Plan |
| 96 | + |
| 97 | +`v1.6.0` should document the initial runtime fact kinds, policy-proof shape, |
| 98 | +redaction levels, and epoch terminology. It should not change request behavior. |
| 99 | + |
| 100 | +Early 1.6 releases should introduce small types in a focused crate or |
| 101 | +`fluxheim-common` if the shape is still tiny: |
| 102 | + |
| 103 | +- `RuntimeFactKind` |
| 104 | +- `RuntimeDecisionKind` |
| 105 | +- `RuntimeDecisionReason` |
| 106 | +- `PolicyProof` |
| 107 | +- `PolicyEpoch` |
| 108 | +- `RuntimeFactVisibility` |
| 109 | + |
| 110 | +Mid 1.6 releases should route selected decision paths through proof objects |
| 111 | +while replacing Pingora boundaries: |
| 112 | + |
| 113 | +- route access policy; |
| 114 | +- GeoIP allow/deny behavior; |
| 115 | +- rate limiting; |
| 116 | +- auth-request; |
| 117 | +- cache admission and origin protection; |
| 118 | +- load-balancer backend selection/ejection; |
| 119 | +- admin runtime mutations. |
| 120 | + |
| 121 | +Later 1.6 releases may add a bounded in-memory fact ring for admin diagnostics. |
| 122 | +The ring must be optional, fixed-size, redacted by type, and safe to disable. |
| 123 | +It must never be required for request forwarding. |
| 124 | + |
| 125 | +## Security Rules |
| 126 | + |
| 127 | +- Runtime facts do not create authority. |
| 128 | +- Policy proofs are deterministic and bounded. |
| 129 | +- Sensitive identifiers are redacted at type boundaries, not manually at each |
| 130 | + log site. |
| 131 | +- Metrics stay low-cardinality. |
| 132 | +- Admin views expose bounded reasons, not raw secrets or private addresses in |
| 133 | + privacy-mode builds. |
| 134 | +- AI or Wasm consumers may only receive facts explicitly granted by policy. |
| 135 | +- Derived or advisory facts are never authoritative unless promoted through a |
| 136 | + deterministic path. |
| 137 | +- If fact collection fails, request handling must keep its configured |
| 138 | + fail-open/fail-closed behavior and record only a bounded diagnostic if safe. |
| 139 | + |
| 140 | +## Why This Matters |
| 141 | + |
| 142 | +Fluxheim has grown beyond a simple proxy. It now has cache, load balancing, |
| 143 | +admin mutation, snapshots, ACME, stream/UDP work, metrics, traces, and future |
| 144 | +Wasm/WAF/HTTP3 plans. A typed runtime-fact model lets operators and reviewers |
| 145 | +ask: |
| 146 | + |
| 147 | +- why was this request denied? |
| 148 | +- why did this backend stop receiving traffic? |
| 149 | +- why was this object not cached? |
| 150 | +- which config epoch made this decision? |
| 151 | +- which admin action changed this pool? |
| 152 | +- which facts are safe to export? |
| 153 | + |
| 154 | +That makes Fluxheim more self-aware and makes pentest review more local, |
| 155 | +without turning the proxy into a database. |
0 commit comments