Constat: faisabilite/generator/brief.schema.json, documenté « Contrat d'entrée » et sibling de version/projets_master (tous deux test-enforced), n'était validé par AUCUN test — _validate_brief() ne garde que le code projet, jamais la forme complète du brief; un brief drifté hors contrat passait inaperçu. Fix (teeth): test_input_briefs_validate_against_brief_schema valide les 2 fixtures contre brief.schema.json via le validateur maison Publiciste (zéro-pip, toujours exécuté, pas de skip sous python -S). Conformité pré-vérifiée sous validateur maison ET oracle jsonschema. L'« incomplet » est conforme au sens schéma (null admis) — incomplet seulement au sens sémantique (prix→placeholders #6). Cascade régénérée (générateurs, jamais à la main #6): regression_plan/run/MANIFEST 16→17 · totaux 624→625 exécutés / 607→608 passés / 17 skippés · quality_report evidence 16→17. Prose gatée réalignée (le gate check-readme-claims a mordu): README module + fiches faisabilite/qa/erpnext_backend. Prose ungatée: GAP_ANALYSIS 16→17 + nouveau bloc daily_report (blocs currency antérieurs = snapshots datés, non réécrits). 0 gate ajouté (#5) · 0 chiffre à la main (#6) · 0 commande VPS (#8). run_ci.sh = 33 PASS · 0 FAIL · 0 SKIP. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4.8 KiB
Générateur Faisabilité 4 volets · Sprint 2
Livrable Faisabilité · Sprint 2 —
03_agents/faisabilite/AGENT.md§Livrable S2 (« Générateur 4 volets automatique »). Cible de portage VPS :otoia/capabilities/faisabilite_agent.py.
Produit une faisabilité canonique data_room/PXX/ (conforme au
TEMPLATE_FAISABILITE_CANONIQUE_v1.0.md)
à partir d'un brief JSON sourcé, puis prouve que le résultat est
consommable par le Publiciste.
Place dans la chaîne de valeur
brief.json ──► faisabilite_gen ──► data_room/PXX/ (template v1.0)
│
▼ (module Publiciste, déjà livré)
publiciste.parser ──► projets_master.json ──► site
Le générateur ferme la boucle amont du Publiciste : ce dernier ne fait que publier ; c'est ici que les 4 volets sont produits et notés.
Zéro invention de chiffres (CLAUDE.md #6)
Principe défensif de bout en bout :
- Les paramètres canoniques (3 % édition · 8.5 % marketing · 52 % point d'équilibre · USD+DOP · Cardnet · Letter US, CLAUDE.md #9/#10) sont imposés par le générateur — ils ne proviennent jamais du brief, donc ne peuvent être faussés projet par projet.
- Tout champ 🔴 absent du brief est rendu en placeholder
{{…}}, listé danschamps_manquants, et rétrograde le statut (jamais « complete » douteux). - Un prix manquant reste
{{…}}(jamais0, jamais une valeur inventée) → le Publiciste publie le projet « En développement ».
Scoring 4Big (§7 du template · 5 axes × 20)
| Axe | Source | Calcul |
|---|---|---|
| Complétude | brief | fraction des champs 🔴 des 4 volets remplis |
| Anti-gap prix | brief §3.2 | fraction des cellules typologies renseignées |
| Traçabilité | brief | sources[] + taux_conversion{date,source} |
| Paramètres canoniques | générateur | 20 (garanti · vérifié dans le rendu) |
| Machine-lisible | preuve | version.json valide + parser Publiciste OK |
L'axe machine-lisible n'est pas auto-décerné : le CLI re-parse le projet
généré avec le parser Publiciste et valide version.json contre
version.schema.json. En cas d'échec, les 20 points
sont retirés, version.json réécrit, et la commande sort en erreur.
Statut « complete » ⇔ score ≥ 95 et aucun champ 🔴 manquant et bloc prix
intégral et 4 volets — cohérent avec la contrainte allOf de
version.schema.json.
Utilisation
# Bilan 4Big d'un brief (sans rien écrire)
python3 faisabilite_gen.py score fixtures/brief_complete.json
# Générer une faisabilité (+ preuve machine-lisible)
python3 faisabilite_gen.py generate fixtures/brief_complete.json -o /tmp/data_room
# Amorcer un nouveau projet (arborescence vide à placeholders)
python3 faisabilite_gen.py scaffold P07 -o /tmp/data_room
# Générer tous les briefs d'un dossier
python3 faisabilite_gen.py batch fixtures -o /tmp/data_room
Puis, via le module Publiciste, publier :
cd ../../publiciste
python3 publiciste.py run /tmp/data_room -o /tmp/site
--generated-at fige l'horodatage (sorties déterministes / tests).
Contrat d'entrée
Voir brief.schema.json. Les fixtures sont synthétiques
("synthetique": true, bannière « ne jamais publier ») :
fixtures/brief_complete.json→ statutcomplete, score 100/100.fixtures/brief_incomplete.json→ prix absents → rétrogradationen_developpement, prix restés en placeholders (démontre l'anti-invention).
Tests
python3 -m unittest discover -s tests -v
17 tests unittest (stdlib pur, zéro pip) : scoring, rétrogradation,
paramètres canoniques, conformité des fixtures au contrat d'entrée
(brief.schema.json), et round-trip end-to-end generator → parser Publiciste
→ projets_master.json validé contre le schéma. Réutilise le parser + le
validateur du Publiciste (aucune duplication · workflow #5). Un oracle
jsonschema est activé en plus s'il est installé.
Job CI : faisabilite-gen-tests (gate .gitea/workflows/ci.yml · Gitea Actions
uniquement · contrainte #2).
Hors périmètre worker (VPS / calendrier ultérieur)
- Application sur les données réelles
data_room/(VPS · Faisabilité/ERPNext). - Archives auto
_ARCHIVES/PXX_v{N}_YYYYMMDD/sur bump MAJOR du template (S3/S4). - Génération des
40_llm_outputs/marché/directeur/fiscal/juridique + rapports bancables FR/EN/ES (S3+ ; seuls brief/masterplan/architecture/paysage/ ingénierie/commercial sont produits ici). - Trigger
otoia-faisabilite.timer+ notification Publiciste/WhatsApp (S6 · VPS).