diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 2b37068..326bd54 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -2812,4 +2812,13 @@ target_link_libraries(step436_test PRIVATE tree_sitter_javascript tree_sitter_typescript tree_sitter_java tree_sitter_rust tree_sitter_go) +add_executable(step437_test tests/step437_test.cpp) +target_include_directories(step437_test PRIVATE src) +target_link_libraries(step437_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/tests/step437_test.cpp b/editor/tests/step437_test.cpp new file mode 100644 index 0000000..f471747 --- /dev/null +++ b/editor/tests/step437_test.cpp @@ -0,0 +1,208 @@ +// Step 437: Phase 19b Integration + Sprint Summary Tests (8 tests) + +#include "CodeAnnotationBadges.h" +#include "CodeAnnotationHeatmap.h" +#include "WorkflowStatusOverlay.h" +#include "ReviewComparisonView.h" +#include "WorkflowTaskBoard.h" +#include "WorkflowProgressDashboard.h" + +#include +#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 WorkItem makeItem(const std::string& id, + const std::string& nodeId, + const std::string& name, + const std::string& status, + const std::string& file, + const std::string& worker) { + WorkItem wi; + wi.id = id; + wi.nodeId = nodeId; + wi.nodeName = name; + wi.status = status; + wi.bufferId = file; + wi.workerType = worker; + wi.priority = "high"; + wi.contextWidth = "file"; + wi.reviewRequired = (status == WI_REVIEW); + wi.result.generatedCode = "void " + name + "() {\n int x = 1;\n}\n"; + return wi; +} + +static WorkflowState makeWorkflow() { + WorkflowState wf("phase19b"); + wf.queue.enqueue(makeItem("t1", "n1", "buildSkeleton", WI_READY, "src/a.cpp", "template")); + wf.queue.enqueue(makeItem("t2", "n2", "emitLogic", WI_IN_PROGRESS, "src/a.cpp", "llm")); + wf.queue.enqueue(makeItem("t3", "n3", "reviewLogic", WI_REVIEW, "src/a.cpp", "human")); + wf.queue.enqueue(makeItem("t4", "n4", "finalize", WI_COMPLETE, "src/b.cpp", "deterministic")); + return wf; +} + +static std::vector makeAnnotations() { + return { + {10, "IntentAnnotation", "intent", "n1"}, + {20, "ComplexityAnnotation", "complex", "n2"}, + {20, "RiskAnnotation", "risk", "n2"}, + {30, "ReviewAnnotation", "review", "n3"} + }; +} + +static std::map makeNodeLines() { + return {{"n1", 10}, {"n2", 20}, {"n3", 30}, {"n4", 40}}; +} + +static std::string extractItemId(const std::string& route) { + const std::string prefix = "task://detail/"; + if (route.find(prefix) != 0) return ""; + return route.substr(prefix.size()); +} + +void test_annotation_badges_visible_on_annotated_code() { + TEST(annotation_badges_visible_on_annotated_code); + auto badges = CodeAnnotationBadges::buildBadges(makeAnnotations()); + CHECK(badges.size() == 4, "expected one badge per annotation"); + PASS(); +} + +void test_heatmap_highlights_complex_regions() { + TEST(heatmap_highlights_complex_regions); + auto cells = CodeAnnotationHeatmap::build(makeAnnotations(), 35, true); + int score10 = 0, score20 = 0; + for (const auto& c : cells) { + if (c.line == 10) score10 = c.score; + if (c.line == 20) score20 = c.score; + } + CHECK(score20 > score10, "complex region should score higher than intent-only region"); + PASS(); +} + +void test_overlay_reflects_live_orchestration_state() { + TEST(overlay_reflects_live_orchestration_state); + auto wf = makeWorkflow(); + auto markers = WorkflowStatusOverlay::build(wf, makeNodeLines(), "src/a.cpp"); + CHECK(markers.size() == 3, "expected three markers for src/a.cpp"); + bool hasReview = false; + for (const auto& m : markers) { + if (m.itemId == "t3" && m.statusIcon == "eye") hasReview = true; + } + CHECK(hasReview, "review item should have eye icon"); + PASS(); +} + +void test_overlay_click_opens_review_comparison() { + TEST(overlay_click_opens_review_comparison); + auto wf = makeWorkflow(); + auto markers = WorkflowStatusOverlay::build(wf, makeNodeLines(), "src/a.cpp"); + std::string route; + for (const auto& m : markers) if (m.itemId == "t3") route = m.detailRoute; + std::string itemId = extractItemId(route); + auto review = ReviewComparisonView::build(wf, itemId); + CHECK(!itemId.empty(), "expected detail route item id"); + CHECK(review.has_value(), "review comparison should open from overlay click"); + PASS(); +} + +void test_task_board_review_item_opens_comparison() { + TEST(task_board_review_item_opens_comparison); + auto wf = makeWorkflow(); + auto board = WorkflowTaskBoard::build(wf); + std::string reviewId; + for (const auto& col : board) { + if (col.key == "review" && !col.cards.empty()) reviewId = col.cards[0].itemId; + } + auto review = ReviewComparisonView::build(wf, reviewId); + CHECK(!reviewId.empty(), "review card id missing"); + CHECK(review.has_value(), "review comparison should open from board selection"); + PASS(); +} + +void test_review_approve_updates_board_and_overlay() { + TEST(review_approve_updates_board_and_overlay); + auto wf = makeWorkflow(); + CHECK(ReviewComparisonView::approve(wf, "t3"), "approve should succeed"); + + auto board = WorkflowTaskBoard::build(wf); + int reviewCount = 0; + int completeCount = 0; + for (const auto& col : board) { + if (col.key == "review") reviewCount = (int)col.cards.size(); + if (col.key == "complete") completeCount = (int)col.cards.size(); + } + auto markers = WorkflowStatusOverlay::build(wf, makeNodeLines(), "src/a.cpp"); + bool t3Complete = false; + for (const auto& m : markers) { + if (m.itemId == "t3" && m.statusIcon == "check") t3Complete = true; + } + + CHECK(reviewCount == 0, "review column should be empty after approval"); + CHECK(completeCount >= 2, "complete column should increase"); + CHECK(t3Complete, "overlay should show approved item as check"); + PASS(); +} + +void test_review_reject_requeues_and_overlay_pending_style() { + TEST(review_reject_requeues_and_overlay_pending_style); + auto wf = makeWorkflow(); + CHECK(ReviewComparisonView::reject(wf, "t3", "needs stronger guard"), "reject should succeed"); + + auto board = WorkflowTaskBoard::build(wf); + int readyCount = 0; + for (const auto& col : board) if (col.key == "ready") readyCount = (int)col.cards.size(); + + auto markers = WorkflowStatusOverlay::build(wf, makeNodeLines(), "src/a.cpp"); + bool t3Outline = false; + for (const auto& m : markers) { + if (m.itemId == "t3" && m.statusIcon == "outline") t3Outline = true; + } + + CHECK(readyCount >= 1, "rejected item should requeue into ready board column"); + CHECK(t3Outline, "overlay should show requeued item as outline"); + PASS(); +} + +void test_end_to_end_visualization_stack_operational() { + TEST(end_to_end_visualization_stack_operational); + auto wf = makeWorkflow(); + auto annotations = makeAnnotations(); + + auto badges = CodeAnnotationBadges::buildBadges(annotations); + auto heatmap = CodeAnnotationHeatmap::build(annotations, 40, true); + auto overlay = WorkflowStatusOverlay::build(wf, makeNodeLines()); + auto review = ReviewComparisonView::build(wf, "t3"); + + WorkflowProgress p(4); + p.recordEvent({"routed", "t1", {{"workerType", "template"}}, "2026-01-01T00:00:00Z"}); + p.recordEvent({"completed", "t4", json::object(), "2026-01-01T00:01:00Z"}); + auto dashboard = WorkflowProgressDashboard::build(wf, p, nullptr); + + CHECK(!badges.empty(), "badges should be available"); + CHECK(!heatmap.empty(), "heatmap should be available"); + CHECK(!overlay.empty(), "overlay should be available"); + CHECK(review.has_value(), "review comparison should be available"); + CHECK(dashboard.totalItems == 4, "dashboard total mismatch"); + PASS(); +} + +int main() { + std::cout << "Step 437: Phase 19b Integration + Sprint Summary Tests\n"; + + test_annotation_badges_visible_on_annotated_code(); // 1 + test_heatmap_highlights_complex_regions(); // 2 + test_overlay_reflects_live_orchestration_state(); // 3 + test_overlay_click_opens_review_comparison(); // 4 + test_task_board_review_item_opens_comparison(); // 5 + test_review_approve_updates_board_and_overlay(); // 6 + test_review_reject_requeues_and_overlay_pending_style(); // 7 + test_end_to_end_visualization_stack_operational(); // 8 + + std::cout << "\nResults: " << passed << "/" << (passed + failed) + << " passed\n"; + return failed == 0 ? 0 : 1; +} diff --git a/progress.md b/progress.md index c95e616..9e8f528 100644 --- a/progress.md +++ b/progress.md @@ -5174,6 +5174,64 @@ integrates approve/reject actions with keyboard shortcut metadata. - `editor/src/MCPServer.h` (`1940` > `600`) - `editor/src/HeadlessAgentRPCHandler.h` (`2768` > `600`) +### Step 437: Phase 19b Integration + Sprint Summary +**Status:** PASS (8/8 tests) + +Added Phase 19b integration coverage validating that annotation overlays, +workflow status overlays, and review comparison views work together in a single +visual workflow path. + +**Files created:** +- `editor/tests/step437_test.cpp` — 8 integration tests covering: + 1. inline annotation badge visibility on annotated code + 2. heatmap emphasis for complex regions + 3. workflow status overlay projection from live state + 4. code-overlay status click -> review comparison access + 5. task-board review selection -> comparison access + 6. approve flow updates board + overlay state + 7. reject flow requeues and reflects overlay status + 8. end-to-end visualization stack operability (badges/heatmap/overlay/review/dashboard) + +**Files modified:** +- `editor/CMakeLists.txt` — `step437_test` target + +**Verification run:** +- `step437_test` — PASS (8/8) new integration coverage +- `step436_test` — PASS (12/12) regression coverage +- `step435_test` — PASS (12/12) regression coverage +- `step434_test` — PASS (12/12) regression coverage + +**Sprint 19 completion snapshot (Steps 428-437):** +- Phase 19a (428-432): task board, task detail, dependency graph, progress dashboard, integration +- Phase 19b (433-437): annotation badges, heatmap, workflow status overlay, review comparison, integration +- Result: workflow visualization stack operational end-to-end across board, code overlays, and review flow + +**Architecture gate check (end of Sprint 19):** +- New Sprint 19 headers within header-size limit: + - `editor/src/WorkflowTaskBoard.h` (`154` <= `600`) + - `editor/src/WorkflowTaskDetail.h` (`121` <= `600`) + - `editor/src/WorkflowDependencyView.h` (`94` <= `600`) + - `editor/src/WorkflowProgressDashboard.h` (`112` <= `600`) + - `editor/src/CodeAnnotationBadges.h` (`88` <= `600`) + - `editor/src/CodeAnnotationHeatmap.h` (`50` <= `600`) + - `editor/src/WorkflowStatusOverlay.h` (`94` <= `600`) + - `editor/src/ReviewComparisonView.h` (`118` <= `600`) +- New Sprint 19 tests within file-size guidance: + - `editor/tests/step428_test.cpp` (`186` lines) + - `editor/tests/step429_test.cpp` (`169` lines) + - `editor/tests/step430_test.cpp` (`155` lines) + - `editor/tests/step431_test.cpp` (`202` lines) + - `editor/tests/step432_test.cpp` (`182` lines) + - `editor/tests/step433_test.cpp` (`141` lines) + - `editor/tests/step434_test.cpp` (`126` lines) + - `editor/tests/step435_test.cpp` (`155` lines) + - `editor/tests/step436_test.cpp` (`173` lines) + - `editor/tests/step437_test.cpp` (`208` lines) +- Legacy oversized headers persist: + - `editor/src/ast/Serialization.h` (`1427` > `600`) + - `editor/src/MCPServer.h` (`1940` > `600`) + - `editor/src/HeadlessAgentRPCHandler.h` (`2768` > `600`) + # Roadmap Planning — Sprints 12-25+ ## Status: Planning Complete (Sprints 12-19 detailed, 20-25 in roadmap.md)