Authorization in Django: From Permissions to Policies — Part 12 — When Boundaries Collapse
Responsibility Drift and the Loss of System Meaning

So far, the system has behaved correctly not because every check succeeded, but because each layer understood where its responsibility ended.
This part examines what happens when those boundaries erode—not through negligence, but through convenience.
Most authorization failures in mature systems are not dramatic. They emerge slowly, as responsibilities drift—when one layer begins answering questions it was never designed to ask.
The failures that follow are subtle, survivable at first, and eventually systemic.
When Permissions Begin to Model State
The first collapse happens quietly.
A permission meant to express capability is modified to express condition. Names begin to encode workflow and state:
publish_draft_articlepublish_own_articlepublish_article_after_review
At a glance, this feels reasonable. The permission name documents intent. The check feels complete.
But something critical has changed. The permission is no longer stable.
Its meaning now depends on article state, ownership, workflow position, or time. Every state transition becomes an authorization event. Permissions must be revoked and re-granted as records move. Migrations begin to encode business rules. Historical meaning dissolves.
Soon, the system can no longer answer a basic question: what does this permission mean independent of today’s workflow?
This is not an access-control failure. It is a loss of identity.
When Policies Attempt to Guarantee Truth
The second collapse is more dangerous because it feels principled.
Policies expand until they resemble proofs. Conditions accumulate:
the article is a draft
the user is the owner
no other publish is in progress
metadata is complete.
The conclusion follows cleanly. All checks are correct. The logic is sound.
And still, the system breaks.
The failure is not in the reasoning, but in the assumption behind it. Policies run before mutation. They operate in a world that has not yet changed. They cannot see concurrent requests, defend against retries, or account for alternate execution paths that bypass the expected flow.
A policy can assert that something should be safe. It cannot ensure that it is safe.
When policies are treated as guarantees, systems fail under load—not because the rules were wrong, but because enforcement was placed too early.
When Invariants Become Optional
The final collapse is the most catastrophic—and the most common.
Invariant checks are omitted for performance. Constraints are removed temporarily. Transactions are narrowed to avoid deadlocks. Each change is justified in isolation, framed as a pragmatic compromise.
The system still works. Most of the time.
Until it doesn’t.
A published article reverts to draft. A finalized record is half-written. Conflicting states coexist. At this point, failure is no longer attributable to a request. There is no user to blame, no policy to revise, no permission to revoke.
The system has violated its own reality.
Recovery becomes forensic rather than corrective.
The Pattern Behind the Failures
Each collapse follows the same shape.
A layer begins answering questions outside its mandate.
Permissions start explaining when.
Policies attempt to enforce truth.
Invariants are treated as advisory rather than absolute.
The system continues to run. Tests still pass. Authorization still appears to work.
But meaning has blurred.
When failures occur, responses become confused. Permission errors surface as business rule violations. Policy failures corrupt data. Invariant violations are silently persisted.
The architecture no longer tells you why something failed—only that it did.
Why This Is Hard to See Early
These failures do not announce themselves.
They emerge during
feature acceleration
refactors under time pressure
background jobs added temporarily
internal tooling that bypasses request flows
Each change is defensible in isolation, often framed as a local optimization or a short-term necessity.
Only later does the pattern become visible—when every authorization decision feels fragile, and no layer can be trusted on its own.
Restoring the Boundary
Systems recover not by adding more checks, but by restoring responsibility:
Permissions return to expressing capability, and nothing more. They define who may attempt an action, without encoding state, timing, or outcome.
Policies return to evaluating context. They determine whether a request is valid in the moment, without pretending to guarantee what will happen next.
Invariants return to the mutation boundary. They are non-negotiable, unavoidable, and final—the last line of defense where reality is enforced, not inferred.
When this separation is restored, failures regain meaning.
A permission failure signals lack of authority. A policy failure signals invalid intent. An invariant failure signals a system defect.
Each failure points to a specific layer. Each can be handled deliberately. Each can be reasoned about in isolation, without ambiguity or overlap.
Where We Go Next (Part 13 Preview)
By the end of this part, the lesson is no longer abstract:
Authorization fails not when checks are missing,
but when guarantees are enforced in the wrong place.
The next—and final—part steps back from mechanics entirely.
It treats authorization not as request logic, but as a long-lived system contract:
one that must survive refactors, scaling, new execution paths, and years of change.
That is where architecture either endures—or decays.
Bibliography / References
Eric Evans (2003). Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley.
https://www.domainlanguage.com/ddd/Martin Fowler (2003). Patterns of Enterprise Application Architecture. Addison-Wesley.
https://martinfowler.com/books/eaa.htmlMartin Kleppmann (2017). Designing Data-Intensive Applications. O’Reilly Media.
https://dataintensive.net/Pat Helland (2007). Life Beyond Distributed Transactions: An Apostate’s Opinion. ACM Queue.
https://queue.acm.org/detail.cfm?id=1295698Michael T. Nygard (2018). Release It! Design and Deploy Production-Ready Software. Pragmatic Bookshelf.
https://pragprog.com/titles/mnee2/release-it-second-edition/Django Software Foundation. Django Authentication and Authorization System. Official Django Documentation.
https://docs.djangoproject.com/en/stable/topics/auth/



