contract(supabase): agent Hermes dédié par utilisateur — schéma + Edge Function (T-115, T-116) #105

Merged
ahitosly merged 5 commits from contract/T-115-hermes-agent-per-user into main 2026-09-06 16:36:01 +02:00
Owner

Tâche

T-xxx — (titre dans docs/STATUS.md)

Changements

Contrat modifié ?

  • Non
  • Oui : packages/contract / supabase/migrations — docs/API.md / docs/DATA.md mis à jour, label contract, approbation humaine requise

Tests

  • scripts/check.sh vert
  • Test manuel (OS, scénario) :

Impacts cross-domaine

Fichiers hors périmètre de l'agent (et pourquoi) :

Suivi

  • docs/STATUS.md mis à jour (ligne de la tâche)
  • docs/CHANGELOG.md : entrée ajoutée sous Unreleased
  • docs/DECISIONS.md / docs/ECARTS.md mis à jour si décision ou écart
## Tâche T-xxx — (titre dans docs/STATUS.md) ## Changements - ## Contrat modifié ? - [ ] Non - [ ] Oui : `packages/contract` / `supabase/migrations` — `docs/API.md` / `docs/DATA.md` mis à jour, label `contract`, approbation humaine requise ## Tests - [ ] `scripts/check.sh` vert - [ ] Test manuel (OS, scénario) : ## Impacts cross-domaine Fichiers hors périmètre de l'agent (et pourquoi) : ## Suivi - [ ] `docs/STATUS.md` mis à jour (ligne de la tâche) - [ ] `docs/CHANGELOG.md` : entrée ajoutée sous Unreleased - [ ] `docs/DECISIONS.md` / `docs/ECARTS.md` mis à jour si décision ou écart
Ouvre le jalon M8 (ADR-015) : chaque utilisateur a son propre agent Hermes, créé sur
l'opérateur hermes-swarm par une Edge Function Supabase au login, au lieu du Hermes
unique et partagé de `ubuntu-01` (PoC personnel, jamais une cible).

- ADR-015 : Edge Function seule détentrice de `OPERATOR_API_KEY` (l'opérateur est
  root-equivalent sur son hôte Swarm, le serveur Aria est exposé publiquement) ;
  garantie « un agent, le sien, un seul » structurelle (nom dérivé du `sub` du JWT,
  `user_id` en PK, arbitrage de course en SQL) ; secrets et champs visibles séparés
  par deux tables reliées par un trigger de projection ; pool de clés LLM alloué par
  RPC en `for update skip locked` ; bascule `creating -> ready` par sonde `/health`.
- Migration : `aria_hermes_agents` (interne, deny-all), `aria_hermes_agent_access`
  (projection, select own), `aria_hermes_llm_keys` (pool, invisible), 2 triggers,
  2 fonctions `security definer`. Vérifiée sur un Postgres 16 jetable : applique,
  idempotente, 11 comportements testés, 4 tests négatifs de privilèges verts.
- Edge Function `provision-hermes-agent` : sans dépendance externe (`fetch` brut),
  réparation automatique sur 409 grâce au nom déterministe, ne renvoie jamais
  l'`api_url`/`api_key` de l'agent au client.
- STATUS : M8 ouvert, T-115 -> T-120. T-117 (serveur), T-118/T-119 (desktop) et
  T-120 (déploiement) restent à faire.

Impacts cross-domaine : `docs/API.md` annonce la valeur `not_ready` d'`AgentResult`
livrée par T-117 (backend) ; `.env.example` documente `HERMES_URL` comme fallback de
développement à retirer par T-120.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LDKJe4fgpa3cZyXFfmrxW7
chore(supabase): dry-run réel de la migration T-115 contre l'instance partagée ; T-116 bloquée sur l'accès infra
All checks were successful
ci / server (pull_request) Successful in 14s
ci / desktop-ts (pull_request) Successful in 27s
ci / desktop-rust (pull_request) Successful in 3m17s
9fa24df1ab
Migration appliquée dans une transaction annulée (ROLLBACK explicite, rien
persisté) : grants conformes à ce que documente le fichier. Contrat régénéré
(scripts/gen-contract.sh) — pas de table aria_hermes_* tant que la migration
n'est pas appliquée pour de vrai, mais rattrape le drift aria_agent_sessions
(non régénéré depuis T-005/T-103). T-116 : déploiement de l'Edge Function
tenté, bloqué faute d'accès SSH/Docker à srv-supabase.cloud-rennais.local
depuis cette session — détail et action humaine requise documentés.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015yEJwho9a66ZhLao91PtaG
Author
Owner

Vérification post-déploiement (2026-09-06, orchestrator) : la fonction provision-hermes-agent est bien déployée et exécute son propre code (GET/OPTIONS → 405 method_not_allowed, plus jamais InvalidWorkerCreation).

Problème trouvé : POST sans JWT (ou avec un JWT bidon, ou sans body) renvoie systématiquement 500 {"error":"function_not_configured"} au lieu du 401 attendu — ce garde-fou (index.ts) précède la vérification du JWT et se déclenche si SUPABASE_URL/SUPABASE_SERVICE_ROLE_KEY/HERMES_OPERATOR_URL/HERMES_OPERATOR_API_KEY est vide côté conteneur functions. Le rejet 401 attendu n'a donc pas pu être vérifié.

Vérifié à part : l'opérateur hermes-swarm est joignable et sain (/healthz → {"status":"ok"}). Aucun JWT utilisateur réel disponible dans cette session pour tester le chemin nominal.

PR non mergée (migration T-115 toujours en attente d'approbation humaine, règle 3b). Détail complet dans docs/STATUS.md (ligne T-116 et « Vérifications manuelles en attente »).

Vérification post-déploiement (2026-09-06, orchestrator) : la fonction `provision-hermes-agent` est bien déployée et exécute son propre code (`GET`/`OPTIONS` → `405 method_not_allowed`, plus jamais `InvalidWorkerCreation`). Problème trouvé : `POST` sans JWT (ou avec un JWT bidon, ou sans body) renvoie systématiquement `500 {"error":"function_not_configured"}` au lieu du `401` attendu — ce garde-fou (`index.ts`) précède la vérification du JWT et se déclenche si `SUPABASE_URL`/`SUPABASE_SERVICE_ROLE_KEY`/`HERMES_OPERATOR_URL`/`HERMES_OPERATOR_API_KEY` est vide côté conteneur `functions`. Le rejet 401 attendu n'a donc pas pu être vérifié. Vérifié à part : l'opérateur hermes-swarm est joignable et sain (`/healthz` → `{"status":"ok"}`). Aucun JWT utilisateur réel disponible dans cette session pour tester le chemin nominal. PR non mergée (migration T-115 toujours en attente d'approbation humaine, règle 3b). Détail complet dans `docs/STATUS.md` (ligne T-116 et « Vérifications manuelles en attente »).
chore(docs): vérifie le déploiement de provision-hermes-agent — 500 function_not_configured (T-116)
All checks were successful
ci / server (pull_request) Successful in 13s
ci / desktop-ts (pull_request) Successful in 27s
ci / desktop-rust (pull_request) Successful in 2m37s
d4f34dad24
L'humain a déployé l'Edge Function avec HERMES_OPERATOR_URL/HERMES_OPERATOR_API_KEY sur
srv-supabase.cloud-rennais.local. Vérifié : la fonction exécute son propre code (405 sur
GET/OPTIONS, plus jamais InvalidWorkerCreation), mais POST sans JWT/avec JWT invalide/sans
body renvoie systématiquement 500 function_not_configured, un garde-fou qui précède la
vérification du JWT dans index.ts — le rejet 401 attendu n'a donc pas pu être vérifié.
Aucun JWT utilisateur réel disponible dans cette session pour tester le chemin nominal.
PR #105/#106 non mergées (migration T-115 toujours non appliquée, règle 3b).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015yEJwho9a66ZhLao91PtaG
chore(docs): retest provision-hermes-agent — 401 confirmé après --force-recreate (T-116)
All checks were successful
ci / server (pull_request) Successful in 14s
ci / desktop-ts (pull_request) Successful in 27s
ci / desktop-rust (pull_request) Successful in 2m40s
c933acfad3
Le 500 function_not_configured précédent était dû à un `restart` du
conteneur functions qui ne rechargeait pas les variables d'environnement
(les 4 étaient déjà présentes). Après `docker compose up -d --force-recreate`
fait par l'humain, POST sans JWT / JWT bidon / body vide renvoie désormais
401 {"error":"unauthorized"} de façon stable — garde-fou de config et
vérification JWT confirmés atteints. Reste un test avec un vrai JWT
utilisateur (login réel, hors périmètre agent) pour valider le provisioning
de bout en bout. PR #105 toujours non mergée (migration T-115, règle 3b).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015yEJwho9a66ZhLao91PtaG
supabase(T-115): applique la migration aria_hermes_agents pour de vrai
All checks were successful
ci / server (pull_request) Successful in 14s
ci / desktop-ts (pull_request) Successful in 27s
ci / desktop-rust (pull_request) Successful in 2m41s
0862d5ae91
Migration appliquée contre l'instance partagée après autorisation humaine
explicite (docs/STATUS.md -> Décisions récentes, 2026-09-06). Grants/RLS
revérifiés en base réelle (pas seulement en dry-run) : conformes.
supabase.types.ts régénéré (E-008 toujours respecté, uniquement aria_*).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015yEJwho9a66ZhLao91PtaG
ahitosly scheduled this pull request to auto merge when all checks succeed 2026-09-06 16:35:19 +02:00
ahitosly deleted branch contract/T-115-hermes-agent-per-user 2026-09-06 16:36:02 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
cloud-rennais/aria!105
No description provided.