fix(review): close 5 follow-up gaps from Stage 6 audit re-review
- F-T-003 actually closed: clients/typescript/src/subscribe.ts now bounds the 401-refresh loop at 3 consecutive refusals, surfaces an onError describing the loop, and resets on any successful stream open. New test covers the cap. The Stage 2 dashboard fix only addressed adminRequest in dashboard/src/lib/api.ts; the originally- cited TS client file was untouched. - users/invitations subtab dropped the redundant api.apps.get fetch the other 5 subtabs already shed in Stage 6. - Queue visibility-timeout validator pulled out as validate_queue_visibility_timeout, with two thresholds: hard-reject below MIN_QUEUE_VISIBILITY_TIMEOUT_SECS (30s — catches typos), warn- log between MIN and SAFE_VISIBILITY_VS_EXEC_BUDGET_SECS (300s) so operators see when their visibility is below the dispatcher's per-message executor budget. Stage 6 only had the hard floor; the reviewer caught that a 60s handler still races a 30s visibility even after the floor. Four new unit tests cover none/above-safe/ between/below-min. - pic dead-letters count subcommand: cheap headless probe for unresolved DL totals, parallels the dashboard's badge query. - pic dead-letters replay now has a happy-path integration test (replay_against_real_dl_row_succeeds): inserts a synthetic DL row directly via the rust-postgres sync driver (added as dev-dep), drives `pic dead-letters replay`, asserts the row is resolved with reason=replayed and count drops back to 0. Plus a count smoke test. All 75 CLI integration tests + 16 TS client tests + 4 new visibility-timeout unit tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -96,4 +96,30 @@ describe('subscribe', () => {
|
||||
await vi.waitFor(() => expect(onError).toHaveBeenCalled());
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
it('caps the 401-refresh loop after consecutive failures', async () => {
|
||||
// onTokenExpired keeps returning a fresh-looking-but-still-rejected
|
||||
// token. Without the cap the loop would reconnect forever.
|
||||
const fetchMock = queuedFetch([
|
||||
async () => emptyResponse(401),
|
||||
async () => emptyResponse(401),
|
||||
async () => emptyResponse(401),
|
||||
async () => emptyResponse(401),
|
||||
async () => emptyResponse(401)
|
||||
]);
|
||||
const client = new PicloudClient({ baseURL: 'https://api.test', fetch: fetchMock });
|
||||
const onError = vi.fn();
|
||||
const onTokenExpired = vi.fn(() => 'never-good-enough');
|
||||
const unsubscribe = client.subscribe('chat', () => {}, {
|
||||
onTokenExpired,
|
||||
onError
|
||||
});
|
||||
await vi.waitFor(() => expect(onError).toHaveBeenCalled(), { timeout: 1000 });
|
||||
unsubscribe();
|
||||
// The cap is 3 consecutive 401s — at most 3 fetches should have
|
||||
// been issued before the loop bailed.
|
||||
expect(fetchMock.mock.calls.length).toBeLessThanOrEqual(3);
|
||||
const errMsg = String(onError.mock.calls[0]?.[0]);
|
||||
expect(errMsg).toContain('401-refresh loop');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user