@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
Markdown
---
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.