diff --git a/.plans/opencc-agent-proxy-GRILLED_PLAN.md b/.plans/opencc-agent-proxy-GRILLED_PLAN.md new file mode 100644 index 0000000..b7e8318 --- /dev/null +++ b/.plans/opencc-agent-proxy-GRILLED_PLAN.md @@ -0,0 +1,808 @@ +# GRILLED_PLAN - `cc-agent-proxy` + programme Lua `opencc` + +> Compagnon de `.plans/opencc-agent-proxy-plan.md`. Chaque question a une +> recommandation par defaut et un bloc `TODO: answer` que tu remplis. Un +> prochain `/grill-me` lira ce fichier et le condensera en plan v2 pret a +> executer. +> +> Convention : +> - Remplace `TODO: answer` par ta reponse (1-3 lignes suffisent). +> - Si tu choisis une option listee, ecris `Option N` + raison breve. +> - Si tu inventes une 5e option, ecris-la in extenso. +> - Si une question devient sans objet apres une reponse majeure, ecris +> `N/A - voir Q`. +> - Laisse `TODO: answer (optionnel)` tel quel si pas d'avis. + +## Regles de base du PoC + +- Une turtle, un OpenCode, un proxy, une reponse utilisable. Rien de plus. +- Contraintes explicites > design generique. +- Pas de packaging tant que la boucle n'a pas tourne in-game. +- Aucun secret commit. +- La forme des reponses OpenCode est suspecte tant qu'on ne l'a pas vue en vrai. + +--- + +## A. Les 8 questions determinantes + +A repondre en premier. Le reste devient souvent trivial une fois ces choix +trances. + +### A1. Critere d'acceptation du PoC + +Quand dit-on "c'est fini" ? + +- **Option 1 - curl roundtrip** : `curl /ask` retourne une vraie reponse + OpenCode. Pas d'in-game. +- **Option 2 - CraftOS-PC roundtrip** : `opencc "salut"` repond dans + l'emulateur, en pointant sur le proxy local. +- **Option 3 - in-game ATM10** : `opencc` marche sur une vraie turtle apres + config `http.rules`. +- **Option 4 - conversation in-game** : Option 3 + verifier que la session + persistante garde le contexte sur plusieurs prompts. + +Recommandation : **Option 4**. C'est ce qui prouve que le pipeline tient bout +en bout. 1-3 sont des jalons intermediaires. Premier prompt anodin (`dis +bonjour`) avant prompts libres. + +Pourquoi ca compte : decide si async, multi-turtle, logs riches, quotas, +packaging et UX terminale sont hors scope. + +TODO: answer + +### A2. Autorite et workspace d'OpenCode + +Le proxy parle a un `opencode serve` qui a, potentiellement, acces complet a +des fichiers et a un shell. Une turtle qui prompt = un acteur exterieur qui +peut indirectement declencher des actions cote hote. + +- **Option 1 - workspace dedie jetable** : `opencode serve` lance dans un dir + temporaire (`/tmp/opencc-poc`) sans secrets, sans repo perso. +- **Option 2 - workspace projet dedie** : un dossier `~/opencc-workspace/` + vide ou minimal, persistant entre runs. +- **Option 3 - repo perso** : non, trop risque. +- **Option 4 - sandbox container** : OpenCode dans Docker avec mount limite. + Plus de cout pour le PoC. + +Recommandation : **Option 1**. Workspace jetable, recree a chaque session de +test. Documenter le dir exact dans `.env`. + +Pourquoi ca compte : c'est la vraie frontiere de confiance, plus que le +token Lua. + +TODO: answer + +### A3. Cycle de vie de la session + +- **Option 1 - session unique partagee** : le proxy cree une session au boot, + toutes les turtles tapent dedans. Conflits de memoire conversationnelle. +- **Option 2 - session par turtle, persistee cote turtle** : la turtle stocke + `sessionId` dans `settings` ; le proxy se contente de relayer. +- **Option 3 - session ephemere par prompt** : chaque `/ask` cree+detruit. Pas + de continuite. Plus simple, perd le contexte. +- **Option 4 - session par turtle, mappee cote proxy** : table + `turtleId -> sessionId` cote proxy. Necessite d'identifier la turtle. + +Recommandation : **Option 2**. Le proxy reste sans etat ; la turtle envoie +`sessionId` optionnel, le proxy en cree une si absent et le renvoie dans la +reponse. + +TODO: answer + +### A4. Sync vs async pour `/ask` + +`POST /session/:id/message` peut bloquer longtemps. CC:Tweaked a des +timeouts HTTP (~30s typiques, depend du serveur). + +- **Option 1 - sync stricte** : le proxy attend la fin et renvoie. Risque de + timeout cote turtle. +- **Option 2 - async + polling** : `POST /ask` -> `jobId`, `GET /ask/:jobId` + pour poll. Plus robuste, plus complexe. +- **Option 3 - keepalive / chunked** : inutile en HTTP CC standard. +- **Option 4 - sync now, async later** : on commence en sync (prompts courts + pour PoC), on documente la limite, on bascule async si on l'atteint. API + `/ask` reste compatible. + +Recommandation : **Option 4**. + +TODO: answer + +### A5. Topologie de deploiement + +Le plan source dit "deploiement HTTPS, RP, firewall, exposition publique +geres separement par Guillaume". + +- **Option 1 - tout sur ta machine perso** : `opencode serve` + + `cc-agent-proxy` en localhost, expose via tunnel (Cloudflare, ngrok). +- **Option 2 - VPS dedie** : meme hote distant, HTTPS via Caddy/nginx. +- **Option 3 - homelab** : Option 2 mais chez toi, derriere ton RP existant. +- **Option 4 - deux hotes separes** : OpenCode sur GPU dedie, proxy ailleurs. + +Conditionne : auth (A6), `OPENCODE_BASE_URL`, qui termine TLS. + +Recommandation : **Option 3** si tu as un homelab, sinon Option 1. Proxy + +opencode sur le meme hote, loopback entre les deux, proxy expose en HTTPS. + +TODO: answer + +### A6. Modele d'authentification turtle <-> proxy + +- **Option 1 - token unique partage** : un seul `PROXY_TOKEN`, meme valeur + sur toutes les turtles via `settings`. Pas de revocation granulaire. +- **Option 2 - token par turtle** : table de tokens cote proxy. Permet + revocation par turtle. +- **Option 3 - HMAC signe** : turtle envoie `os.getComputerID()` + HMAC. + Plus complexe, peu de gain sans rotation. +- **Option 4 - allowlist IP** : impossible, la turtle sort via le proxy HTTP + du serveur Minecraft. + +Recommandation : **Option 1**. Helper `isTokenValid(token)` pour permettre +une table plus tard sans refactor. + +TODO: answer + +### A7. Forme de la reponse renvoyee a la turtle + +OpenCode retourne `parts`, tool calls, code blocks. La turtle a peu de RAM. + +- **Option 1 - texte plat** : `{ reply }`. Tout ce qui n'est pas texte est + jete. +- **Option 2 - texte + meta** : `{ reply, model, tokens, sessionId }`. +- **Option 3 - parts brutes** : la turtle parse. Trop couteux. +- **Option 4 - texte plat + troncature** : `{ reply, sessionId, truncated }` + avec `MAX_REPLY_CHARS` (ex. 4 KiB). Logs proxy gardent le complet. + +Recommandation : **Option 4**. + +TODO: answer + +### A8. Scope minimal v1 (in et out) + +- **Option 1 - hello world** : turtle envoie "ping", recoit "pong". Une seule + route, sync, pas de session persistante. +- **Option 2 - conversation 1 turtle / 1 session** : echange sur plusieurs + prompts, sessionId persistante. +- **Option 3 - + outils OpenCode** : agent peut lire/ecrire un fichier dans le + workspace. +- **Option 4 - + multi-turtle** : deux turtles en parallele sans collision. + +Recommandation : **Option 2**. + +Hors-scope explicite du PoC : async, multi-turtles, package ccpm, deploiement +auto, Docker, quotas, UI terminale riche, streaming OpenCode (`/event`). + +TODO: answer + +--- + +## B. Scope, contraintes de temps, cleanup + +### B1. Limite de temps et plan de bascule + +Si la forme de l'API OpenCode bloque, qu'est-ce qu'on fait ? + +Recommandation : **une seule passe d'implementation**. Si l'API OpenCode bloque, +on arrete d'abstraire et on capture le contrat reel via curl avant de coder. + +TODO: answer + +### B2. Rollback / cleanup post-PoC + +Comment on nettoie une fois la demo faite ? + +Recommandation : stop proxy, stop `opencode serve`, supprimer sessions de +test, rotation du `PROXY_TOKEN` et du `OPENCODE_PASSWORD` utilises. + +TODO: answer + +--- + +## C. OpenCode upstream : contrat et comportement + +### C1. Version OpenCode et Basic Auth verifies au premier run + +OpenCode evolue. Le plan suppose Basic Auth active. A valider. + +Recommandation : enregistrer `opencode --version` utilise lors de la +validation ; pinger `/global/health` avec Basic Auth via curl avant de coder +le client. + +TODO: answer + +### C2. Spec exacte de `POST /session/:id/message` + +Plan : `{ parts: [{ type: "text", text }], model? }`. Marque comme inconnu. + +Recommandation : `curl http://localhost:4096/doc` une fois OpenCode lance, +capturer un sample reel de reponse, le commiter sanitize dans +`cc-agent-proxy/test/fixtures/`. + +TODO: answer + +### C3. Provider et modele LLM + +`OPENCODE_MODEL` optionnel. Quel provider Guillaume utilise (anthropic, +openai, ollama local) ? + +Recommandation : laisser defaut OpenCode, ne passer `model` que si +`OPENCODE_MODEL` est defini dans `.env`. + +TODO: answer + +### C4. Timeout amont vers OpenCode + +Recommandation : `REQUEST_TIMEOUT_MS` configurable, defaut 60s. Au dela -> +504 cote proxy. + +TODO: answer + +### C5. Exposition des erreurs OpenCode au turtle + +Recommandation : pas de stack trace ni secret. Renvoyer +`{ error: "...", code: "..." }` avec message public court ; detail dans les +logs proxy uniquement. + +TODO: answer + +### C6. SessionId auto-creation et recovery si stale + +Deux comportements distincts : +- `sessionId` absent dans la requete -> proxy en cree un (recommande **oui**). +- `sessionId` fourni mais 404 amont -> ? + - **Option A** : recreer silencieusement. + - **Option B** : renvoyer `{ error: "session_expired" }`, laisser la + turtle decider (`opencc --new`). + +Recommandation : **Option B**. Auto-recreation cacherait une perte de +contexte deroutante. + +TODO: answer + +### C7. Comportement quand OpenCode est down + +- 502/503 brutal ? +- Retry interne avec backoff ? +- `/health` reflete-t-il l'etat upstream ? + +Recommandation : pas de retry auto, **502** + JSON `{ error: "upstream_down" }`. +`/health` inclut un champ `opencode: "up"/"down"`. + +TODO: answer + +### C8. Gestion des parts non-textuelles (tools, code blocks) + +Recommandation : concatener les parts texte, ignorer les non-textuelles dans +la `reply`, mais logger un compteur cote proxy (`parts_text`, `parts_tool`, +`parts_other`). + +TODO: answer + +--- + +## D. Proxy API shape + +### D1. Routes minimales du proxy + +Plan : `/health`, `/ask`, `/session`. + +- `/session` obligatoire ou implicite via `/ask` ? +- `/health` inclut upstream ? + +Recommandation : +- `GET /health` -> `{ proxy: "ok", opencode: "up"/"down" }`. +- `POST /ask` -> obligatoire, body `{ prompt, sessionId? }`, + response `{ sessionId, reply, truncated }`. +- `POST /session` -> garder, retourne `{ sessionId }`. Pratique pour + initialiser ou nommer une session ; ne casse pas le PoC si on ne l'expose + pas a la turtle. + +TODO: answer + +### D2. Codes HTTP stables pour la turtle + +Recommandation : +- `200` succes +- `400` requete invalide (prompt vide, body malforme) +- `401` token absent/invalide +- `413` prompt trop long +- `502` OpenCode down +- `504` OpenCode timeout +- `500` erreur proxy inattendue + +TODO: answer + +### D3. Limites taille de requete + +- Max prompt length ? +- Max body size HTTP ? + +Recommandation : prompt max **8 KiB** (`MAX_PROMPT_CHARS` env), body max +**32 KiB** cote Fastify. Pas de rate-limit dans le PoC. + +TODO: answer + +### D4. Request IDs / correlation + +Recommandation : `requestId` auto-genere cote proxy, present dans tous les +logs, non expose dans la reponse JSON (juste dans header `x-request-id` pour +debug optionnel). + +TODO: answer + +--- + +## E. Stack Node / TypeScript + +### E1. Runtime et gestionnaire de paquets + +Recommandation : **Node 20+**, **pnpm**. Sinon **npm** si tu prefers vanilla. + +TODO: answer + +### E2. Strictness TypeScript + +Recommandation : `"strict": true` + `noUncheckedIndexedAccess`. +`exactOptionalPropertyTypes` evite (bruit pour peu de valeur en PoC). + +TODO: answer + +### E3. Framework HTTP et validation + +Plan : Fastify + Zod. + +Recommandation : **Fastify** + **Zod** + `fastify-type-provider-zod` pour +validation automatique des routes. Confirme ou propose autre. + +TODO: answer + +### E4. Logging + +Recommandation : **Pino** (default Fastify). `LOG_LEVEL=info` par defaut, +`debug` en dev. Flag `LOG_BODIES=true` pour inclure prompt/reply ; **off +par defaut**. Jamais logger token ni `OPENCODE_PASSWORD`. Logs : status, +duree, `sessionId` (12 premiers chars), `requestId`, longueurs prompt/reply. + +TODO: answer + +### E5. Process / lancement / deploiement + +- `tsx` en dev, `node dist/index.js` apres `tsc` en prod ? +- Dockerfile ? systemd ? pm2 ? +- Bind `0.0.0.0` ? Shutdown gracieux ? + +Recommandation : tsx en dev, node dist en prod, **pas de Docker**, pas de +systemd dans le repo (tu deploies a la main). `0.0.0.0` car expose derriere +RP. Shutdown : `app.close()` sur SIGTERM, rien de plus. + +TODO: answer + +### E6. Tests Node + +Plan : vitest, fetch mocke, `app.inject()`. Pas d'objectif de couverture %. + +Recommandation : couvrir `/ask` happy path, `401`, OpenCode 5xx mock, +prompt vide, prompt trop long, sessionId 404 amont. Fixture OpenCode reelle +(cf C2) utilisee dans `opencode.test.ts`. + +TODO: answer + +### E7. Variables d'env (en plus du tableau du plan) + +A ajouter : +- `LOG_LEVEL` (info/debug) +- `LOG_BODIES` (true/false) +- `MAX_REPLY_CHARS` (defaut 4096) +- `MAX_PROMPT_CHARS` (defaut 8192) +- `REQUEST_TIMEOUT_MS` (defaut 60000) +- `OPENCODE_WORKSPACE` (info uniquement, documente le dir A2) + +Recommandation : oui, ajouter les six. `.env.example` les liste, jamais de +secret reel. + +TODO: answer + +### E8. CORS, body parsing, etat en memoire + +- CORS : non, ce n'est pas un navigateur. +- Body : JSON only. +- Etat : stateless (cf A3 Option 2). + +Recommandation : **garder tel quel**. Confirme ou contredit. + +TODO: answer + +--- + +## F. Auth, secrets, exposition publique + +### F1. Generation du `PROXY_TOKEN` + +Recommandation : genere a la main (`openssl rand -hex 32`), ecrit dans +`.env`. Si absent au boot, le proxy refuse de demarrer (fail-fast). + +TODO: answer + +### F2. HTTPS vs HTTP cote turtle + +ATM10 accepte les deux si dans `http.rules`. Token nu en HTTP = leak. + +Recommandation : **HTTPS uniquement**, meme en homelab, via le RP existant. + +TODO: answer + +### F3. Saisie du token sur la turtle + +Le secret ne doit jamais etre dans un fichier Lua commit. + +Recommandation : `settings set opencc.proxy_token ` + `settings.save()` +manuellement dans l'environnement de chaque turtle. Documenter dans le +quickstart. + +TODO: answer + +### F4. Token en query string ? + +Recommandation : **non**, header uniquement. Les query strings se retrouvent +dans les logs RP/proxy. + +TODO: answer + +### F5. Headers acceptes : Bearer et X-Proxy-Token + +Plan : les deux pour simplicite CC. + +Recommandation : accepter `Authorization: Bearer ` ET `X-Proxy-Token`, +documenter Bearer comme prefere. `X-Proxy-Token` reste seulement si CC pose +souci avec `Authorization` (a tester). + +TODO: answer + +### F6. Comparaison constant-time + +Recommandation : `crypto.timingSafeEqual` apres normalisation (longueur +egalisee) pour eviter le throw sur taille differente. + +TODO: answer + +### F7. Rotation du token + +Recommandation : **hors scope PoC**. Redemarrer proxy + reconfigurer +turtles = acceptable. + +TODO: answer + +### F8. Rate-limit et allowlist IP + +Recommandation : ni l'un ni l'autre dans l'app. Si exposition publique le +demande, c'est au RP / firewall de gerer (donc en dehors du repo). + +TODO: answer + +### F9. Basic Auth OpenCode + +Recommandation : credentials uniquement via env (`OPENCODE_USERNAME`, +`OPENCODE_PASSWORD`), valides au boot, sinon fail-fast. + +TODO: answer + +--- + +## G. Programme Lua `opencc` + +### G1. Emplacement et packaging + +Plan : `apis/libopencc.lua`, `programs/opencc.lua`, `tests/opencc.lua`. + +Recommandation : pas de `packages/tos-agent/ccpm.json` avant validation +in-game (cf I3). Fichiers nus dans `apis/` et `programs/` pendant le PoC. + +TODO: answer + +### G2. Source de config (settings vs fichier vs CLI) + +Clefs `settings` : +- `opencc.proxy_url` (URL complete HTTPS recommandee) +- `opencc.proxy_token` +- `opencc.session_id` (auto-remplie) +- `opencc.timeout` (optionnel) + +Recommandation : **`settings` uniquement** + flags CLI (`--url`, `--token`) +qui overrident pour le debug. Si `proxy_url` ou `proxy_token` manque, +message clair + exit non-zero. Pas de host/port separes. + +TODO: answer + +### G3. Format CLI + +- `opencc --help`, `--version` +- `opencc "prompt"` (argv) ou interactif via `read()` si pas d'arg +- REPL multi-tour ? + +Recommandation : pas de REPL. Un prompt par invocation. Le contexte vient +de la `session_id` persistante. + +TODO: answer + +### G4. Persistance et reset de la session + +- Persistance : `settings.set('opencc.session_id', id); settings.save()` ou + fichier dedie ? +- Reset : `opencc --new` ? `--reset-session` ? + +Recommandation : **`settings`** (coherence G2) ; flag **`opencc --new`** qui +efface `opencc.session_id` et cree une nouvelle session via le prochain +`/ask`. + +TODO: answer + +### G5. Affichage de la reponse + +- Print brut ? +- Word-wrap manuel ? +- Pagination ? +- Print metadata (sessionId, model) ? + +Recommandation : print + word-wrap simple sur largeur terminal. Pas de +pagination. Pas de metadata sauf en mode `--verbose` (a ajouter plus tard). + +TODO: answer + +### G6. Erreurs reseau et `http.rules` + +`http.post` peut renvoyer `nil` (handshake ko, host bloque par `http.rules`) +ou un response status != 200. + +Recommandation : +- `nil` -> "proxy injoignable. Verifie `opencc.proxy_url` et que l'hote + est autorise dans `http.rules`". +- `401` -> "token invalide". +- `413` -> "prompt trop long". +- `502/504` -> "agent indisponible / trop lent". +- Autre -> message generique + status code. + +TODO: answer + +### G7. Timeout HTTP CC + +`http.post` n'a pas de parametre timeout standard. CC:Tweaked >= 1.97 a +`http.request` avec timeout ; a verifier sur ATM10. + +Recommandation : exposer `opencc.timeout`. Si CC l'accepte, on l'utilise ; +sinon documenter la limite et compter sur A4 Option 4 pour la suite. + +TODO: answer + +### G8. Pattern factory et JSON + +Repo : `apis/libccpm.lua` est une factory avec `opts.http` injectable. Meme +chose pour `libopencc` ? Encodage JSON via `textutils.serialiseJSON` ? + +Recommandation : **factory** : `local createOpencc = require('/apis/libopencc'); local opencc = createOpencc({ http = http, settings = settings, computerCraftTimeout = ... })`. JSON via `textutils.serialiseJSON` / `unserialiseJSON`. + +TODO: answer + +### G9. Trim / multiline / vide + +Recommandation : trim final, refus si prompt vide apres trim. Multiline +preserve. + +TODO: answer + +### G10. Tests Lua + +Plan : injection d'un faux `http` via `libtest`. + +Recommandation : `tests/opencc.lua` avec `libtest`, faux `http` qui verifie +URL, headers (Bearer + Content-Type), body JSON, parsing succes, parsing +erreur. Hors-scope : E2E reel avec vrai proxy. + +TODO: answer + +--- + +## H. Tests et validation + +### H1. Fixture OpenCode capturee + +Recommandation : oui (cf C2). Sanitize, store dans +`cc-agent-proxy/test/fixtures/session-message.json`. Sert de reference pour +`opencode.test.ts`. + +TODO: answer + +### H2. E2E manuel vs automatise + +Recommandation : **manuel** pour le PoC. Documenter les commandes (cf H7). + +TODO: answer + +### H3. CraftOS-PC headless avant l'in-game + +Recommandation : oui si `just craftos --headless` peut faire `http.post`. +Premier roundtrip en local avant ATM10. + +TODO: answer + +### H4. Pre-requis ATM10 a documenter + +A documenter : +- `http` enable cote serveur. +- Hote du proxy autorise dans `http.rules` (allow `*.tondomaine.tld:443` ou + IP). +- DNS / IP joignable depuis le serveur Minecraft. +- Token + URL definis dans les settings de la turtle. +- Provider LLM authentifie cote OpenCode. + +Recommandation : checklist dans `docs/opencc-quickstart.md` ecrite **apres** +la premiere validation reelle. + +TODO: answer + +### H5. Hooks `just check` et `just test` + +`pre-commit` = `just check test` (Lua + luacheck). Faut-il y mettre les +tests Node ? + +Recommandation : **non**. Recipe separee `just node-check` (eslint+prettier) +et `just node-test` (vitest) dans un sous-Justfile de `cc-agent-proxy/`. +Eviter une dependance implicite Node pour les commits Lua. + +TODO: answer + +### H6. CI + +Repo : pas de CI publique declaree, juste hooks locaux. + +Recommandation : pas de CI pour le PoC. Plus tard, eventuellement un workflow +GH Actions `node-test` + `lua-check`. + +TODO: answer + +### H7. Transcript de validation manuelle + +Recommandation : apres premier roundtrip reussi, enregistrer les commandes +exactes et outputs sanitize dans `docs/opencc-quickstart.md`, incluant un +deuxieme `/ask` avec le meme `sessionId` pour prouver la persistance. + +TODO: answer + +--- + +## I. Architecture / coherence repo + +### I1. Reuse de `apis/net.lua` + +Recommandation : **non**. `net.lua` est modem/rednet. `http.post` direct +cote Lua est le bon choix. + +TODO: answer + +### I2. Reuse de `apis/eventloop.lua` + +Recommandation : **non**. Le PoC est request/response synchrone. Re-evaluer +si A4 passe en async (G1 post-PoC). + +TODO: answer + +### I3. Packaging ccpm + +Recommandation : **post-PoC**. Apres validation in-game, creer +`packages/tos-agent/ccpm.json` : +- `files` : `apis/libopencc.lua`, `programs/opencc.lua` +- `dependencies` : `tos-core` +- `autostart` : aucun +- Ajouter dans `packages/index.json`. + +Declencheur : PoC reussi + au moins une raison de reinstaller/partager. + +TODO: answer + +### I4. ADR + +Recommandation : ADR-0012 "external agent bridge via HTTPS proxy" ecrit +apres validation. Justifie la presence d'un sous-dossier Node dans un repo +Lua. + +TODO: answer + +### I5. Conformite CLAUDE.md + +- Bump `_VERSION` sur chaque module Lua modifie. +- `--version` / `--help` sur `opencc`. +- Lua : 2-space indent, `;`, `local function`. +- Node : suit Prettier default. + +Recommandation : appliquer tel quel. + +TODO: answer + +--- + +## J. Post-PoC (evolutions, hors scope mais a ne pas peindre dans un coin) + +Reponds seulement si avis fort. + +### J1. Mode async + +Trigger : reponses LLM frequemment > timeout CC/proxy. + +Recommandation : ajouter `POST /ask?async=1` + `GET /ask/:jobId/status`. +Backward-compatible. `opencc` apprend a poll. + +TODO: answer (optionnel) + +### J2. SSE / WebSocket pour streaming + +Pas de SSE en CC:Tweaked, mais `http.websocket` existe. + +Recommandation : proxy WS dedie si streaming devient utile. Hors-scope PoC. + +TODO: answer (optionnel) + +### J3. Multi-turtle isolation et identite + +Trigger : > 1 turtle/utilisateur sur le meme proxy. + +Recommandation : avec A3 Option 2 c'est deja gratuit niveau sessions. Pour +quotas, ajouter `turtleId` (= `os.getComputerID()`) au body et a la table de +tokens. + +TODO: answer (optionnel) + +### J4. Outils OpenCode (lecture/ecriture fichiers) + +Recommandation : sandbox stricte (mount lecture-seule + un dir scratch). +Hors-scope PoC. + +TODO: answer (optionnel) + +### J5. Replacement de `http.post` par `apis/net.lua` + +Recommandation : probablement jamais. `net.lua` est routeur/rednet, pas +sortie HTTP. + +TODO: answer (optionnel) + +### J6. Observabilite (metrics, traces) + +Recommandation : ignorer en PoC. Pino logs suffisent. Prometheus exporter +plus tard si quotas. + +TODO: answer (optionnel) + +--- + +## K. Inconnues a valider au premier run + +Pas de reponse texte ; coche au fur et a mesure. + +- [ ] Version exacte d'OpenCode utilisee (`opencode --version`). +- [ ] Format reel des `parts` retournees par `POST /session/:id/message`. +- [ ] Comportement OpenCode si `model` est passe vs absent. +- [ ] Basic Auth vraiment necessaire dans la config de Guillaume. +- [ ] Timeout effectif `http.post` cote CC sur ATM10 (et si CC:Tweaked + version supporte un parametre timeout). +- [ ] Reaction OpenCode si on hammer une session morte (404 ? autre ?). +- [ ] Limite de longueur d'un message accepte par OpenCode. +- [ ] Cas ou le provider LLM est down : OpenCode renvoie quoi ? +- [ ] CraftOS-PC headless peut-il faire `http.post` HTTPS vers le proxy en + local ? + +--- + +## L. Quoi repondre en priorite + +Si tu veux aller vite, reponds dans cet ordre. Le reste decoule. + +1. A1 - critere d'acceptation +2. A2 - workspace OpenCode (frontiere de confiance) +3. A3 - cycle session +4. A4 - sync vs async +5. A5 - topologie deploiement +6. A6 - auth turtle <-> proxy +7. A7 - forme de la reponse +8. A8 - scope v1 + +Une fois ces 8 trances, on peut souvent ignorer les sections B-J pour le +"go/no-go" et juste valider les recommandations par defaut. Les detailler +n'apporte de la valeur que si tu veux devier d'une recommandation precise.