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
Milestone: v0.3.0 | Tier: Creative Bet | Effort: Medium
Problem
PolicyDenied errors contain a static reason string (e.g., "WRITE capabilities require the 'writer' or 'admin' role"). When policies are complex — especially with declarative YAML/TOML rules (#42) — users struggle to understand:
Why a request was denied (which specific rule matched?)
What they need to change (which role/attribute/justification is missing?)
How close they were (did they fail one condition or many?)
No other capability-based security library provides structured denial explanations. This is a DX differentiator.
Proposed Change
1. explain_denial() method on Kernel
asyncdefexplain_denial(
self,
request: CapabilityRequest,
principal: Principal,
*,
justification: str="",
) ->DenialExplanation:
"""Explain why a request would be denied, and what's needed to fix it."""
2. DenialExplanation model
@dataclassclassDenialExplanation:
"""Structured explanation of a policy denial."""denied: boolrule_name: str# Which rule caused the denialfailed_conditions: list[FailedCondition] # What specifically failedremediation: list[str] # What the principal needs to satisfy the policynarrative: str# Human-readable summary
@dataclassclassFailedCondition:
"""A single condition that was not met."""condition: str# e.g., "roles"required: Any# e.g., ["writer", "admin"]actual: Any# e.g., ["reader"]suggestion: str# e.g., "Add 'writer' or 'admin' role to principal"
3. Example output
explanation=awaitkernel.explain_denial(request, principal, justification="fix bug")
# DenialExplanation(# denied=True,# rule_name="write-requires-writer",# failed_conditions=[# FailedCondition(# condition="roles",# required=["writer", "admin"],# actual=["reader"],# suggestion="Add 'writer' or 'admin' role to principal 'agent-1'"# ),# FailedCondition(# condition="min_justification",# required=15,# actual=7,# suggestion="Provide justification with at least 15 characters (currently 7)"# )# ],# remediation=[# "Grant role 'writer' or 'admin' to principal 'agent-1'",# "Provide a justification of at least 15 characters"# ],# narrative="Request denied by rule 'write-requires-writer': principal 'agent-1' lacks required roles (has: reader, needs: writer or admin) and justification is too short (7/15 chars)."# )
4. Works with both policy engines
DefaultPolicyEngine: Traverse the hardcoded rule chain, identify the first failing check.
Milestone: v0.3.0 | Tier: Creative Bet | Effort: Medium
Problem
PolicyDeniederrors contain a static reason string (e.g., "WRITE capabilities require the 'writer' or 'admin' role"). When policies are complex — especially with declarative YAML/TOML rules (#42) — users struggle to understand:No other capability-based security library provides structured denial explanations. This is a DX differentiator.
Proposed Change
1.
explain_denial()method on Kernel2.
DenialExplanationmodel3. Example output
4. Works with both policy engines
explain()method that returns structured failure details.5. Deterministic — no LLM dependency
Despite the name "explanation engine," this is pure deterministic logic — rule traversal + structured diff. No LLM calls involved.
Acceptance Criteria
explain_denial()returnsDenialExplanationwith correct failed conditionsFailedConditionincludes what was required vs. what the principal hasremediationlist provides actionable steps to fix the denialnarrativeis a complete human-readable sentenceDefaultPolicyEngine(all 5 rule categories covered)DeclarativePolicyEngine(when available from Declarative policy rules (YAML + TOML) #42)denied=Falseand empty failure detailsAffected Files
src/agent_kernel/kernel.py(addexplain_denial()method)src/agent_kernel/models.py(addDenialExplanation,FailedConditiondataclasses)src/agent_kernel/policy.py(addexplain()method toDefaultPolicyEngine)tests/test_policy.py(explanation tests for all denial scenarios)tests/test_kernel.py(end-to-end explain_denial tests)Dependencies
DefaultPolicyEngine