From 98cfb959d7f032e79a789764888f1fca1c590562 Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 16 Feb 2026 15:07:44 -0700 Subject: [PATCH] Step 404: self-hosting phase integration and progress report --- editor/CMakeLists.txt | 9 ++ editor/tests/step404_test.cpp | 219 ++++++++++++++++++++++++++++++++++ progress.md | 48 ++++++++ 3 files changed, 276 insertions(+) create mode 100644 editor/tests/step404_test.cpp diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index e4b9cfa..7f61493 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -2515,4 +2515,13 @@ target_link_libraries(step403_test PRIVATE tree_sitter_javascript tree_sitter_typescript tree_sitter_java tree_sitter_rust tree_sitter_go) +add_executable(step404_test tests/step404_test.cpp) +target_include_directories(step404_test PRIVATE src) +target_link_libraries(step404_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/step404_test.cpp b/editor/tests/step404_test.cpp new file mode 100644 index 0000000..7926b08 --- /dev/null +++ b/editor/tests/step404_test.cpp @@ -0,0 +1,219 @@ +// Step 404: Self-Hosting Progress Report + Phase Integration (8 tests) + +#include +#include +#include +#include +#include + +#include "AnnotationInference.h" +#include "Pipeline.h" +#include "SelfHostHarness.h" +#include "SemannoFormat.h" +#include "ast/Annotation.h" + +namespace { + +struct AggregatedCoverage { + int expected = 0; + int parsed = 0; + int opaque = 0; + + double ratio() const { + return expected > 0 ? static_cast(parsed) / expected : 1.0; + } +}; + +std::string resolvePath(const std::string& name) { + const std::vector candidates = { + "src/" + name, + "editor/src/" + name, + "../src/" + name, + "../../editor/src/" + name + }; + for (const auto& candidate : candidates) { + if (std::filesystem::exists(candidate)) return candidate; + } + return "src/" + name; +} + +std::string conflictHeaderPath() { + static const std::string path = resolvePath("AnnotationConflictExtended.h"); + return path; +} + +std::string validatorHeaderPath() { + static const std::string path = resolvePath("AnnotationValidatorExtended.h"); + return path; +} + +ExpectedStructure expectedConflict() { + ExpectedStructure expected; + expected.filePath = conflictHeaderPath(); + expected.constructs = { + {"struct", "CrossTypeConflict"}, + {"function", "collectCrossTypeConflicts"} + }; + return expected; +} + +ExpectedStructure expectedValidator() { + ExpectedStructure expected; + expected.filePath = validatorHeaderPath(); + expected.constructs = { + {"class", "AnnotationValidatorExtended"} + }; + return expected; +} + +AggregatedCoverage aggregate(const SelfHostResult& a, const SelfHostResult& b) { + AggregatedCoverage out; + out.expected = a.totalExpected + b.totalExpected; + out.parsed = a.totalParsed + b.totalParsed; + out.opaque = a.totalOpaque + b.totalOpaque; + return out; +} + +std::vector collectGaps(const SelfHostResult& result) { + std::vector gaps; + for (const auto& cov : result.coverage) { + if (cov.opaque > 0) { + gaps.push_back(cov.constructType + ":" + std::to_string(cov.opaque)); + } + } + return gaps; +} + +} // namespace + +int main() { + int passed = 0; + + // Test 1: Self-host coverage for both target headers. + { + auto conflict = SelfHostHarness::parseFile(conflictHeaderPath()); + auto validator = SelfHostHarness::parseFile(validatorHeaderPath()); + auto expectConflict = expectedConflict(); + auto expectValidator = expectedValidator(); + SelfHostHarness::checkExpected(conflict, expectConflict); + SelfHostHarness::checkExpected(validator, expectValidator); + assert(conflict.totalParsed == 2); + assert(validator.totalParsed == 1); + std::cout << "PASS: test 1 — per-file self-host coverage metrics\n"; + passed++; + } + + // Test 2: Per-file coverage ratios are at full baseline. + { + auto conflict = SelfHostHarness::parseFile(conflictHeaderPath()); + auto validator = SelfHostHarness::parseFile(validatorHeaderPath()); + SelfHostHarness::checkExpected(conflict, expectedConflict()); + SelfHostHarness::checkExpected(validator, expectedValidator()); + assert(conflict.overallCoverage() == 1.0); + assert(validator.overallCoverage() == 1.0); + std::cout << "PASS: test 2 — baseline coverage ratios at 100%\n"; + passed++; + } + + // Test 3: Combined phase coverage aggregates correctly. + { + auto conflict = SelfHostHarness::parseFile(conflictHeaderPath()); + auto validator = SelfHostHarness::parseFile(validatorHeaderPath()); + SelfHostHarness::checkExpected(conflict, expectedConflict()); + SelfHostHarness::checkExpected(validator, expectedValidator()); + auto totals = aggregate(conflict, validator); + assert(totals.expected == 3); + assert(totals.parsed == 3); + assert(totals.opaque == 0); + assert(totals.ratio() == 1.0); + std::cout << "PASS: test 3 — aggregate coverage accounting\n"; + passed++; + } + + // Test 4: Pipeline end-to-end succeeds on both self-host headers. + { + Pipeline pipeline; + auto conflictSource = SelfHostHarness::readFile(conflictHeaderPath()); + auto validatorSource = SelfHostHarness::readFile(validatorHeaderPath()); + auto conflictRun = pipeline.run(conflictSource, "cpp", "cpp"); + auto validatorRun = pipeline.run(validatorSource, "cpp", "cpp"); + assert(conflictRun.success && conflictRun.ast != nullptr && !conflictRun.generatedCode.empty()); + assert(validatorRun.success && validatorRun.ast != nullptr && !validatorRun.generatedCode.empty()); + std::cout << "PASS: test 4 — pipeline runs for both self-host files\n"; + passed++; + } + + // Test 5: Gap-analysis reporting captures opaque construct deficits. + { + auto conflict = SelfHostHarness::parseFile(conflictHeaderPath()); + ExpectedStructure strictExpected; + strictExpected.filePath = conflictHeaderPath(); + strictExpected.constructs = { + {"struct", "CrossTypeConflict"}, + {"function", "collectCrossTypeConflicts"}, + {"class", "MissingClassForGapReport"}, + {"function", "missingHelperForGapReport"} + }; + SelfHostHarness::checkExpected(conflict, strictExpected); + auto gaps = collectGaps(conflict); + assert(conflict.totalOpaque == 2); + assert(gaps.size() >= 1); + std::cout << "PASS: test 5 — gap-analysis report path\n"; + passed++; + } + + // Test 6: Inferred complexity annotation emits valid Semanno. + { + auto validator = SelfHostHarness::parseFile(validatorHeaderPath()); + AnnotationInference inf; + auto inferred = inf.inferAll(validator.ast.get()); + std::string complexity = "O(1)"; + for (const auto& item : inferred) { + if (item.annotationType == "ComplexityAnnotation") { + complexity = item.value; + break; + } + } + + ComplexityAnnotation anno; + anno.timeComplexity = complexity; + const std::string semanno = SemannoEmitter::emit(&anno); + assert(SemannoParser::isSemannoComment(semanno)); + auto parsed = SemannoParser::parse(semanno); + assert(parsed.type == "complexity"); + std::cout << "PASS: test 6 — semanno output for inferred complexity\n"; + passed++; + } + + // Test 7: Coverage reports include file identity and parse state. + { + auto conflict = SelfHostHarness::parseFile(conflictHeaderPath()); + SelfHostHarness::checkExpected(conflict, expectedConflict()); + auto report = SelfHostHarness::coverageReport(conflict); + assert(report.find(conflictHeaderPath()) != std::string::npos); + assert(report.find("Parse success: yes") != std::string::npos); + std::cout << "PASS: test 7 — report formatting includes file + status\n"; + passed++; + } + + // Test 8: Phase artifact sanity (steps 400-404 test files exist). + { + const std::vector required = { + "tests/step400_test.cpp", + "tests/step401_test.cpp", + "tests/step402_test.cpp", + "tests/step403_test.cpp", + "tests/step404_test.cpp" + }; + int found = 0; + for (const auto& rel : required) { + if (std::filesystem::exists("editor/" + rel)) found++; + } + assert(found == 5); + std::cout << "PASS: test 8 — phase 16b artifact set present\n"; + passed++; + } + + std::cout << "\nStep 404 result: " << passed << "/8 tests passed\n"; + return (passed == 8) ? 0 : 1; +} diff --git a/progress.md b/progress.md index 5356540..66f0330 100644 --- a/progress.md +++ b/progress.md @@ -3572,6 +3572,54 @@ complexity metadata. - `editor/src/MCPServer.h` (`1679` > `600`) - `editor/src/HeadlessAgentRPCHandler.h` (`2623` > `600`) +### Step 404: Self-Hosting Progress Report + Phase Integration +**Status:** PASS (8/8 tests) + +Completed Phase 16b integration reporting with aggregate self-host coverage, +pipeline execution checks over both target headers, Semanno roundtrip checks +from inferred complexity metadata, and explicit gap-reporting behavior. + +**Files created:** +- `editor/tests/step404_test.cpp` — 8 integration tests covering: + 1. per-file self-host coverage metrics + 2. baseline per-file coverage ratios + 3. aggregate phase coverage accounting + 4. `Pipeline.run()` success for both target headers + 5. gap-reporting path for opaque construct deficits + 6. Semanno emit/parse check for inferred complexity + 7. report formatting (file identity + parse status) + 8. phase artifact sanity (step400-404 test files present) + +**Files modified:** +- `editor/CMakeLists.txt` — `step404_test` target + +**Verification run:** +- `step404_test` — PASS (8/8) new integration coverage +- `step403_test` — PASS (12/12) regression coverage +- `step402_test` — PASS (12/12) regression coverage + +**Phase 16b completion snapshot (Steps 400-404):** +- Step 400: Self-hosting harness + coverage tracking (12 tests) +- Step 401: Parse `AnnotationConflictExtended.h` (12 tests) +- Step 402: Parse `AnnotationValidatorExtended.h` (12 tests) +- Step 403: Inference + generation on self-hosted ASTs (12 tests) +- Step 404: Coverage report + phase integration (8 tests) + +**Sprint 16 completion snapshot (Steps 394-404):** +- Phase 16a complete (Steps 394-399, 68 tests) +- Phase 16b complete (Steps 400-404, 56 tests) +- Sprint 16 total: 11 steps, 124 tests + +**Architecture gate check (end of Sprint 16):** +- `editor/tests/step404_test.cpp` within test-file size guidance (`219` lines) +- `editor/tests/step403_test.cpp` within test-file size guidance (`236` lines) +- `editor/tests/step402_test.cpp` within test-file size guidance (`239` lines) +- `editor/src/SelfHostHarness.h` within header-size limit (`308` <= `600`) +- `editor/src/AnnotationValidatorExtended.h` within header-size limit (`349` <= `600`) +- Legacy oversized headers persist and remain queued for split work: + - `editor/src/MCPServer.h` (`1679` > `600`) + - `editor/src/HeadlessAgentRPCHandler.h` (`2623` > `600`) + # Roadmap Planning — Sprints 12-25+ ## Status: Planning Complete (Sprints 12-19 detailed, 20-25 in roadmap.md)