Cross-backend identifier normalizer and baseline render capture (#391) - #437
Conversation
📝 WalkthroughWalkthroughThe test suite adds digest normalization, reproducibility checks for ChangesReproducibility and Baselines
Estimated code review effort: 3 (Moderate) | ~20 minutes Mergeability Score: 🟡 Moderate · up to The new cross-backend normalizer can leave rendered identifiers unchanged when digests follow hexadecimal identifier text, causing future differential comparisons to report false differences. Update the digest boundaries in the implementation and plan example before merging. Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Tests/XCTestHTMLReportTests/ReportNormalizer.swift`:
- Around line 18-23: The identifierPattern in ReportNormalizer.swift must use
hexadecimal-character boundaries instead of \b so digests embedded in
device_<digest> are matched; replace its pattern with
(?<![0-9a-f])[0-9a-f]{32}(?![0-9a-f]). Apply the same pattern update in
docs/superpowers/plans/2026-08-10-xcresulttool-legacy-migration.md lines 198-208
for the copied plan example.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 52470804-8bbc-4aab-9e4a-ba174731e4a1
📒 Files selected for processing (4)
Tests/XCTestHTMLReportTests/BaselineCaptureTests.swiftTests/XCTestHTMLReportTests/ReportNormalizer.swiftTests/XCTestHTMLReportTests/ReproducibilityTests.swiftdocs/superpowers/plans/2026-08-10-xcresulttool-legacy-migration.md
| private let identifierPattern: NSRegularExpression = { | ||
| guard let pattern = try? NSRegularExpression(pattern: "\\b[0-9a-f]{32}\\b") else { | ||
| preconditionFailure("The identifier pattern is a constant and must compile") | ||
| } | ||
| return pattern | ||
| }() |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- implementation ---'
cat -n Tests/XCTestHTMLReportTests/ReportNormalizer.swift | sed -n '1,120p'
printf '%s\n' '--- plan excerpt ---'
cat -n docs/superpowers/plans/2026-08-10-xcresulttool-legacy-migration.md | sed -n '175,225p'
printf '%s\n' '--- related tests and usages ---'
rg -n -C 3 'ReportNormalizer|identifierPattern|device_|[0-9a-f]\{32\}' Tests docs
printf '%s\n' '--- Swift availability ---'
command -v swift || trueRepository: XCTestHTMLReport/XCTestHTMLReport
Length of output: 13266
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- IdentifierPath and identifier rendering ---'
rg -n -C 5 'struct IdentifierPath|class IdentifierPath|enum IdentifierPath|IdentifierPath|device_' Classes Tests | head -n 240
printf '%s\n' '--- normalizer call sites ---'
rg -n -C 5 'normalizeIdentifiers|identifierPattern' Tests docs
printf '%s\n' '--- boundary probe ---'
python3 - <<'PY'
import re
pattern = re.compile(r"\b[0-9a-f]{32}\b")
hex_digest = "0123456789abcdef0123456789abcdef"
for value in [
hex_digest,
"device_" + hex_digest,
"id=" + hex_digest,
"x" + hex_digest,
"_" + hex_digest,
hex_digest + "_suffix",
hex_digest + "0",
"g" + hex_digest,
]:
print(f"{value!r} -> {pattern.sub('ID', value)!r}")
PYRepository: XCTestHTMLReport/XCTestHTMLReport
Length of output: 21795
Use hexadecimal boundaries for IdentifierPath digests — \b does not match the digest in device_<digest>, so cross-backend normalization leaves rendered identifiers unchanged. Use (?<![0-9a-f])[0-9a-f]{32}(?![0-9a-f]) in both the implementation and the copied plan example.
📍 Affects 2 files
Tests/XCTestHTMLReportTests/ReportNormalizer.swift#L18-L23(this comment)docs/superpowers/plans/2026-08-10-xcresulttool-legacy-migration.md#L198-L208
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Tests/XCTestHTMLReportTests/ReportNormalizer.swift` around lines 18 - 23, The
identifierPattern in ReportNormalizer.swift must use hexadecimal-character
boundaries instead of \b so digests embedded in device_<digest> are matched;
replace its pattern with (?<![0-9a-f])[0-9a-f]{32}(?![0-9a-f]). Apply the same
pattern update in
docs/superpowers/plans/2026-08-10-xcresulttool-legacy-migration.md lines 198-208
for the copied plan example.
Implements Tasks 1 and 2 of the xcresulttool legacy migration plan (#391, milestone 4.0).
Task 1 — cross-backend identifier normalizer
Tests/XCTestHTMLReportTests/ReportNormalizer.swift:normalizeIdentifiers(_:)replaces every post-fix: derive report identifiers from bundle content so runs are reproducible #430IdentifierPathdigest (\b[0-9a-f]{32}\b, never RFC-4122 UUIDs) with the literalID.ReproducibilityTests.swift(shipped by fix: derive report identifiers from bundle content so runs are reproducible #430): one pins the replacement to digests and nothing else, one proves the pattern actually matches a rendered report so the Task 12 differential can't silently degrade to comparing raw identifiers.Task 2 — opt-in baseline capture
Tests/XCTestHTMLReportTests/BaselineCaptureTests.swift: writes raw (un-normalized) renders of all three fixtures to$XCHR_BASELINE_DIR; skips with an explicit message when the variable is unset. Guards the Task 5a refactor: capture before, capture after,diff -r, within one fixture generation.Plan amendments
The plan's snippets had never been compiled; three corrections were made and the plan document amended to match in the same commits:
sanityResultsUrlhelper was missing — the Task 1 test snippet references it, but the shippedReproducibilityTests.swiftonly had URL helpers forTestResultsandRetryResults. Added beside them.try!fails the pre-commit SwiftLint gate (force_tryerror) — the normalizer's constant regex now unwraps through apreconditionFailureclosure instead. (Also swappedString(decoding:as:)for failableString(bytes:encoding:)to satisfyoptional_data_string_conversion.)testCaptureNormalizedRenders— a leftover from the pre-fix: derive report identifiers from bundle content so runs are reproducible #430 plan revision; it captures raw bytes, so it is namedtestCaptureRawRenders.Verification
IdentifierPath.swiftpresent (fix: derive report identifiers from bundle content so runs are reproducible #430 /a28b131);ReproducibilityTestsgreen before any change.cannot find 'normalizeIdentifiers' in scopebefore the implementation.XCHR_BASELINE_DIR, writes three non-empty.htmlfiles with it.🤖 Generated with Claude Code
Summary by CodeRabbit
Tests
Documentation