From 421628d49e46be3fce4922fd22f8541b58a235df Mon Sep 17 00:00:00 2001 From: Michael Wolf Date: Sun, 25 Jan 2026 12:11:34 -0600 Subject: [PATCH] Add various doc updates They are still very far from complete. --- docs/commands.md | 125 ++++++++++ docs/concentric-circles.md | 37 +++ docs/freedom-hacking-and-responsibility.md | 142 +++++++++++ docs/groups-and-roles.md | 27 +++ docs/index.md | 17 ++ ...nd-seeders-and-database-table-ownership.md | 34 +++ docs/mutability.md | 1 + docs/nomenclature.md | 11 + docs/ownership.md | 220 +++++++++++++++++- 9 files changed, 613 insertions(+), 1 deletion(-) create mode 100644 docs/commands.md create mode 100644 docs/concentric-circles.md create mode 100644 docs/freedom-hacking-and-responsibility.md create mode 100644 docs/groups-and-roles.md create mode 100644 docs/index.md create mode 100644 docs/migrations-and-seeders-and-database-table-ownership.md create mode 100644 docs/mutability.md diff --git a/docs/commands.md b/docs/commands.md new file mode 100644 index 0000000..273a65c --- /dev/null +++ b/docs/commands.md @@ -0,0 +1,125 @@ +# The Three Types of Commands + +This framework deliberately separates *how* you interact with the system into three distinct command types. The split is not cosmetic; it encodes safety, intent, and operational assumptions directly into the tooling so that mistakes are harder to make under stress. + +The guiding idea: **production should feel boring and safe; exploration should feel powerful and a little dangerous; the application itself should not care how it is being operated.** + +--- + +## 1. Application Commands (`app`) + +**What they are** +Commands defined *by the application itself*, for its own domain needs. They are not part of the framework, even though they are built on top of it. + +The framework provides structure and affordances; the application supplies meaning. + +**Core properties** + +* Express domain behavior, not infrastructure concerns +* Safe by definition +* Deterministic and repeatable +* No environment‑dependent semantics +* Identical behavior in dev, staging, and production + +**Examples** + +* Handling HTTP requests +* Rendering templates +* Running background jobs / queues +* Sending emails triggered by application logic + +**Non‑goals** + +* No schema changes +* No data backfills +* No destructive behavior +* No operational or lifecycle management + +**Rule of thumb** +If removing the framework would require rewriting *how* it runs but not *what* it does, the command belongs here. + +--- + +## 2. Management Commands (`mgmt`) + +**What they are** +Operational, *production‑safe* commands used to evolve and maintain a live system. + +These commands assume real data exists and must not be casually destroyed. + +**Core properties** + +* Forward‑only +* Idempotent or safely repeatable +* Designed to run in production +* Explicit, auditable intent + +**Examples** + +* Applying migrations +* Running seeders that assert invariant data +* Reindexing or rebuilding derived data +* Rotating keys, recalculating counters + +**Design constraints** + +* No implicit rollbacks +* No hidden destructive actions +* Fail fast if assumptions are violated + +**Rule of thumb** +If you would run it at 3am while tired and worried, it must live here. + +--- + +## 3. Development Commands (`develop`) + +**What they are** +Sharp, *unsafe by design* tools meant exclusively for local development and experimentation. + +These commands optimize for speed, learning, and iteration — not safety. + +**Core properties** + +* Destructive operations allowed +* May reset or mutate large amounts of data +* Assume a clean or disposable environment +* Explicitly gated in production + +**Examples** + +* Dropping and recreating databases +* Rolling migrations backward +* Loading fixtures or scenarios +* Generating fake or randomized data + +**Safety model** + +* Hard to run in production +* Requires explicit opt‑in if ever enabled +* Clear, noisy warnings when invoked + +**Rule of thumb** +If it would be irresponsible to run against real user data, it belongs here. + +--- + +## Why This Split Matters + +Many frameworks blur these concerns, leading to: + +* Fearful production operations +* Overpowered dev tools leaking into prod +* Environment‑specific behavior and bugs + +By naming and enforcing these three command types: + +* Intent is visible at the CLI level +* Safety properties are architectural, not cultural +* Developers can move fast *without* normalizing risk + +--- + +## One‑Sentence Summary + +> **App commands run the system, mgmt commands evolve it safely, and develop commands let you break things on purpose — but only where it’s allowed.** diff --git a/docs/concentric-circles.md b/docs/concentric-circles.md new file mode 100644 index 0000000..668ed3a --- /dev/null +++ b/docs/concentric-circles.md @@ -0,0 +1,37 @@ +Let's consider a bullseye with the following concentric circles: + +- Ring 0: small, simple systems + - Single jurisdiction + - Email + password + - A few roles + - Naïve or soft deletion + - Minimal audit needs + +- Ring 1: grown-up systems + - Long-lived data + - Changing requirements + - Shared accounts + - GDPR-style erasure/anonymization + - Some cross-border concerns + - Historical data must remain usable + - “Oops, we should have thought about that” moments + +- Ring 2: heavy compliance + - Formal audit trails + - Legal hold + - Non-repudiation + - Regulatory reporting + - Strong identity guarantees + - Jurisdiction-aware data partitioning + +- Ring 3: banking / defense / healthcare at scale + - Cryptographic auditability + - Append-only ledgers + - Explicit legal models + - Independent compliance teams + - Lawyers embedded in engineeRing + +diachron is designed to be suitable for Rings 0 and 1. Occasionally we may +look over the fence into Ring 2, but it's not what we've principally designed +for. Please take this framing into account when evaluating diachron for +greenfield projects. diff --git a/docs/freedom-hacking-and-responsibility.md b/docs/freedom-hacking-and-responsibility.md new file mode 100644 index 0000000..1f2c568 --- /dev/null +++ b/docs/freedom-hacking-and-responsibility.md @@ -0,0 +1,142 @@ +# Freedom, Hacking, and Responsibility + +This framework is **free and open source software**. + +That fact is not incidental. It is a deliberate ethical, practical, and technical choice. + +This document explains how freedom to modify coexists with strong guidance about *how the framework is meant to be used* — without contradiction, and without apology. + +--- + +## The short version + +* This is free software. You are free to modify it. +* The framework has documented invariants for good reasons. +* You are encouraged to explore, question, and patch. +* You are discouraged from casually undermining guarantees you still expect to rely on. +* Clarity beats enforcement. + +Freedom with understanding beats both lock-in and chaos. + + +--- + +## Your Freedom + +You are free to: + +* study the source code +* run the software for any purpose +* modify it in any way +* fork it +* redistribute it, with or without changes +* submit patches, extensions, or experiments + +…subject only to the terms of the license. + +These freedoms are foundational. They are not granted reluctantly, and they are not symbolic. They exist so that: + +* you can understand what your software is really doing +* you are not trapped by vendor control +* the system can outlive its original authors + +--- + +## Freedom Is Not the Same as Endorsement + +While you are free to change anything, **not all changes are equally wise**. + +Some parts of the framework are carefully constrained because they encode: + +* security assumptions +* lifecycle invariants +* hard-won lessons from real systems under stress + +You are free to violate these constraints in your own fork. + +But the framework’s documentation will often say things like: + +* “do not modify this” +* “application code must not depend on this” +* “this table or class is framework-owned” + +These statements are **technical guidance**, not legal restrictions. + +They exist to answer the question: + +> *If you want this system to remain upgradeable, predictable, and boring — what should you leave alone?* + +--- + +## The Intended Social Contract + +The framework makes a clear offer: + +* We expose our internals so you can learn. +* We provide explicit extension points so you can adapt. +* We document invariants so you don’t have to rediscover them the hard way. + +In return, we ask that: + +* application code respects documented boundaries +* extensions use explicit seams rather than hidden hooks +* patches that change invariants are proposed consciously, not accidentally + +Nothing here is enforced by technical locks. + +It is enforced — insofar as it is enforced at all — by clarity and shared expectations. + +--- + +## Hacking Is Welcome + +Exploration is not just allowed; it is encouraged. + +Good reasons to hack on the framework include: + +* understanding how it works +* evaluating whether its constraints make sense +* adapting it to unfamiliar environments +* testing alternative designs +* discovering better abstractions + +Fork it. Instrument it. Break it. Learn from it. + +Many of the framework’s constraints exist *because* someone once ignored them and paid the price. + +--- + +## Patches, Not Patches-in-Place + +If you discover a problem or a better design: + +* patches are welcome +* discussions are welcome +* disagreements are welcome + +What is discouraged is **quietly patching around framework invariants inside application code**. + +That approach: + +* obscures intent +* creates one-off local truths +* makes systems harder to reason about + +If the framework is wrong, it should be corrected *at the framework level*, or consciously forked. + +--- + +## Why This Is Not a Contradiction + +Strong opinions and free software are not enemies. + +Freedom means you can change the software. + +Responsibility means understanding what you are changing, and why. + +A system that pretends every modification is equally safe is dishonest. + +A system that hides its internals to prevent modification is hostile. + +This framework aims for neither. + diff --git a/docs/groups-and-roles.md b/docs/groups-and-roles.md new file mode 100644 index 0000000..c6a694e --- /dev/null +++ b/docs/groups-and-roles.md @@ -0,0 +1,27 @@ +- Role: a named bundle of responsibilities (editor, admin, member) + +- Group: a scope or context (org, team, project, publication) + +- Permission / Capability (capability preferred in code): a boolean fact about + allowed behavior + + +## tips + +- In the database, capabilities are boolean values. Their names should be + verb-subject. Don't include `can` and definitely do not include `cannot`. + + ✔️ `edit_post` + ❌ `cannot_remove_comment` + +- The capabilities table is deliberately flat. If you need to group them, use + `.` as a delimiter and sort and filter accordingly in queries and in your + UI. + ✔️ `blog.edit_post` + ✔️ `blog.moderate_comment` + or + ✔️ `blog.post.edit` + ✔️ `blog.post.delete` + ✔️ `blog.comment.moderate` + ✔️ `blog.comment.edit` + are all fine. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..934502c --- /dev/null +++ b/docs/index.md @@ -0,0 +1,17 @@ +misc notes for now. of course this needs to be written up for real. + + +## execution context + +The execution context represents facts such as the runtime directory, the +operating system, hardware, and filesystem layout, distinct from environment +variables or request-scoped context. + +## philosophy + +- TODO-DESIGN.md +- concentric-circles.md +- nomenclature.md +- mutability.md +- commands.md +- groups-and-roles.md diff --git a/docs/migrations-and-seeders-and-database-table-ownership.md b/docs/migrations-and-seeders-and-database-table-ownership.md new file mode 100644 index 0000000..a073eda --- /dev/null +++ b/docs/migrations-and-seeders-and-database-table-ownership.md @@ -0,0 +1,34 @@ +Some database tables are owned by diachron and some are owned by the +application. + +This also applies to seeders: some are owned by diachron and some by the +application. + +The database's structure is managed by migrations written in SQL. + +Each migration gets its own file. These files' names should match +`yyyy-mm-dd_ss-description.sql`, eg `2026-01-01_01-users.sql`. + +Files are sorted lexicographically by name and applied in order. + +Note: in the future we may relax or modify the restriction on migration file +names, but they'll continue to be applied in lexicographical order. + +## framework and application migrations + +Migrations owned by the framework are kept in a separate directory from those +owned by applications. Pending framework migrations, if any, are applied +before pending application migrations, if any. + +diachron will go to some lengths to ensure that framework migrations do not +break applications. + +## no downward migrations + +diachron does not provide them. "The only way out is through." + +When developing locally, you can use the command `develop reset-db`. **NEVER +USE THIS IN PRODUCTION!** Always be sure that you can "get back to where you +were". Being careful when creating migrations and seeders can help, but +dumping and restoring known-good copies of the database can also take you a +long way. diff --git a/docs/mutability.md b/docs/mutability.md new file mode 100644 index 0000000..3555291 --- /dev/null +++ b/docs/mutability.md @@ -0,0 +1 @@ +Describe and define what is expected to be mutable and what is not. diff --git a/docs/nomenclature.md b/docs/nomenclature.md index 381e5c9..1b9425e 100644 --- a/docs/nomenclature.md +++ b/docs/nomenclature.md @@ -2,3 +2,14 @@ We use `Call` and `Result` for our own types that wrap `Request` and `Response`. This hopefully will make things less confusing and avoid problems with shadowing. + +## meta + +- We use _algorithmic complexity_ for performance discussions, when + things like Big-O come up, etc + +- We use _conceptual complexity_ for design and architecture + +- We use _cognitive load_ when talking about developer experience + +- We use _operational burden_ when talking about production reality diff --git a/docs/ownership.md b/docs/ownership.md index 9c558e3..5eded9c 100644 --- a/docs/ownership.md +++ b/docs/ownership.md @@ -1 +1,219 @@ -. +# 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 *framework‑owned* and *application‑owned* 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 don’t*, usually during upgrades or emergencies. + +--- + +## Database Ownership + +### Framework‑Owned 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 app‑owned data tightly couples your app to framework internals and blocks safe upgrades. + +--- + +### Application‑Owned Tables + +All domain data belongs to the application. + +Examples: + +* users (as domain actors, not auth primitives) +* posts, orders, comments, invoices +* business‑specific joins and projections +* denormalized or performance‑oriented 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 framework‑exposed identifiers**, or +* introduce **explicit join tables** owned by the application + +No hidden coupling, no magic backfills. + +--- + +## Code Ownership + +### Framework‑Owned Code + +Some classes, constants, and modules are **framework‑owned**. + +These include: + +* core request/response abstractions +* auth and user primitives +* capability/permission evaluation logic +* lifecycle hooks +* low‑level utilities relied on by the framework itself + +#### Rules + +Application code **must not**: + +* modify framework source +* monkey‑patch or override internals +* rely on undocumented behavior +* change constant values or internal defaults + +Framework code is treated as **read‑only** from the app’s 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 trade‑offs + +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 +* forward‑only 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 app’s data or code**. + +--- + +## A Useful Mental Model + +* Framework‑owned things are **constitutional law** +* Application‑owned things are **legislation** + +You can write any laws you want — but you don’t 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** +* Framework‑owned tables and code are read‑only to the app +* Application‑owned 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.