2.8 KiB
Policy Decision And Provenance Contract
govoplan-policy owns policy and retention route contributions. Core keeps the
small shared DTOs that let policy decisions look the same across modules.
Privacy retention implementation lives in this module at
govoplan_policy.backend.retention. It is also exposed as the
policy.privacyRetention capability so older core compatibility imports can
dispatch to the active policy module without owning policy logic in core. Core
does not import this implementation as a hidden fallback when policy is
disabled.
When retention needs audit-log storage behavior, it requests the
audit.retention capability; it does not import audit module tables or
providers directly.
Backend DTOs
Use govoplan_core.core.policy.PolicyDecision for explainable policy results:
allowed: effective decision for the checked action.reason: compact operator-readable explanation.source_path: ordered policy sources that produced the decision.requirements: machine-readable blockers or prerequisites.details: domain-specific structured context, redacted when needed.
Use PolicySourceStep or policy_source_step() for each provenance step:
scope_type:system,tenant,user,group, orcampaign.scope_id: stable ID for non-system scopes.path: stable string path generated bypolicy_source_path().label: concrete source label such asSystem,Tenant,Owner user,Group, orCampaign.applied_fields: field names affected by that step.policy: local policy fragment that explains the applied fields.
Do not build or split provenance paths manually. Use
policy_source_path() and parse_policy_source_path() so IDs are URL-encoded
consistently.
Retention Explain Endpoint
Retention policy exposes the shared shape through:
GET /api/v1/admin/privacy-retention/policies/{scope_type}/explain
The response contains decision, effective_policy, parent_policy,
effective_policy_sources, parent_policy_sources, and blocked_fields.
Clients can use blocked_fields to disable controls before a save attempt.
UI Expectations
Policy UIs should render provenance close to the effective column or field it explains. The display path should use concrete source labels and local values, for example:
System: Allow
> Tenant: Deny without override
If all lower levels still inherit, continue the path until the effective local decision:
System: Allow
> Tenant: Inherit
> Group: Inherit
> Campaign: Deny
When a parent disallows lower-level limits or changes, the UI should disable the affected controls and avoid sending those fields in the save payload.
The shared core WebUI helper PolicySourcePath renders the source path shape
for module UIs. Modules may use their own field layout, but the data contract
should remain this shape.