// Step 1993: ingest_legacy_to_ir → generate_cpp_from_ir chain fix // Verifies that ingest_legacy_to_ir emits a valid SemanticCoreIR "ir" field // that can be passed directly to generate_cpp_from_ir without transformation. #include "MCPServer.h" #include "SemanticCoreIR.h" #include #include #include static json callTool(MCPServer& srv, const std::string& name, json params = json::object()) { json req = {{"jsonrpc", "2.0"}, {"id", 1}, {"method", "tools/call"}, {"params", {{"name", name}, {"arguments", std::move(params)}}}}; return srv.handleRequest(req); } static bool isSuccess(const json& resp) { return resp.contains("result") && resp["result"].contains("isError") && resp["result"]["isError"] == false; } // Parse the content text back to json for deeper inspection. static json resultJson(const json& resp) { if (!resp.contains("result") || !resp["result"].contains("content")) return json::object(); const auto& content = resp["result"]["content"]; if (!content.is_array() || content.empty()) return json::object(); const std::string text = content[0].value("text", "{}"); return json::parse(text, nullptr, false); } int main() { int passed = 0; MCPServer srv; // ---------------------------------------------------------------- // Test 1: ingest_legacy_to_ir returns an "ir" field // ---------------------------------------------------------------- { auto resp = callTool(srv, "whetstone_ingest_legacy_to_ir", {{"source", "MyLegacyModule"}, {"language", "cpp"}}); assert(isSuccess(resp)); json r = resultJson(resp); assert(r["success"] == true); assert(r.contains("ir")); assert(r["ir"].is_object()); std::cout << "Test 1 PASSED: ingest_legacy_to_ir emits ir field\n"; ++passed; } // ---------------------------------------------------------------- // Test 2: ir field is a valid SemanticCoreIR (parses + validates) // ---------------------------------------------------------------- { auto resp = callTool(srv, "whetstone_ingest_legacy_to_ir", {{"source", "MyLegacyModule"}, {"language", "cpp"}}); json r = resultJson(resp); const json& irJson = r["ir"]; SemanticCoreIR ir; std::string err; bool parsed = SemanticCoreIRModel::fromJson(irJson, &ir, &err); assert(parsed && "SemanticCoreIRModel::fromJson failed"); bool valid = SemanticCoreIRModel::validate(ir, &err); assert(valid && "SemanticCoreIRModel::validate failed"); assert(!ir.moduleId.empty()); assert(!ir.nodes.empty()); std::cout << "Test 2 PASSED: ir field parses and validates as SemanticCoreIR\n"; ++passed; } // ---------------------------------------------------------------- // Test 3: ir nodes have unique ids and known kinds // ---------------------------------------------------------------- { auto resp = callTool(srv, "whetstone_ingest_legacy_to_ir", {{"source", "SomeSource"}, {"language", "cpp"}}); json r = resultJson(resp); SemanticCoreIR ir; std::string err; SemanticCoreIRModel::fromJson(r["ir"], &ir, &err); std::set ids; for (const auto& n : ir.nodes) { assert(!n.id.empty()); assert(ids.insert(n.id).second && "duplicate node id"); assert(n.language == "cpp"); } for (const auto& e : ir.edges) { assert(!e.fromId.empty() && !e.toId.empty()); assert(e.relation == "inferred"); } std::cout << "Test 3 PASSED: IR nodes have unique ids and valid edges\n"; ++passed; } // ---------------------------------------------------------------- // Test 4: ir field passes directly to generate_cpp_from_ir // ---------------------------------------------------------------- { auto ingestResp = callTool(srv, "whetstone_ingest_legacy_to_ir", {{"source", "MyLegacyModule"}, {"language", "cpp"}}); assert(isSuccess(ingestResp)); json ingestResult = resultJson(ingestResp); auto genResp = callTool(srv, "whetstone_generate_cpp_from_ir", {{"ir", ingestResult["ir"]}, {"profile", "safe-first"}}); assert(isSuccess(genResp)); json genResult = resultJson(genResp); assert(genResult["success"] == true); assert(genResult.contains("files")); std::cout << "Test 4 PASSED: generate_cpp_from_ir accepts ir from ingest\n"; ++passed; } // ---------------------------------------------------------------- // Test 5: existing ingest output fields are preserved // ---------------------------------------------------------------- { auto resp = callTool(srv, "whetstone_ingest_legacy_to_ir", {{"source", "LegacyTodoModule TODO fix me"}, {"language", "cpp"}}); json r = resultJson(resp); assert(r.contains("graph")); assert(r.contains("api_intent")); assert(r.contains("assumption")); assert(r.contains("ambiguity")); assert(r.contains("readiness")); assert(r.contains("ir")); // new field alongside existing std::cout << "Test 5 PASSED: existing fields preserved alongside ir\n"; ++passed; } std::cout << "\n" << passed << "/5 passed\n"; return passed == 5 ? 0 : 1; }