Story: Report a refused request as a refusal

Table of Contents

This page documents a story in Sprint 27. It captures the goal, current status, acceptance criteria, and the tasks that compose it.

1. Goal

Make every client report a refusal as a refusal, naming the reason the server gave, so a permission problem is never mistaken for a malformed payload.

2. Status

Field Value
State DONE
Parent sprint Sprint 27
Now Nothing.
Waiting on Nothing.
Next Nothing.
Last touched 2026-10-07

3. Acceptance

  • A request refused with X-Error: forbidden prints a message naming the refusal and the subject, and never mentions unpacking or decoding
  • X-Error: unauthorized and bad_request are surfaced the same way, each with its own literal message
  • X-Error: token_expired keeps its current re-authentication behaviour
  • Tests pin each header value against a literal expected message

4. Tasks

Task State Start End Description
Scaffold story: Report a refused request as a refusal DONE 2026-10-07 2026-10-07 Story scaffolding rides this task: documents, sprint wiring, and the scaffold PR. Close it before merging that PR.
Surface a refusal instead of a decode failure DONE   2026-10-07 Initial task for: Report a refused request as a refusal

5. Decisions

6. Out of scope

7. Result

A refusal now reaches the caller as a refusal. The check lives in the NATS decode helpers, so a caller that reads the X-Error header itself keeps the reply it inspects, and only a caller that would decode the empty body is stopped.

Emacs 29.3 (Org mode 9.6.15)