From 5670ab7f5e2638962d24cc904db03f5e8bafac78 Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 10 Feb 2026 09:09:38 -0700 Subject: [PATCH] Step 234: Add session pipeline tests --- PROGRESS.md | 1 + editor/CMakeLists.txt | 3 ++ editor/src/SessionAnonymizer.h | 3 ++ editor/tests/step234_test.cpp | 81 ++++++++++++++++++++++++++++++++++ sprint7_plan.md | 2 +- 5 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 editor/tests/step234_test.cpp diff --git a/PROGRESS.md b/PROGRESS.md index c307979..bd22707 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -753,3 +753,4 @@ vcpkg's imgui 1.91.9 removed the `sdl2-binding` feature (only `sdl3-binding` exi | 2026-02-10 | Codex | Step 231: Session anonymizer (paths, secrets, identifier anonymization, comment/string stripping, levels, deterministic seed). 1/1 tests pass. | | 2026-02-10 | Codex | Step 232: Session-to-trace converter (events->user msgs, RPC->tool calls/results, gap splitting, synthetic thinking). 1/1 tests pass. | | 2026-02-10 | Codex | Step 233: Training data pipeline CLI (load/anonymize/convert/filter/dedup/export + stats). 1/1 tests pass. | +| 2026-02-10 | Codex | Step 234: Session pipeline tests (anonymizer round-trip, no PII, trace conversion, pipeline output count, quality filter, dedup). 1/1 tests pass. | diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 830ea00..8b4ee75 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -1184,6 +1184,9 @@ target_link_libraries(step232_test PRIVATE nlohmann_json::nlohmann_json) add_executable(step233_test tests/step233_test.cpp) target_include_directories(step233_test PRIVATE src) target_link_libraries(step233_test PRIVATE nlohmann_json::nlohmann_json) +add_executable(step234_test tests/step234_test.cpp) +target_include_directories(step234_test PRIVATE src) +target_link_libraries(step234_test PRIVATE nlohmann_json::nlohmann_json) add_executable(step213_test tests/step213_test.cpp) target_include_directories(step213_test PRIVATE src) target_link_libraries(step213_test PRIVATE nlohmann_json::nlohmann_json) diff --git a/editor/src/SessionAnonymizer.h b/editor/src/SessionAnonymizer.h index b411584..4011df2 100644 --- a/editor/src/SessionAnonymizer.h +++ b/editor/src/SessionAnonymizer.h @@ -233,6 +233,9 @@ private: } std::string anonymizeStringValue(const std::string& value, const std::string& key) { + if (key == "method" || key == "jsonrpc") { + return value; + } if (!key.empty() && keyLooksLikePath(key)) { return anonymizePath(value); } diff --git a/editor/tests/step234_test.cpp b/editor/tests/step234_test.cpp new file mode 100644 index 0000000..8f8e4b2 --- /dev/null +++ b/editor/tests/step234_test.cpp @@ -0,0 +1,81 @@ +// Step 234: Session pipeline tests. +#include "SessionPipeline.h" +#include + +static void expect(bool cond, const std::string& name, int& passed, int& failed) { + if (cond) { + std::cout << "Test " << (passed + failed + 1) << " PASS: " << name << "\n"; + ++passed; + } else { + std::cout << "Test " << (passed + failed + 1) << " FAIL: " << name << "\n"; + ++failed; + } +} + +static json sampleSession(const std::string& pathValue, const std::string& method) { + return { + {"sessionId", "s1"}, + {"metadata", {{"language", "python"}}}, + {"events", json::array({{ + {"timestamp", "2026-02-10T10:00:00.000"}, + {"type", "file_opened"}, + {"payload", {{"path", pathValue}}} + }})}, + {"calls", json::array({{ + {"timestamp", "2026-02-10T10:00:01.000"}, + {"method", method}, + {"request", {{"params", json::object()}}}, + {"response", {{"result", json::object()}}} + }})} + }; +} + +int main() { + int passed = 0; + int failed = 0; + + try { + SessionAnonymizer anonymizer; + anonymizer.setLevel(SessionAnonymizer::Level::Medium); + + json session = sampleSession("C:/Users/Bob/project/main.py", "getAST"); + json anon = anonymizer.anonymize(session); + + expect(session["calls"].size() == anon["calls"].size(), "structure preserved", passed, failed); + expect(anon.contains("events") && anon.contains("calls"), "events and calls preserved", passed, failed); + std::string anonPath = anon["events"][0]["payload"].value("path", ""); + expect(anonPath.find("/project/src/") == 0, "paths anonymized", passed, failed); + expect(anon.dump().find("Bob") == std::string::npos, "identifiers removed", passed, failed); + + SessionTraceConverter converter; + auto traces = converter.convert(anon); + expect(!traces.empty() && validateTrace(traces[0]), "trace conversion valid", passed, failed); + + PipelineStats stats; + auto filtered = filterTraces(traces, stats); + std::string jsonl = exportTraces(filtered, "jsonl"); + int lineCount = 0; + for (char c : jsonl) if (c == '\n') lineCount++; + expect(lineCount == (int)filtered.size(), "pipeline output count", passed, failed); + + Trace degenerate; + degenerate.id = "bad"; + degenerate.scenario = "session_replay"; + degenerate.language = "python"; + std::vector withDegenerate = {traces[0], degenerate}; + PipelineStats stats2; + auto filtered2 = filterTraces(withDegenerate, stats2); + expect(filtered2.size() == 1, "quality filter removes degenerate", passed, failed); + + PipelineStats stats3; + auto deduped = dedupeTraces({traces[0], traces[0]}, stats3); + expect(deduped.size() == 1, "deduplication works", passed, failed); + } catch (const std::exception& ex) { + std::cerr << "Exception: " << ex.what() << "\n"; + failed++; + } + + std::cout << "\n=== Step 234 Results: " << passed << " passed, " + << failed << " failed ===\n"; + return failed == 0 ? 0 : 1; +} diff --git a/sprint7_plan.md b/sprint7_plan.md index 43429b8..db27b5a 100644 --- a/sprint7_plan.md +++ b/sprint7_plan.md @@ -440,7 +440,7 @@ Capture real editing sessions, anonymize them, and export as training data. - Validation: all output traces pass schema validation *New:* `editor/src/pipeline_main.cpp` -- [ ] **Step 234: Session pipeline tests** +- [x] **Step 234: Session pipeline tests** Tests for the recording and conversion pipeline: 1. Recorded session round-trips through anonymizer preserving structure 2. Anonymized sessions have no file paths or identifiable content