fix(#1066): retry turn once on 401 before parking for re-login

This commit is contained in:
damocles 2026-06-02 11:23:40 +02:00 committed by mara
commit cbd14e9cd0
2 changed files with 15 additions and 1 deletions

View file

@ -34,7 +34,11 @@ binary, not two) runs:
while the harness is parked. **Auth-failed detection**: both
stdout and stderr pumps also match
`AUTH_FAIL_MARKERS` (`"authentication_failed"`, `401`, etc.).
On match the harness writes `{state_dir}/hyperhive-needs-login`,
On the first 401, `drive_turn` retries the same prompt once
immediately (transient token-refresh races and brief API hiccups
can cause a 401 that clears on retry). Only if the retry also
returns `AuthFailed` does `drive_turn` bubble it up to the serve
loop, which then writes `{state_dir}/hyperhive-needs-login`,
emits `needs_login_idle` status, requeues the inflight message
(so it replays after re-auth), and parks in `wait_for_login`
the same path used at boot. The operator re-authenticates via

View file

@ -320,6 +320,16 @@ pub async fn drive_turn(prompt: &str, files: &TurnFiles, bus: &Bus) -> TurnOutco
// Rate-limited: no point retrying immediately — bubble up so the
// serve loop can park + emit status before the next attempt.
TurnOutcome::RateLimited => return TurnOutcome::RateLimited,
// Auth failed: may be a transient token-refresh race or brief API
// hiccup. Retry once before bubbling up so the serve loop parks for
// re-login. The retry outcome is passed through unchanged — if it
// fails again the serve loop handles it as usual.
TurnOutcome::AuthFailed => {
bus.emit(LiveEvent::Note {
text: "got 401 — retrying once before parking for re-login".into(),
});
run_turn(prompt, files, bus).await
}
other => other,
};
// Proactive: a turn just completed on a still-healthy session. If its