chore: updated grilled plan

This commit is contained in:
Guillaume ARM 2026-06-08 20:53:35 +02:00
parent f533d49c93
commit d4dab69573

View File

@ -48,7 +48,9 @@ bonjour`) avant prompts libres.
Pourquoi ca compte : decide si async, multi-turtle, logs riches, quotas, Pourquoi ca compte : decide si async, multi-turtle, logs riches, quotas,
packaging et UX terminale sont hors scope. packaging et UX terminale sont hors scope.
TODO: answer Option 4. Le PoC est fini seulement quand `opencc` marche in-game sur une
vraie turtle et que deux prompts successifs prouvent la session persistante.
Les curls OpenCode faits sur `4242` restent des jalons de contrat API.
### A2. Autorite et workspace d'OpenCode ### A2. Autorite et workspace d'OpenCode
@ -70,7 +72,9 @@ test. Documenter le dir exact dans `.env`.
Pourquoi ca compte : c'est la vraie frontiere de confiance, plus que le Pourquoi ca compte : c'est la vraie frontiere de confiance, plus que le
token Lua. token Lua.
TODO: answer Option 1. `opencode serve` doit tourner dans un workspace jetable dedie au PoC,
pas dans ce repo : les endpoints serveur peuvent piloter le TUI et declencher
le LLM, donc la frontiere de confiance est le workspace OpenCode.
### A3. Cycle de vie de la session ### A3. Cycle de vie de la session
@ -87,7 +91,9 @@ 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 `sessionId` optionnel, le proxy en cree une si absent et le renvoie dans la
reponse. reponse.
TODO: answer Option 2. La turtle garde `opencc.session_id` dans `settings`; le proxy cree
une session si absent et renvoie toujours le `sessionId`. Cela evite un etat
proxy et colle au contrat reel `POST /session` puis `/session/:id/message`.
### A4. Sync vs async pour `/ask` ### A4. Sync vs async pour `/ask`
@ -105,7 +111,9 @@ timeouts HTTP (~30s typiques, depend du serveur).
Recommandation : **Option 4**. Recommandation : **Option 4**.
TODO: answer Option 4. On demarre en sync avec prompts courts, car `POST /session/:id/message`
attend bien la reponse LLM quand `noReply` est absent. Si les timeouts CC
apparaissent, on ajoute async/polling sans changer le happy path `/ask`.
### A5. Topologie de deploiement ### A5. Topologie de deploiement
@ -123,7 +131,9 @@ Conditionne : auth (A6), `OPENCODE_BASE_URL`, qui termine TLS.
Recommandation : **Option 3** si tu as un homelab, sinon Option 1. Proxy + 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. opencode sur le meme hote, loopback entre les deux, proxy expose en HTTPS.
TODO: answer Option 3 pour moi : homelab/RP si expose a une turtle ATM10 reelle. Proxy et
OpenCode restent sur le meme hote, OpenCode en loopback, seul le proxy sort en
HTTPS. Pour dev local, Option 1 avec tunnel reste acceptable.
### A6. Modele d'authentification turtle <-> proxy ### A6. Modele d'authentification turtle <-> proxy
@ -139,7 +149,9 @@ TODO: answer
Recommandation : **Option 1**. Helper `isTokenValid(token)` pour permettre Recommandation : **Option 1**. Helper `isTokenValid(token)` pour permettre
une table plus tard sans refactor. une table plus tard sans refactor.
TODO: answer Option 1 pour le PoC. Token unique partage, header seulement, helper
`isTokenValid` pour permettre token par turtle plus tard sans changer le
programme Lua.
### A7. Forme de la reponse renvoyee a la turtle ### A7. Forme de la reponse renvoyee a la turtle
@ -154,7 +166,9 @@ OpenCode retourne `parts`, tool calls, code blocks. La turtle a peu de RAM.
Recommandation : **Option 4**. Recommandation : **Option 4**.
TODO: answer Option 4. Le proxy renvoie `{ reply, sessionId, truncated }`; il concatene les
parts `text` uniquement et tronque pour la turtle. Les parts tools/reasoning
observees dans OpenCode doivent rester cote proxy/logs, pas cote turtle.
### A8. Scope minimal v1 (in et out) ### A8. Scope minimal v1 (in et out)
@ -171,7 +185,9 @@ Recommandation : **Option 2**.
Hors-scope explicite du PoC : async, multi-turtles, package ccpm, deploiement Hors-scope explicite du PoC : async, multi-turtles, package ccpm, deploiement
auto, Docker, quotas, UI terminale riche, streaming OpenCode (`/event`). auto, Docker, quotas, UI terminale riche, streaming OpenCode (`/event`).
TODO: answer Option 2. Scope v1 = une turtle, une session persistante, un prompt par
invocation. Les endpoints TUI sont utiles pour piloter un client humain, mais
le proxy turtle doit utiliser `/session/:id/message` directement.
--- ---
@ -184,7 +200,9 @@ 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, 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. on arrete d'abstraire et on capture le contrat reel via curl avant de coder.
TODO: answer Confirme. Une seule passe : avant de coder le client OpenCode, capturer le
contrat reel par curl. On a deja valide `GET /global/health`, `POST /session`,
`POST /session/:id/message`, `GET /session/:id/message` et `/tui/*`.
### B2. Rollback / cleanup post-PoC ### B2. Rollback / cleanup post-PoC
@ -193,7 +211,9 @@ Comment on nettoie une fois la demo faite ?
Recommandation : stop proxy, stop `opencode serve`, supprimer sessions de Recommandation : stop proxy, stop `opencode serve`, supprimer sessions de
test, rotation du `PROXY_TOKEN` et du `OPENCODE_PASSWORD` utilises. test, rotation du `PROXY_TOKEN` et du `OPENCODE_PASSWORD` utilises.
TODO: answer Confirme. Stopper proxy + `opencode serve`, supprimer les sessions PoC si besoin,
et rotation du `PROXY_TOKEN`/`OPENCODE_SERVER_PASSWORD`. Ne jamais garder les
sorties `/provider` dans les logs partages.
--- ---
@ -207,7 +227,9 @@ Recommandation : enregistrer `opencode --version` utilise lors de la
validation ; pinger `/global/health` avec Basic Auth via curl avant de coder validation ; pinger `/global/health` avec Basic Auth via curl avant de coder
le client. le client.
TODO: answer Valide sur OpenCode `1.16.2`. `/global/health` retourne
`{"healthy":true,"version":"1.16.2"}`. Basic Auth reste a retester avec
`OPENCODE_SERVER_PASSWORD`; sans password, le serveur avertit qu'il est unsecured.
### C2. Spec exacte de `POST /session/:id/message` ### C2. Spec exacte de `POST /session/:id/message`
@ -217,7 +239,9 @@ Recommandation : `curl http://localhost:4096/doc` une fois OpenCode lance,
capturer un sample reel de reponse, le commiter sanitize dans capturer un sample reel de reponse, le commiter sanitize dans
`cc-agent-proxy/test/fixtures/`. `cc-agent-proxy/test/fixtures/`.
TODO: answer Contrat valide : `POST /session/:id/message` body minimal
`{"parts":[{"type":"text","text":"..."}]}`. `noReply:true` cree seulement
le message user; sans `noReply`, OpenCode declenche le LLM et attend la reponse.
### C3. Provider et modele LLM ### C3. Provider et modele LLM
@ -227,14 +251,17 @@ openai, ollama local) ?
Recommandation : laisser defaut OpenCode, ne passer `model` que si Recommandation : laisser defaut OpenCode, ne passer `model` que si
`OPENCODE_MODEL` est defini dans `.env`. `OPENCODE_MODEL` est defini dans `.env`.
TODO: answer Confirme. Laisser le modele par defaut OpenCode pour le PoC. Ne passer
`model:{providerID,modelID}` que si `OPENCODE_MODEL` est defini, car l'appel
sans model marche deja avec la session courante.
### C4. Timeout amont vers OpenCode ### C4. Timeout amont vers OpenCode
Recommandation : `REQUEST_TIMEOUT_MS` configurable, defaut 60s. Au dela -> Recommandation : `REQUEST_TIMEOUT_MS` configurable, defaut 60s. Au dela ->
504 cote proxy. 504 cote proxy.
TODO: answer Confirme. `REQUEST_TIMEOUT_MS=60000` par defaut cote proxy. Le timeout doit
englober l'appel bloquant `/session/:id/message`; 504 public si depassement.
### C5. Exposition des erreurs OpenCode au turtle ### C5. Exposition des erreurs OpenCode au turtle
@ -242,7 +269,9 @@ Recommandation : pas de stack trace ni secret. Renvoyer
`{ error: "...", code: "..." }` avec message public court ; detail dans les `{ error: "...", code: "..." }` avec message public court ; detail dans les
logs proxy uniquement. logs proxy uniquement.
TODO: answer Confirme. Reponse publique courte, code stable, aucun detail provider/config.
Attention particuliere : des endpoints comme `/provider` peuvent exposer du
materiel d'auth, donc logs sanitize obligatoires.
### C6. SessionId auto-creation et recovery si stale ### C6. SessionId auto-creation et recovery si stale
@ -256,7 +285,9 @@ Deux comportements distincts :
Recommandation : **Option B**. Auto-recreation cacherait une perte de Recommandation : **Option B**. Auto-recreation cacherait une perte de
contexte deroutante. contexte deroutante.
TODO: answer Option B. Si `sessionId` absent, creer via `POST /session`. Si `sessionId`
fourni renvoie 404/stale, repondre `session_expired`; la turtle pourra faire
`opencc --new` plutot que perdre le contexte silencieusement.
### C7. Comportement quand OpenCode est down ### C7. Comportement quand OpenCode est down
@ -267,7 +298,9 @@ TODO: answer
Recommandation : pas de retry auto, **502** + JSON `{ error: "upstream_down" }`. Recommandation : pas de retry auto, **502** + JSON `{ error: "upstream_down" }`.
`/health` inclut un champ `opencode: "up"/"down"`. `/health` inclut un champ `opencode: "up"/"down"`.
TODO: answer Confirme. Pas de retry auto. `/health` proxy ping `/global/health`; si down,
`{ proxy: "ok", opencode: "down" }`. `/ask` renvoie 502
`{ error: "upstream_down" }`.
### C8. Gestion des parts non-textuelles (tools, code blocks) ### C8. Gestion des parts non-textuelles (tools, code blocks)
@ -275,7 +308,9 @@ Recommandation : concatener les parts texte, ignorer les non-textuelles dans
la `reply`, mais logger un compteur cote proxy (`parts_text`, `parts_tool`, la `reply`, mais logger un compteur cote proxy (`parts_text`, `parts_tool`,
`parts_other`). `parts_other`).
TODO: answer Confirme. Les reponses reelles contiennent `text`, `reasoning`, `tool`,
`step-start`, `step-finish`. La `reply` turtle concatene seulement les parts
`text`; les compteurs de parts restent dans les logs proxy.
--- ---
@ -296,7 +331,9 @@ Recommandation :
initialiser ou nommer une session ; ne casse pas le PoC si on ne l'expose initialiser ou nommer une session ; ne casse pas le PoC si on ne l'expose
pas a la turtle. pas a la turtle.
TODO: answer Confirme. `/session` peut rester une route debug/initialisation, mais `/ask`
doit creer implicitement si `sessionId` absent. `/health` inclut l'etat
OpenCode via `/global/health`.
### D2. Codes HTTP stables pour la turtle ### D2. Codes HTTP stables pour la turtle
@ -309,7 +346,8 @@ Recommandation :
- `504` OpenCode timeout - `504` OpenCode timeout
- `500` erreur proxy inattendue - `500` erreur proxy inattendue
TODO: answer Confirme ces codes. Ajouter `409` uniquement si un jour on gere des jobs async
concurrents par session; hors PoC, la liste suffit.
### D3. Limites taille de requete ### D3. Limites taille de requete
@ -319,7 +357,8 @@ TODO: answer
Recommandation : prompt max **8 KiB** (`MAX_PROMPT_CHARS` env), body max Recommandation : prompt max **8 KiB** (`MAX_PROMPT_CHARS` env), body max
**32 KiB** cote Fastify. Pas de rate-limit dans le PoC. **32 KiB** cote Fastify. Pas de rate-limit dans le PoC.
TODO: answer Confirme. `MAX_PROMPT_CHARS=8192`, body JSON max 32 KiB, pas de rate-limit dans
l'app. Ces limites protegent surtout CC/Turtle RAM et les logs.
### D4. Request IDs / correlation ### D4. Request IDs / correlation
@ -327,7 +366,8 @@ Recommandation : `requestId` auto-genere cote proxy, present dans tous les
logs, non expose dans la reponse JSON (juste dans header `x-request-id` pour logs, non expose dans la reponse JSON (juste dans header `x-request-id` pour
debug optionnel). debug optionnel).
TODO: answer Confirme. `requestId` genere cote proxy, logge partout, expose seulement via
header `x-request-id` pour debug. Ne pas le mettre dans le JSON turtle par defaut.
--- ---
@ -337,14 +377,16 @@ TODO: answer
Recommandation : **Node 20+**, **pnpm**. Sinon **npm** si tu prefers vanilla. Recommandation : **Node 20+**, **pnpm**. Sinon **npm** si tu prefers vanilla.
TODO: answer Confirme : Node 20+ et pnpm. Si le repo n'a pas deja pnpm, garder npm possible,
mais le proxy doit rester isole dans son sous-dossier.
### E2. Strictness TypeScript ### E2. Strictness TypeScript
Recommandation : `"strict": true` + `noUncheckedIndexedAccess`. Recommandation : `"strict": true` + `noUncheckedIndexedAccess`.
`exactOptionalPropertyTypes` evite (bruit pour peu de valeur en PoC). `exactOptionalPropertyTypes` evite (bruit pour peu de valeur en PoC).
TODO: answer Confirme : `strict` + `noUncheckedIndexedAccess`, sans
`exactOptionalPropertyTypes` pour limiter le bruit PoC.
### E3. Framework HTTP et validation ### E3. Framework HTTP et validation
@ -353,7 +395,8 @@ Plan : Fastify + Zod.
Recommandation : **Fastify** + **Zod** + `fastify-type-provider-zod` pour Recommandation : **Fastify** + **Zod** + `fastify-type-provider-zod` pour
validation automatique des routes. Confirme ou propose autre. validation automatique des routes. Confirme ou propose autre.
TODO: answer Confirme : Fastify + Zod. Le contrat proxy est petit et beneficie de schemas
explicites pour `prompt`, `sessionId`, `reply`, `truncated`.
### E4. Logging ### E4. Logging
@ -362,7 +405,9 @@ Recommandation : **Pino** (default Fastify). `LOG_LEVEL=info` par defaut,
par defaut**. Jamais logger token ni `OPENCODE_PASSWORD`. Logs : status, par defaut**. Jamais logger token ni `OPENCODE_PASSWORD`. Logs : status,
duree, `sessionId` (12 premiers chars), `requestId`, longueurs prompt/reply. duree, `sessionId` (12 premiers chars), `requestId`, longueurs prompt/reply.
TODO: answer Confirme. Pino/Fastify, `LOG_BODIES=false` par defaut. Ne pas logger les sorties
brutes OpenCode sensibles (`/provider`, config, headers auth) ; loguer seulement
longueurs, status, duree, requestId, prefix sessionId.
### E5. Process / lancement / deploiement ### E5. Process / lancement / deploiement
@ -374,7 +419,8 @@ 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 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. RP. Shutdown : `app.close()` sur SIGTERM, rien de plus.
TODO: answer Confirme. Dev avec `tsx`, prod `node dist/index.js`, pas de Docker/systemd dans
le repo. Bind proxy `0.0.0.0` derriere RP, OpenCode en `127.0.0.1`.
### E6. Tests Node ### E6. Tests Node
@ -384,7 +430,8 @@ Recommandation : couvrir `/ask` happy path, `401`, OpenCode 5xx mock,
prompt vide, prompt trop long, sessionId 404 amont. Fixture OpenCode reelle prompt vide, prompt trop long, sessionId 404 amont. Fixture OpenCode reelle
(cf C2) utilisee dans `opencode.test.ts`. (cf C2) utilisee dans `opencode.test.ts`.
TODO: answer Confirme. Tests vitest avec fetch mocke + `app.inject()`. Ajouter fixture reelle
sanitized de `/session/:id/message` incluant text/reasoning/tool/step parts.
### E7. Variables d'env (en plus du tableau du plan) ### E7. Variables d'env (en plus du tableau du plan)
@ -399,7 +446,8 @@ A ajouter :
Recommandation : oui, ajouter les six. `.env.example` les liste, jamais de Recommandation : oui, ajouter les six. `.env.example` les liste, jamais de
secret reel. secret reel.
TODO: answer Confirme les six variables. Ajouter aussi un commentaire `.env.example` pour
`OPENCODE_BASE_URL=http://127.0.0.1:4242` et credentials Basic Auth si actives.
### E8. CORS, body parsing, etat en memoire ### E8. CORS, body parsing, etat en memoire
@ -409,7 +457,8 @@ TODO: answer
Recommandation : **garder tel quel**. Confirme ou contredit. Recommandation : **garder tel quel**. Confirme ou contredit.
TODO: answer Confirme. Pas de CORS, JSON only, proxy stateless. Les endpoints `/tui/*` ne
sont pas utilises par le proxy turtle ; ils restent une piste d'integration TUI.
--- ---
@ -420,7 +469,8 @@ TODO: answer
Recommandation : genere a la main (`openssl rand -hex 32`), ecrit dans Recommandation : genere a la main (`openssl rand -hex 32`), ecrit dans
`.env`. Si absent au boot, le proxy refuse de demarrer (fail-fast). `.env`. Si absent au boot, le proxy refuse de demarrer (fail-fast).
TODO: answer Confirme. Token genere manuellement, fail-fast si absent. Ne jamais le passer en
query string ni l'afficher dans les logs.
### F2. HTTPS vs HTTP cote turtle ### F2. HTTPS vs HTTP cote turtle
@ -428,7 +478,8 @@ ATM10 accepte les deux si dans `http.rules`. Token nu en HTTP = leak.
Recommandation : **HTTPS uniquement**, meme en homelab, via le RP existant. Recommandation : **HTTPS uniquement**, meme en homelab, via le RP existant.
TODO: answer Confirme : HTTPS uniquement entre turtle et proxy des que ca sort de localhost.
OpenCode peut rester en HTTP loopback derriere le proxy.
### F3. Saisie du token sur la turtle ### F3. Saisie du token sur la turtle
@ -438,14 +489,15 @@ Recommandation : `settings set opencc.proxy_token <token>` + `settings.save()`
manuellement dans l'environnement de chaque turtle. Documenter dans le manuellement dans l'environnement de chaque turtle. Documenter dans le
quickstart. quickstart.
TODO: answer Confirme. Configuration manuelle via `settings`; rien de secret dans les fichiers
Lua commit. Documenter commandes fish/bash separement cote host si besoin.
### F4. Token en query string ? ### F4. Token en query string ?
Recommandation : **non**, header uniquement. Les query strings se retrouvent Recommandation : **non**, header uniquement. Les query strings se retrouvent
dans les logs RP/proxy. dans les logs RP/proxy.
TODO: answer Confirme : non. Token en header seulement, jamais query string.
### F5. Headers acceptes : Bearer et X-Proxy-Token ### F5. Headers acceptes : Bearer et X-Proxy-Token
@ -455,35 +507,39 @@ Recommandation : accepter `Authorization: Bearer <token>` ET `X-Proxy-Token`,
documenter Bearer comme prefere. `X-Proxy-Token` reste seulement si CC pose documenter Bearer comme prefere. `X-Proxy-Token` reste seulement si CC pose
souci avec `Authorization` (a tester). souci avec `Authorization` (a tester).
TODO: answer Confirme. Bearer prefere ; `X-Proxy-Token` accepte pour compat CC si
`Authorization` pose souci, a valider en CraftOS-PC/ATM10.
### F6. Comparaison constant-time ### F6. Comparaison constant-time
Recommandation : `crypto.timingSafeEqual` apres normalisation (longueur Recommandation : `crypto.timingSafeEqual` apres normalisation (longueur
egalisee) pour eviter le throw sur taille differente. egalisee) pour eviter le throw sur taille differente.
TODO: answer Confirme. `timingSafeEqual` avec buffers normalises pour eviter throw et timing
trivial.
### F7. Rotation du token ### F7. Rotation du token
Recommandation : **hors scope PoC**. Redemarrer proxy + reconfigurer Recommandation : **hors scope PoC**. Redemarrer proxy + reconfigurer
turtles = acceptable. turtles = acceptable.
TODO: answer Confirme. Rotation hors scope PoC : redemarrage proxy + reconfiguration turtle.
### F8. Rate-limit et allowlist IP ### F8. Rate-limit et allowlist IP
Recommandation : ni l'un ni l'autre dans l'app. Si exposition publique le 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). demande, c'est au RP / firewall de gerer (donc en dehors du repo).
TODO: answer Confirme. Rate-limit/allowlist hors app, gere par RP/firewall si necessaire.
### F9. Basic Auth OpenCode ### F9. Basic Auth OpenCode
Recommandation : credentials uniquement via env (`OPENCODE_USERNAME`, Recommandation : credentials uniquement via env (`OPENCODE_USERNAME`,
`OPENCODE_PASSWORD`), valides au boot, sinon fail-fast. `OPENCODE_PASSWORD`), valides au boot, sinon fail-fast.
TODO: answer Renommer cote proxy en `OPENCODE_SERVER_USERNAME`/`OPENCODE_SERVER_PASSWORD` ou
documenter clairement le mapping, car OpenCode utilise ces noms pour proteger
`serve`. Valider au boot par `/global/health` avec Basic Auth.
--- ---
@ -496,7 +552,8 @@ Plan : `apis/libopencc.lua`, `programs/opencc.lua`, `tests/opencc.lua`.
Recommandation : pas de `packages/tos-agent/ccpm.json` avant validation Recommandation : pas de `packages/tos-agent/ccpm.json` avant validation
in-game (cf I3). Fichiers nus dans `apis/` et `programs/` pendant le PoC. in-game (cf I3). Fichiers nus dans `apis/` et `programs/` pendant le PoC.
TODO: answer Confirme. Pas de packaging tant que l'in-game n'a pas tourne. Fichiers nus
`apis/libopencc.lua`, `programs/opencc.lua`, `tests/opencc.lua` pour le PoC.
### G2. Source de config (settings vs fichier vs CLI) ### G2. Source de config (settings vs fichier vs CLI)
@ -510,7 +567,8 @@ Recommandation : **`settings` uniquement** + flags CLI (`--url`, `--token`)
qui overrident pour le debug. Si `proxy_url` ou `proxy_token` manque, qui overrident pour le debug. Si `proxy_url` ou `proxy_token` manque,
message clair + exit non-zero. Pas de host/port separes. message clair + exit non-zero. Pas de host/port separes.
TODO: answer Confirme : `settings` uniquement + overrides CLI debug. `opencc.proxy_url`,
`opencc.proxy_token`, `opencc.session_id`, `opencc.timeout` suffisent.
### G3. Format CLI ### G3. Format CLI
@ -521,7 +579,8 @@ TODO: answer
Recommandation : pas de REPL. Un prompt par invocation. Le contexte vient Recommandation : pas de REPL. Un prompt par invocation. Le contexte vient
de la `session_id` persistante. de la `session_id` persistante.
TODO: answer Confirme : pas de REPL. Un prompt par invocation ; le contexte vient du
`session_id` persistant.
### G4. Persistance et reset de la session ### G4. Persistance et reset de la session
@ -533,7 +592,8 @@ Recommandation : **`settings`** (coherence G2) ; flag **`opencc --new`** qui
efface `opencc.session_id` et cree une nouvelle session via le prochain efface `opencc.session_id` et cree une nouvelle session via le prochain
`/ask`. `/ask`.
TODO: answer Confirme. `opencc --new` efface `opencc.session_id`; le prochain `/ask` cree
une session. Pas besoin d'appeler `/session` explicitement cote turtle.
### G5. Affichage de la reponse ### G5. Affichage de la reponse
@ -545,7 +605,8 @@ TODO: answer
Recommandation : print + word-wrap simple sur largeur terminal. Pas de Recommandation : print + word-wrap simple sur largeur terminal. Pas de
pagination. Pas de metadata sauf en mode `--verbose` (a ajouter plus tard). pagination. Pas de metadata sauf en mode `--verbose` (a ajouter plus tard).
TODO: answer Confirme. Print avec word-wrap simple, pas de pagination. Metadata uniquement
si `--verbose` est ajoute plus tard.
### G6. Erreurs reseau et `http.rules` ### G6. Erreurs reseau et `http.rules`
@ -560,7 +621,8 @@ Recommandation :
- `502/504` -> "agent indisponible / trop lent". - `502/504` -> "agent indisponible / trop lent".
- Autre -> message generique + status code. - Autre -> message generique + status code.
TODO: answer Confirme ces messages. Ajouter un cas "session expiree" pour `session_expired` :
"session perdue, relance avec `opencc --new`".
### G7. Timeout HTTP CC ### G7. Timeout HTTP CC
@ -570,7 +632,8 @@ TODO: answer
Recommandation : exposer `opencc.timeout`. Si CC l'accepte, on l'utilise ; Recommandation : exposer `opencc.timeout`. Si CC l'accepte, on l'utilise ;
sinon documenter la limite et compter sur A4 Option 4 pour la suite. sinon documenter la limite et compter sur A4 Option 4 pour la suite.
TODO: answer Confirme. Tester si ATM10/CC:Tweaked accepte un timeout via `http.request`; si
non, documenter et garder sync court pour le PoC.
### G8. Pattern factory et JSON ### G8. Pattern factory et JSON
@ -579,14 +642,15 @@ 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`. Recommandation : **factory** : `local createOpencc = require('/apis/libopencc'); local opencc = createOpencc({ http = http, settings = settings, computerCraftTimeout = ... })`. JSON via `textutils.serialiseJSON` / `unserialiseJSON`.
TODO: answer Confirme. Factory injectable comme `libccpm.lua`; JSON via `textutils.serialiseJSON`
et `textutils.unserialiseJSON`.
### G9. Trim / multiline / vide ### G9. Trim / multiline / vide
Recommandation : trim final, refus si prompt vide apres trim. Multiline Recommandation : trim final, refus si prompt vide apres trim. Multiline
preserve. preserve.
TODO: answer Confirme. Trim final, refuser prompt vide apres trim, preserver multiline.
### G10. Tests Lua ### G10. Tests Lua
@ -596,7 +660,8 @@ Recommandation : `tests/opencc.lua` avec `libtest`, faux `http` qui verifie
URL, headers (Bearer + Content-Type), body JSON, parsing succes, parsing URL, headers (Bearer + Content-Type), body JSON, parsing succes, parsing
erreur. Hors-scope : E2E reel avec vrai proxy. erreur. Hors-scope : E2E reel avec vrai proxy.
TODO: answer Confirme. Tests `libtest` avec faux `http`, headers, body JSON, success,
erreurs proxy et sauvegarde `session_id`.
--- ---
@ -608,20 +673,23 @@ Recommandation : oui (cf C2). Sanitize, store dans
`cc-agent-proxy/test/fixtures/session-message.json`. Sert de reference pour `cc-agent-proxy/test/fixtures/session-message.json`. Sert de reference pour
`opencode.test.ts`. `opencode.test.ts`.
TODO: answer Oui. Capturer une fixture sanitized de la reponse reelle OpenCode. Important :
ne pas y inclure sortie `/provider` ni headers/auth.
### H2. E2E manuel vs automatise ### H2. E2E manuel vs automatise
Recommandation : **manuel** pour le PoC. Documenter les commandes (cf H7). Recommandation : **manuel** pour le PoC. Documenter les commandes (cf H7).
TODO: answer Confirme : E2E manuel pour le PoC. Les commandes de validation doivent etre
documentees, avec versions fish si utilisees par Guillaume.
### H3. CraftOS-PC headless avant l'in-game ### H3. CraftOS-PC headless avant l'in-game
Recommandation : oui si `just craftos --headless` peut faire `http.post`. Recommandation : oui si `just craftos --headless` peut faire `http.post`.
Premier roundtrip en local avant ATM10. Premier roundtrip en local avant ATM10.
TODO: answer Oui. CraftOS-PC headless avant ATM10 si possible, mais sans ajouter de harness
standalone Lua. Utiliser les recettes repo existantes.
### H4. Pre-requis ATM10 a documenter ### H4. Pre-requis ATM10 a documenter
@ -636,7 +704,8 @@ A documenter :
Recommandation : checklist dans `docs/opencc-quickstart.md` ecrite **apres** Recommandation : checklist dans `docs/opencc-quickstart.md` ecrite **apres**
la premiere validation reelle. la premiere validation reelle.
TODO: answer Confirme. Ecrire la checklist apres premiere validation reelle, pas avant de
figer des details faux.
### H5. Hooks `just check` et `just test` ### H5. Hooks `just check` et `just test`
@ -647,7 +716,8 @@ Recommandation : **non**. Recipe separee `just node-check` (eslint+prettier)
et `just node-test` (vitest) dans un sous-Justfile de `cc-agent-proxy/`. et `just node-test` (vitest) dans un sous-Justfile de `cc-agent-proxy/`.
Eviter une dependance implicite Node pour les commits Lua. Eviter une dependance implicite Node pour les commits Lua.
TODO: answer Confirme. Ne pas coupler Node aux hooks Lua existants pour le PoC ; recipes
Node separees dans le sous-dossier proxy.
### H6. CI ### H6. CI
@ -656,7 +726,7 @@ Repo : pas de CI publique declaree, juste hooks locaux.
Recommandation : pas de CI pour le PoC. Plus tard, eventuellement un workflow Recommandation : pas de CI pour le PoC. Plus tard, eventuellement un workflow
GH Actions `node-test` + `lua-check`. GH Actions `node-test` + `lua-check`.
TODO: answer Confirme. Pas de CI PoC.
### H7. Transcript de validation manuelle ### H7. Transcript de validation manuelle
@ -664,7 +734,8 @@ Recommandation : apres premier roundtrip reussi, enregistrer les commandes
exactes et outputs sanitize dans `docs/opencc-quickstart.md`, incluant un exactes et outputs sanitize dans `docs/opencc-quickstart.md`, incluant un
deuxieme `/ask` avec le meme `sessionId` pour prouver la persistance. deuxieme `/ask` avec le meme `sessionId` pour prouver la persistance.
TODO: answer Confirme. Transcript manuel sanitize dans `docs/opencc-quickstart.md` apres
roundtrip : `/health`, premier `/ask`, deuxieme `/ask` meme `sessionId`.
--- ---
@ -675,14 +746,14 @@ TODO: answer
Recommandation : **non**. `net.lua` est modem/rednet. `http.post` direct Recommandation : **non**. `net.lua` est modem/rednet. `http.post` direct
cote Lua est le bon choix. cote Lua est le bon choix.
TODO: answer Confirme. `apis/net.lua` est hors sujet pour HTTP externe.
### I2. Reuse de `apis/eventloop.lua` ### I2. Reuse de `apis/eventloop.lua`
Recommandation : **non**. Le PoC est request/response synchrone. Re-evaluer Recommandation : **non**. Le PoC est request/response synchrone. Re-evaluer
si A4 passe en async (G1 post-PoC). si A4 passe en async (G1 post-PoC).
TODO: answer Confirme. Pas d'eventloop Lua pour le PoC sync.
### I3. Packaging ccpm ### I3. Packaging ccpm
@ -695,7 +766,7 @@ Recommandation : **post-PoC**. Apres validation in-game, creer
Declencheur : PoC reussi + au moins une raison de reinstaller/partager. Declencheur : PoC reussi + au moins une raison de reinstaller/partager.
TODO: answer Confirme. Packaging seulement apres PoC in-game reussi et besoin de diffusion.
### I4. ADR ### I4. ADR
@ -703,7 +774,7 @@ Recommandation : ADR-0012 "external agent bridge via HTTPS proxy" ecrit
apres validation. Justifie la presence d'un sous-dossier Node dans un repo apres validation. Justifie la presence d'un sous-dossier Node dans un repo
Lua. Lua.
TODO: answer Confirme. ADR apres validation, pour justifier proxy Node + pont agent externe.
### I5. Conformite CLAUDE.md ### I5. Conformite CLAUDE.md
@ -714,7 +785,8 @@ TODO: answer
Recommandation : appliquer tel quel. Recommandation : appliquer tel quel.
TODO: answer Confirme. Respecter `_VERSION`, `--help`/`--version`, indent 2 spaces,
semicolons Lua, `local function`.
--- ---
@ -729,7 +801,9 @@ Trigger : reponses LLM frequemment > timeout CC/proxy.
Recommandation : ajouter `POST /ask?async=1` + `GET /ask/:jobId/status`. Recommandation : ajouter `POST /ask?async=1` + `GET /ask/:jobId/status`.
Backward-compatible. `opencc` apprend a poll. Backward-compatible. `opencc` apprend a poll.
TODO: answer (optionnel) Avis : garder ce design. Le test direct a confirme que sync fonctionne, mais
`noReply:true` donne deja un equivalent "enqueue sans reponse" cote OpenCode si
on doit construire un mode async plus tard.
### J2. SSE / WebSocket pour streaming ### J2. SSE / WebSocket pour streaming
@ -737,7 +811,10 @@ Pas de SSE en CC:Tweaked, mais `http.websocket` existe.
Recommandation : proxy WS dedie si streaming devient utile. Hors-scope PoC. Recommandation : proxy WS dedie si streaming devient utile. Hors-scope PoC.
TODO: answer (optionnel) Avis : ne pas confondre avec `/event` OpenCode. Le SSE existe et marche pour
observer le serveur, mais CC ne le consomme pas bien. Pour piloter un TUI, les
endpoints `/tui/append-prompt`, `/tui/submit-prompt`, `/tui/select-session`
sont utiles, mais hors proxy turtle.
### J3. Multi-turtle isolation et identite ### J3. Multi-turtle isolation et identite
@ -747,28 +824,33 @@ Recommandation : avec A3 Option 2 c'est deja gratuit niveau sessions. Pour
quotas, ajouter `turtleId` (= `os.getComputerID()`) au body et a la table de quotas, ajouter `turtleId` (= `os.getComputerID()`) au body et a la table de
tokens. tokens.
TODO: answer (optionnel) Avis : confirmer. Ajouter `turtleId` plus tard seulement pour quotas/audit ;
la vraie isolation conversationnelle reste le `sessionId` garde cote turtle.
### J4. Outils OpenCode (lecture/ecriture fichiers) ### J4. Outils OpenCode (lecture/ecriture fichiers)
Recommandation : sandbox stricte (mount lecture-seule + un dir scratch). Recommandation : sandbox stricte (mount lecture-seule + un dir scratch).
Hors-scope PoC. Hors-scope PoC.
TODO: answer (optionnel) Avis fort : sandbox obligatoire avant d'activer des outils capables d'ecrire.
Le test `/tui/*` prouve qu'un client externe peut declencher le LLM ; le
workspace OpenCode ne doit donc jamais etre un repo sensible pour le PoC.
### J5. Replacement de `http.post` par `apis/net.lua` ### J5. Replacement de `http.post` par `apis/net.lua`
Recommandation : probablement jamais. `net.lua` est routeur/rednet, pas Recommandation : probablement jamais. `net.lua` est routeur/rednet, pas
sortie HTTP. sortie HTTP.
TODO: answer (optionnel) Confirme : probablement jamais. HTTP direct est le bon chemin pour sortir vers
le proxy ; `net.lua` reste pour modem/rednet.
### J6. Observabilite (metrics, traces) ### J6. Observabilite (metrics, traces)
Recommandation : ignorer en PoC. Pino logs suffisent. Prometheus exporter Recommandation : ignorer en PoC. Pino logs suffisent. Prometheus exporter
plus tard si quotas. plus tard si quotas.
TODO: answer (optionnel) Confirme : Pino logs suffisent. Ajouter metrics seulement si plusieurs turtles
ou quotas reels.
--- ---
@ -776,15 +858,18 @@ TODO: answer (optionnel)
Pas de reponse texte ; coche au fur et a mesure. Pas de reponse texte ; coche au fur et a mesure.
- [ ] Version exacte d'OpenCode utilisee (`opencode --version`). - [x] Version exacte d'OpenCode utilisee (`opencode --version`) : `1.16.2`.
- [ ] Format reel des `parts` retournees par `POST /session/:id/message`. - [x] Format reel des `parts` retournees par `POST /session/:id/message` :
- [ ] Comportement OpenCode si `model` est passe vs absent. `text`, `reasoning`, `tool`, `step-start`, `step-finish` observes.
- [x] Comportement OpenCode si `model` est passe vs absent : absent fonctionne
avec le modele/session par defaut ; `noReply:true` cree sans LLM.
- [ ] Basic Auth vraiment necessaire dans la config de Guillaume. - [ ] Basic Auth vraiment necessaire dans la config de Guillaume.
- [ ] Timeout effectif `http.post` cote CC sur ATM10 (et si CC:Tweaked - [ ] Timeout effectif `http.post` cote CC sur ATM10 (et si CC:Tweaked
version supporte un parametre timeout). version supporte un parametre timeout).
- [ ] Reaction OpenCode si on hammer une session morte (404 ? autre ?). - [ ] Reaction OpenCode si on hammer une session morte (404 ? autre ?).
- [ ] Limite de longueur d'un message accepte par OpenCode. - [ ] Limite de longueur d'un message accepte par OpenCode.
- [ ] Cas ou le provider LLM est down : OpenCode renvoie quoi ? - [ ] Cas ou le provider LLM est down : OpenCode renvoie quoi ? Ne pas tester
via `/provider` en logs partages, cet endpoint peut exposer l'auth.
- [ ] CraftOS-PC headless peut-il faire `http.post` HTTPS vers le proxy en - [ ] CraftOS-PC headless peut-il faire `http.post` HTTPS vers le proxy en
local ? local ?