From 7de00387cc8c80658cc95c7aeb6835ba884e2697 Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 17 Feb 2026 11:16:39 -0700 Subject: [PATCH] Sprint 32: end-of-sprint architecture refactor pass --- editor/src/AcceptanceCriteriaBinding.h | 25 ++-------- editor/src/IntakeTextUtil.h | 48 +++++++++++++++++++ editor/src/MarkdownSpecParser.h | 26 ++-------- ...RequirementNormalizationConflictDetector.h | 17 +------ progress.md | 38 +++++++++++++++ 5 files changed, 97 insertions(+), 57 deletions(-) create mode 100644 editor/src/IntakeTextUtil.h diff --git a/editor/src/AcceptanceCriteriaBinding.h b/editor/src/AcceptanceCriteriaBinding.h index e380a3b..60f2867 100644 --- a/editor/src/AcceptanceCriteriaBinding.h +++ b/editor/src/AcceptanceCriteriaBinding.h @@ -1,10 +1,9 @@ #pragma once // Step 581: Acceptance-Criteria Binding +#include "IntakeTextUtil.h" #include "TaskitemConfidenceAmbiguity.h" -#include -#include #include #include @@ -61,23 +60,9 @@ public: private: static std::string makeTestSkeleton(const std::string& taskId, const std::string& checkText) { - return "test_" + sanitize(taskId) + "_" + sanitize(checkText); - } - - static std::string sanitize(const std::string& text) { - std::string out; - bool lastUnderscore = false; - for (char c : text) { - if (std::isalnum(static_cast(c))) { - out.push_back(static_cast(std::tolower(static_cast(c)))); - lastUnderscore = false; - } else if (!lastUnderscore) { - out.push_back('_'); - lastUnderscore = true; - } - } - while (!out.empty() && out.front() == '_') out.erase(out.begin()); - while (!out.empty() && out.back() == '_') out.pop_back(); - return out.empty() ? "check" : out; + const std::string a = intakeSanitizeToken(taskId, '_'); + const std::string b = intakeSanitizeToken(checkText, '_'); + return "test_" + (a.empty() ? std::string("task") : a) + "_" + + (b.empty() ? std::string("check") : b); } }; diff --git a/editor/src/IntakeTextUtil.h b/editor/src/IntakeTextUtil.h new file mode 100644 index 0000000..15263c3 --- /dev/null +++ b/editor/src/IntakeTextUtil.h @@ -0,0 +1,48 @@ +#pragma once +// Sprint 32 refactor: shared intake text normalization helpers + +#include +#include +#include + +inline std::string intakeToLower(const std::string& value) { + std::string out = value; + std::transform(out.begin(), out.end(), out.begin(), [](unsigned char c) { + return static_cast(std::tolower(c)); + }); + return out; +} + +inline std::string intakeCompactLowerAlnumSpaces(const std::string& text) { + std::string out; + bool lastSpace = false; + for (char c : text) { + if (std::isalnum(static_cast(c))) { + out.push_back(static_cast(std::tolower(static_cast(c)))); + lastSpace = false; + } else if (!lastSpace) { + out.push_back(' '); + lastSpace = true; + } + } + while (!out.empty() && out.front() == ' ') out.erase(out.begin()); + while (!out.empty() && out.back() == ' ') out.pop_back(); + return out; +} + +inline std::string intakeSanitizeToken(const std::string& text, char separator) { + std::string out; + bool lastSep = false; + for (char c : intakeToLower(text)) { + if (std::isalnum(static_cast(c))) { + out.push_back(c); + lastSep = false; + } else if (!lastSep) { + out.push_back(separator); + lastSep = true; + } + } + while (!out.empty() && out.front() == separator) out.erase(out.begin()); + while (!out.empty() && out.back() == separator) out.pop_back(); + return out; +} diff --git a/editor/src/MarkdownSpecParser.h b/editor/src/MarkdownSpecParser.h index d1c5fbc..8e86a91 100644 --- a/editor/src/MarkdownSpecParser.h +++ b/editor/src/MarkdownSpecParser.h @@ -1,6 +1,8 @@ #pragma once // Step 574: Markdown Spec Parser +#include "IntakeTextUtil.h" + #include #include #include @@ -71,7 +73,7 @@ public: item.line = lineNo; if (item.text.empty()) continue; - const std::string lowerTitle = toLower(currentSection.title); + const std::string lowerTitle = intakeToLower(currentSection.title); if (contains(lowerTitle, "goal")) { spec.goals.push_back(item); } else if (contains(lowerTitle, "constraint")) { @@ -101,14 +103,6 @@ private: return text.find(needle) != std::string::npos; } - static std::string toLower(const std::string& value) { - std::string out = value; - std::transform(out.begin(), out.end(), out.begin(), [](unsigned char c) { - return static_cast(std::tolower(c)); - }); - return out; - } - static std::string trimLeft(const std::string& value) { std::size_t i = 0; while (i < value.size() && std::isspace(static_cast(value[i]))) ++i; @@ -124,19 +118,7 @@ private: } static std::string makeAnchor(const std::string& title) { - std::string anchor; - bool previousDash = false; - for (char c : toLower(title)) { - if (std::isalnum(static_cast(c))) { - anchor.push_back(c); - previousDash = false; - } else if (!previousDash) { - anchor.push_back('-'); - previousDash = true; - } - } - while (!anchor.empty() && anchor.front() == '-') anchor.erase(anchor.begin()); - while (!anchor.empty() && anchor.back() == '-') anchor.pop_back(); + std::string anchor = intakeSanitizeToken(title, '-'); return anchor.empty() ? "section" : anchor; } }; diff --git a/editor/src/RequirementNormalizationConflictDetector.h b/editor/src/RequirementNormalizationConflictDetector.h index 72e8903..e6e29d9 100644 --- a/editor/src/RequirementNormalizationConflictDetector.h +++ b/editor/src/RequirementNormalizationConflictDetector.h @@ -1,9 +1,9 @@ #pragma once // Step 575: Requirement Normalization and Conflict Detection +#include "IntakeTextUtil.h" #include "MarkdownSpecParser.h" -#include #include #include #include @@ -81,20 +81,7 @@ private: } static std::string normalizeText(const std::string& text) { - std::string out; - bool lastSpace = false; - for (char c : text) { - if (std::isalnum(static_cast(c))) { - out.push_back(static_cast(std::tolower(static_cast(c)))); - lastSpace = false; - } else { - if (!lastSpace) out.push_back(' '); - lastSpace = true; - } - } - while (!out.empty() && out.front() == ' ') out.erase(out.begin()); - while (!out.empty() && out.back() == ' ') out.pop_back(); - return out; + return intakeCompactLowerAlnumSpaces(text); } static bool isAmbiguous(const std::string& normalizedText) { diff --git a/progress.md b/progress.md index 6ee9e7c..28953ba 100644 --- a/progress.md +++ b/progress.md @@ -10913,3 +10913,41 @@ signals into phase/sprint outcomes with closure diagnostics. - **New tests in this sprint plan:** 112/112 passing - **Phase 32a (574-578):** 56/56 passing - **Phase 32b (579-583):** 56/56 passing + +### Sprint 32 End Refactor Pass (Architecture Compliance) +**Status:** PASS (112/112 tests revalidated) + +Performed a focused post-sprint refactor to centralize intake text +normalization/sanitization logic used by markdown parsing, requirement +normalization, and acceptance test-skeleton generation. + +**Files added:** +- `editor/src/IntakeTextUtil.h` - shared intake text helpers: + - lowercase normalization helper + - compact alnum-space normalization helper + - generic token sanitization helper with configurable separators + +**Files modified:** +- `editor/src/MarkdownSpecParser.h` - switched heading/lowercase/anchor normalization paths to shared intake text helpers +- `editor/src/RequirementNormalizationConflictDetector.h` - switched requirement text canonicalization to shared compact-normalization helper +- `editor/src/AcceptanceCriteriaBinding.h` - switched test-skeleton token sanitization to shared intake token sanitizer + +**Verification run:** +- `cmake --build editor/build-native --target step574_test step575_test step576_test step577_test step578_test step579_test step580_test step581_test step582_test step583_test` - PASS +- `./editor/build-native/step574_test` - PASS (12/12) +- `./editor/build-native/step575_test` - PASS (12/12) +- `./editor/build-native/step576_test` - PASS (12/12) +- `./editor/build-native/step577_test` - PASS (12/12) +- `./editor/build-native/step578_test` - PASS (8/8) +- `./editor/build-native/step579_test` - PASS (12/12) +- `./editor/build-native/step580_test` - PASS (12/12) +- `./editor/build-native/step581_test` - PASS (12/12) +- `./editor/build-native/step582_test` - PASS (12/12) +- `./editor/build-native/step583_test` - PASS (8/8) + +**Architecture gate check:** +- `editor/src/IntakeTextUtil.h` within header-size limit (`48` <= `600`) +- `editor/src/MarkdownSpecParser.h` within header-size limit (`124` <= `600`) +- `editor/src/RequirementNormalizationConflictDetector.h` within header-size limit (`153` <= `600`) +- `editor/src/AcceptanceCriteriaBinding.h` within header-size limit (`68` <= `600`) +- Shared normalization centralization reduces duplicated string-normalization logic and stays aligned with `ARCHITECTURE.md`