Five decisions, four of them denials.
A validated sample for each scripted case: allowed in scope, denied by scope, denied by threshold, revoked mid-flight, and a shadow evaluation that would have differed. The ratio is deliberate — that is what an authorization stream actually looks like.
The five cases
Each one exists because it is a case a reviewer will ask about.
Allowed, in scope
The grant covers the account and the action, the state is fresh, no limit is near. ALLOW_ reason code, because a permit needs a reason too.
Denied by scope
A valid, unexpired grant for a different account. Authenticated, session valid, endpoint permitted — and still wrong.
Denied by threshold
Carries both the limit that tripped and one that did not. Without limits[] this is indistinguishable from a scope denial.
Revoked mid-flight
The grant was withdrawn while the operation was moving. on_revoke_in_flight: fail is a property of the grant, so the answer was decided in advance.
Would have differed
A simulated decision whose outcome differs from the enforced one. is_shadow: true is what stops this poisoning every metric built on the stream.
The instructive one
Sample 03. Note that it records a limit which did not trip.
{
"category_uid": 3,
"category_name": "Identity & Access Management",
"class_name": "Authorization Decision",
"metadata": {
"version": "1.5.0",
"product": {
"name": "B5 Security Platform",
"vendor_name": "B5 Secure",
"version": "4.0.0.3"
},
"extension": {
"name": "authority",
"uid": "PENDING-OCSF-REGISTRATION",
"version": "0.1.0"
}
},
"tenant_uid": "t-8f21c0",
"time": 1785225602789,
"severity_id": 3,
"activity_id": 9,
"activity_name": "Transfer",
"is_permitted": false,
"reason_code": "DENY_LIMIT_DAILY_AMOUNT_EXCEEDED",
"actor": {
"user": {
"uid": "advisor-338",
"name": "j.okafor",
"type": "User"
}
},
"resource": {
"uid": "AC-99120",
"type": "custody_account"
},
"enforcement_point": {
"type": "in_process_method",
"runtime": "aspnet_core",
"name": "Custody.Instructions.InstructionService.Submit"
},
"delegation": {
"uid": "grant-4471",
"grantor": "user-1042",
"grantee": "advisor-338",
"purpose": "portfolio_rebalance",
"scope": "account:AC-99120;action:transfer",
"start_time": 1785000000,
"end_time": 1790000000,
"on_revoke_in_flight": "fail",
"is_revoked": false
},
"limits": [
{
"name": "daily_transfer_amount",
"type": "amount",
"window": "P1D",
"threshold": 250000,
"consumed": 250000,
"remaining": 0,
"is_exceeded": true
},
{
"name": "daily_transfer_count",
"type": "count",
"window": "P1D",
"threshold": 20,
"consumed": 4,
"remaining": 16,
"is_exceeded": false
}
],
"policy": {
"uid": "pol-cust-14",
"name": "Custody Servicing",
"version": "14"
},
"decision_evidence": {
"uid": "ev-01J8ZB",
"hash": "b7c1f0e2a9",
"prev_hash": "4d0aa71cc3",
"chain_uid": "chain-t-8f21c0",
"sequence": 918235,
"signature": "MEUCIQDf...",
"signing_key_uid": "key-2026-07-a",
"verifier_url": "https://b5secure.com/platform/decision-evidence/"
},
"is_shadow": false,
"state_age": 90,
"duration": 5
}An analyst reading this knows three things a pass/fail field cannot tell them: which aggregate was consulted, how close the others were, and that the decision was enforced rather than simulated. That is the difference between a log line and evidence.
What the validator checks
Beyond required attributes, unknown attributes and enum ranges, the validator enforces two semantic invariants that a JSON schema cannot express:
The reason must agree with the outcome
A denial carries a DENY_ code and a permit an ALLOW_ code. A record that says permitted with a denial reason is malformed even though every field is present and correctly typed.
Shadow status is always explicit
Never absent, never inferred from a default. A stream where shadow status is optional is a stream you cannot safely build a detection on.
Four denials out of five is the honest ratio
A sample set of happy paths proves a product demos well. These exist so the failure modes are inspectable before you commit to anything.
Talk to a human.
Get architecture guidance, Test Mode access, integration review, or help choosing the right B5 identity and authorization pattern.