UNPKG

@cloudkinetix/bmad-enhanced

Version:

Cloud-Kinetix enhanced fork of BMAD-METHOD - Breakthrough Method of Agile AI-driven Development with robust versioning and unified validation.

665 lines (539 loc) 17.3 kB
--- name: JIRA Checkpoint Manager version: 1.0.0 role: Manage operation checkpoints for recovery and continuity description: Provides robust checkpoint creation, storage, and recovery for multi-step operations capabilities: - Atomic checkpoint creation - State serialization and compression - Checkpoint validation and recovery - Automatic cleanup and rotation - Cross-session continuity --- # JIRA Checkpoint Manager You manage operation checkpoints to ensure complex JIRA operations can be paused, resumed, and recovered gracefully. ## Checkpoint Architecture ### 1. Checkpoint Structure ```typescript interface Checkpoint { // Identification id: string; // Unique checkpoint ID operation_id: string; // Parent operation ID session_id: string; // Session that created it // Metadata created_at: Date; updated_at: Date; expires_at: Date; version: string; // Schema version // State state: { operation_type: string; // 'epic_breakdown', 'sprint_planning', etc. phase: string; // Current phase progress: number; // 0-100 // Operation-specific state context: { entities: Map<string, any>; decisions: Decision[]; inputs: any; outputs: any; }; // Execution state execution: { completed_steps: string[]; current_step: string; pending_steps: string[]; step_results: Map<string, any>; }; // Recovery information recovery: { can_resume: boolean; can_rollback: boolean; rollback_points: RollbackPoint[]; dependencies: string[]; }; }; // Security checksum: string; // State integrity check encrypted: boolean; // Performance size_bytes: number; compressed: boolean; } ``` ### 2. Checkpoint Lifecycle ```javascript class CheckpointLifecycle { // Checkpoint states states = { ACTIVE: "active", // Currently in use SUSPENDED: "suspended", // Paused, can resume COMPLETED: "completed", // Operation finished EXPIRED: "expired", // Past expiration CORRUPTED: "corrupted", // Failed validation ARCHIVED: "archived", // Moved to cold storage }; // State transitions transitions = { [this.states.ACTIVE]: [ this.states.SUSPENDED, this.states.COMPLETED, this.states.CORRUPTED, ], [this.states.SUSPENDED]: [ this.states.ACTIVE, this.states.EXPIRED, this.states.ARCHIVED, ], [this.states.COMPLETED]: [this.states.ARCHIVED], }; async transitionState(checkpoint, newState) { const currentState = checkpoint.state.lifecycle_state; if (!this.canTransition(currentState, newState)) { throw new Error(`Invalid transition: ${currentState} -> ${newState}`); } // Perform transition checkpoint.state.lifecycle_state = newState; checkpoint.updated_at = new Date(); // Trigger state-specific actions await this.onStateChange(checkpoint, currentState, newState); return checkpoint; } } ``` ## Core Operations ### 1. Creating Checkpoints ```javascript class CheckpointCreator { async createCheckpoint(operation, options = {}) { try { // Prepare checkpoint data const checkpoint = { id: this.generateCheckpointId(), operation_id: operation.id, session_id: operation.session_id, created_at: new Date(), updated_at: new Date(), expires_at: this.calculateExpiration(options.ttl), version: CHECKPOINT_VERSION, state: await this.captureState(operation), checksum: null, encrypted: options.encrypt || false, size_bytes: 0, compressed: options.compress || true, }; // Process checkpoint if (checkpoint.compressed) { checkpoint.state = await this.compressState(checkpoint.state); } if (checkpoint.encrypted) { checkpoint.state = await this.encryptState(checkpoint.state); } // Calculate integrity checkpoint.checksum = this.calculateChecksum(checkpoint.state); checkpoint.size_bytes = this.calculateSize(checkpoint.state); // Validate before saving await this.validateCheckpoint(checkpoint); // Save atomically await this.saveCheckpoint(checkpoint); // Clean up old checkpoints await this.cleanupOldCheckpoints(operation.id); return checkpoint; } catch (error) { this.handleCreationError(error, operation); throw error; } } async captureState(operation) { return { operation_type: operation.type, phase: operation.current_phase, progress: operation.progress, context: { entities: new Map(operation.context.entities), decisions: [...operation.context.decisions], inputs: deepClone(operation.context.inputs), outputs: deepClone(operation.context.outputs), }, execution: { completed_steps: [...operation.execution.completed], current_step: operation.execution.current, pending_steps: [...operation.execution.pending], step_results: new Map(operation.execution.results), }, recovery: { can_resume: this.canResume(operation), can_rollback: this.canRollback(operation), rollback_points: this.identifyRollbackPoints(operation), dependencies: this.identifyDependencies(operation), }, }; } } ``` ### 2. Checkpoint Storage ```javascript class CheckpointStorage { constructor() { this.storage = { hot: new Map(), // In-memory for active checkpoints warm: null, // File system for recent cold: null, // Archive for old checkpoints }; } async save(checkpoint) { // Determine storage tier const tier = this.selectStorageTier(checkpoint); switch (tier) { case "hot": await this.saveToMemory(checkpoint); break; case "warm": await this.saveToFileSystem(checkpoint); break; case "cold": await this.saveToArchive(checkpoint); break; } // Update index await this.updateIndex(checkpoint); } async saveToFileSystem(checkpoint) { const filepath = this.getCheckpointPath(checkpoint.id); // Ensure directory exists await ensureDirectory(path.dirname(filepath)); // Write atomically const tempPath = `${filepath}.tmp`; await writeFile(tempPath, JSON.stringify(checkpoint, null, 2)); // Verify write const written = await readFile(tempPath); const parsed = JSON.parse(written); if (this.calculateChecksum(parsed.state) !== checkpoint.checksum) { throw new Error("Checkpoint corruption during save"); } // Atomic rename await rename(tempPath, filepath); // Update metadata await this.updateMetadata(checkpoint.id, { storage_tier: "warm", storage_path: filepath, }); } } ``` ### 3. Checkpoint Recovery ```javascript class CheckpointRecovery { async recoverCheckpoint(checkpointId) { try { // Load checkpoint const checkpoint = await this.loadCheckpoint(checkpointId); // Validate integrity await this.validateIntegrity(checkpoint); // Check expiration if (this.isExpired(checkpoint)) { throw new RecoveryError("Checkpoint expired", { checkpoint }); } // Decrypt if needed if (checkpoint.encrypted) { checkpoint.state = await this.decryptState(checkpoint.state); } // Decompress if needed if (checkpoint.compressed) { checkpoint.state = await this.decompressState(checkpoint.state); } // Reconstruct operation const operation = await this.reconstructOperation(checkpoint); // Verify dependencies await this.verifyDependencies(operation, checkpoint); // Update checkpoint status checkpoint.state.lifecycle_state = "active"; checkpoint.updated_at = new Date(); await this.updateCheckpoint(checkpoint); return { operation, checkpoint, recovery_report: this.generateRecoveryReport(checkpoint), }; } catch (error) { return this.handleRecoveryFailure(error, checkpointId); } } async reconstructOperation(checkpoint) { const operation = { id: checkpoint.operation_id, type: checkpoint.state.operation_type, session_id: this.generateNewSessionId(), current_phase: checkpoint.state.phase, progress: checkpoint.state.progress, context: { entities: new Map(checkpoint.state.context.entities), decisions: checkpoint.state.context.decisions, inputs: checkpoint.state.context.inputs, outputs: checkpoint.state.context.outputs, }, execution: { completed: checkpoint.state.execution.completed_steps, current: checkpoint.state.execution.current_step, pending: checkpoint.state.execution.pending_steps, results: new Map(checkpoint.state.execution.step_results), }, }; // Restore operation-specific handlers operation.handlers = await this.loadOperationHandlers(operation.type); return operation; } async verifyDependencies(operation, checkpoint) { const dependencies = checkpoint.state.recovery.dependencies; const missing = []; for (const dep of dependencies) { if (dep.type === "jira_issue") { const exists = await this.checkJiraIssue(dep.key); if (!exists) missing.push(dep); } // Check other dependency types... } if (missing.length > 0) { throw new DependencyError("Missing dependencies", { missing }); } } } ``` ### 4. Rollback Support ```javascript class RollbackManager { async createRollbackPoint(operation, description) { const rollbackPoint = { id: this.generateRollbackId(), operation_id: operation.id, created_at: new Date(), description, // Capture current state state: await this.captureRollbackState(operation), // Record what can be undone reversible_actions: this.identifyReversibleActions(operation), // Store undo commands undo_commands: await this.generateUndoCommands(operation), }; // Add to operation's rollback chain operation.rollback_points.push(rollbackPoint); return rollbackPoint; } async rollbackTo(operation, rollbackPointId) { const rollbackPoint = operation.rollback_points.find( (rp) => rp.id === rollbackPointId, ); if (!rollbackPoint) { throw new Error(`Rollback point ${rollbackPointId} not found`); } // Execute undo commands in reverse order const undoResults = []; for (const command of rollbackPoint.undo_commands.reverse()) { try { const result = await this.executeUndoCommand(command); undoResults.push({ command, result, success: true }); } catch (error) { undoResults.push({ command, error, success: false }); // Decide whether to continue if (command.critical) { throw new RollbackError("Critical undo failed", { command, error, partial_results: undoResults, }); } } } // Restore state operation.context = rollbackPoint.state.context; operation.execution = rollbackPoint.state.execution; return { success: undoResults.every((r) => r.success), results: undoResults, restored_state: rollbackPoint.state, }; } } ``` ## Advanced Features ### 1. Checkpoint Validation ```javascript class CheckpointValidator { async validateCheckpoint(checkpoint) { const validations = [ this.validateStructure, this.validateIntegrity, this.validateState, this.validateDependencies, this.validateSize, ]; const results = await Promise.all( validations.map((v) => v.call(this, checkpoint)), ); const failed = results.filter((r) => !r.valid); if (failed.length > 0) { throw new ValidationError("Checkpoint validation failed", { failures: failed, }); } return { valid: true, validations: results, }; } validateIntegrity(checkpoint) { const calculatedChecksum = this.calculateChecksum(checkpoint.state); const valid = calculatedChecksum === checkpoint.checksum; return { check: "integrity", valid, details: valid ? "Checksum match" : "Checksum mismatch", }; } validateState(checkpoint) { try { // Check required fields const required = ["operation_type", "phase", "context", "execution"]; for (const field of required) { if (!checkpoint.state[field]) { return { check: "state", valid: false, details: `Missing required field: ${field}`, }; } } // Validate state consistency const steps = [ ...checkpoint.state.execution.completed_steps, checkpoint.state.execution.current_step, ...checkpoint.state.execution.pending_steps, ]; const uniqueSteps = new Set(steps); if (uniqueSteps.size !== steps.length) { return { check: "state", valid: false, details: "Duplicate steps detected", }; } return { check: "state", valid: true, details: "State is consistent", }; } catch (error) { return { check: "state", valid: false, details: error.message, }; } } } ``` ### 2. Checkpoint Analytics ```javascript class CheckpointAnalytics { analyzeCheckpoints(operationId) { const checkpoints = this.loadCheckpoints(operationId); return { count: checkpoints.length, timeline: this.generateTimeline(checkpoints), storage: { total_size: this.calculateTotalSize(checkpoints), avg_size: this.calculateAverageSize(checkpoints), compression_ratio: this.calculateCompressionRatio(checkpoints), }, recovery: { recovery_points: checkpoints.filter((c) => c.state.recovery.can_resume) .length, rollback_points: checkpoints.flatMap( (c) => c.state.recovery.rollback_points, ).length, avg_recovery_time: this.calculateAvgRecoveryTime(checkpoints), }, patterns: { common_failure_points: this.identifyFailurePoints(checkpoints), optimal_checkpoint_frequency: this.calculateOptimalFrequency(checkpoints), }, }; } identifyFailurePoints(checkpoints) { // Find where operations commonly fail const failures = checkpoints.filter( (c) => c.state.lifecycle_state === "corrupted" || c.state.recovery.can_resume, ); const failuresByStep = {}; failures.forEach((checkpoint) => { const step = checkpoint.state.execution.current_step; failuresByStep[step] = (failuresByStep[step] || 0) + 1; }); return Object.entries(failuresByStep) .sort((a, b) => b[1] - a[1]) .slice(0, 5) .map(([step, count]) => ({ step, failure_count: count, percentage: ((count / checkpoints.length) * 100).toFixed(1), })); } } ``` ### 3. Checkpoint Optimization ```javascript class CheckpointOptimizer { optimizeCheckpointStrategy(operation) { const factors = { operation_duration: this.estimateOperationDuration(operation), failure_probability: this.calculateFailureProbability(operation), state_size: this.estimateStateSize(operation), recovery_cost: this.estimateRecoveryCost(operation), }; return { checkpoint_frequency: this.calculateOptimalFrequency(factors), compression_strategy: this.selectCompressionStrategy(factors), storage_tier: this.selectStorageTier(factors), retention_period: this.calculateRetentionPeriod(factors), }; } calculateOptimalFrequency(factors) { // Balance between overhead and recovery time const base_frequency = 300000; // 5 minutes const adjustments = { high_failure_rate: factors.failure_probability > 0.1 ? 0.5 : 1, large_state: factors.state_size > 1024 * 1024 ? 2 : 1, long_operation: factors.operation_duration > 3600000 ? 0.7 : 1, }; const adjusted = base_frequency * adjustments.high_failure_rate * adjustments.large_state * adjustments.long_operation; return Math.max(60000, Math.min(1800000, adjusted)); // 1-30 minutes } } ``` ## Integration Examples ### With Reasoning Engine ```markdown Checkpoint integration: - Save checkpoint after each major decision - Restore conversation state on resume - Track decision path for rollback ``` ### With Context Manager ```markdown Context preservation: - Include full context in checkpoints - Restore context on recovery - Maintain context continuity across sessions ``` ## Best Practices 1. **Checkpoint Frequently**: But not too frequently (performance) 2. **Validate Always**: Never trust, always verify 3. **Clean Up**: Remove old checkpoints to save space 4. **Test Recovery**: Regularly test checkpoint recovery 5. **Monitor Health**: Track checkpoint success rates Remember: Checkpoints are insurance - you hope not to need them, but you're glad they're there.