Ce que chaque produit sait faire aujourd'hui

Document de séance — réunion du 31 août 2026. Toutes les sorties encadrées de cette page ont été produites le 2026-08-31 10:45:27 CEST en exécutant le code, hors ligne, sans aucun appel à un service payant.

Règle de lecture. Chaque bloc porte une étiquette et une seule. RÉEL = la sortie affichée sort d'une exécution, la commande exacte et son horodatage sont donnés au-dessus ; vous pouvez la relancer. NON DÉMONTRABLE HORS LIGNE = rien n'est montré, et la raison est écrite. Aucune maquette, aucune capture d'écran d'intention, aucun chiffre sans sa commande. Les statuts produits reprennent ceux de tout le dossier : FAIT ET VÉRIFIÉ, ÉCRIT, PAS INTÉGRÉ, SPÉCIFIÉ, PAS COMMENCÉ.

Comment rejouer cette page

bash verifier-demo.sh (même dossier) ré-exécute les quatre preuves, recompare chaque nombre cité ici et sort en erreur si l'un d'eux a bougé. Les sorties brutes sont archivées dans demo-sorties/.

1. PLU+ — un rapport d'urbanisme qui dit ce qu'il ne sait pas

Pour un architecte : vous donnez une parcelle, le rapport vous rend les règles opposables — hauteur, emprise, recul, stationnement — et à côté de chaque règle, d'où elle vient (document, article, page, date) et ce qu'on en sait. Une règle non lue n'est jamais rendue comme une règle absente.

FAIT ET VÉRIFIÉ RÉEL

À dire avant de regarder le tableau. Les règles ci-dessous viennent d'un extracteur de test (mock/llm-test) et d'un règlement fabriqué pour l'exercice — pas d'une lecture par modèle de langage d'un vrai PLU communal. Ce qui est démontré ici, c'est la mécanique du rapport : les cinq états, la provenance à six champs, l'arbitrage d'une contradiction. Ce qui n'est pas démontré, c'est la qualité de lecture d'un règlement réel : elle exige le run avec clé plafonnée à 5 $ et le corpus de référence rédigé par un architecte (voir §6).
Commande — exécutée le 2026-08-31 10:45:27 CESTcd $SCRATCH/demo-aq && PYTHONPATH=. .venv-plu/bin/python demo-sorties/demo_plu.py demo-sorties/

1.1 Les cinq états, et la contradiction 12 m / 9 m

Le règlement écrit dit 12 m à l'article UB 10 (page 42). Le règlement graphique dit 9 m. Le rapport ne choisit pas en silence : il déclare l'état Contradictoire, cite les deux sources, retient la valeur la plus restrictive (9 m) et écrit que l'arbitrage est à confirmer en mairie.

RègleValeurÉtatSource (document · article · page · date)Confiance
Article UB 10 — Hauteur La hauteur maximale est de 12 m. Confirmé PDF règlement p.42 · art. UB 10 · p.42 · 2024-06-01
Extrait lu tel quel au règlement (pdfplumber)
0.70
Hauteur max m 12.0 Confirmé LLM extraction from article UB 10 (mock/llm-test) · art. UB 10 · 2024-06-01
Valeur citée à l'article — « hauteur maximale 12 mètres »
0.90
Divergence hauteur texte / graphique texte 12 m ≠ graphique 9 m — retenu 9 m (le plus restrictif) Contradictoire règlement graphique — GPU / règlement graphique (hauteur maximale de façade) vs article UB 10 · art. UB 10 (écrit) / hauteur maximale de façade (graphique) · 2024-06-01
CONTRADICTION : règlement écrit 12 m (article UB 10) vs règlement graphique — GPU / règlement graphique (hauteur maximale de façade) 9 m — la plus restrictive (9 m) est retenue, arbitrage à confirmer en mairie
0.60
Hauteur maximale retenue 9 m Contradictoire règlement graphique — GPU / règlement graphique (hauteur maximale de façade) · art. UB 10 · 2024-06-01
CONTRADICTION : règlement écrit 12 m (article UB 10) vs règlement graphique — GPU / règlement graphique (hauteur maximale de façade) 9 m — la plus restrictive (9 m) est retenue, arbitrage à confirmer en mairie
0.60

1.2 « Non vérifié » n'est pas « absent » — et la cause est écrite

Règlement fourni en PDF scanné, donc illisible. Le rapport ne dit pas « aucune règle de hauteur » : il dit Non vérifié, avec le code de cause pdf_scanne dans la provenance, et l'action à faire.

RègleValeurÉtatSource (document · article · page · date)Confiance
Règles de constructibilité non déterminées règlement fourni en PDF scanné, aucun texte extractible — aucune règle chiffrée ne peut être avancée. Non vérifié Document d'urbanisme existant, règlement non lu (pdf_scanne)
cause : pdf_scanne — règlement non lu ; non lu n'est pas absent, aucune valeur n'est inventée
0.90

1.3 « Absent (confirmé) » — une absence constatée dans un règlement lu

Même parcelle, règlement réellement parsé : rien sur le stationnement. Là, et là seulement, le rapport a le droit de dire Absent — et il écrit sur quoi il s'appuie pour le dire.

RègleValeurÉtatSource (document · article · page · date)Confiance
Cos Aucune règle trouvée dans le règlement lu Absent (confirmé) Règlement PDF lu — 2 sections parsées · 2024-06-01
Règle « cos » cherchée dans le règlement lu et non trouvée — absence constatée, pas un défaut de lecture
0.70
Stationnement min Aucune règle trouvée dans le règlement lu Absent (confirmé) Règlement PDF lu — 2 sections parsées · 2024-06-01
Règle « stationnement_min » cherchée dans le règlement lu et non trouvée — absence constatée, pas un défaut de lecture
0.70

1.4 « Ambigu » — la règle existe mais n'est pas chiffrable

« L'emprise au sol maximale varie selon la destination des constructions » : pas un nombre. Le rapport le dit, cite l'article, et n'émet aucun verdict.

RègleStatutÉtat donnéeRaison / Source
Emprise au sol À vérifier — donnée non disponible Ambigu
art. UB 9
Valeur non chiffrée dans le règlement : « selon destination » (UB 9) — interprétation manuelle requise

1.5 Le rapport répond au projet, pas au règlement

Même parcelle (800 m², bâti existant 120 m² d'emprise, 110 m² de plancher, 6 m de haut), projet déclaré : extension de 42 m² d'emprise. Le rapport raisonne le projet et rend le calcul, pas seulement la règle.

QuestionVerdictÉtat donnéeCalcul & démarche
Puis-je agrandir sans dépasser l'emprise au sol autorisée ? Autorisé Confirmé
UB 9 · p.12 · 2024-03-15
Démarche : aucune formalité
  1. parcel 800 × CES 0.40 = emprise_brute 320 m²
  2. emprise existante 120 m² + extension 42 m² = 162 m²
  3. 162 m² ≤ emprise maximale 320 m² → l'extension tient dans l'emprise autorisée
règlement écrit, article UB 9
Quelle démarche dois-je engager pour cette extension ? Conditionnel Confirmé
R.421-14 du code de l'urbanisme
Démarche : permis de construire
  1. zone UB : zone urbaine d'un PLU → seuil de déclaration préalable porté à 40 m² (R.421-14 du code de l'urbanisme)
  2. 42 m² > 40 m² → permis de construire (R.421-14 du code de l'urbanisme)
code de l'urbanisme, régime des autorisations d'urbanisme
Dois-je faire appel à un architecte ? Conditionnel Confirmé
art. 4 de la loi n° 77-2 du 3 janvier 1977, seuil fixé par R.431-2 du code de l'urbanisme
Démarche : recours à un architecte obligatoire
  1. surface de plancher existante 110 m² + 42 m² créés
  2. surface de plancher totale 152 m² > 150 m² → recours à un architecte obligatoire (art. 4 de la loi n° 77-2 du 3 janvier 1977, seuil fixé par R.431-2 du code de l'urbanisme)
loi n° 77-2 du 3 janvier 1977 sur l'architecture

Et voici ce qui compte le plus pour vous : le même projet, sur un règlement où le coefficient d'emprise au sol n'a pas été lu. Le rapport ne bascule pas sur une valeur nationale par défaut et ne dit jamais « autorisé » : il dit Non vérifié et donne la démarche pour lever le doute.

QuestionVerdictÉtat donnéeCalcul & démarche
Puis-je agrandir sans dépasser l'emprise au sol autorisée ? Non vérifié Non vérifié
Démarche : certificat d'urbanisme opérationnel (CUb)
  1. emprise au sol maximale non lue au règlement — le défaut RNU (0.6) ne serait pas la règle de la commune
  2. donnée(s) manquante(s) : emprise au sol maximale du règlement — aucun verdict d'emprise possible
règlement PLU — emprise au sol (art. 9 / CES)
Quelle démarche dois-je engager pour cette extension ? Conditionnel Confirmé
R.421-14 du code de l'urbanisme
Démarche : permis de construire
  1. zone UB : zone urbaine d'un PLU → seuil de déclaration préalable porté à 40 m² (R.421-14 du code de l'urbanisme)
  2. 42 m² > 40 m² → permis de construire (R.421-14 du code de l'urbanisme)
code de l'urbanisme, régime des autorisations d'urbanisme
Dois-je faire appel à un architecte ? Conditionnel Confirmé
art. 4 de la loi n° 77-2 du 3 janvier 1977, seuil fixé par R.431-2 du code de l'urbanisme
Démarche : recours à un architecte obligatoire
  1. surface de plancher existante 110 m² + 42 m² créés
  2. surface de plancher totale 152 m² > 150 m² → recours à un architecte obligatoire (art. 4 de la loi n° 77-2 du 3 janvier 1977, seuil fixé par R.431-2 du code de l'urbanisme)
loi n° 77-2 du 3 janvier 1977 sur l'architecture
Tests — exécutée le 2026-08-31 10:45:27 CESTcd $SCRATCH/demo-aq && PYTHONPATH=. .venv-plu/bin/python -m pytest tests/test_plu_plus_*.py tests/test_plu_phase2*.py tests/test_plu_parcelle_reelle.py -q
438 passed, 1 skipped, 639 warnings in 22.61s

Dont 39 tests pour les cinq états (tests/test_plu_plus_etats.py) et 27 pour le raisonnement par projet (tests/test_plu_plus_project_reasoner.py). Deux fichiers de tests du dépôt hors périmètre PLU+ (test_admin_core_basic.py, test_output_and_sketch3d.py) échouent : ils ne sont pas comptés dans ce chiffre et rien ici ne prétend que le dépôt entier est vert.

Ce qui manque encore

2. Ze Fabrik — un ouvrage devient une liste de matériaux chiffrée

Pour un ingénieur : vous décrivez un ouvrage une fois (une cloison 72/48, une ouverture dans un container), vous donnez les dimensions, le moteur rend la liste des matériaux, les quantités, le nombre d'unités de vente, le prix et le temps de pose — et chaque nombre porte sa formule, ses entrées, sa perte et sa source.

FAIT ET VÉRIFIÉ RÉEL — module pur : aucune base de données, aucun réseau.

Commande — exécutée le 2026-08-31 10:45:27 CESTcd $SCRATCH/demo-zf && backend/.venv-fabrik/bin/python demo-sorties/demo_fabrik.py backend/ demo-sorties/

2.1 Marché rénovation — cloison 72/48, mur de 3,20 × 2,50 m avec une porte

Paramètres : longueur_m 3,2 · hauteur_m 2,5 · nb_portes 1 · quantite_ouvrage 8,0. Résultat : 197,5 € de matériaux, 7,95 h de main-d'œuvre, 12 lignes, total_partiel = true.

LigneQuantitéUnités de ventePrix unitaireTotal Statut
Plaque de plâtre BA13 standard 13mm14,1903 m258,1 €40,5 €PROVISOIRE
Rail métallique 48mm (haut/bas)6,72 ml35,5 €16,5 €PROVISOIRE
Montant métallique 48mm18,2 ml75,9 €41,3 €PROVISOIRE
Montant métallique 48mm6,0632 ml35,9 €17,7 €PROVISOIRE
Laine de verre 45mm (isolation phonique cloison)6,9375 m2224,9 €49,8 €PROVISOIRE
Vis TRPB 25mm (plaque sur métal)168,0 u19,9 €9,9 €PROVISOIRE
Bande à joint papier8,4 ml14,9 €4,9 €PROVISOIRE
Enduit à joint poudre2,64 kg116,9 €16,9 €PROVISOIRE
Implantation, pose des rails et des montants2,0 h—prix inconnu—PROVISOIRE
Pose des plaques, 2 faces2,8 h—prix inconnu—PROVISOIRE
Bandes et enduit, 2 passes + poncage2,4 h—prix inconnu—PROVISOIRE
Encadrement d'ouverture (par porte)0,75 h—prix inconnu—PROVISOIRE

2.2 La chaîne de provenance d'une seule ligne, en entier

Ligne ba13_faces — Plaque de plâtre BA13 standard 13mm :

  1. Formule de la recette — 2 * (longueur_m * hauteur_m - nb_portes * largeur_porte_m * hauteur_porte_m)
  2. Entrées — longueur_m = 3,2, hauteur_m = 2,5, nb_portes = 1, largeur_porte_m = 0,83, hauteur_porte_m = 2,04
  3. Quantité brute — 12,6136 m² (les deux faces, ouverture de porte déduite)
  4. Perte appliquée — calepinage_plaques (calepinage), valeur 12,5 %.
    Calepinage en rangees verticales de plaques de 1,20 m de large : la derniere plaque est recoupee, la chute est fonction de la longueur, pas un taux plat. [formule: (ceil(longueur_m / largeur_plaque_m) * largeur_plaque_m) / longueur_m - 1]
  5. Quantité retenue — 14,1903 m²
  6. Conditionnement — plaque de 3,0 m² → 5 plaques
  7. Prix — 5 plaques × 8,1 € = 40,5 €
  8. Source — regle de l'art: DTU 25.41 — 1 plaque BA13 par face, 2 faces. · statut PROVISOIRE

Ce calcul est écrit à la main dans la docstring du test qui garde le moteur (backend/tests/test_assemblies_moteur.py) : aucune valeur attendue n'y est recopiée depuis la sortie du moteur. Extrait réel :

CAS DE RÉFÉRENCE CLOISON — mur de 3,20 m × 2,50 m = 8,00 m², 1 porte 0,83 × 2,04 m
=================================================================================
Recette `data/assemblies/exemples/cloison_72_48.json`, catalogue
`data/materiaux_second_oeuvre.json` (coef_chute et conditionnements cités ligne à ligne).

  surface brute      3,20 × 2,50                                  = 8,0000 m²
  ouverture porte    0,83 × 2,04                                  = 1,6932 m²
  surface nette      8,0000 − 1,6932                              = 6,3068 m²

  BA13 (2 faces)     2 × 6,3068                                   = 12,6136 m²
    calepinage       ceil(3,20/1,20) = 3 plaques → 3 × 1,20 = 3,60 m posés
                     3,60/3,20 − 1                                = 12,5 %   (remplace le
                     coef_chute catalogue de 10 % : remplace_coef_materiau = true)
    avec chute       12,6136 × 1,125                              = 14,1903 m²
    conditionnement  plaque de 3 m² → 14,1903/3 = 4,7301 → ceil    = 5 PLAQUES

  Rail 48            2 × 3,20 (rail haut + rail bas)              = 6,4000 ml
    coef catalogue   rail_48 coef_chute = 0,05 → 6,40 × 1,05      = 6,7200 ml
    conditionnement  barre de 3 m → 6,72/3 = 2,24 → ceil           = 3 BARRES

  Montants courants  (ceil(3,20/0,60) = 6, +1 de rive) = 7 montants × 2,50
                                                                  = 17,5000 ml
  Montants encadr.   1 porte × (2 × 2,50 + 0,83)                  = 5,8300 ml
    chute barre      ceil(2,50/2,60) = 1 barre → 2,60/2,50 − 1     = 4 %
                     17,50 × 1,04 = 18,2000 ml → /2,60 = 7,00     = 7 BARRES
                      5,83 × 1,04 =  6,0632 ml → /2,60 = 2,3320   = 3 BARRES
                     total montant_48                              = 10 BARRES

  Laine 45           6,3068 m² (surface nette, porte déduite)
    coef catalogue   0,10 → 6,3068 × 1,10                         = 6,9375 m²
    conditionnement  paquet de 5,4 m² → 1,2847 → ceil              = 2 PAQUETS

  Visserie           20 × 8,00 = 160 u ; ×1,05 = 168 → boîte 1000  = 1 BOÎTE
  Bande              1 × 8,00 = 8,00 ml ; ×1,05 = 8,40 → rouleau 75 = 1 ROULEAU
  Enduit             0,3 × 8,00 = 2,40 kg ; ×1,10 = 2,64 → sac 25  = 1 SAC

  Total matériaux    5×8,10 + 3×5,50 + 7×5,90 + 3×5,90 + 2×24,90
                     + 1×9,90 + 1×4,90 + 1×16,90
                   = 40,50 + 16,50 + 41,30 + 17,70 + 49,80 + 9,90 + 4,90 + 16,90
                                                                  = 197,50 €
  Main-d'œuvre       8,00 m² × (0,25 + 0,35 + 0,30) = 7,20 h
                     + 0,75 h × 1 porte (temps global)             = 7,95 h

2.3 Marché container — ouverture avec cadre de renfort sur un 20 pieds

Paramètres : largeur_ouverture_m 2,0 · hauteur_ouverture_m 2,1 · type_container 20ft. Le moteur rend 9 lignes et 18,62 h de main-d'œuvre, mais aucun total en euros : les quatre références matériaux de cet ouvrage n'existent pas dans le catalogue rénovation, et le moteur refuse de composer un total incomplet.

LigneQuantitéUnités de ventePrix unitaireTotal Statut
tube_acier_60x40_3mm9,072 ml—prix inconnu—INTROUVABLE
disque_tronconnage_2304,0 u—prix inconnu—INTROUVABLE
fil_fourre_mag_1_21,312 kg—prix inconnu—INTROUVABLE
primaire_epoxy_antirouille1,476 L—prix inconnu—INTROUVABLE
poste_grutage_camion_grue_demi_journee1,0 forfait—prix inconnu—INTROUVABLE
Tracage et decoupe de la tremie4,92 h—prix inconnu—PROVISOIRE
Debit, presentation et soudure du cadre de renfort8,2 h—prix inconnu—PROVISOIRE
Preparation et application du primaire anticorrosion1,5 h—prix inconnu—PROVISOIRE
Manutention et calage pendant grutage4,0 h—prix inconnu—PROVISOIRE

Avertissements produits par le moteur lui-même :

2.4 Le défaut connu, mesuré, et affiché ici volontairement

La recette de cloison migrée en base (les 40 ouvrages, migrations/2026-08-01_materiaux_ouvrages.sql ligne 168) compte les montants d'ossature avec un ratio plat de 1,67 mètre par m² — exact pour un mur infiniment long, faux pour un mur court. Nous avons rejoué le même mur avec ce ratio :

Ratio v0 (1,67 ml/m²)13,36 ml
Formule géométrique v1, montants courants 17,5 ml
Écart sur le poste « montants courants » +31,0 %
v1 avec l'encadrement de porte (inexprimable en v0) 23,33 ml (+74,6 %)
Total matériaux du mur : v0 → v1 173,9 € → 197,5 € (+13,6 %)

La mesure documentée dans le dossier (BRIEF-01-AVANCEMENT.md) annonce 31 % d'erreur sur le poste et 6,5 % sur le prix total — notre run reproduit exactement les 31 % sur les montants courants, et mesure +13,6 % sur le total une fois compté l'encadrement de porte, que la recette v0 ne sait pas exprimer du tout. L'erreur est maximale entre 2 et 5 mètres : la rénovation courante.

Et la tolérance de ±5 % que nous nous sommes fixée n'a jamais été validée par un professionnel. C'est l'une des trois questions à trancher aujourd'hui.

Le moteur refuse par ailleurs de se déclarer opposable tant qu'aucun calcul vérifié n'a tourné. Avertissements du BOM cloison :

Tests — exécutée le 2026-08-31 10:45:27 CESTcd $SCRATCH/demo-zf/backend && .venv-fabrik/bin/python -m pytest tests/ -q -p no:randomly
3333 passed, 3 skipped, 12 warnings in 31.08s

Dont 78 tests pour le moteur d'ouvrages et son schéma (test_assemblies_moteur.py + test_assemblies_schema.py).

Ce qui manque encore

3. IMAGEin — un client ne voit rien de ce qui appartient à un autre

Pour un architecte : c'est la condition d'entrée pour vendre le produit à plus d'un client. Un client B qui connaît l'identifiant d'un bien du client A doit se heurter à un mur, sur toutes les portes, pas seulement sur la porte principale.

FAIT ET VÉRIFIÉ RÉEL

Commande — exécutée le 2026-08-31 10:45:27 CESTcd $SCRATCH/demo-aq/imagein/backend && .venv_scratch/bin/python -m pytest tests/test_isolation.py -v
============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-8.3.4, pluggy-1.6.0 -- /home/arthur/repos/artqad-saas/imagein/backend/.venv_scratch/bin/python
cachedir: .pytest_cache
rootdir: /tmp/claude-1000/-home-arthur/89b8efba-d18f-4bf4-922d-643f9e3ae3b3/scratchpad/demo-aq/imagein/backend
configfile: pytest.ini
plugins: anyio-4.14.1, cov-7.1.0
collecting ... collected 15 items

tests/test_isolation.py::test_tenant_b_gets_404_on_every_project_surface_of_a PASSED [  6%]
tests/test_isolation.py::test_listing_of_b_contains_no_project_of_a PASSED [ 13%]
tests/test_isolation.py::test_owner_sees_own_project PASSED              [ 20%]
tests/test_isolation.py::test_owner_ref_in_payload_is_ignored_on_create PASSED [ 26%]
tests/test_isolation.py::test_owner_ref_in_payload_is_ignored_on_patch PASSED [ 33%]
tests/test_isolation.py::test_no_key_keeps_previous_behaviour PASSED     [ 40%]
tests/test_isolation.py::test_legacy_null_owner_project_is_reclaimed PASSED [ 46%]
tests/test_isolation.py::test_require_key_rejects_anonymous PASSED       [ 53%]
tests/test_isolation.py::test_unknown_or_revoked_key_is_401 PASSED       [ 60%]
tests/test_isolation.py::test_key_is_never_stored_in_clear PASSED        [ 66%]
tests/test_isolation.py::test_share_token_reads_its_project_only PASSED  [ 73%]
tests/test_isolation.py::test_share_token_hides_owner_identity PASSED    [ 80%]
tests/test_isolation.py::test_share_token_forbids_every_write PASSED     [ 86%]
tests/test_isolation.py::test_expired_share_token_is_401 PASSED          [ 93%]
tests/test_isolation.py::test_revoked_share_token_is_401 PASSED          [100%]

============================== 15 passed in 0.70s ==============================

3.1 Les 19 surfaces testées, extraites du test lui-même

Chacune est appelée avec la clé du client B sur un bien du client A, et doit répondre 404. Pas 403 : un 403 dirait « ça existe, mais ce n'est pas à vous ». Un 404 ne dit rien du tout — le client B n'apprend même pas que le bien existe.

    surfaces = [
        ("GET", f"/projects/{pid}", {}),
        ("PATCH", f"/projects/{pid}", {"json": {"name": "volé"}}),
        ("GET", f"/projects/{pid}/plan", {}),
        ("PUT", f"/projects/{pid}/plan", {"json": _PLAN}),
        ("POST", f"/projects/{pid}/items", {"json": {"catalog_product_id": "x"}}),
        ("GET", f"/projects/{pid}/items", {}),
        ("DELETE", f"/projects/{pid}/items/{item_id}", {}),
        ("GET", f"/projects/{pid}/budget", {}),
        ("GET", f"/projects/{pid}/renders", {}),
        ("POST", f"/projects/{pid}/scans", {"json": {}}),
        ("GET", f"/projects/{pid}/scans", {}),
        ("GET", f"/projects/{pid}/scans/{sid}", {}),
        ("POST", f"/projects/{pid}/scans/{sid}/upload",
         {"files": {"file": ("x.ply", b"ply", "application/octet-stream")}}),
        ("POST", f"/projects/{pid}/scans/{sid}/process", {}),
        ("GET", f"/projects/{pid}/scans/{sid}/splat", {}),
        ("POST", f"/scans/{sid}/detect", {}),
        ("GET", f"/scans/{sid}/detections", {}),
        ("POST", "/renders/photoreal",
         {"json": {"image_base64": TINY_PNG_B64, "project_id": pid, "scan_id": sid}}),
        ("POST", "/renders/photoreal", {"json": {"image_base64": TINY_PNG_B64, "project_id": pid}}),
    ]

Le test vérifie ensuite que le bien du client A est intact : ni renommé, ni vidé de son mobilier. Les 14 autres tests couvrent le jeton de partage qui ne lit que son seul projet, le jeton expiré ou révoqué qui rend 401, la clé jamais stockée en clair, et l'identifiant de propriétaire envoyé dans le corps de la requête, qui est ignoré à la création comme à la modification.

3.2 Le moteur de plans, rejoué hors ligne

Commande — exécutée le 2026-08-31 10:45:27 CESTcd $SCRATCH/demo-aq/imagein/web && npx --offline tsx scripts/check-plan-engine.ts
Rendu 11 plans (35 niveaux) dans plan-engine-out/
OK — validatePlan (plan-engine) : 0 violation sur 35 niveau(x).

Un des 35 niveaux rendus, inséré ici tel quel (dessin vectoriel, aucune image chargée depuis l'extérieur) :

CHAMBRE 173,1 m²CHAMBRE 273,1 m²CHAMBRE 373,1 m²SALLE DE BAIN40,2 m²PALIER29,3 m²10,185,754,1820,117,000,187,1814,36maquette-2 — R+1 · surface 288,9 m²éch. 1:100
Tests — exécutée le 2026-08-31 10:45:27 CESTcd $SCRATCH/demo-aq/imagein/backend && .venv_scratch/bin/python -m pytest tests/ -q
284 passed in 3.96s

Ce qui manque encore

4. Studio OS — huit situations qui coûtent de l'argent, détectées sans IA

Pour un gérant d'agence : le logiciel relit tous les jours les projets, les phases, les factures, les paiements et le planning, et sort la liste de ce qui dérape. Huit règles, écrites en dur, sans appel à un modèle de langage : donc sans coût par requête, sans latence, et avec un résultat identique d'un jour à l'autre pour les mêmes données.

FAIT ET VÉRIFIÉ RÉEL

Commande — exécutée le 2026-08-31 10:45:27 CESTcd $SCRATCH/demo-aq/backend && $SCRATCH/venv-studio/bin/python demo-sorties/demo_studio.py . demo-sorties/

Une agence fictive de cinq personnes a été peuplée pour déclencher les huit règles à la fois (date de référence : 26 août 2026). Sortie réelle de run_rules() — 11 alertes :

RègleNiveauMessage rendu
budget_overrunREDCoûts à 150% des honoraires
overdue_invoiceREDFacture #F-2026-007 en retard de 12 jours
invoice_gapORANGEAvancement 100% mais facturé seulement 0%
phase_lateORANGEPhase Phase PRO en retard : échéance 2026-08-11, avancement 40%
invoice_gapORANGEAvancement 50% mais facturé seulement 0%
invoice_gapORANGEAvancement 40% mais facturé seulement 0%
slow_clientORANGEVille de Bordeaux : délai de paiement moyen de 70 jours (seuil 45 jours)
overloadORANGEMarie D. : 6.0 j planifiés pour 5.0 j de capacité (semaine du 2026-08-24)
margin_declineORANGEMarge en baisse 4 mois consécutifs : 18000 € → -18000 €
missing_invoice_on_milestoneORANGEJalon atteint sur Phase APD (Projet 2026-008-MAISON-CAUDERAN) mais aucune facture émise
missing_invoice_on_milestoneORANGEJalon atteint sur Phase PRO (Projet 2026-008-MAISON-CAUDERAN) mais aucune facture émise

Trois lectures utiles. Une : la marge du mois en cours ressort négative parce que 18 000 € de sous-traitance ont été engagés sans facturation en face — c'est exactement ce que la règle sert à voir. Deux : la phase PRO déclenche « jalon atteint » non parce qu'elle est terminée, mais parce que son échéance est dépassée et qu'aucune facture ne la touche. Trois : les messages sont des gabarits que chaque agence peut réécrire, seuils compris.

Et le résumé quotidien, build_digest(), qui ne garde que les trois problèmes les plus graves :

: les 3 problemes du jour ---
digest_date    : 2026-08-26
findings_count : 11
items          : 3
11 problème(s) détecté(s) le 2026-08-26.
1. [RED] Coûts à 150% des honoraires
2. [RED] Facture #F-2026-007 en retard de 12 jours
3. [ORANGE] Avancement 100% mais facturé seulement 0%
Tests — exécutée le 2026-08-31 10:45:27 CESTcd $SCRATCH/demo-aq/backend && $SCRATCH/venv-studio/bin/python -m pytest tests/test_ai_rules.py -q
30 passed, 3 warnings in 48.89s
Honnêteté sur ce chiffre. 30 est le nombre de tests de tests/test_ai_rules.py, et c'est le seul chiffre citable pour Studio OS. La suite complète du backend ne tourne pas hors PostgreSQL : mesurée aujourd'hui, elle donne 73 échecs, 202 succès et 217 erreurs de collecte, et deux modules ne se collectent même pas. Aucune affirmation de ce document ne porte sur cette suite complète.

Ce qui manque encore

5. Visite virtuelle 3D — rien à montrer aujourd'hui

Ce que c'est : se promener dans le relevé 3D d'un logement existant, depuis un navigateur, sans rien installer.

ÉCRIT, PAS INTÉGRÉ NON DÉMONTRABLE HORS LIGNE

Pourquoi rien n'est montré : la correction d'isolation d'IMAGEin (§3) a fermé l'accès direct au fichier de nuage de points, dont la visite avait besoin. Le correctif est identifié — une URL signée à durée limitée pour ce seul fichier — mais il n'est pas écrit. Montrer une visite aujourd'hui reviendrait à montrer la version d'avant l'isolation, c'est-à-dire une version qu'on ne peut pas vendre.

6. Ce qui ne peut pas être démontré aujourd'hui, et pourquoi

SujetStatutPourquoi rien n'est montré
Visite virtuelle 3D ÉCRIT, PAS INTÉGRÉ Cassée par l'isolation IMAGEin. Correctif identifié : URL signée pour le fichier de nuage de points. Non écrit à ce jour.
IA designer, rendus photoréalistes SPÉCIFIÉ Passent par une interface payante (fal.ai), interdite dans cette démonstration. Et surtout : aucun architecte d'intérieur n'a encore jugé ces propositions à l'aveugle contre un travail humain. Tant que ce jugement n'existe pas, le module est invendable, quelle que soit la qualité des images.
Lecture d'un vrai règlement de PLU par modèle de langage ÉCRIT, PAS INTÉGRÉ La démonstration du §1 tourne avec un extracteur de test. Le run réel exige une clé d'API plafonnée à 5 $ — geste administratif non fait.
Fiabilité annoncée de PLU+ PAS COMMENCÉ Aucun taux ne peut être publié tant qu'un architecte n'a pas rédigé la bonne réponse sur 50 à 100 dossiers réels. C'est la condition de mise en vente du rapport à l'unité comme de l'abonnement (décision D3).
Trousseau / atelier-core (briques partagées entre les produits) ÉCRIT, PAS INTÉGRÉ Lu, pas exécuté dans cette démonstration. Aucune sortie n'est présentée, et rien ici ne repose dessus.
Mise en ligne PAS COMMENCÉ Rien de tout ce qui précède n'est déployé. Deux dépôts attendent le feu vert d'Arthur ; tout ce que montre cette page tourne en local.

7. Tous les chiffres cités, avec la commande qui les produit

ChiffreCommande (depuis un clone jetable)
PLU+ — 438 passed, 1 skipped PYTHONPATH=. .venv-plu/bin/python -m pytest tests/test_plu_plus_*.py tests/test_plu_phase2*.py tests/test_plu_parcelle_reelle.py -q
dont 5 états — 39 passed … -m pytest tests/test_plu_plus_etats.py -q
dont raisonnement projet — 27 passed … -m pytest tests/test_plu_plus_project_reasoner.py -q
Ze Fabrik — 3333 passed, 3 skipped cd backend && .venv-fabrik/bin/python -m pytest tests/ -q -p no:randomly
dont moteur d'ouvrages — 78 passed … -m pytest tests/test_assemblies_moteur.py tests/test_assemblies_schema.py -q -p no:randomly
IMAGEin — 284 passed cd imagein/backend && .venv_scratch/bin/python -m pytest tests/ -q
dont isolation — 15 passed … -m pytest tests/test_isolation.py -v
Studio OS — 30 passed (seul chiffre citable) cd backend && venv-studio/bin/python -m pytest tests/test_ai_rules.py -q
BOM cloison — 197,50 € / 7,95 h / 12 lignes .venv-fabrik/bin/python demo-sorties/demo_fabrik.py backend/ demo-sorties/
Écart du ratio v0 — +31,0 % sur les montants courants même commande, section DEFAUT CONNU
Plans IMAGEin — 11 plans, 35 niveaux, 0 violation npx --offline tsx scripts/check-plan-engine.ts

Sur quel code ces chiffres ont été mesurés : artqad-saas commit 8383c291 augmenté des trois lots livrés la veille (correctif des fausses contradictions PLU+, raisonnement par projet, IA opératrice de Studio OS), et ze-fabrik commit d5a0adb. Les dépôts de travail avancent sous d'autres sessions ; les mesures, elles, tournent sur des clones figés sur ces deux empreintes, et ne sont donc pas affectées. Aucun fichier suivi de ces dépôts n'a été modifié : bash verifier-demo.sh le contrôle aussi. Sorties brutes complètes, rapports HTML entiers et scripts de démonstration : dossier demo-sorties/ à côté de cette page.