You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add WithEffectPrecedence for deny-overrides evaluation
Introduces an optional effect precedence strategy that resolves
conflicts by highest-priority effect instead of first-match-wins.
This prevents misconfigured rule ordering from letting an ALLOW
slip past a DENY or REVIEW in custody contexts.
Copy file name to clipboardExpand all lines: README.md
+41Lines changed: 41 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -37,6 +37,7 @@ Key use cases include:
37
37
## Features
38
38
-**Deterministic evaluations** powered by compiled expr programs
39
39
-**Default effects** at document and policy level with a DENY-overrides-ALLOW model
40
+
-**Effect precedence** (optional) for deny-overrides evaluation — highest-priority effect wins regardless of rule order
40
41
-**Strict schema validation** (optional) via `WithSchemaDefinition`
41
42
-**Friendly error reporting** that surfaces the failing rule and expression issue
42
43
-**Zero-config loader** for JSON policy documents
@@ -215,6 +216,46 @@ func main() {
215
216
216
217
Because the caller defines what each effect means, you can extend the decision space (e.g., `RATE_LIMIT`, `QUARANTINE`, `NOTIFY_COMPLIANCE`) without changing the engine.
217
218
219
+
### Effect precedence (deny-overrides)
220
+
221
+
By default the engine uses first-match-wins for non-deny effects. This works well when rule ordering is deliberate, but in custody and treasury contexts a priority mistake can accidentally let an `ALLOW` slip in before a `DENY` or `REVIEW`.
222
+
223
+
`WithEffectPrecedence` switches to a **highest-priority-wins** strategy. You declare the hierarchy once at compile time and the engine enforces it regardless of rule or policy ordering:
|`DENY` + `ALLOW`|`DENY`| DENY has higher precedence |
238
+
|`REVIEW` + `ALLOW`|`REVIEW`| REVIEW has higher precedence than ALLOW |
239
+
|`ALLOW` only |`ALLOW`| Single match, returned as-is |
240
+
| Nothing matched |`DENY`| Document default kicks in |
241
+
242
+
The engine still short-circuits when the highest-priority effect (first in the list) is matched — there is no point evaluating further once a `DENY` is found. All other matches are collected and the winner is selected at the end, so `Evaluated` on the decision always reflects the full rule count.
243
+
244
+
Effects not listed in the precedence order are treated as lowest priority. They can still win when they are the only match, but any effect that *is* in the list will beat them.
0 commit comments