Repository navigation
fix(test): attribute Go failures from go test -json and carry their output (#283) - #297
Merged
Merged
Conversation
…utput (#283) procoder test and the gate's test leg scraped `^--- FAIL: (\S+)` out of go test's text stream. Two misattributions were demonstrated on real go test output: - a test that prints a `--- FAIL: TestOther` line to stdout is reported as TestOther failing, and the count is wrong; - a package that fails outside any test (build or setup failure, a panic in a background goroutine, a timeout) has no `--- FAIL:` line, so it vanished beside a real test failure and, alone, was summarised as the first line of output, which can be an unrelated package's "ok". The Go runner now reads `go test -json`: failures come from the framework's fail events, subtests are named by the leaf that failed, and package-only failures are named by package with go's reason ("[build failed]"). Each failure carries a bounded excerpt of its own output (3 failures, 20 lines each keeping the head where a panic names itself, 240-byte lines, 4 KiB total) under the FAIL line in procoder test and in the gate's finding, so the next unreproducible red says what it asserted rather than only a name. The store guard tests now tolerate a file that vanished between the walk and the parse, and only that: a present file that does not parse, partial writes included, still fails the guard.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved issues remain in diagnostic attribution, excerpt preservation, and excerpt size limits.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 2
Open (2)
What changed in this PR
Updates Go test execution to use go test -json, improve failure attribution, preserve bounded diagnostics, and tolerate vanished store files.
Changes:
- Adds JSON-based failure parsing and excerpts to reports and gate findings.
- Adds regression tests for attribution, output limits, and disappearing files.
- Updates related documentation and command expectations.
| File | Summary |
|---|---|
internal/testrun/testrun.go |
Integrates JSON parsing and failure output. |
internal/testrun/gojson.go |
Parses Go events and builds excerpts. |
internal/testrun/gojson_test.go |
Adds parser and attribution tests. |
internal/testrun/gate.go |
Adds excerpts to gate findings. |
internal/testrun/filter_test.go |
Updates expected Go arguments. |
internal/store/coverage_test.go |
Handles vanished files during parsing. |
docs/domains.md |
Documents JSON-based Go testing. |
docs/commands.md |
Documents Go failure diagnostics. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Review of #297: a long subtest name or import path was written uncapped and could spend the excerpt budget before the diagnosis; and on Go before 1.24 the stray stderr stream was copied under every package that failed outside a test, reading as each package's own error.
This was referenced Sep 23, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Refs #283
What this does
The failing package's output is now kept (the issue's suggested next step). Every Go failure carries a short excerpt of its own output: the assertion, the panic or the build error. It appears under the FAIL line in
procoder testand in the gate's finding. It has hard limits: 3 failures, 20 lines each (the first 5 are kept, because that is where a panic says what it was), 240 bytes per line and 4 KiB in total. The one-line summary is unchanged.Hypothesis 1 (wrong test name reported): the parser does misattribute. The runner used to pull
^--- FAIL: (\S+)out ofgo test's text output. I ran it against realgo testoutput and found two problems:--- FAIL: TestNoDirectProcoderFileIO (0.10s)to stdout, it is reported as that test failing, and the failure count goes up. The text stream can't tell a printed line from the framework's own verdict.--- FAIL:line: a build or setup failure, a panic in a background goroutine, a timeout. When another package had a real test failure, this package disappeared from the report. When it failed alone, the summary was just the first line of output, which can be another package'sok.The Go runner now uses
go test -json. Failures come from the framework'sfailevents. A failed subtest is named by the subtest itself (TestParent/child), and its parent isn't counted again. A package that failed outside any test is named by package, with go's reason (pkg [build failed]). Output is matched to a test by the event's Test field, so parallel tests can't mix their output. Pass counts,[no test files],[no tests to run]and the coverage average are worked out from the package-level lines, so the pass path reports the same thing as before (checked against the old binary on this repository).Hypothesis 2 (a file parsed mid-write). Both store guards now use
parseListed. It skips a file that no longer exists when it is parsed, and only that case. A file that exists but does not parse, including a half-written one, still fails the guard.Why Refs and not Fixes
This does not prove what failed on run 34395461728. Nothing in this repository prints a
--- FAIL:line, and no test runs the suite inside another test, so I can't show that the spoofing case is what happened there. What this change does is make the next occurrence explain itself. The report will have the real failing test or package plus its output, and if the guard fails on a parse error, the path and the parser error will be in the excerpt.Tests (each one fails if its change is reverted)
TestAPrintedFailLineIsNotAFailingTest: the spoofing caseTestAPackageThatFailedOutsideAnyTestIsNamed: a panic in a background goroutine plus a build failure, next to a real test failureTestALoneBuildFailureIsNamedByPackageTestAFailedSubtestIsNamedOnceTestParallelOutputStaysWithItsTest: parallel tests plus a test that panicsTestTheGateFindingCarriesTheAssertion: the gate finding andprocoder testboth carry the excerptTestTheExcerptIsBoundedTestPreJSONBuildErrorsStillReachTheExcerpt: before Go 1.24, build errors are printed as stderr text rather than JSON eventsTestParseListedForgivesOnlyAVanishedFile: a vanished file is skipped, a partial file still failsVerification
procoder test:ok go pass (57 package(s))procoder check:procoder gate: 8 clean, 0 unformatted, 0 unchecked, 0 out of scope, 10 hygiene finding(s) (0 blocking)