Override a rule
Tighten, switch off or change an inherited rule, within its override policy.
A child changes an inherited rule under overrides.rules. It may set severity, enabled,
acknowledgement and acceptance, and must give a reason. The rule's overridePolicy decides
what is allowed: tighten-only (the default) only makes the rule stricter, open allows any
change, and locked allows none.
Syntax
overrides:
rules:
- rule: <inherited rule id>
set: { severity: warning, acknowledgement: required }
reason: <why this level needs it>Example
The outlet raises the note rule from info to a warning that needs an acknowledgement (a
tightening), and switches off the open express check. The order is denied until the note
warning is acknowledged.
ruleCascade: 1.0.0
kind: RuleSet
metadata: { id: learn.outlet, version: 1.0.0, title: "Outlet rules" }
scope:
- { level: organization, id: learn }
- { level: project, id: outlet }
extends:
- { ruleset: learn.store-rules, version: "^1.0.0" }
overrides:
rules:
- rule: store.notes.recommended
set: { severity: warning, acknowledgement: required }
reason: The outlet warehouse needs a note on every order.
- rule: store.express.check
set: { enabled: false }
reason: The outlet has no express delivery surcharge.
rules: []
tests:
- name: the note is now a warning to acknowledge, and the express check is off
entity: Order
operation: create
given:
data: { quantity: 2, express: true, country: "PT" }
expect:
decision: deny
findings:
- { rule: store.notes.recommended, severity: warning, blocking: true }
- name: acknowledging the note allows the order
entity: Order
operation: create
given:
data: { quantity: 2, express: true, country: "PT" }
resolutions:
- { rule: store.notes.recommended, type: acknowledge }
expect:
decision: allow
findings:
- { rule: store.notes.recommended, status: acknowledged }ruleCascade: 1.0.0
kind: RuleSet
metadata: { id: learn.store-rules, version: 1.0.0, title: "Store rules" }
scope:
- { level: organization, id: learn }
entities:
Order:
schema: { $ref: "./learn.openapi.yaml#/components/schemas/Order" }
rules:
- id: store.quantity.min
kind: validation
target: { entity: Order, field: /quantity }
operations: [create]
assert: { op: gte, args: [{ var: data.quantity }, 1] }
severity: error
finding: { code: LRN-ROV-001, message: store.quantityMin }
- id: store.notes.recommended
kind: validation
target: { entity: Order, field: /notes }
operations: [create]
assert: { op: exists, args: [{ var: data.notes }] }
severity: info
finding: { code: LRN-ROV-002, message: store.notesRecommended }
- id: store.express.check
kind: validation
target: { entity: Order, field: /express }
operations: [create]
overridePolicy: open
assert: { op: ne, args: [{ var: data.express }, true] }
severity: warning
finding: { code: LRN-ROV-003, message: store.expressCheck }
- id: store.country.required
kind: validation
target: { entity: Order, field: /country }
operations: [create]
overridePolicy: locked
assert: { op: exists, args: [{ var: data.country }] }
severity: error
finding: { code: LRN-ROV-004, message: store.countryRequired }
messages:
en:
store.quantityMin: "Order at least one item."
store.notesRecommended: "A note helps the warehouse."
store.expressCheck: "Express delivery costs extra."
store.countryRequired: "Choose a country."{
"entity": "Order",
"operation": "create",
"data": {
"quantity": 2,
"express": true,
"country": "PT"
}
}Result, from the engine
Decisiondeny1 finding, server channel
LRN-ROV-002warningblockingA note helps the warehouse./notes
Common mistakes
- Loosening a
tighten-onlyrule: disabling it, lowering its severity, allowing an acceptance or removing a required acknowledgement. Below, the outlet lowers an error to a warning, so it does not load:RULE_LOOSENED. - Changing a
lockedrule (RULE_LOCKED) or a rule id that is not inherited (RULE_UNKNOWN).
ruleCascade: 1.0.0
kind: RuleSet
metadata: { id: learn.outlet, version: 1.0.0, title: "Outlet rules" }
scope:
- { level: organization, id: learn }
- { level: project, id: outlet }
extends:
- { ruleset: learn.store-rules, version: "^1.0.0" }
overrides:
rules:
- rule: store.quantity.min
set: { severity: warning }
reason: Let empty orders through.
rules: []
tests:
- name: zero items
entity: Order
operation: create
given:
data: { quantity: 0, country: "PT", notes: "x" }
expect:
decision: deny
findings:
- { rule: store.quantity.min, severity: error }ruleCascade: 1.0.0
kind: RuleSet
metadata: { id: learn.store-rules, version: 1.0.0, title: "Store rules" }
scope:
- { level: organization, id: learn }
entities:
Order:
schema: { $ref: "./learn.openapi.yaml#/components/schemas/Order" }
rules:
- id: store.quantity.min
kind: validation
target: { entity: Order, field: /quantity }
operations: [create]
assert: { op: gte, args: [{ var: data.quantity }, 1] }
severity: error
finding: { code: LRN-ROV-001, message: store.quantityMin }
- id: store.notes.recommended
kind: validation
target: { entity: Order, field: /notes }
operations: [create]
assert: { op: exists, args: [{ var: data.notes }] }
severity: info
finding: { code: LRN-ROV-002, message: store.notesRecommended }
- id: store.express.check
kind: validation
target: { entity: Order, field: /express }
operations: [create]
overridePolicy: open
assert: { op: ne, args: [{ var: data.express }, true] }
severity: warning
finding: { code: LRN-ROV-003, message: store.expressCheck }
- id: store.country.required
kind: validation
target: { entity: Order, field: /country }
operations: [create]
overridePolicy: locked
assert: { op: exists, args: [{ var: data.country }] }
severity: error
finding: { code: LRN-ROV-004, message: store.countryRequired }
messages:
en:
store.quantityMin: "Order at least one item."
store.notesRecommended: "A note helps the warehouse."
store.expressCheck: "Express delivery costs extra."
store.countryRequired: "Choose a country."{
"entity": "Order",
"operation": "create",
"data": {
"quantity": 0,
"country": "PT",
"notes": "x"
}
}Result, from the engine
does not loadThe engine refuses the ruleset before it evaluates anything.
RULE_LOOSENEDlearn.outlet: rule store.quantity.min is tighten-only (line 11)
Exercise
Instead of switching the express check off, make it an error that a manager may accept without a reason. Test that an express order is denied, and allowed when a manager accepts it.
Hint
The express check is open, so its override may set severity: error and an acceptance with roles: [manager].
Show answer
ruleCascade: 1.0.0
kind: RuleSet
metadata: { id: learn.outlet, version: 1.0.0, title: "Outlet rules" }
scope:
- { level: organization, id: learn }
- { level: project, id: outlet }
extends:
- { ruleset: learn.store-rules, version: "^1.0.0" }
overrides:
rules:
- rule: store.notes.recommended
set: { severity: warning, acknowledgement: required }
reason: The outlet warehouse needs a note on every order.
- rule: store.express.check
set:
severity: error
acceptance: { allowed: true, roles: [manager], justification: none }
reason: Express delivery from the outlet needs a manager.
rules: []
tests:
- name: express delivery is an error now
entity: Order
operation: create
given:
data: { quantity: 2, express: true, country: "PT", notes: "back door" }
expect:
decision: deny
findings:
- { rule: store.express.check, severity: error, blocking: true }
- name: a manager accepts it
entity: Order
operation: create
given:
data: { quantity: 2, express: true, country: "PT", notes: "back door" }
actor: { id: m-1, roles: [manager] }
resolutions:
- { rule: store.express.check, type: accept-risk }
expect:
decision: allow
findings:
- { rule: store.express.check, status: accepted }ruleCascade: 1.0.0
kind: RuleSet
metadata: { id: learn.store-rules, version: 1.0.0, title: "Store rules" }
scope:
- { level: organization, id: learn }
entities:
Order:
schema: { $ref: "./learn.openapi.yaml#/components/schemas/Order" }
rules:
- id: store.quantity.min
kind: validation
target: { entity: Order, field: /quantity }
operations: [create]
assert: { op: gte, args: [{ var: data.quantity }, 1] }
severity: error
finding: { code: LRN-ROV-001, message: store.quantityMin }
- id: store.notes.recommended
kind: validation
target: { entity: Order, field: /notes }
operations: [create]
assert: { op: exists, args: [{ var: data.notes }] }
severity: info
finding: { code: LRN-ROV-002, message: store.notesRecommended }
- id: store.express.check
kind: validation
target: { entity: Order, field: /express }
operations: [create]
overridePolicy: open
assert: { op: ne, args: [{ var: data.express }, true] }
severity: warning
finding: { code: LRN-ROV-003, message: store.expressCheck }
- id: store.country.required
kind: validation
target: { entity: Order, field: /country }
operations: [create]
overridePolicy: locked
assert: { op: exists, args: [{ var: data.country }] }
severity: error
finding: { code: LRN-ROV-004, message: store.countryRequired }
messages:
en:
store.quantityMin: "Order at least one item."
store.notesRecommended: "A note helps the warehouse."
store.expressCheck: "Express delivery costs extra."
store.countryRequired: "Choose a country."{
"entity": "Order",
"operation": "create",
"data": {
"quantity": 2,
"express": true,
"country": "PT",
"notes": "back door"
}
}Result, from the engine
Decisiondeny1 finding, server channel
LRN-ROV-003errorblockingExpress delivery costs extra./express