LOCAL TEACHING REST CONTRACT v1 — no public deployment
Base: http://127.0.0.1:<printed ephemeral port>
GET /health -> 200 {"status":"ok","mode":"fictional-local-lab"}
POST /v1/summary -> 200 JSON result for a stateless calculation (no saved resource).
Required: one Content-Length header, no Transfer-Encoding, one Content-Type:
application/json OR application/json; charset=utf-8. UTF-8 body <=16384 bytes.
Browser Origin headers are refused; no CORS permission. This is not authentication.
Closed envelope {"orders":[{"order_id":"F01","channel":"web","amount_cents":12000}]}.
0..100 rows. Each row has exactly those three keys. order_id: unique nonblank text <=40 chars;
leading/trailing whitespace is not normalized, so document exact source IDs.
channel: web or store, case-sensitive. amount_cents: exact integer 0..100000000; bool refused.
Only EUR is implied in this fixture. Mixed currencies require a different explicit contract.
Repeated JSON keys/nonfinite constants are rejected; invalid records are never silently dropped.
Output: {"count":1,"total_cents":12000,"by_channel":{"web":12000,"store":0}}.
Headers include Cache-Control:no-store and nosniff. Source values are not echoed in errors/logs.
Statuses: 400 malformed JSON/length/transfer encoding; 403 browser Origin; 404 unknown route;
405 PUT/PATCH/DELETE; 408 body timeout; 411 missing length; 413 body too large;
415 media type; 422 invalid orders. Other unsupported methods may use stdlib 501 HTML.
HTTP/1.0 closes connections. Body read timeout:3s; teaching client timeout:5s.
No authentication, TLS, persistent storage, durable idempotency, rate-limit service or concurrency.
No payment, registration or website DB operation. Python http.server is not production hosting.
An Origin refusal or loopback bind is not a substitute for production authorization.
