diff --git a/docs/design-principles.md b/docs/design-principles.md index 977583d1..69efed46 100644 --- a/docs/design-principles.md +++ b/docs/design-principles.md @@ -24,6 +24,12 @@ the phased build plan should be traceable back to one of these. - **Safety over speed.** The consequences of a bug are data loss in production systems, so a feature must be *safe* and *safe-by-default* before it is fast. Speed work (parallelism, watermark optimization) only lands on top of a proven-correct path. +- **Make mistakes hard to commit.** An action that is + hard to undo needs explicit, specific intent: a typed acknowledgement naming its target, never + one inferred from an absence or granted broadly. When the engine cannot tell intent from + accident, it refuses. This is why a desired file that no longer lists a column refuses + rather than drops it, and why the destructive acknowledgement names one table and exists only + where the operator wrote the statement. - **Decisions, not options.** Prefer sensible defaults over configuration knobs; non-default options are poorly tested and a source of surprise. The engine should make the right call for the user rather than expose another flag. diff --git a/docs/invariants.md b/docs/invariants.md index 762d3ed7..63218c22 100644 --- a/docs/invariants.md +++ b/docs/invariants.md @@ -1339,7 +1339,8 @@ Each refusal is a preflight **error with a stated reason** — never a warning, intent is explicit. The rename-overlap pattern Spirit refuses (one `ALTER` that renames a column and reuses or retypes it) is unrepresentable: PostgreSQL parses a rename as its own statement and the front door admits one statement (`TestClassifyRejectsARename*`). *Source:* - [low-level-design § declarative safety rules](low-level-design.md#safety-rules-inherited-philosophy-surprise-free-decisions-not-options), Spirit. + [low-level-design § declarative safety rules](low-level-design.md#safety-rules-inherited-philosophy-surprise-free-decisions-not-options), + [make mistakes hard to commit](design-principles.md#make-mistakes-hard-to-commit), Spirit. - **RF-5** — The dangerous literal never runs silently: risky statements with a safer native idiom get the idiom (reported) or a recommendation; running as-submitted requires a loud, typed, audited acknowledgement: `--force` on the routes it governs, or `--accept-blocking` @@ -1414,7 +1415,8 @@ Each refusal is a preflight **error with a stated reason** — never a warning, `TestRunAllowDestructiveDoesNotLiftADropIndexRefusal`, `TestAdmitDestructive`, `TestMigrateDryRunReportsTheDestructiveRefusal`, `TestAllowDestructiveFlagGrammar`, `demo/tour.sh` (`refused_destructive`). *Source:* - [design principles](design-principles.md#declarative-review-first-workflow), + [design principles](design-principles.md#declarative-review-first-workflow) + ([make mistakes hard to commit](design-principles.md#make-mistakes-hard-to-commit)), SchemaBot's `--allow-unsafe` acknowledgement for destructive plans. - **RF-11** — A table is judged idle only when the connected server's statistics prove no use inside the window: no other session holds a lock on it, both last-scan times are recorded