test(oauth-client): dedicated per-AC tests + fake AS DPoP-Nonce header fix
Address the 12 coverage gaps the test-analyst agent flagged. Root cause:
the sub-stages' `run()` functions mutate shared `FlowScript` state across
their per-flow runs, masking happy-path AC6/AC7 coverage when they're the
only test vehicles. Add `tests/oauth_client_ac_coverage.rs` which drives
each AC directly against a FRESH ServerHandle + RP pair, bypassing
`run()`'s state-leakage entirely:
- AC4.5: PAR log preserves body bytes, method, path, timestamp (from
`FakeClock`), and DPoP header verbatim.
- AC5.1: interactive::run emits only Stage::INTERACTIVE rows (pipeline
ordering is enforced by run_pipeline's sequential stage calls).
- AC5.2: all-static-pass run produces every Phase 7 + Phase 8 interactive
check in the output.
- AC5.4: a non-gating static failure (grant_types_includes_refresh_token)
doesn't block ServerBound or other inventory.
- AC6.1: full-grant approve records 1 PAR + 1 authorize + 1 token; token
response carries refresh_token; PAR body carries PKCE S256 + DPoP.
- AC6.2: partial-grant returns a narrower scope in the token response.
- AC6.3: user denial surfaces AuthorizeOutcome::Error with access_denied
and no subsequent token request.
- AC6.4: downscoped refresh body carries `scope=atproto` (narrower).
- AC7.1: DPoP nonce rotation — second PAR's DPoP proof claims contain
the nonce issued by the server.
- AC7.2: rt2 differs from rt1 and rt1 reuse is rejected (401).
- AC7.3: replay rejection (same jti twice) surfaces 401 without retry.
To make AC7.1 pass, fix a latent bug in the fake AS: the `use_dpop_nonce`
error response now advertises the issued nonce via the `DPoP-Nonce`
response header (RFC 9449 §8.2) so the RP can adopt it. The sub-stage
default-run snapshots update accordingly (refresh_token_reuse now Passes
on the happy path, which is correct). Added
`dpop_edges_with_refresh_token_reuse_violation_snapshot` to keep the
refresh_token_reused diagnostic code in the check-id-coverage enforcer's
sights.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>