diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index f5d8f7a..2f0a2dc 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -4180,4 +4180,13 @@ target_link_libraries(step588_test PRIVATE tree_sitter_javascript tree_sitter_typescript tree_sitter_java tree_sitter_rust tree_sitter_go) +add_executable(step589_test tests/step589_test.cpp) +target_include_directories(step589_test PRIVATE src) +target_link_libraries(step589_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) diff --git a/editor/src/ReleaseReadinessGatePack.h b/editor/src/ReleaseReadinessGatePack.h new file mode 100644 index 0000000..31613c1 --- /dev/null +++ b/editor/src/ReleaseReadinessGatePack.h @@ -0,0 +1,55 @@ +#pragma once +// Step 589: Release Readiness Gate Pack + +#include +#include + +struct ReleaseGateSignals { + bool uxChecks = false; + bool runtimeChecks = false; + bool regressionChecks = false; + bool telemetryChecks = false; + bool documentationChecks = false; +}; + +struct ReleaseReadinessResult { + bool ready = false; + std::vector blockedGates; + std::vector notes; +}; + +class ReleaseReadinessGatePack { +public: + static ReleaseReadinessResult evaluate(const ReleaseGateSignals& s) { + ReleaseReadinessResult r; + if (!s.uxChecks) r.blockedGates.push_back("ux"); + if (!s.runtimeChecks) r.blockedGates.push_back("runtime"); + if (!s.regressionChecks) r.blockedGates.push_back("regression"); + if (!s.telemetryChecks) r.blockedGates.push_back("telemetry"); + if (!s.documentationChecks) r.blockedGates.push_back("documentation"); + + r.ready = r.blockedGates.empty(); + if (r.ready) { + r.notes.push_back("release:go"); + r.notes.push_back("release:gates_all_green"); + } else { + r.notes.push_back("release:no_go"); + for (const auto& gate : r.blockedGates) r.notes.push_back("blocked:" + gate); + } + return r; + } + + static bool canShipHotfix(const ReleaseGateSignals& s) { + return s.runtimeChecks && s.regressionChecks; + } + + static int readinessScore(const ReleaseGateSignals& s) { + int score = 0; + if (s.uxChecks) score += 20; + if (s.runtimeChecks) score += 25; + if (s.regressionChecks) score += 25; + if (s.telemetryChecks) score += 15; + if (s.documentationChecks) score += 15; + return score; + } +}; diff --git a/editor/tests/step589_test.cpp b/editor/tests/step589_test.cpp new file mode 100644 index 0000000..7fbaf6f --- /dev/null +++ b/editor/tests/step589_test.cpp @@ -0,0 +1,154 @@ +// Step 589: Release Readiness Gate Pack (12 tests) + +#include "ReleaseReadinessGatePack.h" + +#include + +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 bool hasNote(const ReleaseReadinessResult& r, const std::string& note) { + for (const auto& n : r.notes) if (n == note) return true; + return false; +} + +static ReleaseGateSignals allGreen() { + ReleaseGateSignals s; + s.uxChecks = true; + s.runtimeChecks = true; + s.regressionChecks = true; + s.telemetryChecks = true; + s.documentationChecks = true; + return s; +} + +void test_all_green_ready() { + TEST(all_green_ready); + auto r = ReleaseReadinessGatePack::evaluate(allGreen()); + CHECK(r.ready, "release should be ready"); + PASS(); +} + +void test_missing_ux_blocks_release() { + TEST(missing_ux_blocks_release); + auto s = allGreen(); + s.uxChecks = false; + auto r = ReleaseReadinessGatePack::evaluate(s); + CHECK(!r.ready, "release should be blocked"); + CHECK(!r.blockedGates.empty() && r.blockedGates[0] == "ux", "ux should be blocked"); + PASS(); +} + +void test_missing_runtime_blocks_release() { + TEST(missing_runtime_blocks_release); + auto s = allGreen(); + s.runtimeChecks = false; + auto r = ReleaseReadinessGatePack::evaluate(s); + CHECK(!r.ready, "release should be blocked"); + CHECK(hasNote(r, "blocked:runtime"), "runtime note expected"); + PASS(); +} + +void test_missing_regression_blocks_release() { + TEST(missing_regression_blocks_release); + auto s = allGreen(); + s.regressionChecks = false; + auto r = ReleaseReadinessGatePack::evaluate(s); + CHECK(!r.ready, "release should be blocked"); + CHECK(hasNote(r, "blocked:regression"), "regression note expected"); + PASS(); +} + +void test_missing_telemetry_blocks_release() { + TEST(missing_telemetry_blocks_release); + auto s = allGreen(); + s.telemetryChecks = false; + auto r = ReleaseReadinessGatePack::evaluate(s); + CHECK(!r.ready, "release should be blocked"); + CHECK(hasNote(r, "blocked:telemetry"), "telemetry note expected"); + PASS(); +} + +void test_missing_documentation_blocks_release() { + TEST(missing_documentation_blocks_release); + auto s = allGreen(); + s.documentationChecks = false; + auto r = ReleaseReadinessGatePack::evaluate(s); + CHECK(!r.ready, "release should be blocked"); + CHECK(hasNote(r, "blocked:documentation"), "documentation note expected"); + PASS(); +} + +void test_multiple_missing_gates_accumulate() { + TEST(multiple_missing_gates_accumulate); + ReleaseGateSignals s; + auto r = ReleaseReadinessGatePack::evaluate(s); + CHECK(r.blockedGates.size() == 5, "all gates should be blocked"); + PASS(); +} + +void test_release_go_notes_emitted_on_ready() { + TEST(release_go_notes_emitted_on_ready); + auto r = ReleaseReadinessGatePack::evaluate(allGreen()); + CHECK(hasNote(r, "release:go"), "go note expected"); + CHECK(hasNote(r, "release:gates_all_green"), "green note expected"); + PASS(); +} + +void test_release_no_go_note_on_failure() { + TEST(release_no_go_note_on_failure); + ReleaseGateSignals s; + auto r = ReleaseReadinessGatePack::evaluate(s); + CHECK(hasNote(r, "release:no_go"), "no-go note expected"); + PASS(); +} + +void test_hotfix_allowed_with_runtime_and_regression() { + TEST(hotfix_allowed_with_runtime_and_regression); + ReleaseGateSignals s; + s.runtimeChecks = true; + s.regressionChecks = true; + CHECK(ReleaseReadinessGatePack::canShipHotfix(s), "hotfix should be allowed"); + PASS(); +} + +void test_hotfix_blocked_without_runtime_or_regression() { + TEST(hotfix_blocked_without_runtime_or_regression); + ReleaseGateSignals s; + s.runtimeChecks = true; + s.regressionChecks = false; + CHECK(!ReleaseReadinessGatePack::canShipHotfix(s), "hotfix should be blocked"); + PASS(); +} + +void test_readiness_score_weights_applied() { + TEST(readiness_score_weights_applied); + auto s = allGreen(); + CHECK(ReleaseReadinessGatePack::readinessScore(s) == 100, "all-green score should be 100"); + s.telemetryChecks = false; + CHECK(ReleaseReadinessGatePack::readinessScore(s) == 85, "score should drop by telemetry weight"); + PASS(); +} + +int main() { + std::cout << "Step 589: Release Readiness Gate Pack\n"; + + test_all_green_ready(); // 1 + test_missing_ux_blocks_release(); // 2 + test_missing_runtime_blocks_release(); // 3 + test_missing_regression_blocks_release(); // 4 + test_missing_telemetry_blocks_release(); // 5 + test_missing_documentation_blocks_release(); // 6 + test_multiple_missing_gates_accumulate(); // 7 + test_release_go_notes_emitted_on_ready(); // 8 + test_release_no_go_note_on_failure(); // 9 + test_hotfix_allowed_with_runtime_and_regression();// 10 + test_hotfix_blocked_without_runtime_or_regression();// 11 + test_readiness_score_weights_applied(); // 12 + + std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n"; + return failed == 0 ? 0 : 1; +} diff --git a/progress.md b/progress.md index 50c293e..6c3a424 100644 --- a/progress.md +++ b/progress.md @@ -11126,3 +11126,37 @@ readiness gate for onboarding value visibility. **Phase 33a totals (584-588):** - **Steps completed:** 5 - **New tests in this phase plan:** 56/56 passing + +### Step 589: Release Readiness Gate Pack +**Status:** PASS (12/12 tests) + +Implements consolidated release go/no-go gate evaluation for UX, runtime, +regression, telemetry, and documentation readiness. + +**Files added:** +- `editor/src/ReleaseReadinessGatePack.h` - readiness gate module: + - gate signal aggregation and release ready/no-go decision + - blocked gate note emission + - hotfix-shipping policy helper + - weighted readiness scoring helper +- `editor/tests/step589_test.cpp` - 12 tests covering: + - all-green pass behavior + - per-gate failure behavior + - multi-gate blocking behavior + - note emission behavior + - hotfix policy behavior + - weighted score behavior + +**Files modified:** +- `editor/CMakeLists.txt` - `step589_test` target + +**Verification run:** +- `cmake -S editor -B editor/build-native` - PASS +- `cmake --build editor/build-native --target step589_test step588_test` - PASS +- `./editor/build-native/step589_test` - PASS (12/12) +- `./editor/build-native/step588_test` - PASS (8/8) regression coverage + +**Architecture gate check:** +- `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`