You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a sibling 4.0 workstream to #391, not a follow-up release. The migration design (docs/superpowers/specs/2026-08-10-xcresulttool-legacy-migration-design.md) already concedes the point: the report's visual contract breaks in 4.0 either way once activityType loses its data source — the five activity-type states stop being renderable no matter what the templates look like. Breaking the visual contract once, in the same major release, is cheaper than breaking it twice.
Sequencing (strict)
Templates stay frozen until Migrate off xcresulttool --legacy before Apple removes it #391's legacy/modern differential passes. The differential attributes every rendered diff to the reader swap; if reader and markup change together it can no longer attribute anything. No template PR merges before that gate.
Design exploration is not blocked. Palette, type, layout, dark-mode strategy can all be worked out concurrently on the current markup — only the merge is serialized behind the differential.
HTMLTemplates.swift claims to be generated, but the generator was deleted in #295 #434 must be resolved before any markup is written.Sources/XCTestHTMLReportCore/Classes/HTMLTemplates.swift is the real, hand-maintained source despite its stale "autogenerated — DO NOT EDIT" header; Sources/XCTestHTMLReportCore/HTML/*.html is a dead copy excluded from the build and 28 diff hunks behind. Anyone who starts the redesign from HTML/ is editing markup that does not ship. Whichever of HTMLTemplates.swift claims to be generated, but the generator was deleted in #295 #434's options is chosen, it has to land first so the redesign has exactly one source of truth (and one the linters actually see).
The structural problem
The stylesheet is 585 lines with zero custom properties, zero @media queries, no dark mode, no grid; all 16 colours are hardcoded hex literals (plus bare white/red), the font stack pins "SF Pro Display" with no system-ui and no generic fallback, and sizing is 99 fixed-px values with a single em in the whole sheet. There is no token layer, so every visual refresh is a scattered find-and-replace across literals — which is why there has been none since 2020.
A 2026-08-12 visual audit (rendered from the three fixture bundles next to Xcode 26's report on the same TestResults.xcresult) confirmed all of the above empirically — with the OS in dark mode, the report renders identical light — and catalogued the user-facing consequences:
No run summary of any kind: no counts visualization, no failure digest, no run date/duration/OS headline. The overview is just the tree. Xcode leads with a donut, per-device bars, a failure digest with messages, and build/runtime warnings.
A fixed three-pane layout spends ~200px on a device sidebar (even for single-device runs) and ~28% of the window on a right pane that almost always says "No Selected Attachment".
No <meta viewport> and fixed-px panes make small screens unusable: at 375px the sidebar eats over half the viewport and test rows clip mid-word.
Mixed-outcome (1 failed, 1 succeeded) and unknown-state tests render a blank status cell — only pass/fail/skip have icons.
Raw internals leak into the UI (kXCTAttachmentScreenRecording as an attachment label); the selected video keeps playing in the right pane after switching to the Logs tab.
The default linking-mode output silently breaks if moved anywhere: markup references TestResults.xcresult/<file>, so a report rendered with -o <elsewhere> has every attachment 404 with no warning — and the export mutates the source bundle. Inline mode (-i) is the true single-file artifact, at 8.6MB for the 54-second sample run.
Still worth protecting: the single-artifact shareability (our reason to exist), whole-run-in-one-tree visibility (Xcode hides passed tests behind filter dropdowns), compact retry/iteration rendering, JUnit export, instant client-side filters.
expectedFailure is now a named status in the ParsedResult model, though the renderer still flattens it — the redesign can surface it.
Swift Testing parameterized-test arguments exist in the port (ParsedTestCase.arguments, empty on legacy); the current templates have no slot for them.
Per-activity durations and the five activityType states are gone — activities carry start ordering and isFailure only. Xcode's own report shows elapsed offsets rather than per-activity durations, so this is a design opportunity, not just a loss.
Non-goal
This issue deliberately does not propose a visual direction (palette, type, layout, dark-mode approach). That exploration is unstarted on purpose and is the maintainer's call.
Scope and relationship to #391
This is a sibling 4.0 workstream to #391, not a follow-up release. The migration design (
docs/superpowers/specs/2026-08-10-xcresulttool-legacy-migration-design.md) already concedes the point: the report's visual contract breaks in 4.0 either way onceactivityTypeloses its data source — the five activity-type states stop being renderable no matter what the templates look like. Breaking the visual contract once, in the same major release, is cheaper than breaking it twice.Sequencing (strict)
Sources/XCTestHTMLReportCore/Classes/HTMLTemplates.swiftis the real, hand-maintained source despite its stale "autogenerated — DO NOT EDIT" header;Sources/XCTestHTMLReportCore/HTML/*.htmlis a dead copy excluded from the build and 28 diff hunks behind. Anyone who starts the redesign fromHTML/is editing markup that does not ship. Whichever of HTMLTemplates.swift claims to be generated, but the generator was deleted in #295 #434's options is chosen, it has to land first so the redesign has exactly one source of truth (and one the linters actually see).The structural problem
The stylesheet is 585 lines with zero custom properties, zero
@mediaqueries, no dark mode, no grid; all 16 colours are hardcoded hex literals (plus barewhite/red), the font stack pins"SF Pro Display"with nosystem-uiand no generic fallback, and sizing is 99 fixed-px values with a singleemin the whole sheet. There is no token layer, so every visual refresh is a scattered find-and-replace across literals — which is why there has been none since 2020.A 2026-08-12 visual audit (rendered from the three fixture bundles next to Xcode 26's report on the same
TestResults.xcresult) confirmed all of the above empirically — with the OS in dark mode, the report renders identical light — and catalogued the user-facing consequences:<meta viewport>and fixed-px panes make small screens unusable: at 375px the sidebar eats over half the viewport and test rows clip mid-word.1 failed, 1 succeeded) and unknown-state tests render a blank status cell — only pass/fail/skip have icons.kXCTAttachmentScreenRecordingas an attachment label); the selected video keeps playing in the right pane after switching to the Logs tab.TestResults.xcresult/<file>, so a report rendered with-o <elsewhere>has every attachment 404 with no warning — and the export mutates the source bundle. Inline mode (-i) is the true single-file artifact, at 8.6MB for the 54-second sample run.New data the redesign can act on once #391 lands
expectedFailureis now a named status in the ParsedResult model, though the renderer still flattens it — the redesign can surface it.argumentsexist in the port (ParsedTestCase.arguments, empty on legacy); the current templates have no slot for them.activityTypestates are gone — activities carrystartordering andisFailureonly. Xcode's own report shows elapsed offsets rather than per-activity durations, so this is a design opportunity, not just a loss.Non-goal
This issue deliberately does not propose a visual direction (palette, type, layout, dark-mode approach). That exploration is unstarted on purpose and is the maintainer's call.