Add local-first recovery contract

This commit is contained in:
Mikhail Chusavitin
2026-03-07 23:16:57 +03:00
parent d2e11b8bdd
commit 5a69e0bba8
3 changed files with 101 additions and 2 deletions

View File

@@ -1,6 +1,6 @@
# Contract: Database Patterns (Go / MySQL / MariaDB)
Version: 1.6
Version: 1.7
## MySQL Transaction Cursor Safety (CRITICAL)
@@ -127,6 +127,7 @@ Rules:
## Migration Policy
- For local-first desktop applications, startup and migration recovery must follow the `local-first-recovery` contract.
- Migrations are numbered sequentially and never modified after merge.
- Trigger, take, and verify a fresh backup through the application-owned backup mechanism before applying migrations to any non-ephemeral database.
- Each migration must be reversible where possible (document rollback in a comment).

View File

@@ -0,0 +1,95 @@
# Contract: Local-First Recovery
Version: 1.1
## Purpose
Shared recovery and migration rules for local-first desktop applications that keep local state and may rebuild part of that state from sync, reload, import, or other deterministic upstream sources.
## Core Rule
A migration or startup strategy is not considered sufficient merely because it succeeded once on the current developer database.
Priority order:
- Priority 1: protect user data. Do not do anything that can damage, discard, or silently rewrite non-recoverable user data.
- Priority 2: preserve availability. Do not do anything that unnecessarily prevents the application from starting or operating in a reduced mode.
If user data is safe, prefer degraded startup over startup failure. If minimum useful functionality can be started safely, start it.
Startup and schema-migration behavior must be designed for degraded real-world states, including:
- legacy schema versions
- interrupted migrations
- stale temp tables
- invalid payloads
- duplicates
- `NULL` in required columns
- partially migrated tables
## Required Data Classification
The architecture must explicitly separate:
- disposable cache tables
- protected user data tables
Definitions:
- Disposable cache tables are read-only, sync-derived, imported, or otherwise rebuildable from a trusted source.
- Protected user data tables contain user-authored or otherwise non-rebuildable data.
Do not mix both classes in one table if recovery semantics differ.
## Availability Policy For Disposable Data
For disposable cache tables, availability has priority.
Rules:
- If a table cannot be migrated safely, it may be quarantined, dropped, or recreated empty.
- The application must continue startup after such recovery.
- The application must restore disposable data through the normal sync, reload, import, or rebuild path.
- Recovery must not require manual SQL intervention for routine degraded states.
## Protection Policy For User Data
For protected user data, destructive reset is forbidden.
Rules:
- Do not drop, truncate, or recreate protected tables as a recovery shortcut.
- Backup-before-change is mandatory and must follow the `backup-management` contract.
- Validate-before-migrate is mandatory.
- Migration logic must use fail-safe semantics: stop before applying a risky destructive step when invariants are broken or input is invalid.
- The application must emit explicit diagnostics that identify the blocked table, migration step, and reason.
## Recovery Logic Requirements
Rules:
- Recovery logic must be deterministic.
- Recovery logic must be idempotent.
- Recovery logic must be retry-safe on every startup.
- Recovery logic must be observable through structured logs.
- Re-running startup after a partial failure must move the system toward a valid state, not deeper into corruption.
## Quality Bar
The application must either:
- self-recover and continue startup
or:
- stop only when continuing would risk loss or corruption of non-recoverable user data
Stopping for disposable cache corruption alone is not acceptable when the data can be rebuilt safely.
If the full feature set cannot be restored safely during startup, the application should start with the minimum safe functionality instead of failing startup, as long as protected user data remains safe.
## Testing Requirements
Degraded and legacy states must be tested explicitly, not only happy-path fresh installs.
Required test coverage includes:
- legacy schema upgrades
- interrupted migration recovery
- partially migrated tables
- duplicate rows where uniqueness is expected
- `NULL` in required columns
- invalid payloads in persisted rows
- disposable-table reset and rebuild flow
- protected-data migration refusal with explicit diagnostics

View File

@@ -1,6 +1,6 @@
# Contract: Testing Policy
Version: 1.0
Version: 1.1
## Purpose
@@ -17,10 +17,13 @@ Version: 1.0
- **Трансформации** — конвертация единиц, нормализация, маппинг полей
- **Бизнес-правила** — расчёты, фильтрация, агрегация, приоритизация
- **Граничные случаи** — пустой ввод, нулевые значения, переполнение, отсутствующие поля
- **Degraded / legacy states** — legacy schema, interrupted migrations, duplicates, invalid persisted rows, partially migrated tables
- **Регрессии** — если баг был найден, тест фиксирует его до исправления
Тест пишется в том же коммите, что и функциональность. Функциональность без теста (там где он обязателен) — неполный коммит.
Для local-first desktop приложений правила деградированных состояний и recovery-тестов определяются также `local-first-recovery` contract.
---
## Когда тест не нужен