Files
cleveragents-core/features/plan_resume_fields_persistence.feature
freemo 77251e7623
CI / lint (pull_request) Successful in 30s
CI / quality (pull_request) Successful in 33s
CI / typecheck (pull_request) Successful in 54s
CI / security (pull_request) Successful in 1m5s
CI / build (pull_request) Successful in 28s
CI / helm (pull_request) Successful in 23s
CI / unit_tests (pull_request) Failing after 6m41s
CI / docker (pull_request) Has been skipped
CI / e2e_tests (pull_request) Successful in 20m49s
CI / integration_tests (pull_request) Successful in 23m3s
CI / coverage (pull_request) Successful in 10m30s
CI / status-check (pull_request) Failing after 1s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Successful in 57m32s
fix(persistence): persist reversion_count, last_completed_step, and last_checkpoint_id on LifecyclePlanModel
Implemented persistence for three previously missing Plan fields to ensure proper resume and reversion behavior across restarts. The changes address the gaps in the database, ORM mapping, repository logic, and tests.

- Alembic migration
  - File: alembic/versions/m9_002_plan_resume_fields.py
  - Adds three columns to the v3_plans table:
    - reversion_count: INTEGER NOT NULL DEFAULT 0 (server_default)
    - last_completed_step: INTEGER NOT NULL DEFAULT -1 (server_default)
    - last_checkpoint_id: TEXT nullable (no server_default)
  - Migration chains from m9_001_session_name_column to align with existing plan schema evolution.

- SQLAlchemy model
  - File: src/cleveragents/infrastructure/database/models.py
  - Updated LifecyclePlanModel to include reversion_count, last_completed_step, and last_checkpoint_id columns.
  - from_domain(): updated to serialize all three fields.
  - to_domain(): updated to deserialize all three fields with proper cast() typing, ensuring correct domain conversions.

- Repository fix
  - File: src/cleveragents/infrastructure/database/repositories.py
  - Fixed LifecyclePlanRepository.update() which was silently dropping the three fields on every update.
  - This remediation ensures updates preserve reversion_count, last_completed_step, and last_checkpoint_id.

- Behave tests
  - Files: features/plan_resume_fields_persistence.feature and associated steps
  - Added 7 scenarios validating individual field persistence, combined persistence, default values, cross-reconnection persistence, and update persistence.
  - Tests ensure correctness of persistence behavior across restarts and updates.

Key Design Decisions
- server_default used for migration columns to backfill defaults automatically for existing rows without a separate backfill step.
- last_checkpoint_id is nullable (no server_default) because None is the correct default in the domain model.
- The update() fix in LifecyclePlanRepository was a bonus discovery; without it, updates could silently drop the resume fields and break persistence guarantees.

ISSUES CLOSED: #2864
2026-04-05 04:38:31 +00:00

71 lines
3.6 KiB
Gherkin

Feature: Plan resume fields round-trip persistence
As a developer
I want reversion_count, last_completed_step, and last_checkpoint_id to persist through the database
So that plan resume and reversion limits work correctly after process restarts
Background:
Given a fresh in-memory plan persistence database
And a prerequisite action "local/persist-action" exists in the database
Scenario: reversion_count persists through database round-trip
Given a new lifecycle plan with ID "01HV000000000000000000RP01"
And the plan has reversion_count 2
When I persist the plan via the plan repository
And I retrieve the plan by ID "01HV000000000000000000RP01"
Then the retrieved plan reversion_count should be 2
Scenario: last_completed_step persists through database round-trip
Given a new lifecycle plan with ID "01HV000000000000000000RP02"
And the plan has last_completed_step 4
When I persist the plan via the plan repository
And I retrieve the plan by ID "01HV000000000000000000RP02"
Then the retrieved plan last_completed_step should be 4
Scenario: last_checkpoint_id persists through database round-trip
Given a new lifecycle plan with ID "01HV000000000000000000RP03"
And the plan has last_checkpoint_id "01HV000000000000000000CP01"
When I persist the plan via the plan repository
And I retrieve the plan by ID "01HV000000000000000000RP03"
Then the retrieved plan last_checkpoint_id should be "01HV000000000000000000CP01"
Scenario: All three resume fields persist together through database round-trip
Given a new lifecycle plan with ID "01HV000000000000000000RP04"
And the plan has reversion_count 1
And the plan has last_completed_step 3
And the plan has last_checkpoint_id "01HV000000000000000000CP02"
When I persist the plan via the plan repository
And I retrieve the plan by ID "01HV000000000000000000RP04"
Then the retrieved plan reversion_count should be 1
And the retrieved plan last_completed_step should be 3
And the retrieved plan last_checkpoint_id should be "01HV000000000000000000CP02"
Scenario: Default values persist correctly when fields are not set
Given a new lifecycle plan with ID "01HV000000000000000000RP05"
When I persist the plan via the plan repository
And I retrieve the plan by ID "01HV000000000000000000RP05"
Then the retrieved plan reversion_count should be 0
And the retrieved plan last_completed_step should be -1
And the retrieved plan last_checkpoint_id should be None
Scenario: Resume fields persist across database reconnection
Given the plan persistence database is file-based
And a prerequisite action "local/persist-action" exists in the database
And a new lifecycle plan with ID "01HV000000000000000000RP06"
And the plan has reversion_count 3
And the plan has last_completed_step 5
And the plan has last_checkpoint_id "01HV000000000000000000CP03"
When I persist the plan via the plan repository
And I close and reopen the persistence database
And I retrieve the plan by ID "01HV000000000000000000RP06"
Then the retrieved plan reversion_count should be 3
And the retrieved plan last_completed_step should be 5
And the retrieved plan last_checkpoint_id should be "01HV000000000000000000CP03"
Scenario: Updated reversion_count persists after plan update
Given a new lifecycle plan with ID "01HV000000000000000000RP07"
And the plan has reversion_count 0
When I persist the plan via the plan repository
And I update the plan reversion_count to 2
And I retrieve the plan by ID "01HV000000000000000000RP07"
Then the retrieved plan reversion_count should be 2