From e6ac78e311b9a6fc7a0beebce77bceeed676b7ff Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 16 Feb 2026 22:37:47 -0700 Subject: [PATCH] Step 501: add cross-language port scenario and tests --- editor/CMakeLists.txt | 9 + editor/src/CrossLanguagePortScenarioRunner.h | 127 ++++++++++++++ editor/tests/step501_test.cpp | 165 +++++++++++++++++++ progress.md | 34 ++++ 4 files changed, 335 insertions(+) create mode 100644 editor/src/CrossLanguagePortScenarioRunner.h create mode 100644 editor/tests/step501_test.cpp diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 48891f8..49ea464 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -3388,4 +3388,13 @@ target_link_libraries(step500_test PRIVATE tree_sitter_javascript tree_sitter_typescript tree_sitter_java tree_sitter_rust tree_sitter_go) +add_executable(step501_test tests/step501_test.cpp) +target_include_directories(step501_test PRIVATE src) +target_link_libraries(step501_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/CrossLanguagePortScenarioRunner.h b/editor/src/CrossLanguagePortScenarioRunner.h new file mode 100644 index 0000000..52e6728 --- /dev/null +++ b/editor/src/CrossLanguagePortScenarioRunner.h @@ -0,0 +1,127 @@ +#pragma once + +// Step 501: Scenario - Cross-Language Port +// End-to-end scenario for porting a Python ML pipeline to Rust. + +#include "BehavioralEquivalence.h" +#include "ConcurrencyTranslator.h" +#include "IntentTranslator.h" +#include "MemoryModelTranslator.h" +#include "TranspilationConfidence.h" + +#include +#include +#include +#include + +struct PortedFunctionResult { + std::string name; + std::string source; + std::string intent; + bool hotLoop = false; + std::vector annotations; + TranslationChoice translation; + ConfidenceScore confidence; + BehavioralCheckResult equivalence; +}; + +struct CrossLanguagePortScenarioResult { + std::string sourceLanguage; + std::string targetLanguage; + std::string pipelineSource; + std::vector functions; + IntentTranslationResult intentTranslations; + MemoryAnalysisResult memoryAnalysis; + ConcurrencyAnalysisResult concurrencyAnalysis; + std::vector reviewRequiredFunctions; + std::vector notes; + + float averageConfidence() const { + if (functions.empty()) return 0.0f; + float sum = 0.0f; + for (const auto& f : functions) sum += f.confidence.score; + return sum / static_cast(functions.size()); + } +}; + +class CrossLanguagePortScenarioRunner { +public: + static CrossLanguagePortScenarioResult run() { + CrossLanguagePortScenarioResult out; + out.sourceLanguage = "python"; + out.targetLanguage = "rust"; + + const auto funcs = sampleFunctions(); + out.pipelineSource = composePipelineSource(funcs); + out.intentTranslations = IntentTranslator::translate(funcs, out.sourceLanguage, out.targetLanguage); + out.memoryAnalysis = MemoryModelTranslator::analyze( + out.pipelineSource, out.sourceLanguage, out.targetLanguage); + out.concurrencyAnalysis = ConcurrencyTranslator::analyze( + out.pipelineSource, out.sourceLanguage, out.targetLanguage); + + for (size_t i = 0; i < funcs.size(); ++i) { + PortedFunctionResult pf; + pf.name = funcs[i].name; + pf.source = funcs[i].source; + pf.intent = funcs[i].intent; + pf.hotLoop = isHotLoop(funcs[i].source); + if (pf.hotLoop) pf.annotations.push_back("@HotLoop(true)"); + if (!funcs[i].intent.empty()) pf.annotations.push_back("@Intent(" + funcs[i].intent + ")"); + + pf.translation = out.intentTranslations.getTranslation(funcs[i].name); + pf.confidence = TranspilationScorer::score( + funcs[i].name, funcs[i].source, pf.translation.targetCode, + out.sourceLanguage, out.targetLanguage, !funcs[i].intent.empty()); + pf.equivalence = BehavioralChecker::check( + funcs[i].name, funcs[i].source, pf.translation.targetCode, + out.sourceLanguage, out.targetLanguage, {}); + + if (pf.confidence.reviewRequired) out.reviewRequiredFunctions.push_back(pf.name); + out.functions.push_back(std::move(pf)); + } + + out.notes.push_back("Cross-language Python->Rust scenario executed"); + out.notes.push_back("Includes hot-loop tagging, transpilation confidence, and review surfacing"); + return out; + } + +private: + static std::vector sampleFunctions() { + return { + {"train_epoch", "reduce gradient sum", + "def train_epoch(samples):\n" + " total = 0\n" + " for i in range(len(samples)):\n" + " total += samples[i]\n" + " return total\n"}, + {"normalize_scores", "map transform normalize", + "def normalize_scores(scores):\n" + " return [s / 255.0 for s in scores]\n"}, + {"async_fetch_batch", "", + "import asyncio\n" + "async def async_fetch_batch(client, urls):\n" + " out = []\n" + " for u in urls:\n" + " out.append(await client.get(u))\n" + " return out\n"} + }; + } + + static std::string composePipelineSource(const std::vector& funcs) { + std::string out; + for (const auto& f : funcs) { + if (!out.empty()) out += "\n"; + out += f.source; + } + return out; + } + + static bool isHotLoop(const std::string& source) { + std::string s = source; + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) { return static_cast(std::tolower(c)); }); + return s.find("for ") != std::string::npos || + s.find("while ") != std::string::npos || + s.find("range(") != std::string::npos; + } +}; diff --git a/editor/tests/step501_test.cpp b/editor/tests/step501_test.cpp new file mode 100644 index 0000000..c65edf9 --- /dev/null +++ b/editor/tests/step501_test.cpp @@ -0,0 +1,165 @@ +// Step 501: Scenario - Cross-Language Port Tests (12 tests) + +#include "CrossLanguagePortScenarioRunner.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 CrossLanguagePortScenarioResult runNow() { + return CrossLanguagePortScenarioRunner::run(); +} + +void test_source_and_target_languages_are_python_to_rust() { + TEST(source_and_target_languages_are_python_to_rust); + auto r = runNow(); + CHECK(r.sourceLanguage == "python", "expected python source"); + CHECK(r.targetLanguage == "rust", "expected rust target"); + PASS(); +} + +void test_pipeline_source_contains_asyncio_and_loop_constructs() { + TEST(pipeline_source_contains_asyncio_and_loop_constructs); + auto r = runNow(); + CHECK(r.pipelineSource.find("async") != std::string::npos, "expected async pipeline source"); + CHECK(r.pipelineSource.find("for ") != std::string::npos, "expected loop in pipeline source"); + PASS(); +} + +void test_function_extraction_and_port_result_population() { + TEST(function_extraction_and_port_result_population); + auto r = runNow(); + CHECK(r.functions.size() == 3, "expected three functions in scenario"); + CHECK(r.intentTranslations.translations.size() == 3, "expected three translations"); + PASS(); +} + +void test_hot_loop_identification_tags_training_loop_function() { + TEST(hot_loop_identification_tags_training_loop_function); + auto r = runNow(); + bool foundHot = false; + for (const auto& f : r.functions) { + if (f.name == "train_epoch") { + foundHot = true; + CHECK(f.hotLoop, "train_epoch should be tagged hot loop"); + CHECK(!f.annotations.empty(), "expected hot loop annotation"); + } + } + CHECK(foundHot, "missing train_epoch function"); + PASS(); +} + +void test_semantic_transpilation_produces_idiomatic_rust_constructs() { + TEST(semantic_transpilation_produces_idiomatic_rust_constructs); + auto r = runNow(); + CHECK(r.intentTranslations.countIdiomatic() >= 2, "expected idiomatic rust translations"); + CHECK(r.intentTranslations.getTranslation("train_epoch").targetCode.find("fold") != std::string::npos, + "train_epoch should map to reduce/fold pattern"); + PASS(); +} + +void test_memory_model_translation_reflects_gc_to_borrowchecked_shift() { + TEST(memory_model_translation_reflects_gc_to_borrowchecked_shift); + auto r = runNow(); + CHECK(r.memoryAnalysis.sourceModel == OwnershipModel::GC, "python source should be GC model"); + CHECK(r.memoryAnalysis.targetModel == OwnershipModel::BorrowChecked, + "rust target should be borrow-checked model"); + PASS(); +} + +void test_concurrency_translation_maps_asyncio_to_tokio_pattern() { + TEST(concurrency_translation_maps_asyncio_to_tokio_pattern); + auto r = runNow(); + CHECK(r.concurrencyAnalysis.hasPattern("async/await"), "expected async/await translation"); + bool hasTokio = false; + for (const auto& t : r.concurrencyAnalysis.translations) { + if (t.pattern == "async/await" && + (t.annotation.find("tokio") != std::string::npos || + t.note.find("tokio") != std::string::npos)) { + hasTokio = true; + } + } + CHECK(hasTokio, "expected tokio runtime annotation or note"); + PASS(); +} + +void test_confidence_scoring_is_generated_for_every_translation() { + TEST(confidence_scoring_is_generated_for_every_translation); + auto r = runNow(); + for (const auto& f : r.functions) { + CHECK(f.confidence.score > 0.0f, "missing confidence score"); + CHECK(!f.confidence.annotation.empty(), "missing confidence annotation"); + } + CHECK(r.averageConfidence() > 0.0f, "expected positive average confidence"); + PASS(); +} + +void test_low_confidence_translation_is_flagged_for_human_review() { + TEST(low_confidence_translation_is_flagged_for_human_review); + auto r = runNow(); + bool flagged = false; + for (const auto& f : r.functions) { + if (f.name == "async_fetch_batch") { + flagged = true; + CHECK(f.confidence.reviewRequired, "async function should require review"); + } + } + CHECK(flagged, "missing async_fetch_batch function"); + CHECK(!r.reviewRequiredFunctions.empty(), "expected review-required function list"); + PASS(); +} + +void test_equivalence_assertions_are_generated_per_function() { + TEST(equivalence_assertions_are_generated_per_function); + auto r = runNow(); + for (const auto& f : r.functions) { + CHECK(f.equivalence.assertionCount() > 0, "missing equivalence assertions"); + CHECK(!f.equivalence.annotation.empty(), "missing equivalence annotation"); + } + PASS(); +} + +void test_review_queue_matches_low_confidence_functions() { + TEST(review_queue_matches_low_confidence_functions); + auto r = runNow(); + int lowConfidence = 0; + for (const auto& f : r.functions) { + if (f.confidence.reviewRequired) ++lowConfidence; + } + CHECK(static_cast(r.reviewRequiredFunctions.size()) == lowConfidence, + "review queue size mismatch"); + PASS(); +} + +void test_scenario_notes_include_cross_language_execution_summary() { + TEST(scenario_notes_include_cross_language_execution_summary); + auto r = runNow(); + CHECK(r.notes.size() >= 2, "expected scenario notes"); + CHECK(r.notes[0].find("Python->Rust") != std::string::npos, "missing scenario summary note"); + PASS(); +} + +int main() { + std::cout << "Step 501: Scenario - Cross-Language Port Tests\n"; + + test_source_and_target_languages_are_python_to_rust(); // 1 + test_pipeline_source_contains_asyncio_and_loop_constructs(); // 2 + test_function_extraction_and_port_result_population(); // 3 + test_hot_loop_identification_tags_training_loop_function(); // 4 + test_semantic_transpilation_produces_idiomatic_rust_constructs(); // 5 + test_memory_model_translation_reflects_gc_to_borrowchecked_shift(); // 6 + test_concurrency_translation_maps_asyncio_to_tokio_pattern(); // 7 + test_confidence_scoring_is_generated_for_every_translation(); // 8 + test_low_confidence_translation_is_flagged_for_human_review(); // 9 + test_equivalence_assertions_are_generated_per_function(); // 10 + test_review_queue_matches_low_confidence_functions(); // 11 + test_scenario_notes_include_cross_language_execution_summary(); // 12 + + std::cout << "\nResults: " << passed << "/" << (passed + failed) + << " passed\n"; + return failed == 0 ? 0 : 1; +} diff --git a/progress.md b/progress.md index 108614e..e245079 100644 --- a/progress.md +++ b/progress.md @@ -7678,3 +7678,37 @@ with Rust as the migration target. - `editor/src/LegacyModernizationScenarioRunner.h` within header-size limit (`125` <= `600`) - `editor/tests/step500_test.cpp` within test-file size guidance (`147` lines) - Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md` + +### Step 501: Scenario - Cross-Language Port +**Status:** PASS (12/12 tests) + +Implements the third Phase 25b end-to-end scenario for porting a Python ML-style +pipeline to Rust with confidence and review gating. + +**Files added:** +- `editor/src/CrossLanguagePortScenarioRunner.h` - scenario orchestration across: + - Python function intake and hot-loop tagging + - intent-driven semantic transpilation (`python` -> `rust`) + - memory model analysis (GC -> borrow-checked target model) + - concurrency translation (`asyncio`/async-await -> Rust tokio-oriented runtime notes) + - per-function confidence scoring and low-confidence review surfacing + - behavioral equivalence assertion generation +- `editor/tests/step501_test.cpp` - 12 scenario tests covering: + - language/source expectations and function extraction + - hot-loop identification + - idiomatic transpilation patterns + - memory/concurrency translation expectations + - confidence/review semantics + - equivalence assertion generation and scenario notes +- `editor/CMakeLists.txt` - `step501_test` target + +**Verification run:** +- `cmake -S editor -B editor/build-native` - PASS +- `cmake --build editor/build-native --target step501_test step500_test` - PASS +- `./editor/build-native/step501_test` - PASS (12/12) +- `./editor/build-native/step500_test` - PASS (12/12) regression coverage + +**Architecture gate check:** +- `editor/src/CrossLanguagePortScenarioRunner.h` within header-size limit (`127` <= `600`) +- `editor/tests/step501_test.cpp` within test-file size guidance (`165` lines) +- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`