Step 590: add crash recovery reliability sweep

This commit is contained in:
Bill
2026-02-17 11:27:22 -07:00
parent a9dfab4d03
commit cc1136f698
4 changed files with 301 additions and 0 deletions

View File

@@ -4189,4 +4189,13 @@ target_link_libraries(step589_test PRIVATE
tree_sitter_javascript tree_sitter_typescript
tree_sitter_java tree_sitter_rust tree_sitter_go)
add_executable(step590_test tests/step590_test.cpp)
target_include_directories(step590_test PRIVATE src)
target_link_libraries(step590_test PRIVATE
nlohmann_json::nlohmann_json
unofficial::tree-sitter::tree-sitter
tree_sitter_python tree_sitter_cpp tree_sitter_elisp
tree_sitter_javascript tree_sitter_typescript
tree_sitter_java tree_sitter_rust tree_sitter_go)
# Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies)

View File

@@ -0,0 +1,73 @@
#pragma once
// Step 590: Crash + Recovery Reliability Sweep
#include <map>
#include <string>
#include <vector>
struct RecoverySessionSnapshot {
std::string sessionId;
std::string workflowId;
int checkpoint = 0;
std::vector<std::string> openBuffers;
std::vector<std::string> queuedTaskIds;
};
struct RecoveryResult {
bool recovered = false;
bool workflowContinuity = false;
bool queueContinuity = false;
bool bufferContinuity = false;
std::vector<std::string> notes;
};
class CrashRecoveryReliabilitySweep {
public:
bool captureSnapshot(const RecoverySessionSnapshot& snapshot, std::string* error) {
if (!error) return false;
error->clear();
if (snapshot.sessionId.empty()) return fail(error, "session_id_missing");
if (snapshot.workflowId.empty()) return fail(error, "workflow_id_missing");
if (snapshot.checkpoint <= 0) return fail(error, "checkpoint_invalid");
snapshots_[snapshot.sessionId] = snapshot;
return true;
}
RecoveryResult recover(const std::string& sessionId) const {
RecoveryResult result;
auto it = snapshots_.find(sessionId);
if (it == snapshots_.end()) {
result.notes.push_back("recover:session_missing");
return result;
}
const auto& s = it->second;
result.workflowContinuity = !s.workflowId.empty() && s.checkpoint > 0;
result.queueContinuity = !s.queuedTaskIds.empty();
result.bufferContinuity = !s.openBuffers.empty();
result.recovered = result.workflowContinuity && result.queueContinuity && result.bufferContinuity;
if (result.recovered) {
result.notes.push_back("recover:ok");
} else {
result.notes.push_back("recover:partial");
if (!result.workflowContinuity) result.notes.push_back("recover:workflow_missing");
if (!result.queueContinuity) result.notes.push_back("recover:queue_missing");
if (!result.bufferContinuity) result.notes.push_back("recover:buffers_missing");
}
return result;
}
std::vector<std::string> knownSessions() const {
std::vector<std::string> ids;
for (const auto& kv : snapshots_) ids.push_back(kv.first);
return ids;
}
private:
std::map<std::string, RecoverySessionSnapshot> snapshots_;
static bool fail(std::string* error, const char* code) {
*error = code;
return false;
}
};

View File

@@ -0,0 +1,186 @@
// Step 590: Crash + Recovery Reliability Sweep (12 tests)
#include "CrashRecoveryReliabilitySweep.h"
#include <iostream>
static int passed = 0, failed = 0;
#define TEST(name) { std::cout << " " << #name << "... "; }
#define PASS() { std::cout << "PASS\n"; ++passed; }
#define FAIL(msg) { std::cout << "FAIL: " << msg << "\n"; ++failed; }
#define CHECK(cond, msg) if (!(cond)) { FAIL(msg); return; } else {}
static RecoverySessionSnapshot snap(const std::string& sessionId) {
RecoverySessionSnapshot s;
s.sessionId = sessionId;
s.workflowId = "wf-1";
s.checkpoint = 3;
s.openBuffers = {"a.cpp"};
s.queuedTaskIds = {"task-1"};
return s;
}
static bool hasNote(const RecoveryResult& r, const std::string& note) {
for (const auto& n : r.notes) if (n == note) return true;
return false;
}
void test_capture_snapshot_success() {
TEST(capture_snapshot_success);
CrashRecoveryReliabilitySweep sweep;
std::string error;
CHECK(sweep.captureSnapshot(snap("s1"), &error), "capture should succeed");
CHECK(sweep.knownSessions().size() == 1, "session should be stored");
PASS();
}
void test_capture_snapshot_rejects_missing_session() {
TEST(capture_snapshot_rejects_missing_session);
CrashRecoveryReliabilitySweep sweep;
std::string error;
auto s = snap("");
CHECK(!sweep.captureSnapshot(s, &error), "capture should fail");
CHECK(error == "session_id_missing", "wrong error");
PASS();
}
void test_capture_snapshot_rejects_missing_workflow() {
TEST(capture_snapshot_rejects_missing_workflow);
CrashRecoveryReliabilitySweep sweep;
std::string error;
auto s = snap("s1");
s.workflowId.clear();
CHECK(!sweep.captureSnapshot(s, &error), "capture should fail");
CHECK(error == "workflow_id_missing", "wrong error");
PASS();
}
void test_capture_snapshot_rejects_invalid_checkpoint() {
TEST(capture_snapshot_rejects_invalid_checkpoint);
CrashRecoveryReliabilitySweep sweep;
std::string error;
auto s = snap("s1");
s.checkpoint = 0;
CHECK(!sweep.captureSnapshot(s, &error), "capture should fail");
CHECK(error == "checkpoint_invalid", "wrong error");
PASS();
}
void test_recover_success_when_all_continuity_present() {
TEST(recover_success_when_all_continuity_present);
CrashRecoveryReliabilitySweep sweep;
std::string error;
CHECK(sweep.captureSnapshot(snap("s1"), &error), "capture failed");
auto r = sweep.recover("s1");
CHECK(r.recovered, "recovery should be complete");
CHECK(r.workflowContinuity && r.queueContinuity && r.bufferContinuity, "all continuity flags expected");
CHECK(hasNote(r, "recover:ok"), "ok note expected");
PASS();
}
void test_recover_missing_session_returns_note() {
TEST(recover_missing_session_returns_note);
CrashRecoveryReliabilitySweep sweep;
auto r = sweep.recover("missing");
CHECK(!r.recovered, "recovery should fail");
CHECK(hasNote(r, "recover:session_missing"), "missing session note expected");
PASS();
}
void test_recover_partial_when_queue_missing() {
TEST(recover_partial_when_queue_missing);
CrashRecoveryReliabilitySweep sweep;
std::string error;
auto s = snap("s1");
s.queuedTaskIds.clear();
CHECK(sweep.captureSnapshot(s, &error), "capture failed");
auto r = sweep.recover("s1");
CHECK(!r.recovered, "recovery should be partial");
CHECK(!r.queueContinuity, "queue continuity should fail");
CHECK(hasNote(r, "recover:queue_missing"), "queue missing note expected");
PASS();
}
void test_recover_partial_when_buffers_missing() {
TEST(recover_partial_when_buffers_missing);
CrashRecoveryReliabilitySweep sweep;
std::string error;
auto s = snap("s1");
s.openBuffers.clear();
CHECK(sweep.captureSnapshot(s, &error), "capture failed");
auto r = sweep.recover("s1");
CHECK(!r.recovered, "recovery should be partial");
CHECK(!r.bufferContinuity, "buffer continuity should fail");
CHECK(hasNote(r, "recover:buffers_missing"), "buffer missing note expected");
PASS();
}
void test_recover_partial_when_workflow_invalid() {
TEST(recover_partial_when_workflow_invalid);
CrashRecoveryReliabilitySweep sweep;
std::string error;
auto s = snap("s1");
s.workflowId = "wf-1";
s.checkpoint = -1;
s.queuedTaskIds = {"task-1"};
s.openBuffers = {"a.cpp"};
CHECK(!sweep.captureSnapshot(s, &error), "capture should fail");
CHECK(error == "checkpoint_invalid", "wrong checkpoint error");
PASS();
}
void test_known_sessions_returns_all_ids() {
TEST(known_sessions_returns_all_ids);
CrashRecoveryReliabilitySweep sweep;
std::string error;
CHECK(sweep.captureSnapshot(snap("s1"), &error), "capture s1 failed");
CHECK(sweep.captureSnapshot(snap("s2"), &error), "capture s2 failed");
auto ids = sweep.knownSessions();
CHECK(ids.size() == 2, "two ids expected");
PASS();
}
void test_capture_overwrites_existing_session() {
TEST(capture_overwrites_existing_session);
CrashRecoveryReliabilitySweep sweep;
std::string error;
auto s = snap("s1");
CHECK(sweep.captureSnapshot(s, &error), "capture 1 failed");
s.openBuffers = {"b.cpp"};
CHECK(sweep.captureSnapshot(s, &error), "capture 2 failed");
auto r = sweep.recover("s1");
CHECK(r.bufferContinuity, "buffer continuity should remain true");
PASS();
}
void test_partial_recovery_has_partial_note() {
TEST(partial_recovery_has_partial_note);
CrashRecoveryReliabilitySweep sweep;
std::string error;
auto s = snap("s1");
s.openBuffers.clear();
CHECK(sweep.captureSnapshot(s, &error), "capture failed");
auto r = sweep.recover("s1");
CHECK(hasNote(r, "recover:partial"), "partial note expected");
PASS();
}
int main() {
std::cout << "Step 590: Crash + Recovery Reliability Sweep\n";
test_capture_snapshot_success(); // 1
test_capture_snapshot_rejects_missing_session(); // 2
test_capture_snapshot_rejects_missing_workflow(); // 3
test_capture_snapshot_rejects_invalid_checkpoint();// 4
test_recover_success_when_all_continuity_present();// 5
test_recover_missing_session_returns_note(); // 6
test_recover_partial_when_queue_missing(); // 7
test_recover_partial_when_buffers_missing(); // 8
test_recover_partial_when_workflow_invalid(); // 9
test_known_sessions_returns_all_ids(); // 10
test_capture_overwrites_existing_session(); // 11
test_partial_recovery_has_partial_note(); // 12
std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n";
return failed == 0 ? 0 : 1;
}

View File

@@ -11160,3 +11160,36 @@ regression, telemetry, and documentation readiness.
- `editor/src/ReleaseReadinessGatePack.h` within header-size limit (`55` <= `600`)
- `editor/tests/step589_test.cpp` within test-file size guidance (`154` lines)
- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`
### Step 590: Crash + Recovery Reliability Sweep
**Status:** PASS (12/12 tests)
Implements crash/recovery reliability modeling for session snapshots and
continuity checks across workflow, queue, and open-buffer state.
**Files added:**
- `editor/src/CrashRecoveryReliabilitySweep.h` - crash recovery module:
- recovery snapshot capture with validation guards
- session restore evaluation with continuity dimensions
- partial-recovery diagnostic notes
- known session inventory helper
- `editor/tests/step590_test.cpp` - 12 tests covering:
- snapshot capture success/failure behavior
- full recovery behavior
- partial recovery dimensions and notes behavior
- missing-session behavior
- snapshot overwrite and session inventory behavior
**Files modified:**
- `editor/CMakeLists.txt` - `step590_test` target
**Verification run:**
- `cmake -S editor -B editor/build-native` - PASS
- `cmake --build editor/build-native --target step590_test step589_test` - PASS
- `./editor/build-native/step590_test` - PASS (12/12)
- `./editor/build-native/step589_test` - PASS (12/12) regression coverage
**Architecture gate check:**
- `editor/src/CrashRecoveryReliabilitySweep.h` within header-size limit (`73` <= `600`)
- `editor/tests/step590_test.cpp` within test-file size guidance (`186` lines)
- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`