Migration System Specification
Version: 1.0.0 Status: Draft Created: 2025-12-23 Purpose: Simplified, SOLID, DRY migration system for cleo schema evolution1. Overview
1.1 Problem Statement
The current migration system has accumulated complexity:- Multiple version sources (VERSION, lib/migrate.sh constants, template files, schema $id)
- Every schema change requires manual migration function creation
- No distinction between safe changes (relaxations) and breaking changes
- Conflation of schema migration with backup reorganization
1.2 Goals
- Single Source of Truth: One authoritative location for schema version
- Automated Classification: Determine migration requirements from version semantics
- Skip Safe Changes: Constraint relaxations and optional additions require no data transformation
- Clear Separation: Schema migration vs backup taxonomy vs validation vs repair
1.3 Non-Goals
- Automatic schema diffing (too complex, error-prone)
- Supporting downgrades (one-way migration only)
- Cross-major-version jumps in single step (must migrate through intermediate versions)
2. Version Management
2.1 Version Types
| Version Type | Location | Purpose | Example |
|---|---|---|---|
| App Version | VERSION file | Release tracking, user-facing | 0.32.4 |
| Schema Version | schemas/*.schema.json | Data structure compatibility | 2.5.0 |
| Data Version | .cleo/todo.json#.version | Records schema data conforms to | 2.4.0 |
| Spec Version | Schema $id field | Specification document version | v3.1 |
2.2 Single Source of Truth
Schema version lives in the schema file itself:2.3 Semver Semantics for Schema
Schema versions follow strict semantic versioning with specific meanings:| Segment | Meaning | Migration Required | Example Changes |
|---|---|---|---|
| MAJOR | Breaking structural changes | YES (complex) | Type changes, incompatible restructuring |
| MINOR | Additive changes requiring defaults | YES (simple) | Required field addition, field rename |
| PATCH | Backward-compatible relaxations | NO | maxLength increase, optional field addition |
3. Change Type Classification
3.1 Decision Matrix
| Change Type | Version Bump | Migration Action | Validation Action |
|---|---|---|---|
| Constraint relaxation (maxLength increase) | PATCH | Version bump only | None |
| Pattern loosening | PATCH | Version bump only | None |
| Enum value addition | PATCH | Version bump only | None |
| Optional field addition | PATCH | Version bump only | None |
| Default value change | PATCH | Version bump only | None |
| Constraint tightening (maxLength decrease) | MINOR | Check + truncate/warn | Verify compliance |
| Required field addition | MINOR | Add with defaults | Verify presence |
| Field rename | MINOR | Rename in data | Verify new name exists |
| Field removal | MINOR | Remove from data | None (cleanup) |
| Enum value removal | MINOR | Map to replacement | Verify no orphans |
| Structural change (e.g., string to object) | MAJOR | Transform structure | Verify new structure |
| Type change | MAJOR | Convert values | Verify new types |
3.2 Classification Rules
3.3 Safe Change Examples (PATCH - No Migration)
3.4 Migration Required Examples (MINOR/MAJOR)
4. Migration Flow
4.1 Detection Algorithm
4.2 Execution Flow
4.3 Migration Function Naming Convention
4.4 Migration Path Resolution
For multi-version jumps, migrations execute sequentially:5. Component Responsibilities
5.1 Separation of Concerns
5.2 Module Responsibilities
| Module | Responsibility | Does NOT Handle |
|---|---|---|
lib/migrate.sh | Version detection, migration functions, path resolution | Backup creation (delegates), validation (delegates) |
lib/validation.sh | Schema validation, constraint checking | Data transformation, version management |
lib/backup.sh | Backup creation, restoration, rotation | Migration logic, validation |
lib/file-ops.sh | Atomic writes, file operations | Migration logic, version semantics |
scripts/migrate.sh | CLI interface for migration commands | Core migration logic (delegates to lib) |
scripts/reorganize-backups.sh | Legacy backup reorganization (SEPARATE concern) | Schema migration |
5.3 Backup Taxonomy Migration (Separate System)
The backup directory reorganization (.cleo/.backups/ to .cleo/backups/{type}/) is a completely separate concern from schema migration:
- Different trigger: Legacy directory exists vs schema version mismatch
- Different frequency: One-time operation vs ongoing schema evolution
- Different scope: File system layout vs data structure
reorganize-backups.sh to reorganize-backups.sh to avoid confusion.
6. Implementation Guidelines
6.1 Adding a PATCH Release (No Migration)
- Update schema file with relaxed constraints or optional fields
- Increment PATCH in
schemaVersionfield - No migration function needed
- Existing data automatically compatible
6.2 Adding a MINOR Release (Simple Migration)
- Update schema file with new required fields or renames
- Increment MINOR in
schemaVersionfield (reset PATCH to 0) - Add migration function:
- Register in migration path (if not auto-discovered)
6.3 Adding a MAJOR Release (Complex Migration)
- Update schema file with structural changes
- Increment MAJOR in
schemaVersion(reset MINOR and PATCH to 0) - Add comprehensive migration function with:
- Data structure transformation
- Value conversion
- Validation checks
- Document breaking changes
- Consider multi-step migration path
6.4 Migration Function Template
7. CLI Interface
7.1 Commands
7.2 JSON Output
8. Error Handling
8.1 Error Codes
| Code | Meaning | Action |
|---|---|---|
E_VERSION_MISMATCH | Data version newer than schema | Cannot downgrade; manual intervention |
E_MIGRATION_MISSING | No function for required migration | Developer must add migration |
E_MIGRATION_FAILED | Migration function returned error | Auto-restore from backup |
E_VALIDATION_FAILED | Post-migration validation failed | Auto-restore from backup |
E_BACKUP_FAILED | Could not create pre-migration backup | Abort migration |
8.2 Recovery Flow
9. Appendix
A.1 Current Version Inventory (As-Is)
| Source | Current Value | Proposed Change |
|---|---|---|
VERSION | 0.32.4 | Keep as app version (unchanged) |
lib/migrate.sh SCHEMA_VERSION_TODO | 2.4.0 | Remove; read from schema file |
schemas/todo.schema.json | No schemaVersion field | Add "schemaVersion": "2.4.0" |
templates/todo.template.json#.version | 2.2.0 | Update to match schema; or read dynamically |
A.2 Migration from Current System
- Add
schemaVersionfield to all schema files - Remove hardcoded SCHEMA_VERSION_* constants from lib/migrate.sh
- Update
get_expected_version()to read from schema files - Update templates to reference schema version dynamically
- Test with existing migration functions (should work unchanged)
A.3 Example: v2.4.0 to v2.4.1 (PATCH - Notes maxLength)
Schema change:A.4 Example: v2.4.0 to v2.5.0 (MINOR - Required Field)
Schema change:10. References
- SOLID Principles: Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion
- DRY: Don’t Repeat Yourself
- Semver: https://semver.org/
- JSON Schema: https://json-schema.org/
- Related specs: BACKUP-SYSTEM-SPEC.md, CONFIG-SYSTEM-SPEC.md
