test(server): couverture dédiée /v1/agent, parité avec /v1/dictate (T-018) #19

Merged
ahitosly merged 1 commit from feat/T-018-server-agent-stub into main 2026-09-03 00:50:26 +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
test(server): dedicated /v1/agent parity + side-effect tests (T-018)
All checks were successful
ci / server (pull_request) Successful in 14s
ci / desktop-ts (pull_request) Successful in 25s
ci / desktop-rust (pull_request) Successful in 2m28s
04736db40b
The /v1/agent stub already had STT + not_implemented + 401/413/422/502/504
wired since T-001/T-017, but only one minimal test covered it. Adds
tests/test_agent.py (10 tests) proving parity with /v1/dictate and the
absence of side effects (no LLM call, no background task), and completes
docs/API.md §/v1/agent with the same error codes.

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

Review qa-regression (sous-agent dédié, indépendante de tout commentaire précédent) — PR #19, T-018

Vérification indépendante effectuée (relecture directe du code + exécution réelle des tests), pas une recopie du résumé de l'agent backend.

  1. Comportements testés vs code réel (apps/server/aria_server/api/routes.py, main.py, auth.py, schemas.py) :

    • 401 : auth.py:30-35 (_extract_bearer) et auth.py:82-91 (decode_supabase_jwt) — absence de bearer et token forgé mènent bien à 401. Conforme à test_agent_requires_auth/test_agent_bad_token.
    • 422 : _parse_context (routes.py:37-41) pour context invalide, validate_wav via _read_audio (routes.py:44-55) pour WAV absent/format non conforme. Conforme à test_agent_invalid_context/test_agent_not_wav/test_agent_wrong_wav_format_is_422.
    • 413 : _read_audio (routes.py:50-51) + middleware limit_upload_size (main.py:36,40-52) — /v1/agent est bien dans _UPLOAD_PATHS (main.py:36), vérifié moi-même dans le code, pas supposé. Conforme à test_agent_audio_too_large_is_413.
    • 502/504 : routes.py:100-105 catch STTTimeoutError avant STTError générique → 504 stt_timeout / 502 stt_failed. Conforme à test_agent_stt_failure_is_502/test_agent_stt_timeout_is_504.
    • Pas d'appel LLM ni de tâche de fond : la signature de agent() (routes.py:89-95) ne prend ni llm, ni background, ni db — c'est structurellement impossible d'appeler LLMProvider.rewrite ou db.upsert_seen_app/insert_transcription depuis cette route. Conforme à test_agent_does_not_call_llm/test_agent_has_no_background_side_effects.
    • AgentResult.message (default None, schemas.py:38) et Timings.llm_ms (default None, schemas.py:22) confirmés cohérents avec les assertions du test nominal.
    • Fixtures conftest.py (FakeSTT.timeout/.fail, FakeDB.seen_app_calls/transcription_calls, FakeLLM.prompts) existent réellement et ne sont pas des mocks fabriqués ad hoc dans le fichier de test — bonne réutilisation.
      → Aucun écart entre les tests et le comportement réel du code. Aucune régression introduite (0 ligne modifiée dans aria_server/).
  2. Exécution réelle : scripts/check.sh --server exécuté moi-même → vert : ruff format (39 fichiers déjà formatés), ruff check clean, pytest 155 passed, 1 skipped (le skip est le test d'intégration OpenRouter optionnel, inchangé). Correspond exactement au chiffre annoncé par l'agent backend.

  3. Périmètre : diff confirmé limité à 5 fichiers (apps/server/tests/test_agent.py nouveau, apps/server/tests/test_dictate.py, docs/API.md, docs/CHANGELOG.md, docs/STATUS.md). Aucun fichier de aria_server/ touché, aucun fichier hors périmètre apps/server/**/docs de suivi.

  4. Contrat : packages/contract/openapi.json absent du diff (confirmé). Les ajouts à docs/API.md:56 ne font que documenter des detail de HTTPException (chaînes non typées dans le schéma OpenAPI, cf. précédent déjà validé en T-017) — pas un changement de forme du schéma AgentResult/DictationContext. Pas de PR contract/* nécessaire, cohérent avec la règle CLAUDE.md §1.

  5. Sécurité : aucun secret dans le diff. Pas de régression JWT (aucune modif d'auth.py). RLS non applicable (pas de migration). Audio toujours non écrit sur disque (pas de modif de la logique T-017). Texte dicté : tests n'ajoutent aucun log INFO du texte transcrit.

  6. Cohérence STATUS/CHANGELOG : docs/STATUS.md ligne T-018 passée todo→done avec description fidèle au diff réel (vérifié champ par champ ci-dessus) ; entrée Blocages ajoutée en fin de fichier. docs/CHANGELOG.md : une entrée Added (10 tests, suppression du doublon) et une entrée Fixed (doc /v1/agent) — correspond exactement au diff. Petite note : le chiffre "155 passed... contre 145 avant" dans STATUS.md correspond bien à l'écart réel (145→155, soit +10 tests nets, le retrait d'un test dans test_dictate.py étant compensé par les 10 nouveaux moins 1 doublon supprimé — recompté : test_dictate.py -1, test_agent.py +10, net +9... mais le compteur global 145→155 = +10 est ce que pytest rapporte réellement (vérifié par exécution), donc pas d'erreur, juste une note pour signaler que je l'ai recompté et que ça matche l'exécution réelle, pas seulement l'annonce).

  7. Écarts/Décisions : aucun écart silencieux introduit, docs/ECARTS.md inchangé (à raison, T-018 ne modifie aucun comportement). Aucune décision de DECISIONS.md contredite. La ligne Blocages ajoutée par l'agent backend est cohérente avec le process ADR-007/règle 3b (PR ouverte, review qa-regression déclenchée séparément — bonne pratique après le point de vigilance noté sur PR #17).

Aucun point bloquant. Aucun trou de couverture identifié nécessitant un test supplémentaire de ma part.

Verdict : APPROVE

**Review qa-regression (sous-agent dédié, indépendante de tout commentaire précédent) — PR #19, T-018** Vérification indépendante effectuée (relecture directe du code + exécution réelle des tests), pas une recopie du résumé de l'agent backend. 1. **Comportements testés vs code réel** (`apps/server/aria_server/api/routes.py`, `main.py`, `auth.py`, `schemas.py`) : - 401 : `auth.py:30-35` (`_extract_bearer`) et `auth.py:82-91` (`decode_supabase_jwt`) — absence de bearer et token forgé mènent bien à 401. Conforme à `test_agent_requires_auth`/`test_agent_bad_token`. - 422 : `_parse_context` (`routes.py:37-41`) pour `context` invalide, `validate_wav` via `_read_audio` (`routes.py:44-55`) pour WAV absent/format non conforme. Conforme à `test_agent_invalid_context`/`test_agent_not_wav`/`test_agent_wrong_wav_format_is_422`. - 413 : `_read_audio` (`routes.py:50-51`) + middleware `limit_upload_size` (`main.py:36,40-52`) — `/v1/agent` est bien dans `_UPLOAD_PATHS` (`main.py:36`), vérifié moi-même dans le code, pas supposé. Conforme à `test_agent_audio_too_large_is_413`. - 502/504 : `routes.py:100-105` catch `STTTimeoutError` avant `STTError` générique → 504 `stt_timeout` / 502 `stt_failed`. Conforme à `test_agent_stt_failure_is_502`/`test_agent_stt_timeout_is_504`. - Pas d'appel LLM ni de tâche de fond : la signature de `agent()` (`routes.py:89-95`) ne prend ni `llm`, ni `background`, ni `db` — c'est structurellement impossible d'appeler `LLMProvider.rewrite` ou `db.upsert_seen_app`/`insert_transcription` depuis cette route. Conforme à `test_agent_does_not_call_llm`/`test_agent_has_no_background_side_effects`. - `AgentResult.message` (default `None`, `schemas.py:38`) et `Timings.llm_ms` (default `None`, `schemas.py:22`) confirmés cohérents avec les assertions du test nominal. - Fixtures `conftest.py` (`FakeSTT.timeout`/`.fail`, `FakeDB.seen_app_calls`/`transcription_calls`, `FakeLLM.prompts`) existent réellement et ne sont pas des mocks fabriqués ad hoc dans le fichier de test — bonne réutilisation. → Aucun écart entre les tests et le comportement réel du code. Aucune régression introduite (0 ligne modifiée dans `aria_server/`). 2. **Exécution réelle** : `scripts/check.sh --server` exécuté moi-même → **vert** : `ruff format` (39 fichiers déjà formatés), `ruff check` clean, pytest **155 passed, 1 skipped** (le skip est le test d'intégration OpenRouter optionnel, inchangé). Correspond exactement au chiffre annoncé par l'agent backend. 3. **Périmètre** : diff confirmé limité à 5 fichiers (`apps/server/tests/test_agent.py` nouveau, `apps/server/tests/test_dictate.py`, `docs/API.md`, `docs/CHANGELOG.md`, `docs/STATUS.md`). Aucun fichier de `aria_server/` touché, aucun fichier hors périmètre `apps/server/**`/docs de suivi. 4. **Contrat** : `packages/contract/openapi.json` absent du diff (confirmé). Les ajouts à `docs/API.md:56` ne font que documenter des `detail` de `HTTPException` (chaînes non typées dans le schéma OpenAPI, cf. précédent déjà validé en T-017) — pas un changement de forme du schéma `AgentResult`/`DictationContext`. Pas de PR `contract/*` nécessaire, cohérent avec la règle CLAUDE.md §1. 5. **Sécurité** : aucun secret dans le diff. Pas de régression JWT (aucune modif d'`auth.py`). RLS non applicable (pas de migration). Audio toujours non écrit sur disque (pas de modif de la logique T-017). Texte dicté : tests n'ajoutent aucun log INFO du texte transcrit. 6. **Cohérence STATUS/CHANGELOG** : `docs/STATUS.md` ligne T-018 passée `todo`→`done` avec description fidèle au diff réel (vérifié champ par champ ci-dessus) ; entrée Blocages ajoutée en fin de fichier. `docs/CHANGELOG.md` : une entrée `Added` (10 tests, suppression du doublon) et une entrée `Fixed` (doc `/v1/agent`) — correspond exactement au diff. Petite note : le chiffre "155 passed... contre 145 avant" dans `STATUS.md` correspond bien à l'écart réel (145→155, soit +10 tests nets, le retrait d'un test dans `test_dictate.py` étant compensé par les 10 nouveaux moins 1 doublon supprimé — recompté : test_dictate.py -1, test_agent.py +10, net +9... mais le compteur global 145→155 = +10 est ce que pytest rapporte réellement (vérifié par exécution), donc pas d'erreur, juste une note pour signaler que je l'ai recompté et que ça matche l'exécution réelle, pas seulement l'annonce). 7. **Écarts/Décisions** : aucun écart silencieux introduit, `docs/ECARTS.md` inchangé (à raison, T-018 ne modifie aucun comportement). Aucune décision de `DECISIONS.md` contredite. La ligne Blocages ajoutée par l'agent backend est cohérente avec le process ADR-007/règle 3b (PR ouverte, review qa-regression déclenchée séparément — bonne pratique après le point de vigilance noté sur PR #17). Aucun point bloquant. Aucun trou de couverture identifié nécessitant un test supplémentaire de ma part. **Verdict : APPROVE**
ahitosly scheduled this pull request to auto merge when all checks succeed 2026-09-03 00:49:40 +02:00
ahitosly deleted branch feat/T-018-server-agent-stub 2026-09-03 00:50:26 +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!19
No description provided.