Skip to content

feat(mutations): enforce state-transition invariants and fix migration paths - #1101

Closed
Fury03 wants to merge 1 commit into
CredenceOrg:mainfrom
Fury03:feat/state-transition-invariants
Closed

Fury03 wants to merge 1 commit into
CredenceOrg:mainfrom
Fury03:feat/state-transition-invariants

Conversation

@Fury03

@Fury03 Fury03 commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a formal state-transition matrix to the mutation storage layer that prevents illegal status transitions, and fixes several migration/recovery paths that violated it.

Changes

src/lib/mutationStorage.ts

  • LEGAL_TRANSITIONS matrix: Formal definition of all legal MutationStatus transitions (idle → pending → submitting → success/error, with retry and cancel paths)
  • validateStateTransition(): Validates transitions against the matrix
  • updateMutationOperation(): Now rejects illegal transitions — returns the unmodified operation and logs a warning instead of persisting unauthorized state
  • CreateMutationOptions.migrationStatus: New option on createMutationOperation that allows creating operations directly in a terminal status (e.g. success) for migrating legacy records that are already completed

src/lib/bondActionStorage.ts

  • migrateRecordToMutationSystem(): Fixed to use migrationStatus when creating operations from legacy records with terminal states. Previously tried pending → success which is illegal; now creates directly in the target state.

src/lib/mutationRecovery.ts

  • recoverOperation(): Now transitions idle → pending before setting error (matrix requires it)
  • executeOperationAttempt(): Now transitions error/idle → pending before submitting (matrix requires error → pending → submitting)

src/hooks/useEnhancedBondMutations.ts

  • reset(): Unlinks legacy records (operationId, migratedToV2) without trying to modify terminal states in the unified system

State-Transition Matrix

idle ──▶ pending ──▶ submitting ──▶ success
             │            │
             ▼            ▼
          error ◀───── error
             │
             ▼
         pending (retry)

Terminal states (no outgoing edges): success, cancelled

Invariants Enforced

  • Terminal states (success, cancelled) are immutable — no code path can transition out of them
  • Illegal transitions are rejected at the storage layer (nothing persisted)
  • Migration of legacy terminal-state records uses migrationStatus to bypass the normal lifecycle
  • All recovery paths respect the matrix (idle → pending before error, error → pending before submitting)

Testing

  • 27 state-transition matrix tests passing (all legal + illegal transitions verified)
  • 12 migration/recovery flow tests passing
  • Known issue: vitest crashes with Bus error (core dumped) on Node v24.18.0 (jsdom compatibility); tests verified via extracted pure-logic test harness

🤖 Generated with Codebuff
Co-Authored-By: Codebuff noreply@codebuff.com

…n paths

Add a formal state-transition matrix to the mutation storage layer that
prevents illegal status transitions (e.g. success → error, idle →
submitting). updateMutationOperation now validates every status change
against the matrix and rejects violations, guaranteeing that terminal
states (success, cancelled) are immutable and no partial state can persist.

Key changes:
- Add LEGAL_TRANSITIONS matrix and validateStateTransition() to mutationStorage
- Guard updateMutationOperation to reject illegal transitions
- Add migrationStatus option to createMutationOperation for historical
  reconstruction of legacy records that are already in terminal states
- Fix migrateRecordToMutationSystem to use migrationStatus instead of
  illegally transitioning pending → success
- Fix recoverOperation to transition idle → pending before setting error
- Fix executeOperationAttempt to transition error/idle → pending before
  submitting (matrix requires error → pending → submitting)
- Fix reset() to unlink legacy records without modifying terminal states

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
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.

2 participants