Files
diachron/docs/ownership.md
Michael Wolf 421628d49e Add various doc updates
They are still very far from complete.
2026-01-25 12:11:34 -06:00

220 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Framework vs Application Ownership
This document defines **ownership boundaries** between the framework and application code. These boundaries are intentional and non-negotiable: they exist to preserve upgradeability, predictability, and developer sanity under stress.
Ownership answers a simple question:
> **Who is allowed to change this, and under what rules?**
The framework draws a hard line between *frameworkowned* and *applicationowned* concerns, while still encouraging extension through explicit, visible mechanisms.
---
## Core Principle
The framework is not a library of suggestions. It is a **runtime with invariants**.
Application code:
* **uses** the framework
* **extends** it through defined seams
* **never mutates or overrides its invariants**
Framework code:
* guarantees stable behavior
* owns critical lifecycle and security concerns
* must remain internally consistent across versions
Breaking this boundary creates systems that work *until they dont*, usually during upgrades or emergencies.
---
## Database Ownership
### FrameworkOwned Tables
Certain database tables are **owned and managed exclusively by the framework**.
Examples (illustrative, not exhaustive):
* authentication primitives
* session or token state
* internal capability/permission metadata
* migration bookkeeping
* framework feature flags or invariants
#### Rules
Application code **must not**:
* modify schema
* add columns
* delete rows
* update rows directly
* rely on undocumented columns or behaviors
Application code **may**:
* read via documented framework APIs
* reference stable identifiers explicitly exposed by the framework
Think of these tables as **private internal state** — even though they live in your database.
> If the framework needs you to interact with this data, it will expose an API for it.
#### Rationale
These tables:
* encode security or correctness invariants
* may change structure across framework versions
* must remain globally coherent
Treating them as appowned data tightly couples your app to framework internals and blocks safe upgrades.
---
### ApplicationOwned Tables
All domain data belongs to the application.
Examples:
* users (as domain actors, not auth primitives)
* posts, orders, comments, invoices
* businessspecific joins and projections
* denormalized or performanceoriented tables
#### Rules
Application code:
* owns schema design
* owns migrations
* owns constraints and indexes
* may evolve these tables freely
The framework:
* never mutates application tables implicitly
* interacts only through explicit queries or contracts
#### Integration Pattern
Where framework concepts must relate to app data:
* use **foreign keys to frameworkexposed identifiers**, or
* introduce **explicit join tables** owned by the application
No hidden coupling, no magic backfills.
---
## Code Ownership
### FrameworkOwned Code
Some classes, constants, and modules are **frameworkowned**.
These include:
* core request/response abstractions
* auth and user primitives
* capability/permission evaluation logic
* lifecycle hooks
* lowlevel utilities relied on by the framework itself
#### Rules
Application code **must not**:
* modify framework source
* monkeypatch or override internals
* rely on undocumented behavior
* change constant values or internal defaults
Framework code is treated as **readonly** from the apps perspective.
---
### Extension Is Encouraged (But Explicit)
Ownership does **not** mean rigidity.
The framework is designed to be extended via **intentional seams**, such as:
* subclassing
* composition
* adapters
* delegation
* configuration objects
* explicit registration APIs
#### Preferred Patterns
* **Subclass when behavior is stable and conceptual**
* **Compose when behavior is contextual or optional**
* **Delegate when authority should remain with the framework**
What matters is that extension is:
* visible in code
* locally understandable
* reversible
No spooky action at a distance.
---
## What the App Owns Completely
The application fully owns:
* domain models and data shapes
* SQL queries and result parsing
* business rules
* authorization policy *inputs* (not the engine)
* rendering decisions
* feature flags specific to the app
* performance tradeoffs
The framework does not attempt to infer intent from your domain.
---
## What the Framework Guarantees
In return for respecting ownership boundaries, the framework guarantees:
* stable semantics across versions
* forwardonly migrations for its own tables
* explicit deprecations
* no silent behavior changes
* identical runtime behavior in dev and prod
The framework may evolve internally — **but never by reaching into your apps data or code**.
---
## A Useful Mental Model
* Frameworkowned things are **constitutional law**
* Applicationowned things are **legislation**
You can write any laws you want — but you dont amend the constitution inline.
If you need a new power, the framework should expose it deliberately.
---
## Summary
* Ownership is about **who is allowed to change what**
* Frameworkowned tables and code are readonly to the app
* Applicationowned tables and code are sovereign
* Extension is encouraged, mutation is not
* Explicit seams beat clever hacks
Respecting these boundaries keeps systems boring — and boring systems survive stress.