diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 105f896..4589846 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -3577,4 +3577,13 @@ target_link_libraries(step521_test PRIVATE tree_sitter_javascript tree_sitter_typescript tree_sitter_java tree_sitter_rust tree_sitter_go) +add_executable(step522_test tests/step522_test.cpp) +target_include_directories(step522_test PRIVATE src) +target_link_libraries(step522_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/CrossPanelConsistencySweep.h b/editor/src/CrossPanelConsistencySweep.h new file mode 100644 index 0000000..6d162af --- /dev/null +++ b/editor/src/CrossPanelConsistencySweep.h @@ -0,0 +1,81 @@ +#pragma once +// Step 522: Cross-Panel Consistency Sweep + +#include +#include +#include +#include + +struct PanelVisualContract { + std::string panelId; + float spacing = 0.0f; + float elevation = 0.0f; + float border = 0.0f; + std::string stateModelVersion; + std::string tokenVersion; +}; + +struct ConsistencyReport { + bool pass = true; + std::vector drifts; + int checkedPanels = 0; +}; + +class CrossPanelConsistencySweep { +public: + static ConsistencyReport run(const std::vector& panels, + const PanelVisualContract& baseline, + float spacingTolerance = 1.0f, + float elevationTolerance = 1.0f, + float borderTolerance = 0.5f) { + ConsistencyReport r; + r.checkedPanels = (int)panels.size(); + for (const auto& p : panels) { + if (std::abs(p.spacing - baseline.spacing) > spacingTolerance) { + r.pass = false; + r.drifts.push_back("spacing:" + p.panelId); + } + if (std::abs(p.elevation - baseline.elevation) > elevationTolerance) { + r.pass = false; + r.drifts.push_back("elevation:" + p.panelId); + } + if (std::abs(p.border - baseline.border) > borderTolerance) { + r.pass = false; + r.drifts.push_back("border:" + p.panelId); + } + if (p.stateModelVersion != baseline.stateModelVersion) { + r.pass = false; + r.drifts.push_back("state-model:" + p.panelId); + } + if (p.tokenVersion != baseline.tokenVersion) { + r.pass = false; + r.drifts.push_back("token-version:" + p.panelId); + } + } + return r; + } + + static std::vector normalize( + const std::vector& panels, + const PanelVisualContract& baseline) { + std::vector out = panels; + for (auto& p : out) { + p.spacing = baseline.spacing; + p.elevation = baseline.elevation; + p.border = baseline.border; + p.stateModelVersion = baseline.stateModelVersion; + p.tokenVersion = baseline.tokenVersion; + } + return out; + } + + static std::map driftHistogram(const ConsistencyReport& r) { + std::map h; + for (const auto& d : r.drifts) { + auto pos = d.find(':'); + std::string key = pos == std::string::npos ? d : d.substr(0, pos); + h[key] += 1; + } + return h; + } +}; diff --git a/editor/tests/step522_test.cpp b/editor/tests/step522_test.cpp new file mode 100644 index 0000000..a5c1983 --- /dev/null +++ b/editor/tests/step522_test.cpp @@ -0,0 +1,152 @@ +// Step 522: Cross-Panel Consistency Sweep (12 tests) + +#include "CrossPanelConsistencySweep.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 PanelVisualContract baseline() { + return {"baseline", 12.0f, 6.0f, 1.0f, "v2", "v2"}; +} + +static std::vector alignedPanels() { + return { + {"explorer", 12.0f, 6.0f, 1.0f, "v2", "v2"}, + {"editor", 12.0f, 6.0f, 1.0f, "v2", "v2"}, + {"status", 12.0f, 6.0f, 1.0f, "v2", "v2"} + }; +} + +void test_passes_when_all_panels_aligned() { + TEST(passes_when_all_panels_aligned); + auto r = CrossPanelConsistencySweep::run(alignedPanels(), baseline()); + CHECK(r.pass, "aligned panels should pass"); + PASS(); +} + +void test_detects_spacing_drift() { + TEST(detects_spacing_drift); + auto p = alignedPanels(); + p[0].spacing = 20.0f; + auto r = CrossPanelConsistencySweep::run(p, baseline()); + CHECK(!r.pass, "spacing drift should fail"); + PASS(); +} + +void test_detects_elevation_drift() { + TEST(detects_elevation_drift); + auto p = alignedPanels(); + p[1].elevation = 10.0f; + auto r = CrossPanelConsistencySweep::run(p, baseline()); + CHECK(!r.pass, "elevation drift should fail"); + PASS(); +} + +void test_detects_border_drift() { + TEST(detects_border_drift); + auto p = alignedPanels(); + p[2].border = 3.0f; + auto r = CrossPanelConsistencySweep::run(p, baseline()); + CHECK(!r.pass, "border drift should fail"); + PASS(); +} + +void test_detects_state_model_version_drift() { + TEST(detects_state_model_version_drift); + auto p = alignedPanels(); + p[1].stateModelVersion = "v1"; + auto r = CrossPanelConsistencySweep::run(p, baseline()); + CHECK(!r.pass, "state model drift should fail"); + PASS(); +} + +void test_detects_token_version_drift() { + TEST(detects_token_version_drift); + auto p = alignedPanels(); + p[1].tokenVersion = "v1"; + auto r = CrossPanelConsistencySweep::run(p, baseline()); + CHECK(!r.pass, "token version drift should fail"); + PASS(); +} + +void test_normalize_resets_spacing_to_baseline() { + TEST(normalize_resets_spacing_to_baseline); + auto p = alignedPanels(); + p[0].spacing = 99.0f; + auto n = CrossPanelConsistencySweep::normalize(p, baseline()); + CHECK(n[0].spacing == 12.0f, "spacing should normalize"); + PASS(); +} + +void test_normalize_resets_versions_to_baseline() { + TEST(normalize_resets_versions_to_baseline); + auto p = alignedPanels(); + p[0].stateModelVersion = "old"; + p[0].tokenVersion = "old"; + auto n = CrossPanelConsistencySweep::normalize(p, baseline()); + CHECK(n[0].stateModelVersion == "v2" && n[0].tokenVersion == "v2", + "versions should normalize"); + PASS(); +} + +void test_histogram_groups_drift_categories() { + TEST(histogram_groups_drift_categories); + auto p = alignedPanels(); + p[0].spacing = 30.0f; + p[1].spacing = 25.0f; + auto r = CrossPanelConsistencySweep::run(p, baseline()); + auto h = CrossPanelConsistencySweep::driftHistogram(r); + CHECK(h["spacing"] == 2, "histogram should count spacing drifts"); + PASS(); +} + +void test_report_checked_panel_count_matches_input() { + TEST(report_checked_panel_count_matches_input); + auto p = alignedPanels(); + auto r = CrossPanelConsistencySweep::run(p, baseline()); + CHECK(r.checkedPanels == 3, "checked panel count mismatch"); + PASS(); +} + +void test_tolerance_allows_small_spacing_variance() { + TEST(tolerance_allows_small_spacing_variance); + auto p = alignedPanels(); + p[0].spacing = 12.6f; + auto r = CrossPanelConsistencySweep::run(p, baseline(), 1.0f); + CHECK(r.pass, "small spacing variance should pass"); + PASS(); +} + +void test_tolerance_rejects_large_spacing_variance() { + TEST(tolerance_rejects_large_spacing_variance); + auto p = alignedPanels(); + p[0].spacing = 14.5f; + auto r = CrossPanelConsistencySweep::run(p, baseline(), 1.0f); + CHECK(!r.pass, "large spacing variance should fail"); + PASS(); +} + +int main() { + std::cout << "Step 522: Cross-Panel Consistency Sweep\n"; + + test_passes_when_all_panels_aligned(); // 1 + test_detects_spacing_drift(); // 2 + test_detects_elevation_drift(); // 3 + test_detects_border_drift(); // 4 + test_detects_state_model_version_drift(); // 5 + test_detects_token_version_drift(); // 6 + test_normalize_resets_spacing_to_baseline(); // 7 + test_normalize_resets_versions_to_baseline(); // 8 + test_histogram_groups_drift_categories(); // 9 + test_report_checked_panel_count_matches_input(); // 10 + test_tolerance_allows_small_spacing_variance(); // 11 + test_tolerance_rejects_large_spacing_variance(); // 12 + + std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n"; + return failed == 0 ? 0 : 1; +} diff --git a/progress.md b/progress.md index 9e12b1c..1f8934e 100644 --- a/progress.md +++ b/progress.md @@ -8455,3 +8455,37 @@ and stack management rules including persistent critical signaling. - `editor/src/NotificationStatusRefresh.h` within header-size limit (`72` <= `600`) - `editor/tests/step521_test.cpp` within test-file size guidance (`133` lines) - Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md` + +### Step 522: Cross-Panel Consistency Sweep +**Status:** PASS (12/12 tests) + +Implements a cross-panel consistency sweep enforcing shared spacing/elevation/ +border conventions plus state-model and token-version uniformity, with drift +histograms and normalization helpers for rapid alignment. + +**Files added:** +- `editor/src/CrossPanelConsistencySweep.h` - consistency sweep module: + - baseline-vs-panel drift detection with tolerances + - drift categorization and histogram reporting + - normalization pass to align panel contracts to baseline + - checked-panel accounting for sweep coverage +- `editor/tests/step522_test.cpp` - 12 tests covering: + - aligned pass case + - drift detection for spacing/elevation/border/version mismatches + - normalization behavior for metrics and versions + - histogram grouping behavior + - tolerance boundary behavior + +**Files modified:** +- `editor/CMakeLists.txt` - `step522_test` target + +**Verification run:** +- `cmake -S editor -B editor/build-native` - PASS +- `cmake --build editor/build-native --target step522_test` - PASS +- `./editor/build-native/step522_test` - PASS (12/12) +- `./editor/build-native/step521_test` - PASS (12/12) regression coverage + +**Architecture gate check:** +- `editor/src/CrossPanelConsistencySweep.h` within header-size limit (`81` <= `600`) +- `editor/tests/step522_test.cpp` within test-file size guidance (`152` lines) +- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`