test(pipeline): fix Phase 2 tests to require ssr.build execution#126
Conversation
Existing Phase 2 tests validated local DSD transform (shadowrootmode insertion), but the spec says BuildPhase2 must shell out to the configured ssr.build command — Alloy does not perform SSR itself. Changes: - Fix "Phase 2 transforms intermediate HTML" to expect command execution error when ssr.build tool is not installed (not local transform) - Fix "Phase 2 receives Phase 1 output" to use echo as ssr.build command - Fix "with SSR config" to tolerate command execution error - Add "BuildPhase2 returns error when ssr.build command fails" - Add "BuildPhase2 does not fall back to local transform" - Update IMPLEMENTATION.md Phase 4D: BuildPhase2 uses os/exec, no fallback Closes #117 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
zeroedin
left a comment
There was a problem hiding this comment.
Review: PR #126 — test(pipeline): fix Phase 2 tests to require ssr.build command execution
Scope: internal/pipeline/build_test.go (65 additions, 24 deletions), plans/IMPLEMENTATION.md (2 lines)
Background
The spec (PLAN.md §6, lines 1949-1962) is explicit: "Alloy does not import any SSR engine as a Go dependency. External engines are CLI binaries... Alloy runs the ssr.build command after Phase 1 writes _site/." But the current BuildPhase2 implementation at build.go:797-811 calls transformCustomElements() — a local regex-based DSD transform. The existing tests validated this local behavior, which contradicts the spec.
What changed
Modified tests (3):
-
"Phase 2 executes ssr.build command against intermediate HTML" (was "Phase 2 transforms intermediate HTML") — No longer asserts
shadowrootmodein output. Instead asserts thatBuildPhase2returns an error referencing the command (golit,exec, ornot found) since the tool won't exist in CI. Correct: the test proves the function attempts external execution rather than locally transforming. -
"Phase 2 receives Phase 1 output as its input" — Changed
ssr.buildfrom"golit render _site/**/*.html"to"echo ok". Since the test only needs to verify Phase 1 output reaches Phase 2, using a command that exists (echo) but doesn't transform files is sufficient. The_ = errpattern is acceptable here — either success or failure proves Phase 2 accepted the input and attempted execution. -
"with SSR config, Phase 2 runs" — Changed to
"echo ok"and wrapped the SSRSkipped assertion inif err == nil. This is pragmatic: the test's purpose is to verify SSRSkipped is false when SSR is configured, but it can't guaranteeecho okwill succeed on all platforms.
New tests (2):
-
"BuildPhase2 returns error when ssr.build command fails" — Uses
"nonexistent-ssr-tool --transform _site/", asserts error. Clean and direct. -
"BuildPhase2 does not fall back to local transform when command is unavailable" — The key TDD test. If no error, asserts output does NOT contain
shadowrootmode. This directly catches the current bug:transformCustomElementsproducesshadowrootmodeoutput even when the external command doesn't exist.
IMPLEMENTATION.md:
- Phase 4D test count 16→18.
BuildPhase2description updated: "executes the externalssr.buildcommand viaos/exec... no silent fallback."
Analysis
-
Spec alignment is correct: The spec says Alloy shells out. The old tests validated local transform. The new tests require external execution.
-
TDD is well-structured: 3 tests will fail against the current implementation, proving the spec violation. Once
BuildPhase2is changed to useos/exec, all 18 tests should pass. -
The
SatisfyAnymatcher in test 1 is appropriate: Different OS/shell environments report missing commands differently ("executable file not found"vs"not found"vs referencing the command name). Matching any ofgolit/exec/not foundcovers the common cases. -
No orphaned code concern:
transformCustomElementsstill exists inbuild.gobut will become dead code once the implementation PR lands. The implementation PR should remove it.
One observation
Test 3 ("with SSR config") using if err == nil makes the SSRSkipped assertion conditional. If echo ok fails on some platform, the test silently passes without validating the SSRSkipped field. This is a minor coverage gap, but acceptable given the test's comment explains the intent.
Verdict
LGTM — correct spec alignment. The tests now validate the right contract (external command execution, no local fallback). Clean TDD: 15 pass, 3 fail, proving the bug exists.
The "with SSR config" test had a conditional assertion that silently passed when echo failed. Now both branches assert: success path checks SSRSkipped=false, error path verifies the error came from Phase 2 command execution. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
zeroedin
left a comment
There was a problem hiding this comment.
Re-review: PR #126 — commit cf19d07 addresses SSR skip test gap
New commit: cf19d07 — "fix(test): address review — SSR skip test always validates something"
What changed
The "with SSR config, Phase 2 runs" test previously had a silent pass when echo ok errored — the if err == nil guard meant the SSRSkipped assertion was conditional, and the error path had only a comment.
Now both branches assert:
- Error path: Verifies the error came from Phase 2 command execution (matches
echo/exec/ssr), not from Phase 1 or config validation. This proves Phase 2 was attempted. - Success path: Unchanged — asserts
SSRSkipped == false.
Verdict
LGTM — the review concern is resolved. Every code path in the test now validates something meaningful. No other changes in the PR.
Summary
shadowrootmodeinsertion). Per spec §6,BuildPhase2must shell out to the configuredssr.buildcommand — Alloy does not perform SSR itself.BuildPhase2must error when the command fails (not silently fall back to local transform).os/execcommand execution with no fallback.Test changes (16 → 18 specs)
shadowrootmodeoutputecho okas ssr.build commandshadowrootmodevia local fallbackCurrent state: 15 pass, 3 fail
The 3 failing tests prove the bug —
BuildPhase2currently does a localtransformCustomElementsinstead of executingssr.build. These will pass once the implementation shells out viaos/exec.Reopened from #124 (closed with merge conflicts, now resolved).
Test plan
go vet ./internal/pipeline/...compiles cleanCloses #117
🤖 Generated with Claude Code