Aller au contenu

Audit complet du dépôt atlas — 2026-05-29

Date de l’audit : 2026-05-29. Méthode : workflow multi-agents (22 dimensions auditées en parallèle, findings Critical/High vérifiés de manière adversariale par 3 prismes — exactitude, preuve, sévérité — kill si majorité réfute).

  • monorepo : dépôt unique regroupant plusieurs paquets logiciels distincts (apps, libs, services) au lieu d’un dépôt par projet.
  • ADR (Architecture Decision Record) : note courte qui acte une décision d’architecture, son contexte et ses conséquences (format Nygard).
  • workspace : sous-paquet (dossier avec son propre package.json) géré par le gestionnaire de paquets du monorepo (ici pnpm).
  • CLI (Command Line Interface) : programme à exécuter en ligne de commande, livré avec un bin.
  • lib (library) : code réutilisable importé par un autre paquet, sans bin.
  • BaaS (Backend-as-a-Service) : service tiers qui fournit base de données, auth et stockage prêts à l’emploi (ici Appwrite).
  • REDCap : logiciel généraliste de saisie de données structurées via formulaires en ligne (recherche, enquêtes, administration), exposant une API REST.
  • OpenAPI : standard de description d’API HTTP (anciennement Swagger), sert à documenter et valider les contrats.
  • SvelteKit : framework web basé sur Svelte qui gère pages, endpoints et hooks serveur.
  • runes : nouveau système de réactivité de Svelte 5 ($state, $derived, $effect).
  • vitest : framework de tests unitaires/intégration équivalent à Jest, basé sur Vite.
  • Playwright : framework de tests end-to-end (E2E) pilotant un vrai navigateur.
  • MSW (Mock Service Worker) : bibliothèque pour intercepter les appels HTTP au niveau réseau dans les tests.
  • rate limit : limitation du nombre de requêtes autorisées par adresse IP ou utilisateur sur une fenêtre de temps.
  • XSS (Cross-Site Scripting) : injection de code JavaScript via un paramètre utilisateur qui se retrouve réfléchi côté navigateur.
  • CSP (Content Security Policy) : en-tête HTTP qui restreint les sources autorisées de scripts, images, etc.
  • CORS (Cross-Origin Resource Sharing) : règles décidant quels domaines peuvent appeler une API depuis un navigateur.
  • gitleaks : scanner de secrets (clés API, mots de passe) dans l’historique git.
  • CodeQL : moteur d’analyse statique de sécurité (SAST) de GitHub.
  • knip : outil qui détecte le code mort (exports, deps, fichiers) inutilisés dans un projet TypeScript.
  • lefthook : gestionnaire de git hooks (pre-commit, pre-push, etc.).
  • Changesets : outil de gestion de versions et changelogs pour monorepos.
  • Hono : micro-framework HTTP TypeScript utilisé ici pour services/crf.
  • Effect : bibliothèque TypeScript de programmation fonctionnelle (gestion d’erreurs typées, effets explicites).
  • brand (branded type) : technique TS pour distinguer au type-check deux chaînes/nombres sémantiquement différents (ex : RecordId vs string).
  • property-based testing : tests qui génèrent automatiquement des entrées aléatoires pour vérifier des invariants (ici via fast-check).
  • smoke test : test minimal qui vérifie que le chemin nominal d’un système marche de bout en bout.
  • scaffold : squelette de paquet sans contenu fonctionnel, posé comme amorce.
  • flat config : nouveau format de configuration d’ESLint (un seul fichier JavaScript exportant un tableau).
  • Nombre total de findings retenus dans le corps du rapport : 51 (après rejets adversariaux), répartis comme suit :

    • High : 8
    • Medium : 27
    • Low : 14
    • Info : 2
    • 13 findings supplémentaires (dont 1 Critical et 12 High) ont été rejetés par la vérification 3-prismes — listés en annexe A.
  • Top 5 priorités à traiter en premier :

    1. [thresholds-zero-bypass-ci] — 10 paquets ont des seuils de couverture vitest à 0, la CI ne détecte aucune régression sur ces paquets.
    2. [coverage-report-not-enforced] — le rapport global de couverture existe mais n’est branché ni en CI ni en pre-push : son process.exitCode = 1 est inerte.
    3. [zero-files-silently-excluded] — l’agrégation de coverage exclut silencieusement les fichiers à 0%, produisant des « 100% » trompeurs sur 84 fichiers (dont 9 dans services/crf).
    4. [services-crf-real-coverage-low] — le seul microservice du dépôt (ingestion REDCap) déclare un seuil 17/14/24/18 et est le plus exposé.
    5. [no-e2e-in-ci] — aucune suite Playwright E2E n’est exécutée en CI ; les deux smokes existants ne valident le scénario complet qu’à la main.
  • Forces principales du dépôt :

    • Architecture monorepo 8-catégories cohérente, audit-ée par script et documentée par 19 ADR.
    • Hooks lefthook stricts et non bypassables (ADR 0015), couvrant format, lint, typecheck, audits de sécurité.
    • Noyau métier (validators, errors, citation-types, auth, crf-core, crf-client…) à 90-100% de couverture statements/branches.
    • Config partagée riche : flat configs ESLint par catégorie, presets Svelte/TS, vitest commun, prettier base.
    • Outillage de contract testing REDCap réel (fixtures versionnées, 1700+ lignes) et docker-compose sandbox propre.
  • Score d’ensemble par groupe de dimensions (sur 5 ; reflète l’écart entre intention documentée et enforcement réel) :

    • A-E — Architecture & qualité de code : 3,5 / 5 (structure solide mais quelques ADR non enforced)
    • F-H — Documentation : 3 / 5 (présente mais inégale)
    • I-K — Reproductibilité & gouvernance : 4 / 5 (hooks stricts, ADR vivants)
    • L-O — Dépendances & types : 3,5 / 5 (typage strict mais quelques angles morts)
    • P-T — Qualité opérationnelle (tests, sécurité, observabilité) : 2,5 / 5 (pyramide de tests aplatie, observabilité partielle)
    • U-V — Data & cohérence inter-apps : 3 / 5

L’audit a été conduit par un workflow d’agents multiples lancés en parallèle sur 22 dimensions distinctes du dépôt (architecture, tests, sécurité, documentation, dépendances, observabilité, etc.). Chaque agent a produit un rapport structuré (résumé, forces, findings) en s’appuyant uniquement sur les fichiers du dépôt.

Chaque finding est qualifié par trois axes : sévérité (Critical, High, Medium, Low, Info), confiance (High, Medium, Low) et effort estimé pour la correction (XS, S, M, L, XL).

Les findings de sévérité Critical et High ont fait l’objet d’une vérification adversariale : trois agents indépendants ont examiné chacun le finding sous un angle différent — exactitude factuelle, qualité de la preuve, justesse de la sévérité. Le finding est rejeté (« kill ») si au moins deux des trois agents le réfutent. Les findings rejetés sont listés en annexe A pour traçabilité.

Le rapport ci-dessous restitue le résultat de cette consolidation : seuls les findings non réfutés apparaissent dans le corps ; chaque finding High vérifié est détaillé individuellement, les Medium/Low/Info sont synthétisés en tableau.

Résumé. La structure 8-catégories est cohérente, audit-ée et bien documentée (ADR 0002/0019). Les principales fragilités tiennent à des écarts entre règles documentées dans les ADR et règles réellement vérifiées par scripts/audit/workspace-structure.mjs, et à quelques placements de paquets qui contredisent leur catégorie (notamment cli/crf-openapi exposant une lib, packages/citation-validate jouant le rôle d’un CLI, sandbox/crf-sandbox-core scaffold vide).

Forces observées.

  • L’ADR 0002 décrit les 8 catégories avec règles claires et l’ADR 0019 isole nominativement chaque dérogation, ce qui rend les écarts visibles et révisables.
  • scripts/audit/workspace-structure.mjs couvre concrètement présence de bin, dépendances interdites, imports runtime, isolation sandbox, cycles inter-workspaces, repository.directory cohérent.
  • Distinction fine import type vs runtime via RUNTIME_IMPORT_RE / ANY_IMPORT_RE : packages/auth peut importer type Cookies de @sveltejs/kit sans contredire la règle.
  • Le pnpm-workspace.yaml liste explicitement les 8 globs, alignés avec ROOTS du script d’audit.
  • La règle « sandbox isolé » est doublement enforcée (check explicite que nul autre root ne dépend d’un nom dans sandboxNames).

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
1ADR 0008 promet une enforcement audit:structure qui n’existe pasMediumHighSdocs/decisions/0008-clis-thins-logique-dans-packages.md:30
2ADR 0011 affirme un check private:true non implémentéMediumHighXSdocs/decisions/0011-paquets-internes-private.md:47
3ADR 0011 décrit une réalité périmée (tous les apps sont private)MediumHighXSdocs/decisions/0011-paquets-internes-private.md:51
4cli/crf-openapi expose une bibliothèque déguisée en CLIMediumHighMcli/crf-openapi/package.json:17
5packages/citation-validate se décrit comme « CLI tools »MediumHighMpackages/citation-validate/package.json
6sandbox/crf-sandbox-core est un scaffold vide consommé par personneLowHighSsandbox/crf-sandbox-core/README.md:5
7Préfixe atlas- du nom de dossier appliqué sans règle uniformeLowHighSpackages/atlas-stats, cli/atlas-stats
8apps→apps / services→services : interdiction sur deps uniquement, pas sur imports sourceLowHighMscripts/audit/workspace-structure.mjs:416
9L’audit scanne .svelte mais pas les .svelte.ts ni les imports dynamiquesLowMediumSscripts/audit/workspace-structure.mjs:86
10Pas d’ADR explicite sur les dépendances qu’un sandbox peut tirer du dépôtLowMediumSdocs/architecture/monorepo.md:137
11config/ : le script interdit bin mais n’impose pas d’exportsInfoHighXSscripts/audit/workspace-structure.mjs:331
12packages/atlas-stats et cli/atlas-stats partagent le même nom de dossierInfoHighXSpackages/atlas-stats/package.json

Résumé. Outillage homogène (vitest + coverageConfig partagée, seuils par paquet, rapport agrégé), avec un noyau de packages métier entre 96 et 100% statements. Mais l’enforcement est largement contournable : dix paquets ont des seuils à 0, le rapport agrégé n’est jamais exécuté en CI, et la mesure exclut silencieusement les fichiers totalement non couverts, ce qui produit des « 100% » trompeurs sur services/crf (9 fichiers ignorés), atlas-dashboard (4), sillage (1), crf-cli (2).

Forces observées.

  • Outillage homogène : coverageConfig partagée dans config/shared-config/vitest (provider v8, reporters, excludes).
  • Noyau métier solidement testé : validators, errors, citation-types, fetch-one-api-page, baas, citation-fetch, atlas-stats/compute, crf-logs, crf-core (98.4%), crf-client (96.5%), researcher-profiles (98.9%), citation (98.1%), auth (96.7%) tous au-dessus de 90%.
  • Le rapport agrégé coverage-report.mjs est bien fait (distinction « sans vitest » / « avec vitest sans coverage » / « fichiers à 0% exclus », exitCode=1 si paquet < target).
  • Pyramide de tests amarre/sillage documentée (projets unit / ui / integration dans vitest.config).
  • Dynamique active de remontée de couverture (PR #214 cli/crf 10.5→64.6%, PR #216 cli/net 0→50.5%).

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
13Dix paquets ont des seuils vitest à 0HighHighS✓ 3/3cli/biblio/vitest.config.ts:8 + 9 autres
14Le rapport global de couverture n’est jamais exécuté en CIHighHighXS✓ 2/3package.json:29
15Les fichiers à 0% sont silencieusement exclus du dénominateurHighHighS✓ 2/3scripts/audit/coverage-report.mjs:57
16services/crf affiche « 100% » mais seuil déclaré 17/14/24/18HighHighM✓ 3/3services/crf/vitest.config.ts:8
17apps/ecrin seuils très bas (28/18/27/28)MediumHighMapps/ecrin/vitest.config.ts:14
18apps/amarre seuils 25 pts sous la couverture réelleMediumHighSapps/amarre/vitest.config.ts:35
19apps/find-an-expert ne mesure que src/lib/**/*.tsMediumHighMapps/find-an-expert/vite.config.ts:24
204 CLI publiés sans aucun fichier de testMediumHighLcli/biblio, cli/citation, cli/atlas-stats, cli/crf-stats
21ui/atlas-ui : 22 composants Svelte partagés, 0 testMediumHighLui/atlas-ui/package.json:34
22packages/atlas-stats : coverage limité à src/compute.tsMediumHighSpackages/atlas-stats/vitest.config.ts:7
23sandbox/crf-sandbox : tests de contrat exclus par défaut, seuils à 0LowHighSsandbox/crf-sandbox/vitest.config.ts:7
24assets/logos : « test » cosmétique qui vérifie 6 fichiers existentLowHighXSassets/logos/assets.test.ts:19

High — Dix paquets ont des seuils vitest à 0, la CI ne peut détecter aucune régression [thresholds-zero-bypass-ci]

Section intitulée « High — Dix paquets ont des seuils vitest à 0, la CI ne peut détecter aucune régression [thresholds-zero-bypass-ci] »

High — Le rapport global de couverture n’est jamais exécuté en CI ni en pre-push [coverage-report-not-enforced]

Section intitulée « High — Le rapport global de couverture n’est jamais exécuté en CI ni en pre-push [coverage-report-not-enforced] »
  • Locations : package.json:29, .github/workflows/ci.yml:117, lefthook.yml
  • Observation : Le script coverage-report.mjs est écrit pour faire process.exitCode = 1 quand un paquet est sous le target (défaut 80) ou n’a pas de coverage-final.json, mais il n’est jamais appelé : ni ci:checks, ni ci.yml test job, ni lefthook pre-push ne l’invoquent. Le travail est en place et inutilisé.
  • Recommandation : Ajouter pnpm coverage:report 80 après pnpm test:coverage dans le job test de ci.yml et dans la commande pre-push lefthook.
  • Effort : XS
  • Vérification : ✓ 2/3 confirmé.

High — Le rapport exclut silencieusement les fichiers à 0% du dénominateur [zero-files-silently-excluded]

Section intitulée « High — Le rapport exclut silencieusement les fichiers à 0% du dénominateur [zero-files-silently-excluded] »
  • Locations : scripts/audit/coverage-report.mjs:57
  • Observation : L’exécution actuelle montre services/crf 100% / 9 skipped, apps/atlas-dashboard 100% / 4, apps/crf-dashboard 100% / 5, apps/sillage 94-100% / 1, cli/crf-cli 90% / 2, cli/researcher-profiles-cli 100% / 10, etc. — total 84 fichiers « skipped » dont aucune ligne n’est couverte. Un paquet peut afficher 100% tout en n’ayant aucun test sur la majorité du code. Le 100% de services/crf est particulièrement trompeur (le vitest.config.ts y déclare déjà statements: 17).
  • Recommandation : Soit compter les zero-files dans le dénominateur (option --strict), soit publier la liste détaillée des fichiers exclus avec leur taille, et ajouter une règle qui échoue si > N fichiers d’un paquet sont skipped.
  • Effort : S
  • Vérification : ✓ 2/3 confirmé.

High — services/crf affiche 100% mais le seuil déclaré est 17/14/24/18 [services-crf-real-coverage-low]

Section intitulée « High — services/crf affiche 100% mais le seuil déclaré est 17/14/24/18 [services-crf-real-coverage-low] »
  • Locations : services/crf/vitest.config.ts:8, services/crf/src
  • Observation : Le seul service du monorepo (microservice Hono REDCap) déclare des seuils très bas (17/14/24/18) et n’a que 2 fichiers de tests (effect-handler.test.ts, server.test.ts). Le rapport remonte « 100% » trompeur. C’est le composant le plus exposé en ingestion REDCap.
  • Recommandation : Reprendre la couverture du service : tester les autres handlers et la configuration. Aligner les seuils vers > 80% ou documenter la raison dans ADR 0019.
  • Effort : M
  • Vérification : ✓ 3/3 confirmé.

Résumé. Le dépôt expose une pyramide bien intentionnée (unit / ui / integration / smoke E2E) avec ~177 fichiers de tests. Mais la pyramide est en réalité aplatie : il n’existe que deux suites Playwright (amarre, sillage) jamais exécutées en CI, et la majorité des endpoints SvelteKit n’ont aucun test direct.

Forces observées.

  • Pyramide explicitement nommée et structurée dans vitest.config.ts d’apps/amarre et apps/sillage (projets unit / ui / integration, environnements distincts node/happy-dom).
  • Vraie suite de contract testing REDCap (sandbox/crf-sandbox/tests/contract/api-contract.test.ts, 1700+ lignes) avec fixtures versionnées (projects.json).
  • Vraie suite d’intégration apps/amarre/tests/integration/ qui sollicite Appwrite + Mailpit + REDCap via docker-compose et skipIf(!reachable) propre.
  • Smoke E2E Playwright sandbox/amarre-sandbox/tests/e2e/smoke.spec.ts couvrant signup→magic-link→logout avec auto-cleanup.
  • Tests anti-XSS et 401 documentés sur certains endpoints (Phase 7.2 explicite).

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
25Aucune suite Playwright E2E ne tourne en CIHighHighM✓ 2/3.github/workflows/ci.yml, sandbox/amarre-sandbox/tests/e2e/smoke.spec.ts:35
26Couverture des endpoints SvelteKit très inégale entre appsHighHighM✓ 2/3apps/ecrin/src/routes/api/v1/, apps/find-an-expert/src/routes/api/v1/, apps/amarre/src/routes/api/v1/
27Tests « wrapper-only » sur-mockés (sillage services-auth, baas)MediumHighXSapps/sillage/tests/integration/services-auth.test.ts:13
28Pas de mock HTTP au niveau réseau (MSW absent), tout mocké en fonctionMediumHighMpackages/citation/src/fetch/fetch-citation.test.ts:5
29Tests anti-XSS présents seulement sur un endpointMediumHighSapps/find-an-expert/src/routes/api/v1/institutions/search/server.test.ts:67
30Tests anti-dérive OpenAPI limités à amarreMediumHighMapps/amarre/tests/routes/api/v1/surveys/list.test.ts:11
317 CLI sur 9 ont un seuil coverage à 0MediumHighScli/biblio/vitest.config.ts:1
32Rate limit en mémoire partagé entre tests sans cleanup unifiéLowMediumXSpackages/auth/src/handlers.test.ts:242
33Absence de property-based testing sur validators / brandsLowHighSpackages/validators/src/index.test.ts, packages/crf-core/src/brands/
34config/shared-config/vitest.config.ts pointe vers un dossier inexistantLowMediumXSconfig/shared-config/vitest.config.ts:5
35Smoke E2E sans isolation d’état Bootstrap entre testsLowMediumSsandbox/amarre-sandbox/tests/e2e/smoke.spec.ts:66

High — Aucune suite Playwright E2E ne tourne en CI [no-e2e-in-ci]

Section intitulée « High — Aucune suite Playwright E2E ne tourne en CI [no-e2e-in-ci] »
  • Locations : .github/workflows/ci.yml, sandbox/amarre-sandbox/tests/e2e/smoke.spec.ts:35, sandbox/sillage-sandbox/playwright.config.ts
  • Observation : Les deux seuls smoke E2E (amarre-sandbox, sillage-sandbox) sont rédigés correctement mais ne sont déclenchés par aucun workflow GitHub Actions. Le scénario complet signup→magic-link→survey→logout n’est validé qu’à la main par le développeur qui sait monter la stack docker. Toute régression sur l’orchestration (cookie, redirection, modal Bootstrap) ne sera détectée qu’en aval.
  • Recommandation : Ajouter un job CI nightly (ou matrix sur PR concernant apps/amarre|sillage) qui démarre la docker-compose sandbox via pnpm -F @univ-lehavre/atlas-amarre-sandbox start, attend la disponibilité (Mailpit + Appwrite + REDCap) puis exécute pnpm test:smoke. Conserver test.skip pour les runs locaux sans docker.
  • Effort : M
  • Vérification : ✓ 2/3 confirmé.

High — Couverture des endpoints SvelteKit très inégale entre apps [endpoint-coverage-uneven]

Section intitulée « High — Couverture des endpoints SvelteKit très inégale entre apps [endpoint-coverage-uneven] »
  • Locations : apps/ecrin/src/routes/api/v1/, apps/find-an-expert/src/routes/api/v1/, apps/amarre/src/routes/api/v1/
  • Observation : Comptages observés : ecrin 14 endpoints / 4 tests, find-an-expert 17 / 3, amarre 9 / 5. Les endpoints sensibles non testés incluent surveys/url, account/push, repositories/[id]/contributors, /pulls, /issues, /analysis. La promesse de la Phase 7.2 reste à étendre aux endpoints métier.
  • Recommandation : Établir un inventaire +server.ts → test associé dans chaque app, puis fixer un seuil minimal (chaque endpoint a au moins un test 401 + un test 200 + un test payload malformé). Faire émerger un helper partagé createRouteEvent({ locals, body, ip }).
  • Effort : M
  • Vérification : ✓ 2/3 confirmé.

Résumé. Le socle (flat configs partagés, presets par catégorie, lefthook strict, ESLint security/unicorn/functional/typescript-strict) est riche et bien pensé. Mais l’usage réel est en décalage : aucun preset Svelte strict en apps, des paquets sandbox sans script lint, des warnings ESLint jamais bloquants, et un répertoire src exclusif qui laisse scripts/tests/fixtures hors format:check.

Forces observées.

  • Architecture du config partagé claire et factorisée : config/shared-config/eslint/ expose 4 presets (typescript/svelte/svelteRelaxed/scripts) avec architectureCategory enforcement.
  • Hooks lefthook complets et non bypassables (ADR 0015).
  • Durcissement sécurité Svelte explicitement listé et commenté dans config/shared-config/eslint/svelte.js pour compenser la non-couverture .svelte par CodeQL.
  • Règles strictes activées pour les libs TS : strict-boolean-expressions, no-floating-promises, consistent-type-imports, switch-exhaustiveness-check.
  • Le script scripts/lint-staged.mjs groupe les fichiers stagés par package root pour préserver tsconfigRootDir.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
36Le preset Svelte strict (Phase 1.1 DevSecOps) n’est utilisé par aucune appHighHighS✓ 2/3config/shared-config/eslint/svelte.js:226, apps/amarre/eslint.config.js:1
37format:check restreint à src laisse tests, scripts et configs hors contrôleMediumHighSpackages/auth/package.json, packages/atlas-stats/package.json
383 sandboxes sur 4 n’ont aucun script lint malgré du code TypeScriptMediumHighSsandbox/amarre-sandbox/package.json, sandbox/sillage-sandbox/package.json, sandbox/crf-sandbox-core/package.json
39Aucun --max-warnings 0 : règles warn silencieuses en CIMediumHighXSconfig/shared-config/eslint/base.js:113
40eslint-comments/require-description désactivé : disables sans justificationMediumHighXSconfig/shared-config/eslint/base.js:9

High — Le preset Svelte strict n’est utilisé par aucune app [svelte-strict-preset-unused]

Section intitulée « High — Le preset Svelte strict n’est utilisé par aucune app [svelte-strict-preset-unused] »

Résumé. Les builds des paquets publiables reposent sur tsc ou svelte-package, déclenchés via turborepo. Les pipelines sont fonctionnels mais quelques paquets n’exposent pas de script build cohérent, et le cache turbo n’inclut pas tous les inputs pertinents.

Forces observées.

  • Turbo configure les dépendances de tâche (build^, test^, lint) de manière cohérente.
  • Les paquets publiables exposent exports, files, types selon les bonnes pratiques.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
41Inputs turbo.json n’incluent pas tous les configs (vitest, eslint)LowMediumSturbo.json

Résumé. Les commentaires JSDoc sont présents mais inégaux. Les README de paquets publics ont des longueurs variables ; le finding « squelettes » a été rejeté par vérification (cf annexe A).

Forces observées.

  • Certains paquets exposent une vraie doc inline (auth, validators, crf-core).
  • ADR vivants et systématiquement référencés dans le code.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
42Commentaires TODO sans owner ni dateLowMediumSsources multiples

Résumé. Le site VitePress est en place, structuré et publié. Quelques pages restent à étoffer mais le runbook incident-response (initialement signalé comme vide pour les contacts admins) a été rejeté en vérification.

Forces observées.

  • Navigation cohérente, ADR indexés.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
43Quelques pages « TBD » dans le menuLowMediumSdocs/

Résumé. Le README racine et les CLAUDE.md sont à jour. Les prérequis système exhaustifs et la remédiation knip ont été rejetés en vérification (cf annexe A).

Forces observées.

  • README racine pointe clairement vers la doc VitePress.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
44Quickstart contributeur dispersé entre README et docs/LowMediumSREADME.md

I. Reproductibilité (lockfile, versions Node, Docker)

Section intitulée « I. Reproductibilité (lockfile, versions Node, Docker) »

Résumé. pnpm-lock.yaml versionné, .nvmrc présent, Dockerfiles reproductibles, sandboxes utilisent docker-compose figés.

Forces observées.

  • ADR 0004 sur volumes anonymes sillage-sandbox documenté.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
45Pas de pin SHA pour les actions GitHubLowMediumS.github/workflows/

J. Gouvernance et processus (ADR, Changesets, conventional commits)

Section intitulée « J. Gouvernance et processus (ADR, Changesets, conventional commits) »

Résumé. 19 ADR vivants, Changesets configuré, commit lints actifs via lefthook.

Forces observées.

  • ADR systématiquement référencé dans le code et les hooks d’audit.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
46Quelques ADR décrivent un état historique périmé (cf finding 3)MediumHighXSdocs/decisions/0011-paquets-internes-private.md

Résumé. Lefthook strict (ADR 0015), workflows GitHub Actions structurés. Mais le rapport coverage n’est pas branché (finding 14), aucun job E2E (finding 25).

Forces observées.

  • Hooks non bypassables, audits security/licenses/lockfile/test/cpd/knip en pre-push.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
47Caching CI Node/pnpm non optimiséLowMediumS.github/workflows/ci.yml

Résumé. Licences validées en pre-push, deps régulièrement mises à jour. Quelques dérogations documentées (ADR 0019).

Forces observées.

  • pnpm audit et license-checker actifs.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
48Quelques deps en ^ larges sur paquets publiablesLowMediumSsources multiples

Résumé. TypeScript strict activé, runes Svelte 5 utilisées. Le finding sur exactOptionalPropertyTypes / noUncheckedIndexedAccess a été rejeté en vérification.

Forces observées.

  • Migration Svelte 5 effective dans toutes les apps.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
49Quelques any résiduels dans paquets historiquesLowMediumSsources multiples

Résumé. ui/atlas-ui partage 22 composants Svelte mais sans tests (cf finding 21).

Forces observées.

  • Storybook en place pour preview.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
50Theming dispersé entre apps consommatricesLowMediumMui/atlas-ui

O. Architecture backend (services, handlers, Effect)

Section intitulée « O. Architecture backend (services, handlers, Effect) »

Résumé. services/crf (Hono + Effect) bien structuré mais sous-couvert en tests (cf finding 16).

Forces observées.

  • Pattern Effect-handler factorisé et réutilisé.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
51Pas de standardisation handler→app entre amarre/ecrin/find-an-expertMediumMediumMsources multiples

Résumé. Rate-limit, validation Zod, anti-XSS partiel. Le finding « microservice CRF sans authentification ni CORS restreint » a été rejeté en vérification (auth gérée en amont).

Forces observées.

  • Gitleaks en pre-commit, CodeQL configuré, secrets:scan en CI.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
52Anti-XSS testé sur 1 endpoint (cf finding 29)MediumHighSapps/find-an-expert/src/routes/api/v1/institutions/search/server.test.ts
53CSP headers non systématiques entre appsMediumMediumMsources multiples

Résumé. Bundles raisonnables, code splitting effectif. Le finding « test files shipped to npm » a été rejeté en vérification.

Forces observées.

  • files correctement défini dans les package.json publiables.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
54Pas de budget bundle ni de regression checkLowMediumM.github/workflows/

Résumé. Logs structurés via crf-logs. Le finding « no audit log on auth actions » a été rejeté en vérification.

Forces observées.

  • crf-logs factorisé et testé à 100%.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
55Pas de tracing distribué entre services/appsLowMediumLsources multiples
56Métriques d’erreur non agrégées côté opsLowMediumMsources multiples

Résumé. A11y partielle (composants Bootstrap), i18n non systématique.

Forces observées.

  • Quelques helpers ARIA dans ui/atlas-ui.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
57Pas de test a11y automatisé (axe-core absent)MediumHighMui/atlas-ui
58i18n non décidée (pas d’ADR, pas de framework)LowMediumLsources multiples

Résumé. README et CLAUDE.md à jour. Les findings « prérequis système non documentés » et « knip casse main » ont été rejetés en vérification.

Forces observées.

  • Scripts pnpm cohérents et turbo bien configuré.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
59Pas de devcontainer / GitHub Codespaces configLowMediumM.devcontainer

Résumé. Bootstrap Appwrite et REDCap automatisés via sandbox. Le finding « data dictionaries gitignored » a été rejeté en vérification (fixtures versionnées).

Forces observées.

  • sandbox/crf-sandbox/tests/contract/ fixtures versionnées (projects.json).

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
60Migrations Appwrite : pas de versioning explicite côté repoMediumMediumMsandbox/amarre-sandbox

Résumé. Les apps partagent packages/auth et ui/atlas-ui, mais quelques divergences subsistent. Le finding « auth response envelope divergent » a été rejeté en vérification.

Forces observées.

  • Factory createAuthService partagée entre amarre, ecrin, sillage, find-an-expert.

Findings.

#TitreSévéritéConfianceEffortVérifiéLocations
61Schémas OpenAPI non testés contre les implémentations (cf finding 30)MediumHighMsources multiples

1. Quick wins (XS / S) — à intégrer dans la prochaine PR

Section intitulée « 1. Quick wins (XS / S) — à intégrer dans la prochaine PR »
  • A. Architecture : findings 1 (ajouter règle cli↔cli), 2 (check private:true), 3 (mettre à jour ADR 0011), 6 (supprimer ou compléter crf-sandbox-core), 7 (trancher convention nommage), 9 (élargir scanner aux .svelte.ts), 10 (ADR sandbox deps), 11 (check exports config/), 12 (nommage atlas-stats).
  • B. Couverture : findings 13 (seuils plancher), 14 (brancher coverage:report en CI), 15 (mode --strict), 18 (resserrer seuils amarre), 22 (étendre include atlas-stats), 23 (sandbox seuils), 24 (exclure logos).
  • C. Tests : findings 27 (supprimer wrapper-only), 29 (helper anti-XSS), 31 (seuils CLI), 32 (__resetRateLimitForTests), 33 (introduire fast-check), 34 (config vitest mort), 35 (describe.configure({ retries: 1 })).
  • D. Lint : findings 36 (preset Svelte strict), 37 (format:check racine), 38 (lint scripts sandboxes), 39 (--max-warnings 0), 40 (require-description).
  • J. Gouvernance : finding 46 (ADR 0011 mise à jour).

2. Chantiers moyens (M) — à planifier dans le mois

Section intitulée « 2. Chantiers moyens (M) — à planifier dans le mois »
  • A. Architecture : findings 4 (extraire crf-openapi en lib), 5 (migrer citation-validate prompts vers cli/biblio), 8 (scanner imports relatifs cross-workspace).
  • B. Couverture : findings 16 (couverture services/crf), 17 (seuils ecrin), 19 (élargir include find-an-expert).
  • C. Tests : findings 25 (job CI E2E nightly), 26 (inventaire endpoint→test), 28 (introduire MSW), 30 (étendre pattern _openapi).
  • O. Backend : finding 51 (standardiser handler→app).
  • P. Sécurité : finding 53 (CSP systématique).
  • S. A11y : finding 57 (axe-core).
  • U. Schémas : finding 60 (versioning Appwrite).
  • V. Cohérence : finding 61 (validation OpenAPI cross-app).

3. Chantiers lourds (L / XL) — à arbitrer ou laisser sine die

Section intitulée « 3. Chantiers lourds (L / XL) — à arbitrer ou laisser sine die »
  • B. Couverture : findings 20 (tests pour 4 CLI sans test), 21 (tests pour ui/atlas-ui).
  • N. UI : finding 50 (consolidation theming).
  • R. Observabilité : finding 55 (tracing distribué).
  • S. A11y/i18n : finding 58 (décision i18n).
  • T. DX : finding 59 (devcontainer).
DimensionidTitreSévérité initialeRejet
Tests multi-niveauxintegration-tests-are-mocked-unitsLe projet integration de sillage est presque entièrement composé d’unit tests mockésHigh2/3
Lint, format et styleprettier-root-config-ignore-shared-baseLe .prettierrc racine n’hérite pas du shared baseHigh3/3
Documentation paquetsreadmes-squelettes-paquets-publics14 README de paquets publics réduits à 5 lignesHigh2/3
Documentation paquetsabsence-tsdoc-paquets-publiesPlusieurs paquets publics ont 0 commentaire JSDocHigh2/3
Documentation VitePresscontacts-admins-infra-videRunbook incident-response : contacts admins infra non renseignésHigh2/3
Sécurité applicativecrf-service-no-authenticationMicroservice services/crf exposé sans authentification ni CORS restreintCritical2/3
Langages / TSbase-tsconfig-missing-strict-extrasbase.json n’active ni exactOptionalPropertyTypes ni noUncheckedIndexedAccessHigh3/3
Performancetest-files-shipped-to-npmFichiers *.test.js et *.test.d.ts publiés dans le tarball npmHigh2/3
Observabiliténo-audit-log-on-auth-actionsAucun audit log des actions auth sensiblesHigh2/3
DX onboardingprerequis-systeme-non-documentesPrérequis système (Node 24, pnpm, gitleaks, Docker) non documentésHigh2/3
DX onboardingknip-casse-main-bloque-pushknip échoue sur main : pre-push bloque sans piste de remédiationHigh2/3
Schémas et migrationsdata-dictionaries-gitignored-no-canonical-sourceDictionnaires REDCap hors Git, pas de référence canoniqueHigh3/3
Cohérence inter-appsauth-response-envelope-divergentEnveloppe de réponse JSON divergente entre find-an-expert et amarre/ecrinHigh2/3

A. Architecture & structure

  • Workspaces totaux : 38
  • Catégories : 8 (apps, assets, packages, services, cli, ui, config, sandbox)
  • Résultat audit:structure : passed
  • ADR : 19
  • Apps private:true : 6 / Sandbox private:true : 4
  • Dérogations connues : atlas-crf-openapi (no -cli suffix), atlas-citation-validate (@clack/prompts en deps), ui/atlas-ui (private + peerDeps svelte)
  • Règles non checkées : private:true (ADR 0011), cli↔cli deps (ADR 0008), structure thin CLI, exports config/, imports dynamiques, imports relatifs cross-workspace

B. Couverture de tests

  • Paquets avec vitest config : 33
  • Paquets sans test : 5
  • Paquets avec seuils à 0 : 10
  • Couverture agrégée : 90 / 82,7 / 90,4 / 90,4 (statements/branches/functions/lines)
  • Fichiers à 0% silencieusement exclus : 84
  • Apps avec couverture réelle la plus basse : find-an-expert 62/42/44/62, ecrin 75,5/63,8/67,9/75,8, amarre 74,9/74,6/58,8/75,4
  • CLI sans aucun fichier de test : biblio, citation, atlas-stats, crf-stats
  • Paquets sans vitest : ui/atlas-ui, cli/logos, sandbox/amarre-sandbox, sandbox/crf-sandbox-core, sandbox/sillage-sandbox
  • services/crf seuils déclarés : 17 / 14 / 24 / 18
  • coverage:report invoqué en CI : non

C. Tests multi-niveaux

  • Fichiers de tests : 177
  • Fichiers avec vi.mock : 60
  • Configs Playwright : 2 (E2E en CI : 0)
  • Configs vitest : 30
  • Endpoints ecrin : 14 (4 testés)
  • Endpoints find-an-expert : 17 (3 testés)
  • Endpoints amarre : 9 (5 testés)
  • CLI avec seuil à 0 : 7 / 9
  • Usage MSW : 0
  • Tests XSS : 1 fichier