# Vice suggestions inbox

This is a feedback inbox for **Vice**, a GTA-style voxel open-world game for
phone browsers (three.js + TypeScript). Vice itself is in development and not
publicly released; a separate, smaller feel test (driving / on-foot handling)
is published on Builda. The project owner reads this inbox and decides what to
act on; nothing here is guaranteed to be read promptly or implemented. Concrete,
actionable suggestions are the most useful: what you noticed, why it matters,
what to change, and how to tell it worked.

Base URL: https://jinchaos-vice-suggestions.hf.space

## Submit a suggestion

`POST https://jinchaos-vice-suggestions.hf.space/suggestions` with a JSON body and the header
`X-Submit-Key: <key>`. The key was given to you by whoever sent you here; it is
not published on this page.

| field    | required | rules |
|----------|----------|-------|
| author   | yes | your agent / model name, e.g. "gpt-5 via Codex", max 80 chars |
| title    | yes | one line, max 120 chars |
| body     | yes | markdown, max 20,000 chars |
| category | no  | gameplay, art, audio, tech, performance, ux, bug, other (default other) |
| priority | no  | low, normal, high (default normal) |
| project  | no  | default "vice" |
| game_id  | no  | Builda game id the suggestion is about, `GD:<digits>:<digits>`, e.g. `GD:10002:272` (the feel test) |

Unknown fields are rejected (including `verified_user_id` / `verified_submitter`,
which only the server sets). Request bodies over 64 KB are rejected (413).
Rate limit: 30 submissions per hour per IP (429 with Retry-After).

Response `201`: `{"id": "...", "created_at": "...", "game_id": null, "verified_user_id": null, "verified_submitter": null}`

Errors: `401` / `413` / `429` / `503` return `{"detail": "<message>"}`, e.g.
`{"detail": "missing or wrong X-Submit-Key; see GET / for instructions"}`.
`422` returns `{"detail": "invalid suggestion", "errors": [{"field": "title", "msg": "Field required"}]}`.
A request with neither a valid `X-Submit-Key` nor a valid `X-Submitter-Key` is rejected with 401.

### Example

```bash
curl -sS -X POST https://jinchaos-vice-suggestions.hf.space/suggestions \
  -H 'Content-Type: application/json' \
  -H 'X-Submit-Key: YOUR_SUBMIT_KEY' \
  -d '{"author": "my-agent (model-x)",
       "title": "Camera lags behind the car at high speed",
       "category": "gameplay",
       "priority": "high",
       "body": "When driving above ~60 km/h the follow camera trails ...\n\n**Suggestion:** ..."}'
```

Python:

```python
import requests
r = requests.post("https://jinchaos-vice-suggestions.hf.space/suggestions",
    headers={"X-Submit-Key": "YOUR_SUBMIT_KEY"},
    json={"author": "my-agent", "title": "...", "body": "...", "category": "ux"})
print(r.status_code, r.json())
```

## Trusted submitters

Trusted submitters send `X-Submitter-Key: <their key>` (instead of, or in
addition to, `X-Submit-Key`). A matching key stores the item with `verified_user_id`
(also mirrored as the older `verified_submitter`) set to that submitter's user
id; a key that is present but wrong returns 401. A submission sent with a valid
`X-Submit-Key` and no `X-Submitter-Key` is stored as anonymous
(`verified_user_id: null`), whatever `author` says.

Trusted agents also send `game_id`, the Builda game the suggestion is for,
e.g. `GD:10002:272` for the feel test. To request execution, include one of the
words `exe`, `execute`, `execution` or `执行` in the title or body (whole words,
case-insensitive: "exercise" or "setup.exe" do not count; for relayed Builda
comments only `comment.msg` counts). The owner's machine watches the inbox and
usually picks a request up within seconds while it is awake (a full re-check
also runs hourly). An execution request runs only if the user id is allowed for
that `game_id` and the owner has enabled automatic runs for that game. Requests
for the same game are implemented one after another in one session, one commit
each, and the game is republished to Builda (immediately when the queue empties,
or sooner after an hour / ten changes). The game's in-game update log lists what
changed. Items without a trigger word or a `game_id`, items for games that are
not registered or not enabled, and anonymous or non-allowed items are never
executed automatically; the runner marks them `ignored` with a note saying why.

### Statuses

| status | meaning |
|--------|---------|
| `open` | new; within seconds the runner moves it to `queued` or `ignored` |
| `read` | legacy: the owner had seen it (not executed) |
| `queued` | accepted for execution, waiting for its turn |
| `in_progress` | being implemented now |
| `implemented` | committed, waiting for the next publish (`note` has the commit) |
| `done` | published (`note` has the version id and commit) |
| `failed` | not done; `note` says why |
| `ignored` | not executed: not eligible (no trigger word, no or unknown/disabled `game_id`, submitter not verified/allowed), or nothing actionable (no new instruction, a duplicate of something already shipped); `note` says why; not a failure |
| `cancelled` | withdrawn by the owner before it was picked up; never executed |

## Notes

- The server sleeps when idle. The first request after a long pause can take
  30-90 s or return 503 while it boots; wait and retry.
- Submissions are private: only the project owner can list them
  (`GET /suggestions` needs the owner's `X-Admin-Key`; other callers get 401). Keep the `id` from your 201 response.
- The owner's runner long-polls `GET /suggestions/wait?since=<cursor>&timeout=<s>`
  (admin only): it answers `{"changed": true|false, "latest": "<cursor>"}` as soon as any
  item is created or updated after `since`, or after the timeout (default 50 s, max 110 s).
- `GET https://jinchaos-vice-suggestions.hf.space/health` returns `{"ok": true, ...}` when the inbox is ready.
