Audit de clôture du chantier opt-ins¶
Ticket :
OPTINS-CLOSING-AUDIT-001. Audit documentaire de fin de chantier — aucun code fonctionnel n'est ajouté. Instantané pris après le dernier ticket opt-ins (efc2f70,OPTINS-CLI-LIST-001).
Verdict¶
Le chantier opt-ins est clôturable. Le modèle de branchement local des opt-ins tient sur un cas réel et complet — Forge IoT — avec un cycle cohérent :
optins/ (contrat) → starter welcome-iot → forge optin:enable iot
→ --apply (fichiers + mvc/routes.py si reconnu) → forge optin:list (état)
Le modèle est explicite, lisible, idempotent, lecture-seule par
défaut, sans discovery magique. Il n'est validé que pour iot — c'est
volontaire : la généralisation à RBAC/media/… est reportée à des
tickets d'audit dédiés, après cette clôture.
Résumé exécutif¶
- 6 tickets opt-ins livrés (contrat → bridge starter → audit enable →
enable iot → routes apply → list), tous commités sur
main. - 2 commandes CLI :
forge optin:enable <name>(dry-run par défaut,--applypour écrire) etforge optin:list(lecture seule). - Couche
optins/générée à l'identique par le starterwelcome-iotet parforge optin:enable iot— structure cohérente. - 99 tests opt-ins verts (
tests/test_optins_*.py+tests/meta/test_optins_*.py). - Les packages restent dans
packages/forge-mvc-*;optins/est une couche de branchement local, jamais une copie du code.
Tickets livrés¶
| Ticket | Commit | Sujet |
|---|---|---|
OPTINS-PROJECT-STRUCTURE-001 |
2cc45e2 |
Contrat de la structure optins/ |
OPTINS-IOT-PROJECT-BRIDGE-001 |
7dd5f69 |
welcome-iot génère optins/iot/ |
OPTINS-CLI-ENABLE-AUDIT-001 |
9d275cf |
Conception de forge optin:enable |
OPTINS-CLI-ENABLE-IOT-001 |
6dbc247 |
forge optin:enable iot (dry-run/apply) |
OPTINS-CLI-ENABLE-ROUTES-APPLY-001 |
3a97ab6 |
Branchement prudent de mvc/routes.py |
OPTINS-CLI-LIST-001 |
efc2f70 |
forge optin:list (lecture seule) |
Le présent ticket OPTINS-CLOSING-AUDIT-001 n'ajoute que cet audit et
son garde-fou méta.
Architecture obtenue¶
- Packages distribués : inchangés, dans
packages/forge-mvc-*(source de vérité, PyPI). Aucun déplacement. optins/: couche côté projet utilisateur, branchement local uniquement (routes, README, repères de migration) — pas le code du paquet.- Forge Core indépendant des opt-ins : ni
core/ni la commandeoptin:listn'importentforge_mvc_iot;optin:enablevérifie la présence du paquet viaimportlib.util.find_spec, sans l'importer. - Pas de discovery magique : le branchement est explicite via
optins/registry.py, appelé depuismvc/routes.py.
Structure optins/¶
Modèle cible (contrat OPTINS-PROJECT-STRUCTURE-001), généré tel quel
pour IoT :
optins/
├── __init__.py
├── registry.py
└── iot/
├── __init__.py
├── routes.py
├── README.md
└── migrations/
└── README.md
Rappels verrouillés :
- les packages restent dans
packages/forge-mvc-*; optins/est une couche de branchement local, pas une copie du paquet ;- le README local reste court et renvoie vers la doc officielle.
Cas Forge IoT¶
Le seul opt-in branché par ce chantier. optins/iot/routes.py délègue à
l'API publique du paquet :
from forge_mvc_iot import register_iot_routes
def register(router):
register_iot_routes(router) # /api/iot/events, etc.
Et optins/registry.py l'appelle explicitement :
def register_optins(router):
from optins.iot.routes import register as register_iot
register_iot(router)
Commandes CLI disponibles¶
| Commande | Rôle | Écrit ? |
|---|---|---|
forge optin:enable iot |
aperçu (dry-run) du branchement IoT | non |
forge optin:enable iot --apply |
crée optins/iot/ + branche mvc/routes.py si reconnu |
oui |
forge optin:list |
affiche l'état local des opt-ins | non (lecture seule) |
Comportement de forge optin:enable iot¶
- dry-run par défaut : sans
--apply, rien n'est écrit ([DRY-RUN] … serait créé) ; --applynécessaire pour écrire : crée les fichiersoptins/absents ;- idempotence : fichier absent → créé ; identique →
[OK] déjà présent; différent →[WARN]+ aucune écriture (jamais d'écrasement silencieux) ; - paquet absent →
[ERREUR]+pip install --pre forge-mvc-iot(exit 1, même en dry-run) ; - pas de discovery magique (aucun
pkgutil/scan).
mvc/routes.py¶
--applyne branchemvc/routes.pyque si la structure est reconnue (présence derouter = Router()) : insère alors l'importfrom optins.registry import register_optins+ l'appelregister_optins(router), idempotemment ;- structure ambiguë (ou fichier absent) →
[WARN]+ instruction manuelle, aucune modification ; - pas de marqueurs imposés (idempotence par présence de l'appel) ;
- aucune modification arbitraire de fichiers.
Comportement de forge optin:list¶
- strictement lecture seule : ne crée, ne modifie, n'installe rien ;
- n'importe pas
forge_mvc_iotni aucun paquet opt-in (lecture de texte uniquement) ; - états
iot:absent,partiel(structure présente maisregister_optins(router)absent demvc/routes.py),activé; - pas de discovery magique, pas de scan global des paquets installés ;
- exit
0toujours.
Starter welcome-iot¶
OPTINS-IOT-PROJECT-BRIDGE-001 a fait du starter l'exemple vivant :
welcome-iotgénèreoptins/iot/(mêmes fichiers queoptin:enable iot) ;optins/registry.pyest explicite ;optins/iot/routes.pyappelleregister_iot_routes;- un README local court existe (
optins/iot/README.md).
Documentation disponible¶
- Structure des opt-ins (projet) ;
- Audit
forge optin:enable; - Référence CLI — Opt-ins
(
optin:enable,optin:list) ; - Starter Bonjour IoT.
Tests et validations¶
- 99 tests opt-ins verts :
tests/test_optins_*.py(commande + bridge) +tests/meta/test_optins_*.py(contrat, audit, clôture). - Garde-fous transverses :
core/n'importe pas les opt-ins ;optin:listsans import IoT ni écriture (AST) ; cohérence CLI ↔ doc (test_forge_help_coverage_001,test_cli_help_flags_closing_audit_001). - Validations standard vertes :
compileall,ruff check .,mkdocs build --strict,git diff --check.
Limites assumées¶
Le chantier opt-ins est volontairement minimal :
- seul
iotest supporté (enable + list) ; - pas de
rbac/media/workflow/stats/mfa; - pas de
forge optin:disable; - pas de
forge optin:list --json; - pas de gestion avancée des conflits (un fichier divergent → WARN, pas de fusion/diff) ;
- pas de rollback automatique ;
- pas de
migration:applyautomatique (l'utilisateur lanceforge iot:initpuisforge migration:apply) ; - pas de modification de fichiers arbitraires (seuls
optins/et, si reconnu,mvc/routes.py) ; - pas de discovery magique des opt-ins.
Dettes restantes¶
- Généralisation du modèle à un 2e opt-in (RBAC) non encore éprouvée — c'est l'objet du prochain audit.
forge optin:listne distingue pas encore l'étatconflit(minimum utile :absent/partiel/activé).
Tickets reportés¶
OPTINS-CLI-ENABLE-RBAC-AUDIT-001— auditer l'extension à RBAC.OPTINS-CLI-ENABLE-MEDIA-AUDIT-001— auditer l'extension à media.OPTINS-CLI-DISABLE-AUDIT-001— concevoir un éventueloptin:disable.OPTINS-CLI-LIST-JSON-001— sortie--jsonpouroptin:list.OPTINS-CONFLICT-REPORT-001— rapport de conflits plus détaillé.
Décision de clôture¶
Chantier opt-ins : CLÔTURÉ pour le périmètre iot. Le cycle
enable → routes apply → list est cohérent, testé, documenté ; les
limites sont explicites et la dette structurelle (généralisation) est
isolée dans des tickets reportés. Deux chemins possibles ensuite :
OPTINS-CLI-ENABLE-RBAC-AUDIT-001 (généraliser prudemment) ou
RELEASE-BETA12-PRE-AUDIT-001 (préparer une bêta après IoT + opt-ins).
La généralisation à RBAC/media ne doit pas être ouverte avant
validation de cet audit.