Print startup errors once and drop the fx event log (closes #359) #366

Merged
clawbot merged 2 commits from issue-359-quiet-fx-log into next 2026-11-11 22:26:52 +01:00
Collaborator

closes #359

pixad no longer writes the dependency-injection library's event log ([Fx] PROVIDE ..., [Fx] HOOK OnStop ...) to stderr. A startup or shutdown error is printed once, as the error that caused it, for example config key "signing_key" (environment variable PIXA_SIGNING_KEY): value too short: must be at least 32 characters, got 5. The exit status is unchanged: 1 on a start or stop error.

  • internal/app/app.go: the fx app is built with fx.NopLogger. Since fx reported errors only through that logger, runApp replaces fx.App.Run with the same start, wait and stop steps and prints each error through dig.RootCause, which strips the fx and dig frames.
  • go.mod: go.uber.org/dig, already in the build through fx, becomes a direct requirement.
  • Two commits, kept on merge: the first adds tests that fail against the old code; the second is the fix, plus the tests of runApp, a function the old code does not have.

Trip-wire for reviewers: the tests in internal/app/app_test.go run pixad as a child process (the test binary re-run with TEST_RUN_PIXAD_IN_CHILD=1). The child gets GOCOVERDIR, because a test binary built with -cover otherwise warns on stderr at exit.

Model: opus-5-5

closes https://git.eeqj.de/sneak/pixa/issues/359 pixad no longer writes the dependency-injection library's event log (`[Fx] PROVIDE ...`, `[Fx] HOOK OnStop ...`) to stderr. A startup or shutdown error is printed once, as the error that caused it, for example `config key "signing_key" (environment variable PIXA_SIGNING_KEY): value too short: must be at least 32 characters, got 5`. The exit status is unchanged: 1 on a start or stop error. - `internal/app/app.go`: the `fx` app is built with `fx.NopLogger`. Since `fx` reported errors only through that logger, `runApp` replaces `fx.App.Run` with the same start, wait and stop steps and prints each error through `dig.RootCause`, which strips the `fx` and `dig` frames. - `go.mod`: `go.uber.org/dig`, already in the build through `fx`, becomes a direct requirement. - Two commits, kept on merge: the first adds tests that fail against the old code; the second is the fix, plus the tests of `runApp`, a function the old code does not have. Trip-wire for reviewers: the tests in `internal/app/app_test.go` run pixad as a child process (the test binary re-run with `TEST_RUN_PIXAD_IN_CHILD=1`). The child gets `GOCOVERDIR`, because a test binary built with `-cover` otherwise warns on stderr at exit. Model: opus-5-5
clawbot added the needs-review label 2026-11-11 21:34:15 +01:00
clawbot self-assigned this 2026-11-11 21:34:15 +01:00
Author
Collaborator

Verdict: FAIL
Head: 80e81363eb

needs-rework

  1. internal/app/app.go, runApp, lines 102-114: no test covers the stop path. runApp now replaces fx.App.Run. It carries the exit status 1 that README promises when pixa fails to stop, and the exit code 1 that a listen error asks for. Nothing checks that a failed stop prints its error once and returns 1, or that runApp returns the exit code a shutdown request names. Acceptable: a test for each, for example on a small fx app built with fx.NopLogger: one with a stop hook that returns an error, one with a shutdown requested with fx.ExitCode(3).
  2. internal/app/app_test.go:130: //nolint:forcetypeassert silences the linter instead of fixing the code. AGENTS.md says every linter report is fixed in the code, and internal/server/shutdown_internal_test.go:71 makes the same lookup with a checked assertion. Acceptable: addr, ok := listener.Addr().(*net.TCPAddr), t.Fatalf when !ok, no nolint.
  3. internal/app/app_test.go:166, waitForHealthCheck: when pixad exits or never answers, TestRunWritesNothingToStderrOnStartAndStop fails after 30 seconds with only "did not answer its health check". The reason, pixad's stderr, is never shown. Acceptable: that failure message includes pixad's stderr, as the test's other failure messages do.

Model: opus-5-5

Verdict: FAIL Head: 80e81363eb343028b1bde49fb1012604f7c6d503 `needs-rework` 1. `internal/app/app.go`, `runApp`, lines 102-114: no test covers the stop path. `runApp` now replaces `fx.App.Run`. It carries the exit status 1 that README promises when pixa fails to stop, and the exit code 1 that a listen error asks for. Nothing checks that a failed stop prints its error once and returns 1, or that `runApp` returns the exit code a shutdown request names. Acceptable: a test for each, for example on a small `fx` app built with `fx.NopLogger`: one with a stop hook that returns an error, one with a shutdown requested with `fx.ExitCode(3)`. 2. `internal/app/app_test.go:130`: `//nolint:forcetypeassert` silences the linter instead of fixing the code. `AGENTS.md` says every linter report is fixed in the code, and `internal/server/shutdown_internal_test.go:71` makes the same lookup with a checked assertion. Acceptable: `addr, ok := listener.Addr().(*net.TCPAddr)`, `t.Fatalf` when `!ok`, no `nolint`. 3. `internal/app/app_test.go:166`, `waitForHealthCheck`: when pixad exits or never answers, `TestRunWritesNothingToStderrOnStartAndStop` fails after 30 seconds with only "did not answer its health check". The reason, pixad's stderr, is never shown. Acceptable: that failure message includes pixad's stderr, as the test's other failure messages do. Model: opus-5-5
clawbot added 1 commit 2026-11-11 22:00:33 +01:00
Both tests run pixad as a child process. They fail against this code:
every start writes the dependency-injection library's event log to
stderr, and a startup error is printed twice inside its frames.

Model: opus-5-5
clawbot force-pushed issue-359-quiet-fx-log from 80e81363eb to f416e73611 2026-11-11 22:00:33 +01:00 Compare
clawbot added 1 commit 2026-11-11 22:02:45 +01:00
pixad builds its fx app with fx.NopLogger and runs start, wait and stop
itself, so that it can print a start or stop error to stderr once.
dig.RootCause strips the frames fx and dig wrap around the error, which
leaves the line that names the setting. The exit status is as before.

Two tests run runApp on a small fx app. A stop hook that fails has its
error printed once, with exit status 1. A shutdown request's exit code
is returned.

Model: opus-5-5
clawbot force-pushed issue-359-quiet-fx-log from f416e73611 to 2679139492 2026-11-11 22:02:45 +01:00 Compare
Author
Collaborator
  1. Fixed: internal/app/app_internal_test.go adds TestRunAppPrintsStopErrorOnce and TestRunAppReturnsShutdownExitCode; runApp now takes the writer it prints errors to, so the first test can read it.
  2. Fixed: checked assertion with t.Fatalf, no nolint.
  3. Fixed: on timeout, waitForHealthCheck kills pixad, waits for it to exit, then fails with its stderr.

Judgement call: the two new tests are in the fix commit, since they call runApp, which the first commit's code does not have.

Model: opus-5-5

1. Fixed: `internal/app/app_internal_test.go` adds `TestRunAppPrintsStopErrorOnce` and `TestRunAppReturnsShutdownExitCode`; `runApp` now takes the writer it prints errors to, so the first test can read it. 2. Fixed: checked assertion with `t.Fatalf`, no `nolint`. 3. Fixed: on timeout, `waitForHealthCheck` kills pixad, waits for it to exit, then fails with its stderr. Judgement call: the two new tests are in the fix commit, since they call `runApp`, which the first commit's code does not have. Model: opus-5-5
Author
Collaborator

Verdict: PASS
Head: 2679139492

pixad no longer writes the fx event log, prints a startup or stop error once as the error that caused it, and keeps its exit statuses.

Judgement call: the fix commit also adds new tests of runApp. It changes no assertion of the first commit's tests, so I accepted the two-commit shape.

Model: opus-5-5

Verdict: PASS Head: 2679139492921623efb7cce1a9083ea47caaa750 pixad no longer writes the `fx` event log, prints a startup or stop error once as the error that caused it, and keeps its exit statuses. Judgement call: the fix commit also adds new tests of `runApp`. It changes no assertion of the first commit's tests, so I accepted the two-commit shape. Model: opus-5-5
clawbot merged commit 851a374e53 into next 2026-11-11 22:26:52 +01:00
clawbot deleted branch issue-359-quiet-fx-log 2026-11-11 22:26:52 +01:00
Sign in to join this conversation.