Skip to content

fix: keep diagnostics off stdout - #48

Merged
refsz merged 1 commit into
mainfrom
fix/diagnostics-off-stdout
Aug 20, 2026
Merged

fix: keep diagnostics off stdout#48
refsz merged 1 commit into
mainfrom
fix/diagnostics-off-stdout

Conversation

@refsz

@refsz refsz commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Reported from real use, and the reporter is right that it matters more than the migration that surfaced it. A task that reads sputnik completion bash to compare it against the installed file got a discovery warning as line one of the script:

$ sputnik completion bash | head -2
Skipped task 'list' in .../ProbeListTask.php: the name is reserved by a built-in command …
# This file is part of the Symfony package.

That line would have been written into the completion file. And --silent / -q are no help: they suppress the script along with the warning, because both were on the same stream. The consumer worked around it by stripping everything before the first # — a workaround in the wrong place.

The same bug where nobody had looked

Diagnostics now go to stderr, which the redacting decorator already covers, so secrets stay masked there.

Checking whether completion was the only affected command turned up something worse: list --format=json has never been parseable. Three separate things landed on stdout around the JSON — the discovery warning, our header before it, and the Available tasks section after it.

So for any list format other than the default txt, and for --raw, the decoration is left out entirely. Those formats exist to be read by something else.

Verified against the binary

completion bash    stdout: # This file is part of the Symfony package.
                   stderr: Skipped task 'list' in …

list --format=json valid JSON, 10 commands
list --raw         the raw command list, nothing around it
list               header and grouped task section, unchanged

The last line has its own test, because moving decoration behind a condition is how you lose it.

Note on the reporter's other observation

The switching between "writes" and "is up to date" under 0.2.1 has the same root: the shadow warning was on stdout on every invocation, so it was captured into the file, which then never matched what the binary emitted next time. #46 made that a -v notice and this makes it stderr — both halves of that behaviour are gone now, and the consumer's #-stripping can go with them.

vendor/bin/phpunit                        773 tests, 1330 assertions, OK (3 new)
vendor/bin/phpstan analyse                [OK] No errors
vendor/bin/php-cs-fixer fix --dry-run     0 of 156 files
vendor/bin/rector --dry-run               [OK]
mkdocs build --strict                     clean

Docs: cli.md states that Sputnik's own diagnostics go to stderr and that --silent is the wrong tool for separating them, and documents --format on list with a jq example.

🤖 Generated with Claude Code

https://claude.ai/code/session_018CTvnzcNYmFgm2HQcm821A

Reported from real use: a task that reads `sputnik completion bash` to compare it
against the installed file got a discovery warning as line one of the script.

    $ sputnik completion bash | head -2
    Skipped task 'list' in .../ProbeListTask.php: the name is reserved ...
    # This file is part of the Symfony package.

The warning would have been written into the completion file. --silent and -q do
not help - they suppress the script along with the warning, because both were on
the same stream.

Diagnostics now go to stderr, where the redacting decorator already masks
secrets. Looking into it turned up the same class of bug in a place nobody had
tried: `list --format=json` was never parseable. Three separate things landed on
stdout around the JSON - the discovery warning, our header before it, and the
"Available tasks" section after it.

So for any list format other than the default txt, and for --raw, the decoration
is left out entirely: those exist to be read by something else.

    completion bash   stdout: # This file is part of the Symfony package.
                      stderr: Skipped task 'list' in ...
    list --format=json  valid JSON, 10 commands
    list --raw          the raw command list, nothing around it
    list                header and grouped task section, unchanged

The last line has its own test, because moving decoration behind a condition is
how you lose it.
@refsz
refsz merged commit 89c1b59 into main Aug 20, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant