Skip to content

feat(e2): make plan and state loading non-destructive#227

Open
agustif wants to merge 1 commit intopeteromallet:mainfrom
agustif:feat/e2-nondestructive-persistence
Open

feat(e2): make plan and state loading non-destructive#227
agustif wants to merge 1 commit intopeteromallet:mainfrom
agustif:feat/e2-nondestructive-persistence

Conversation

@agustif
Copy link

@agustif agustif commented Mar 4, 2026

Summary

Implements Epic #208 and sub-issues #215 #216 #217 #218.

This PR removes destructive load-time fallback behavior for plan/state persistence and adds explicit safety controls.

What Changed

1) Explicit persistence safety errors

  • Added PersistenceSafetyError for deterministic persistence failures.
  • Added explicit error-code prefixes:
    • DLP_PERSISTENCE_PLAN_*
    • DLP_PERSISTENCE_STATE_*

2) Quarantine snapshot recovery path

  • On unreadable/invalid payloads, loaders now write a *.quarantine.*.json snapshot with:
    • source path
    • reason
    • raw text
  • Load now fails with actionable error instead of silently resetting to empty.

3) Future schema guard

  • Loading future schema versions now fails by default.
  • Added CLI/global recovery override:
    • --allow-unsafe-coerce
  • Unsafe override path is explicitly marked and logged.

4) Non-destructive malformed-section handling

  • Plan/state normalization now preserves malformed sections in _load_quarantine rather than silently dropping data.
  • Added section-level quarantine for:
    • container type mismatches
    • invalid issue payloads (state)
    • invalid skipped entries (plan)

5) Save-path hardening

  • save_plan / save_state now block writes when _unsafe_load_reasons exists.
  • Override is possible only with --allow-unsafe-coerce (manual recovery workflow).
  • Internal unsafe markers are stripped before persistence output.

6) Runtime + CLI wiring

  • Added runtime context flag: allow_unsafe_coerce.
  • Added parser flag: --allow-unsafe-coerce.
  • CLI runtime scope now propagates this setting to persistence loaders/savers.

Test Coverage Added/Updated

  • Added: desloppify/tests/plan/test_persistence_safety.py
  • Updated: desloppify/tests/state/test_state.py

Test Evidence

Executed with local venv (.venv):

  1. python -m pytest desloppify/tests/plan/test_persistence_safety.py desloppify/tests/state/test_state.py -q
  • Result: 66 passed
  1. python -m pytest desloppify/tests/plan/test_schema_migrations.py desloppify/tests/state/test_state_internal_direct.py desloppify/tests/core/test_runtime_state.py desloppify/tests/core/test_config.py -q
  • Result: 54 passed
  1. python -m pytest desloppify/tests/commands/test_cli.py -q
  • Result: 97 passed
  1. python -m compileall -q desloppify
  • Result: success

Tracking

Parent program: #206

@agustif agustif force-pushed the feat/e2-nondestructive-persistence branch from 5cd3f92 to 0674092 Compare March 4, 2026 22:39
@agustif agustif marked this pull request as ready for review March 4, 2026 22:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant