# Changelog

## 2026-10-15

The public host serves guides next to the API. A later pass the same day aims the same host at agents. The public worker is IPA API. `GET /health` is `ipa-api zipa`. `POST /v1/tutor` and `api: tutor-v1` stay. The MCP registry name stays `com.raymati/ipa`.

### Audio as JSON

Chat, Claude, and Gemini pass JSON to tools. They do not attach a microphone. `proximity` is not retuned.

- `score`, `heard_as`, and `recognize` accept `ipa`, `audio_base64` (at most 256 KiB decoded), or `audio_url`. `ipa` wins when it is also sent.
- `create_upload` returns a PUT URL. This build stores the wav in process memory for 15 minutes (32 slots). It does not sign Cloudflare R2. When `R2_ACCOUNT_ID`, `R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY`, and `R2_BUCKET` are all set, the note says so and still returns the memory URL. The response does not echo those values.
- `ui://ipa/record.html` (`GET /apps/record`) is a record-button stub. The MIME type is `text/html;profile=mcp-app`. `score` and `score_attempt` point at it.
- HTML responses send `Content-Security-Policy`. `script-src` includes `'unsafe-inline'` so the landing JSON-LD block and the record widget can run.
- [Install](/docs/install.md), [Privacy](/privacy.md), and [Terms](/terms.md). Privacy and terms are placeholders for Aaron to review.
- `robots.txt` always allows the search and user-triggered agents. `ALLOW_TRAINING_CRAWLERS` in `scripts/build_api_docs.py` defaults to allow for `GPTBot`, `ClaudeBot`, `Google-Extended`, and `CCBot`.
- `/server.json` is the official MCP registry document. The name is `com.raymati/ipa`. It is not published. `/server-card.json` is the same JSON.
- Anonymous callers stay on the free tier. [Auth](/docs/auth.md) is the OAuth 2.1 design. This host does not serve `/.well-known/oauth-protected-resource`.

### Agent discovery

The score contract is unchanged. `proximity` is not retuned.

- `POST /mcp` lists `score`, `heard_as`, `recognize`, `create_upload`, and `score_attempt` (alias of `score`). `heard_as` is the `heard_as` object from the same score and does not change `proximity`.
- HTML GETs honor `Accept: text/markdown` and set `Vary: Accept`. `Prefer: return=consolidated` also gets `Preference-Applied`. That pair is draft-consolidated-content-01, not an RFC. `.md` URLs stay.
- `robots.txt` allows the documented AI crawler tokens, including the `Google-Extended` and `Applebot-Extended` control tokens.
- The landing page embeds schema.org `WebAPI` JSON-LD.
- `/.well-known/agent-card.json` is the A2A v1 discovery file. This host does not implement an A2A task endpoint.
- [Registries](/docs/registries.md) and [Submitting](/docs/submitting.md) have the submit steps. Nothing was submitted.

### Guides

- OpenAPI 3.1 at `/openapi.json`. Response examples are filled by the scorer from the requests in `openapi.yaml`.
- `/llms.txt`, `/llms-full.txt`, and a Markdown alternate for each HTML guide (`Link: rel=alternate; type=text/markdown` and `rel=describedby`).
- `/.well-known/security.txt` (RFC 9116). Convenience copies: `openapi.json`, `ai-plugin.json`, `ai-catalog.json`. The server card is `/server-card.json`.
- Errors are `application/problem+json`. `detail` keeps the previous plain-text sentence. Success bodies are unchanged.
- `RateLimit-Policy: "tutor";q=10;w=60` for an anonymous caller and `"tutor";q=120;w=60` for an `ipa_live_` key, on `POST /v1/tutor` and `POST /mcp` `tools/call`. Bindings `TUTOR` and `TUTOR_KEY` are the limits when they are bound. The in-memory window is the fallback. POST bodies are capped at 400 KiB. `audio_url` is https-only with a 256 KiB streamed cap. Proximity is not retuned.

Audio still reaches ZIPA through the container behind the Rust worker (route wiring `04354ee`, image prototype `a16c62c`). Proximity does not read GOP.

The lexicon and the Platt map remain the `d0b6159` set. This documentation pass does not retune proximity, stress, `different_word`, or `heard_as`.
