be-coder-08, reviewing #1086, found the diagnostic is not diagnostic-only.
At all three call sites it was written as the last command of an && list:
declare -F explain_tea_user_does_not_exist >/dev/null && explain_tea_user_does_not_exist
and it sits immediately BEFORE the Gitea API fallback. Under `set -e` a failing
diagnostic (stderr closed or full) therefore exits the script and the fallback
never runs -- a diagnostic that suppresses the recovery path it exists to explain.
The asymmetry is what makes it dangerous: the fault only appears when the helper
is PRESENT, so the helper-absent path -- the pre-#1086 behaviour -- keeps working
and reads as a passing control. Measured on /dev/full:
helper present rc=1 fallback NOT reached
helper absent rc=0 fallback reached
Wrapping in `{ ...; } || true` makes the diagnostic status-neutral, which is what
the PR claimed to be in the first place.
test-explain-diagnostic-status-neutral.sh probes all four combinations of
{helper present, absent} x {stderr ok, failing} for each of the three call sites,
and lifts the construct FROM THE SHIPPED FILE rather than restating it -- a probe
that retypes the fixed form passes on a build whose real call sites still carry
the bare && form. Verified RED on the pre-fix tree (16 failures, behavioural half
included) and GREEN here. Enumerated on test:framework-shell.
Reported-by: be-coder-08
`user does not exist [uid: 0, name: ]` from tea reads as a missing account.
It almost always means a revoked or stale token: `tea login` keeps its own
copy of the token, so rotating the credential store does not update it. The
error points at the account; the cause is the cached credential.
Adds explain_tea_user_does_not_exist() to detect-platform.sh and invokes it
from the three tea-failure fallback paths, each guarded by `declare -F` so
the call site is independent of load order and a no-op if the helper is absent.
Purely additive: stderr only, no control flow, no gate or credential changes.
Verified both directions: the helper emits when sourced, and the guarded call
is a silent no-op (exit 1, no output) when it is not.
Refs #1082
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Amf1Neca162odgcbCWMk1y