// Step 1927: Sprint 279 Integration // poly-sort: Python data-gen calls Rust sort-core. // DAP proxy handles stack trace request; decoder labels Python+Rust frames; // detector finds the Python→Rust seam; router directs to the active adapter. // // t1: DAP proxy handles stackTrace, returns custom frame list // t2: decoder labels poly-sort stack (Python then Rust frames) // t3: seam detector finds Python→Rust boundary in poly-sort stack // t4: adapter router switches from Python to Rust at seam // t5: full pipeline: stack request → decode → detect seam → switch adapter // t6: Sprint279IntegrationSummary reports complete #include "DAPProxyServer.h" #include "DebugAdapterRouter.h" #include "PolyglotStackTraceDecoder.h" #include "LanguageSeamFrameDetector.h" #include "Sprint279IntegrationSummary.h" #include #include using json = nlohmann::json; namespace ws = whetstone; static int p=0,f=0; #define T(n) { std::cout<<" "<<#n<<"... "; } #define P() { std::cout<<"PASS\n"; ++p; } #define F(m) { std::cout<<"FAIL: "< polySortRawFrames() { return { {1, "main", "datagen/main.py", 10}, {2, "generate", "datagen/gen.py", 42}, {3, "sort_array", "sort-core/lib.rs", 5}, {4, "partition", "sort-core/lib.rs", 18}, {5, "swap", "sort-core/lib.rs", 30}, }; } void t1(){ T(dap_proxy_handles_stackTrace); ws::DAPProxyServer srv; srv.registerHandler("stackTrace", [](const json& args) -> json { return {{"stackFrames", json::array({ {{"id",1},{"name","main"}, {"source","datagen/main.py"}, {"line",10}}, {{"id",2},{"name","generate"}, {"source","datagen/gen.py"}, {"line",42}}, {{"id",3},{"name","sort_array"}, {"source","sort-core/lib.rs"}, {"line",5}} })}}; }); json req = {{"seq",1},{"type","request"},{"command","stackTrace"}, {"arguments",{{"threadId",1}}}}; auto resp = srv.handle(req); C(resp["success"] == true, "success"); C(resp["body"]["stackFrames"].size() == 3, "three frames"); C(resp["body"]["stackFrames"][2]["name"] == "sort_array", "rust frame present"); P(); } void t2(){ T(decoder_labels_polysort_stack); ws::PolyglotStackTraceDecoder dec; auto frames = dec.decode(polySortRawFrames()); C(frames.size() == 5, "five frames"); C(frames[0].language == "Python", "frame0 Python"); C(frames[1].language == "Python", "frame1 Python"); C(frames[2].language == "Rust", "frame2 Rust"); C(frames[3].language == "Rust", "frame3 Rust"); C(frames[4].language == "Rust", "frame4 Rust"); C(frames[2].astNodeId == "Rust:sort_array", "astNodeId for sort_array"); P(); } void t3(){ T(seam_detector_finds_python_rust_boundary); ws::PolyglotStackTraceDecoder dec; ws::LanguageSeamFrameDetector det; auto frames = dec.decode(polySortRawFrames()); C(det.seamCount(frames) == 2, "two seam frames"); C(det.primarySeam(frames) == 1, "primary seam at index 1 (generate)"); C(det.crossesBoundary(frames,"Python","Rust"), "Python→Rust transition present"); auto langs = det.frameLanguages(frames); C(langs.size() == 2, "two languages"); C(langs[0] == "Python", "Python first"); C(langs[1] == "Rust", "Rust second"); P(); } void t4(){ T(adapter_router_switches_at_seam); ws::DebugAdapterRouter router; router.registerAdapter("Python", {"stackTrace","continue","stepIn","next"}); router.registerAdapter("Rust", {"stackTrace","continue","next"}); // Start in Python (data-gen side) router.setActiveLanguage("Python"); C( router.routeCommand("stepIn","Python"), "Python can stepIn"); C(!router.routeCommand("stepIn","Rust"), "Rust can't stepIn (not active)"); // Cross the seam into Rust router.setActiveLanguage("Rust"); C( router.routeCommand("continue","Rust"), "Rust can continue"); C(!router.routeCommand("stepIn","Python"), "Python no longer active"); C(!router.routeCommand("stepIn","Rust"), "Rust lacks stepIn"); P(); } void t5(){ T(full_pipeline_stack_decode_seam_switch); ws::DAPProxyServer srv; ws::PolyglotStackTraceDecoder dec; ws::LanguageSeamFrameDetector det; ws::DebugAdapterRouter router; router.registerAdapter("Python", {"stackTrace","continue","stepIn"}); router.registerAdapter("Rust", {"stackTrace","continue"}); router.setActiveLanguage("Python"); // 1. DAP request brings back raw frames auto raw = polySortRawFrames(); // 2. Decode auto frames = dec.decode(raw); // 3. Detect seam int seam = det.primarySeam(frames); C(seam == 1, "seam at index 1"); // 4. The frame at the seam's next index is Rust — switch adapter std::string seamLang = frames[seam + 1].language; C(seamLang == "Rust", "seam crosses into Rust"); router.setActiveLanguage(seamLang); // 5. Rust adapter now active C(router.getActiveLanguage() == "Rust", "Rust is active"); C( router.routeCommand("continue","Rust"), "Rust handles continue"); C(!router.routeCommand("stepIn","Rust"), "Rust lacks stepIn — expected"); P(); } void t6(){ T(sprint279_integration_summary_complete); ws::Sprint279IntegrationSummary s; C(s.stepsCompleted == 5, "5 steps"); C(s.success, "success"); C(s.sprintName().find("279") != std::string::npos, "279 in name"); P(); } int main(){ std::cout << "Step 1927: Sprint 279 Integration (poly-sort: Python + Rust DAP)\n"; t1(); t2(); t3(); t4(); t5(); t6(); std::cout << "\n" << p << "/" << (p+f) << " passed\n"; return f > 0 ? 1 : 0; }