Agent-First PSQL v0.8.1: The Release Check Reads the Right Stream

by Agent-First Kit Contributors

v0.8.0's own release smoke test still read errors from stdout, so it failed the binary build after publishing and shipped v0.8.0 without downloadable binaries. v0.8.1 fixes the check — including a secret-leak assertion that had started passing against an empty string — and moves it into the release gate so it runs before anything irreversible.

v0.8.0 changed where events go: a finite query now sends its result to stdout and its diagnostics to stderr. The tests were updated for that. One script was not — afpsql’s own release smoke test, which builds the release binaries and checks that afpsql-readonly refuses what it should refuse.

That script captured only stdout:

output="$($READONLY "$@")"
if [ "$status" -eq 0 ] || ! grep -q '"code":"invalid_request"' <<<"$output"; then

Under the new routing the rejection is on stderr, so $output was empty and the check failed. The binary was correct; the check was looking at the wrong stream.

The part that mattered more

A failing check is loud. The quiet one was three lines further down, where the smoke test writes a canary secret into a config file and asserts it never comes back out:

if grep -q "$canary" <<<"$config_output"; then

With $config_output empty, that assertion passed no matter what. A test that had been verifying a secret does not leak had become a test that verifies nothing — and it would have kept reporting success. v0.8.1 checks both streams, because “the secret must not appear in the output” was never a claim about one file descriptor.

The redirect checks moved the same way: the runtime error is a diagnostic, so it is --stderr-file that must receive it, and a new case asserts that --output-to stdout moves that same error into --stdout-file instead.

Why it escaped the gate

release-smoke ran in exactly one place: the Release workflow, which runs after cargo publish. So v0.8.0 published successfully, then failed while building its platform binaries — leaving a real crates.io release with no downloadable artifacts and no Homebrew or Scoop update.

This was the second gate hole in one release. The first was CI running cargo test --tests without --features db-tests, so every live-PostgreSQL test reported as ignored; v0.8.0 fixed that by moving the test entrypoint into the project as scripts/test.sh and having CI call it. But all still did not run the release smoke, so the smoke kept its old privilege of being checked only where failure is expensive.

all now runs it. The rule the gate is converging on: if a check can fail a release, it has to be able to fail the gate first.

Upgrading

v0.8.1 is a drop-in for v0.8.0 — no CLI, protocol, or behavior changes. It exists so the platform binaries, Homebrew formula, and Scoop manifest for this line actually ship. If you installed v0.8.0 from crates.io, nothing about your setup is wrong; if you were waiting on brew or scoop, v0.8.1 is the version they point at.