feat(r2): C3 server side — 204 on an explicit JSON Accept, and back=view

- wants_json: true only for an exact `application/json` entry with q > 0.
  Absent, empty, wildcard, application/*, near misses, q=0 and malformed
  headers all fall through to the 303.
- The four mark routes share one exit, _mark_done: 204 with no body for the
  in-place client, otherwise _mark_redirect unchanged.
- back=view lands on /b/<name>/view?f=<rel>#rail, only for a media item of
  this booth. It is built from the resolved rel and never echoed. Anything
  else takes the no-`back` landing.
- tests/golden/r2_mark_303.json: 108 responses recorded from the PRE-R2
  code (6 route cases x back absent|marks x 9 non-JSON Accepts), replayed
  byte for byte (INV-4). Two mutations (q>=0, substring match) turn it red.
- The contract now states the q=0 rule.
This commit is contained in:
vh
2026-09-23 08:36:54 -07:00
parent 277554a3f7
commit b9750d221a
4 changed files with 2315 additions and 6 deletions
+5 -2
View File
@@ -129,10 +129,13 @@ no route derives it.
### C3 — in-place judgment (app.py, base.html)
**`wants_json(request) -> bool`** is True **only** when the `Accept` header,
split on commas with parameters stripped, contains the exact media type
`application/json`.
split on commas, contains an entry whose media type, parameters stripped, is
exactly `application/json` and whose q-value is absent or greater than 0.
- Absent, empty, `*/*` or `application/*` → False.
- `application/json;q=0` → False. A client that explicitly refuses JSON gets
the redirect.
- A near miss such as `application/jsonx` → False.
- Any header that fails to parse → False.
- **It fails toward the 303.**