Defines a staged migration from one permission model to another using shadow evaluation, divergence evidence, explicit cutover cohorts, rollback, and fail-closed enforcement boundaries.
Package status: reference context ready for human review. The contract and test scenarios are complete, but no claim is made that an adopting implementation has passed them.
Decision
Run old and new policy engines side by side, but keep exactly one authoritative result per cohort. Log pseudonymous divergences, remediate them, then cut over by bounded cohorts with a reversible policy-version switch.
Scope
- Policy translation, shadow comparison, cohort cutover, session behavior, cache versioning, and rollback.
- Enforcement across synchronous APIs, jobs, exports, search, caches, and administrative tools.
- Evidence needed to retire the old policy.
Outside this block
- Changing product entitlements at the same time as migrating their representation.
- Maintaining two independent sources of truth after migration.
Contract
- Every enforcement request carries tenant, subject, action, resource, and selected policy version.
- Shadow output cannot authorize or deny user actions; only the cohort's authoritative engine can.
- Divergence records classify expected translation differences separately from unexplained allows and denies.
- Permission and decision caches include policy version and tenant scope in their keys.
- Cutover is monotonic per cohort unless an explicit rollback switches that cohort back.
- Old-policy retirement requires zero unexplained high-risk divergences, tested rollback, and coverage of non-HTTP enforcement paths.
Implementation guidance
- Create a canonical permission vocabulary, then adapters from both models.
- Use representative, privacy-reduced decision fixtures and production shadow samples.
- Propagate policy version into sessions or re-evaluate sessions at the enforcement layer after cutover.
- Design rollback to switch authority without reverse-writing partially migrated assignments.
Failure handling and safeguards
- If the new engine is unavailable for a migrated cohort, follow the declared fail-closed or protected fallback policy; never silently use an unversioned cache.
- If divergence volume loses observability, stop cohort expansion.
- If assignment translation is ambiguous, quarantine the assignment for review rather than broadening access.
Verification and operations
- Measure divergence by action/risk class, evaluation latency, cache misses, migration coverage, rollback time, and unexplained authorization failures.
- Gate each cohort on an evidence window and named approver.
- Keep the old engine read-only through the rollback window, then remove all call paths deliberately.
The executable-looking examples in this package are fixtures and acceptance contracts. Run
python tools/validate.py from the collection root to check package structure and metadata; then
implement and execute the scenarios in the target repository.
Adoption assumptions
- Names and numeric values in
example.yamlare an adoption profile, not universal defaults. - The adopting team must map actors, data classes, error vocabulary, and ownership to its system.