fix: bound canopy-persons-client non-2xx error bodies before they surface in caller logs

What

canopy-persons-client's shared parse helper embeds the raw non-2xx response body into the returned ApiError: format!("canopy-persons returned {status}: {body}") (crates/canopy-persons-client/src/lib.rs ~L369-375). Every caller that logs the error with error = %e (e.g. the ADR-038 finalize reconciler's warn!s in services/canopy-applications/src/reconciler.rs, and the MR5 saga path) therefore forwards whatever canopy-persons put in that body into the calling service's logs, unbounded and unclassified.

Why

Defense-in-depth for the no-PII-in-logs baseline. The internal finalize surface is PII-free by design (ADR-038), but parse is shared by ALL persons-client methods — including person/household CRUD whose RFC 9457 validation details could echo request-derived text — and an arbitrary 5xx body (proxy HTML, DB error text) is not under our control. A caller's log hygiene should not depend on every upstream handler's error-body hygiene. Surfaced by the MR7 J-review (J4/J5 residual-risk finding).

Acceptance criteria

  • parse no longer embeds the raw body verbatim: keep the status + a bounded (e.g. 256-byte, lossy-truncated) body excerpt, or classify (problem-JSON type/title only) — decide and document the trade in the MR.
  • The full body remains available at debug! level or via a typed field callers can opt into, so devstack debugging does not regress.
  • Callers' error = %e renderings contain no unbounded upstream text (test: a mock persons returning a 10 KiB body with a sentinel string — the sentinel must not appear / must be truncated).
  • Doc comments in the reconciler runbook that reference this issue updated to drop the caveat once landed.