
# Comment Sovrium est construit

Si vous avez cloné Sovrium depuis GitHub et cherché les tests, vous n'en avez trouvé aucun. Le constat est exact, et il mérite une vraie réponse plutôt qu'une formule rassurante.

Le dépôt GitHub n'est pas l'endroit où Sovrium est développé. C'est l'artefact produit par une publication. Cette page explique ce que cela signifie, ce que contient le dépôt de développement, pourquoi il est privé aujourd'hui, et ce qu'il advient de votre instance si l'entreprise derrière Sovrium s'arrête.

## Le dépôt GitHub est un artefact de publication

Sovrium est développé dans un monorepo privé hébergé sur une instance Forgejo auto-hébergée. Chaque publication exécute `scripts/filtered-mirror.sh`, qui construit une copie filtrée de cet arbre et la publie sur `github.com/sovrium/sovrium`.

Le filtre est une **liste d'autorisation**. Rien n'atteint GitHub sans qu'une ligne de ce script le copie explicitement. Le code source, le paquet `@sovrium/types`, les scripts de build, les migrations, les modèles, le Dockerfile et les métadonnées de publication sont copiés. Tout le reste est absent par défaut, notamment :

| Exclu                                                   | De quoi il s'agit                                                              |
| ------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `specs/`                                                | La suite de tests de bout en bout                                              |
| `*.test.ts` / `*.test.tsx` sous `src/` et `packages/`   | Les tests unitaires colocalisés, supprimés après la copie                      |
| `.forgejo/`                                             | Les workflows de CI                                                            |
| `playwright.config.ts`                                  | La configuration du lanceur E2E                                                |
| `scripts/check-quality.ts`, `scripts/check-progress.ts` | Les deux pipelines de qualité                                                  |
| `eslint/`                                               | La configuration de lint modulaire, dont les règles de frontière entre couches |
| `docs/`                                                 | Les décisions d'architecture, les patterns et les user stories                 |
| `.claude/`, `CLAUDE.md`                                 | Les instructions de développement internes                                     |

Ces exclusions sont appliquées, pas seulement souhaitées. Le script embarque des canaris à sécurité positive : si un chemin protégé se retrouve dans l'arbre construit, la publication s'interrompt avant tout envoi. Le `package.json` racine est remplacé par un manifeste public dont le bloc `scripts` est réduit au sous-ensemble de build, ce qui explique qu'aucun script `test:` ne soit visible sur GitHub, et un second canari interrompt la publication si une cible de script interne s'y glisse.

La publication est un commit enfant en avance rapide sur le `HEAD` GitHub existant. Ni commit orphelin ni poussée forcée : l'historique public reste continu et consultable, à raison d'un commit par version.

## Pourquoi l'infrastructure de développement est privée

La vraie raison est concurrentielle, et elle mérite d'être énoncée telle quelle plutôt que déguisée en politique.

Le moteur est gratuit pour toujours en auto-hébergement. La suite de tests, la CI et l'outillage interne sont autre chose : avec le code source, ils forment un plan de reproduction du produit qui fonctionne. Avec l'assistance de l'IA d'aujourd'hui, une suite de spécifications complète est presque un plan de construction. Sovrium est bootstrappé et fondé par une seule personne, et cette asymétrie est l'une des rares dont il dispose.

Le kit de reproduction est donc retenu. Le produit, non. Chaque fonctionnalité marche dans le binaire auto-hébergé, sans clés de licence, sans fonctionnalités bridées, sans édition payante.

À lire comme **différé, pas soustrait**. L'engagement de continuité ci-dessous fixe la condition dans laquelle l'infrastructure privée est publiée.

## Ce que couvre la suite

Ces chiffres proviennent de `SPEC-PROGRESS.md`, généré par `bun run progress` et régénéré par la CI à chaque poussée. Ils comptent statiquement ce que la suite _contient_ : `bun run progress` lit les fichiers de specs, il ne les exécute pas. Le résultat de ces tests sur un commit donné est ce que rapporte la CI, pas ce tableau.

|                              |                                                          |
| ---------------------------- | -------------------------------------------------------- |
| Fichiers de specs            | 908                                                      |
| Tests E2E                    | 7 933 au total : 6 902 `@spec` + 1 031 `@regression`     |
| Implémentés                  | 7 901                                                    |
| Emplacements non implémentés | 32 `test.fixme()`, suivis                                |
| Fichiers de tests unitaires  | 826 (787 sous `src/`, 39 sous `scripts/`)                |
| Cas de tests unitaires       | ~10 300, comptés statiquement                            |
| User stories                 | 894, traçant 7 426 identifiants de spec                  |
| Domaines fonctionnels        | 23 domaines du moteur plus 2 domaines applicatifs métier |

La structure compte davantage que le décompte, car c'est elle qui relie un test à une exigence.

Chaque fichier `.spec.ts` contient deux niveaux. Le premier est un ensemble de tests `@spec`, un par critère d'acceptation, chacun portant l'identifiant de la user story qu'il satisfait. Le second est un unique test `@regression` qui rejoue ces mêmes critères sous forme de sections `test.step()` dans un parcours continu. Une fonctionnalité est donc couverte deux fois : critère par critère, puis telle qu'un utilisateur la traverse réellement. Les 894 user stories et les 7 426 identifiants tracés forment la jointure entre les deux, et c'est ce qui fait de la couverture une question à laquelle on peut répondre plutôt qu'une impression.

### Ce qui n'est pas mesuré

Sovrium ne publie **aucun pourcentage de couverture de code**, parce qu'il n'en mesure aucun.

Le pipeline de qualité impose un invariant de présence de **fichier** de test : chaque fichier source de la couche domaine doit avoir un `*.test.ts` colocalisé. C'est une règle structurelle, pas un seuil de lignes ou de branches. Aucun seuil de couverture n'est configuré nulle part dans le projet, et un fichier de test présent mais vide satisfait la porte.

Un chiffre serait facile à produire et ne voudrait pas dire grand-chose. La limite est énoncée à la place.

## Ce qui s'exécute, et quand

Le workflow de CI se déclenche à **chaque poussée et chaque pull request** vers `main`. Il exécute trois jobs sur un runner dédié de 8 vCPU / 32 Go, avec un plafond de 50 minutes sur le plus long.

1. **Lint.** ESLint sur tout l'arbre, dont les règles de frontière entre couches qui rendent le sens des dépendances de l'architecture opposable plutôt que déclaratif.
2. **Typage et tests unitaires.** Vérification `tsc` complète, suite unitaire, validation de chaque configuration d'exemple livrée par la vraie commande `sovrium validate`, et un garde-fou de dérive des migrations qui régénère les jeux PostgreSQL et SQLite et échoue si un changement de schéma n'a atteint qu'un seul des deux dialectes.
3. **E2E.** Conditionné à la réussite des deux jobs précédents, pour que la suite navigateur ne s'exécute jamais sur un typage cassé.

Une précision, parce que c'est le genre de détail qu'il vaut mieux énoncer juste plutôt qu'arrondir à notre avantage : la CI exécute `playwright test --grep "@regression|@packaging"`. C'est le niveau régression de 1 031 tests plus le niveau packaging, qui éprouve le binaire compilé construit plus tôt dans le même job. Ce n'est **pas** le corpus `@spec` complet de 6 902 tests, trop lent pour conditionner chaque poussée, et exécuté localement et à la demande.

En local, deux pipelines se placent avant un commit.

`bun run quality` enchaîne treize portes et s'arrête à la première qui échoue : Prettier, ESLint, lint des workflows, un contrôle de dérive consolidé (jetons de design, identité de marque, assets générés, schéma, changelog, liens de documentation, et plus), validation des configurations de guides, recherche de secrets commités, audit des dépendances contre le lockfile, TypeScript, diagnostics Effect (optionnels), tests unitaires, Knip pour le code mort, l'invariant de présence de fichier de test, et une étape E2E intelligente qui analyse les fichiers modifiés et n'exécute que les specs de régression associées.

`bun run progress` valide la qualité de contenu des specs et des user stories elles-mêmes, et régénère `SPEC-PROGRESS.md`.

## Posture de sécurité

Les vulnérabilités se signalent à **security@sovrium.com**. Vous recevrez un accusé de réception sous **48 heures** et une première évaluation sous **5 jours ouvrés**. N'ouvrez pas de ticket public. Les personnes qui signalent sont créditées dans les notes de version, avec leur accord.

Le code est écrit contre cinq règles permanentes, appliquées à la couche plateforme pour que chaque application en hérite sans configuration :

- **Authentification avant toute logique sensible**, avec un contrôle d'autorisation au niveau de l'objet sur chaque requête, et un `404` plutôt qu'un `403` en cas d'échec, afin que l'existence d'une ressource reste inobservable.
- **Un seul assainisseur HTML canonique** pour tout contenu rendu à partir de données utilisateur ou d'enregistrements. Il n'y en a délibérément qu'un, parce qu'un second assainisseur est un second jeu de bugs.
- **Requêtes SQL à paramètres liés** à l'exécution, avec des identifiants validés échappés séparément.
- **Aucun secret dans les bundles client ni dans les journaux**, et aucune ligne brute de base de données renvoyée par une route d'API.
- **Export et effacement RGPD** partout où une fonctionnalité touche à des données personnelles, l'effacement étant une suppression définitive et non logique.

[Durcissement de la sécurité](/fr/docs/security-hardening) documente ce que cela produit à l'exécution : le jeu d'en-têtes de réponse, l'application CSRF et cross-origin, les limitations de débit et le comportement anti-énumération.

**Aucun test d'intrusion par un tiers n'a été commandité à ce jour.** Le travail de sécurité ci-dessus est interne : règles de conception, relecture de code, et specs qui verrouillent le comportement. Ce n'est pas un audit indépendant, et cela ne doit pas se lire comme tel.

## Continuité

La vraie question derrière « est-ce que je peux construire là-dessus » ne porte pas vraiment sur les tests. Elle est : qu'advient-il de mon instance si vous vous arrêtez ?

**Le moteur est gratuit pour toujours en auto-hébergement.** Pas de clés de licence, pas de fonctionnalités bridées, pas d'édition entreprise, pas d'appel au serveur, pas d'interrupteur d'arrêt. Sovrium lit votre configuration et l'exécute. Si l'entreprise disparaissait demain, chaque instance en fonctionnement continuerait de tourner, parce qu'il n'y a rien auprès de quoi elle doive se signaler.

**La licence bascule d'elle-même.** Sovrium est publié sous BSL 1.1, qui devient Apache 2.0 le **2030-08-01**. Cette conversion est inscrite dans [`LICENSE.md`](https://github.com/sovrium/sovrium/blob/main/LICENSE.md) et ne demande d'action à personne, nous compris. Voir [Licence](/fr/docs/license) pour ce que les termes permettent d'ici là.

**Le facteur de bus est de un.** Sovrium est fondé par une seule personne et bootstrappé. Prétendre le contraire serait exactement le genre d'affirmation que cette page existe pour éviter. Le contrepoids est une discipline de documentation : des décisions d'architecture qui consignent le pourquoi de chaque choix, des user stories qui énoncent à quoi sert chaque fonctionnalité, et une suite de specs qui fige le comportement. Ces artefacts existent pour qu'une personne reprenant la maintenance puisse retrouver le contexte au lieu de le reconstituer par rétro-ingénierie.

**Si l'entreprise cesse son activité, l'infrastructure de développement privée est publiée.** La suite de specs, la CI et l'outillage interne. La raison de les retenir est une entreprise en activité qui n'existerait plus, et les personnes qui feraient tourner Sovrium auraient précisément besoin de ces artefacts pour le maintenir. Cet engagement est consigné dans [`SECURITY.md`](https://github.com/sovrium/sovrium/blob/main/SECURITY.md) du dépôt public, pour qu'il ne dépende pas du maintien en ligne de cette page.

## Voir aussi

- [Licence](/fr/docs/license) pour les termes de la BSL 1.1 et la date de bascule
- [Durcissement de la sécurité](/fr/docs/security-hardening) pour les garanties de sécurité à l'exécution
- [Contribuer](/fr/docs/contributing) pour proposer des changements
- [Marque déposée](/fr/docs/trademark) pour l'usage du nom et du logo Sovrium
