feat(r5): maquettes HD IA — 6 écrans à valider, l'IA propose, l'humain valide

Design d'abord : aucune ligne de code apps/ai avant validation.
Assistant RAG sourcé (citations numérotées → document/page/extrait
exact, ouvrables), refus explicite hors corpus (anti-hallucination
visible), suggestion de codes de bilan web + mobile (codes existants
seulement, pré-remplissage « suggéré », enregistrement humain), corpus
& ingestion administrable (bibliothèque R3 + bilans codés, exclusion
réversible, bandeau 09-08), voix en option (opt-in, transcription
relue, audio purgé immédiatement). Bi-thème, tokens répliqués.

5 décisions soumises avec les écrans : aucune écriture automatique,
sourcé ou silencieux, corpus fermé et visible, anonymisation à
l'ingestion (09-08), voix purgée. ADR-004 (modèles/embeddings) au
lancement du socle R5.1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
pr-daaif
2026-07-17 11:37:28 +01:00
parent a5e8ca6d62
commit 199fce69d0
3 changed files with 593 additions and 1 deletions

View File

@@ -59,5 +59,6 @@ pnpm + Turborepo. `apps/api` : NestJS, Prisma, PostgreSQL (pgvector + PostGIS),
- **R4.2 — terrain en ligne** : scanner QR réel (expo-camera, `analyseScan` testée, résolution locale D4, QR étrangers refusés), fiche ascenseur (D3, historique scopé), fiche OT (machine à états, coûts figés, garde par `closureBlockers` API), clôture terrain (bilan 6 champs au pouce), préventif grille cochable (appui long = N/A, `aria-checked`). Écritures en ligne assumées (bandeaux) la file est R4.3. Vérifié 12/12 en Expo web (dont clôture complète d'un OT de test), 12 tests jest-expo.
- **R4.3 — file & verrou** : verrou optimiste serveur (`baseUpdatedAt` 409 contextualisé, toute écriture avance la version, web inchangé, ADR-003 sécurité/routage mobile) ; file persistée rejouée dans l'ordre (propagation de version intra-lot, arrêt sur conflit, patchs optimistes, photos D5 compressées en file), écran Synchro & conflits (rejouer sur version à jour / abandonner), préchargement parc+référentiels, purge complète à la déconnexion. Recette « mode avion » 13/13 en Expo web (conflit tranché par l'humain, serveur DONE + bilan), 17 tests jest-expo, 74 tests API.
- 🏁 **R4 CLOSE (17/07/2026, tag `release/r4`)** : posé sur décision du référent avec la recette « mode avion » validée 13/13 en Expo web piloté ; **la recette sur téléphone (Expo Go — vrai mode avion, scan caméra) est reportée et reste due avant toute production client mobile**.
- 🔄 **Reprise ici** : R5 IA design d'abord : maquettes (assistant RAG sourcé, suggestion de codes de bilan) + décisions à acter, AUCUN code `apps/ai` avant validation. Restes : recette R4 sur appareil, redéploiement Dokploy de `release/r3`.
- **R5 — maquettes rédigées** (17/07) : `maquette-r5.html`, 6 écrans (assistant RAG à citations sources document/page/extrait, refus explicite hors corpus, suggestion de bilan web+mobile à validation humaine, corpus & ingestion administrable, voix opt-in avec purge) + 5 décisions à acter (aucune écriture automatique, sourcé ou silencieux, corpus fermé, anonymisation 09-08, voix purgée).
- 🔄 **Reprise ici** : validation des maquettes + 5 décisions R5 par le référent R5.1 socle `apps/ai` (FastAPI/uv, ADR-004 modèles/embeddings pgvector). Restes : recette R4 sur appareil, redéploiement Dokploy de `release/r3`.
- Détail quotidien : `docs/journal/journal.md`. Dépôt : `siop-spelev/siop2` (privé), jalons R0R5.

View File

@@ -0,0 +1,576 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SIOP V2 — Maquettes HD · R5 IA</title>
</head>
<body>
<!--
SIOP V2 — Maquettes HD de la release R5 « IA » (design-first).
À VALIDER PAR LE RÉFÉRENT AVANT TOUT CODE `apps/ai` (principe n°1).
Deux capacités (cadrage) : assistant RAG qui CITE SES SOURCES, et
suggestion de codes de bilan depuis une description libre. Voix : si
budget temps, avec purge de l'audio (loi 09-08).
Principe permanent : L'IA PROPOSE, L'HUMAIN VALIDE — aucune écriture
automatique. Tokens répliqués de ../tokens.css, bi-thème.
-->
<style>
/* ═══ Tokens (répliques de ../tokens.css) ═══ */
:root{
--primaire:#1f4fb8;--primaire-actif:#1a439c;--primaire-doux:#eaf0fb;
--safran:#dd8a0b;--safran-doux:#fdf3e3;
--fond:#f5f7fa;--surface:#ffffff;--surface-2:#eef2f7;
--bordure:#dce3ec;--bordure-forte:#b9c4d4;
--encre:#1b2534;--encre-2:#55647a;--encre-3:#8494ab;
--st-ouvert:#3d6fe0;--st-ouvert-fond:#e9effc;--st-encours:#6d5bd8;--st-encours-fond:#efecfa;
--st-attente:#b96f07;--st-attente-fond:#fbf1df;--st-termine:#178a50;--st-termine-fond:#e6f5ec;
--prio-bloque:#d92626;--prio-bloque-fond:#fdeaea;
--succes:#178a50;--alerte:#b96f07;--danger:#d92626;--info:#3d6fe0;
--nav-fond:#16233b;--nav-encre:#c6d2e4;--nav-encre-vif:#ffffff;--nav-bordure:#24344f;
--police-ui:"Manrope","Avenir Next","Segoe UI Variable",system-ui,sans-serif;
--rayon:10px;--rayon-controle:8px;--ombre-menu:0 8px 24px rgb(16 30 54/.14);
}
@media (prefers-color-scheme:dark){:root{
--primaire:#6e92e8;--primaire-actif:#8facf0;--primaire-doux:#1d2c4c;
--safran:#e89a1f;--safran-doux:#33270f;
--fond:#0f1622;--surface:#182234;--surface-2:#1e2a40;
--bordure:#2b3850;--bordure-forte:#3d4d6b;
--encre:#e8edf5;--encre-2:#a7b4c8;--encre-3:#6d7d96;
--st-ouvert:#7da2ee;--st-ouvert-fond:#1c2a47;--st-encours:#a394ec;--st-encours-fond:#262040;
--st-attente:#e0a33c;--st-attente-fond:#322510;--st-termine:#4bc084;--st-termine-fond:#12301f;
--prio-bloque:#f26d6d;--prio-bloque-fond:#3a1414;
--succes:#4bc084;--alerte:#e0a33c;--danger:#f26d6d;--info:#7da2ee;
--nav-fond:#0c1524;--nav-encre:#a7b4c8;--nav-encre-vif:#f2f6fc;--nav-bordure:#1e2c44;
--ombre-menu:0 8px 24px rgb(0 0 0/.45);
}}
:root[data-theme="light"]{
--primaire:#1f4fb8;--primaire-actif:#1a439c;--primaire-doux:#eaf0fb;
--safran:#dd8a0b;--safran-doux:#fdf3e3;
--fond:#f5f7fa;--surface:#ffffff;--surface-2:#eef2f7;
--bordure:#dce3ec;--bordure-forte:#b9c4d4;
--encre:#1b2534;--encre-2:#55647a;--encre-3:#8494ab;
--st-ouvert:#3d6fe0;--st-ouvert-fond:#e9effc;--st-encours:#6d5bd8;--st-encours-fond:#efecfa;
--st-attente:#b96f07;--st-attente-fond:#fbf1df;--st-termine:#178a50;--st-termine-fond:#e6f5ec;
--prio-bloque:#d92626;--prio-bloque-fond:#fdeaea;
--succes:#178a50;--alerte:#b96f07;--danger:#d92626;--info:#3d6fe0;
--nav-fond:#16233b;--nav-encre:#c6d2e4;--nav-encre-vif:#ffffff;--nav-bordure:#24344f;
--ombre-menu:0 8px 24px rgb(16 30 54/.14);
}
:root[data-theme="dark"]{
--primaire:#6e92e8;--primaire-actif:#8facf0;--primaire-doux:#1d2c4c;
--safran:#e89a1f;--safran-doux:#33270f;
--fond:#0f1622;--surface:#182234;--surface-2:#1e2a40;
--bordure:#2b3850;--bordure-forte:#3d4d6b;
--encre:#e8edf5;--encre-2:#a7b4c8;--encre-3:#6d7d96;
--st-ouvert:#7da2ee;--st-ouvert-fond:#1c2a47;--st-encours:#a394ec;--st-encours-fond:#262040;
--st-attente:#e0a33c;--st-attente-fond:#322510;--st-termine:#4bc084;--st-termine-fond:#12301f;
--prio-bloque:#f26d6d;--prio-bloque-fond:#3a1414;
--succes:#4bc084;--alerte:#e0a33c;--danger:#f26d6d;--info:#7da2ee;
--nav-fond:#0c1524;--nav-encre:#a7b4c8;--nav-encre-vif:#f2f6fc;--nav-bordure:#1e2c44;
--ombre-menu:0 8px 24px rgb(0 0 0/.45);
}
/* ═══ Base ═══ */
*{box-sizing:border-box;margin:0}
html,body{background:var(--fond)}
body{font-family:var(--police-ui);color:var(--encre);font-size:14px;line-height:1.5}
button{font:inherit;cursor:pointer;border:0;background:none;color:inherit}
button:focus-visible,a:focus-visible{outline:2px solid var(--primaire);outline-offset:2px;border-radius:4px}
.num{font-variant-numeric:tabular-nums}
/* ═══ Barre de revue ═══ */
.revue{position:sticky;top:0;z-index:50;display:flex;align-items:center;gap:12px;flex-wrap:wrap;
padding:10px 16px;background:var(--nav-fond);color:var(--nav-encre);font-size:13px}
.revue b{color:var(--nav-encre-vif);letter-spacing:.02em}
.revue .onglets{display:flex;gap:4px;flex-wrap:wrap}
.revue .onglets button{padding:6px 10px;border-radius:6px;color:var(--nav-encre)}
.revue .onglets button:hover{background:rgb(255 255 255/.08);color:var(--nav-encre-vif)}
.revue .onglets button[aria-selected="true"]{background:rgb(255 255 255/.12);color:var(--nav-encre-vif);
box-shadow:inset 3px 0 0 var(--safran)}
.revue .droite{margin-left:auto}
.revue .theme{padding:6px 10px;border:1px solid var(--nav-bordure);border-radius:6px}
.note-ecran{max-width:1180px;margin:14px auto 0;padding:0 20px;color:var(--encre-2);font-size:13px}
.note-ecran b{color:var(--encre)}
/* ═══ Coquille web (simplifiée — la vraie est celle des releases passées) ═══ */
.ecran{display:none;max-width:1180px;margin:14px auto 44px;padding:0 20px}
.ecran.actif{display:block}
.app{display:grid;grid-template-columns:210px 1fr;min-height:680px;border:1px solid var(--bordure);
border-radius:14px;overflow:hidden;background:var(--fond)}
.nav{background:var(--nav-fond);color:var(--nav-encre);padding:16px 0;font-size:13px}
.nav .logo{display:flex;align-items:center;gap:8px;padding:0 16px 14px;color:var(--nav-encre-vif);
font-weight:800;font-size:17px;letter-spacing:.04em}
.nav .logo i{color:var(--safran);font-style:normal}
.nav .groupe{padding:10px 16px 3px;font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:#6b7f9e}
.nav a{display:block;padding:7px 16px;color:var(--nav-encre);text-decoration:none;border-left:3px solid transparent}
.nav a.actif{background:rgb(255 255 255/.09);color:var(--nav-encre-vif);border-left-color:var(--safran)}
.contenu{padding:18px 20px;display:flex;flex-direction:column;gap:12px}
.entete{display:flex;align-items:center;gap:10px}
.entete h2{font-size:18px}
.entete .fin{margin-left:auto;font-size:12px;color:var(--encre-3)}
.carte{background:var(--surface);border:1px solid var(--bordure);border-radius:var(--rayon);padding:14px}
.carte h3{font-size:10.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--encre-2);margin-bottom:8px}
.btn{display:inline-flex;align-items:center;gap:6px;padding:8px 13px;border-radius:var(--rayon-controle);
border:1px solid var(--bordure-forte);font-weight:600;font-size:13px;background:var(--surface)}
.btn.prim{background:var(--primaire);border-color:var(--primaire);color:#fff}
.btn.ghost{border-color:transparent;color:var(--primaire)}
/* ═══ Assistant (chat sourcé) ═══ */
.chat{display:flex;flex-direction:column;gap:12px;max-width:760px}
.msg-q{align-self:flex-end;background:var(--primaire);color:#fff;border-radius:14px 14px 4px 14px;
padding:10px 14px;max-width:75%;font-size:13.5px}
.msg-r{background:var(--surface);border:1px solid var(--bordure);border-radius:14px 14px 14px 4px;
padding:12px 14px;max-width:88%;font-size:13.5px;display:flex;flex-direction:column;gap:10px}
.msg-r p b{color:var(--encre)}
.cite{display:inline-flex;align-items:center;justify-content:center;min-width:16px;height:16px;
border-radius:5px;background:var(--primaire-doux);color:var(--primaire);font-size:10.5px;font-weight:800;
vertical-align:2px;margin:0 1px;cursor:pointer}
.sources{display:flex;flex-direction:column;gap:6px;border-top:1px dashed var(--bordure);padding-top:10px}
.source{display:flex;gap:10px;align-items:flex-start;background:var(--surface-2);border-radius:9px;padding:8px 10px}
.source .no{flex:none;width:18px;height:18px;border-radius:5px;background:var(--primaire-doux);
color:var(--primaire);display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:800}
.source b{font-size:12.5px}
.source .ou{color:var(--encre-2);font-size:11.5px}
.source .extrait{color:var(--encre-2);font-size:12px;font-style:italic;border-left:2px solid var(--safran);
padding-left:8px;margin-top:3px}
.source .ouvrir{margin-left:auto;color:var(--primaire);font-weight:700;font-size:12px;white-space:nowrap}
.avert{display:flex;gap:8px;align-items:center;background:var(--safran-doux);color:var(--alerte);
border-radius:9px;padding:8px 10px;font-size:12px;font-weight:600}
.saisie-chat{display:flex;gap:8px;max-width:760px}
.saisie-chat input{flex:1;border:1.5px solid var(--bordure-forte);border-radius:10px;background:var(--surface);
padding:11px 13px;font:inherit;color:var(--encre)}
.refus{background:var(--surface);border:1.5px dashed var(--bordure-forte);border-radius:14px;
padding:12px 14px;max-width:88%;font-size:13.5px;display:flex;flex-direction:column;gap:8px}
.refus b{color:var(--encre)}
.refus .pourquoi{color:var(--encre-2);font-size:12.5px}
/* ═══ Suggestion de bilan ═══ */
.grille-2{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.zone-libre{width:100%;min-height:74px;border:1.5px solid var(--bordure-forte);border-radius:10px;
background:var(--surface);padding:10px 12px;font:inherit;font-size:13px;color:var(--encre)}
.suggestion{display:flex;gap:10px;align-items:flex-start;border:1.5px solid var(--primaire);
background:var(--primaire-doux);border-radius:10px;padding:10px 12px}
.suggestion .ia{flex:none;font-size:15px}
.suggestion b{font-size:13px}
.suggestion .just{color:var(--encre-2);font-size:12px}
.confiance{margin-left:auto;font-size:10.5px;font-weight:800;color:var(--primaire);white-space:nowrap}
.actions-sug{display:flex;gap:8px;margin-top:4px}
.champ{display:flex;flex-direction:column;gap:4px;font-size:12px}
.champ label{font-weight:700;color:var(--encre-2);font-size:11px}
.champ label em{color:var(--danger);font-style:normal}
.select{border:1.5px solid var(--bordure-forte);border-radius:9px;background:var(--surface);
padding:8px 10px;font-size:13px;color:var(--encre)}
.select.pre{border-color:var(--primaire);background:var(--primaire-doux);position:relative}
.select.pre::after{content:'suggéré';position:absolute;top:-8px;right:8px;font-size:9px;font-weight:800;
color:var(--primaire);background:var(--surface);padding:0 5px;border-radius:99px;border:1px solid var(--primaire)}
.select.vide{color:var(--encre-3)}
/* ═══ Corpus ═══ */
table{border-collapse:collapse;width:100%;font-size:13px}
th{text-align:left;font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--encre-2);
background:var(--surface-2);padding:8px 10px}
td{padding:8px 10px;border-top:1px solid var(--bordure)}
.st{font-size:10.5px;font-weight:700;padding:2px 8px;border-radius:999px;white-space:nowrap}
.st.ok{color:var(--st-termine);background:var(--st-termine-fond)}
.st.encours{color:var(--st-ouvert);background:var(--st-ouvert-fond)}
.st.exclu{color:var(--encre-3);background:var(--surface-2)}
.interrupteur{width:34px;height:19px;border-radius:99px;background:var(--succes);position:relative;display:inline-block}
.interrupteur::after{content:'';position:absolute;top:2px;right:2px;width:15px;height:15px;border-radius:50%;background:#fff}
.interrupteur.off{background:var(--bordure-forte)}
.interrupteur.off::after{right:auto;left:2px}
/* ═══ Téléphone (repris de maquette-r4) ═══ */
.tels{display:flex;gap:28px;justify-content:center;flex-wrap:wrap}
.tel{width:310px;border:1px solid var(--bordure-forte);border-radius:28px;overflow:hidden;background:var(--fond);
box-shadow:var(--ombre-menu);display:flex;flex-direction:column}
.tel .encoche{height:26px;background:var(--nav-fond);display:flex;justify-content:center;align-items:center}
.tel .encoche i{width:70px;height:7px;border-radius:999px;background:rgb(255 255 255/.18)}
.tel .legende{text-align:center;font-size:11.5px;font-weight:700;letter-spacing:.05em;
text-transform:uppercase;color:var(--encre-3);padding:8px;background:var(--surface-2)}
.ecran-tel{padding:14px;display:flex;flex-direction:column;gap:10px;min-height:540px}
.entete-tel{display:flex;align-items:center;gap:8px;font-weight:800;font-size:15px}
.entete-tel i{color:var(--safran);font-style:normal}
.carte-tel{background:var(--surface);border:1px solid var(--bordure);border-radius:12px;padding:12px;
display:flex;flex-direction:column;gap:8px;font-size:12.5px}
.carte-tel h4{font-size:10.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--encre-2)}
.btn-tel{display:flex;justify-content:center;align-items:center;gap:8px;padding:11px;border-radius:10px;
font-weight:700;font-size:13.5px;background:var(--primaire);color:#fff}
.btn-tel.contour{background:var(--surface);color:var(--primaire);border:1.5px solid var(--primaire)}
.chip-sug{display:inline-flex;align-items:center;gap:5px;border:1.5px solid var(--primaire);
background:var(--primaire-doux);color:var(--primaire);border-radius:999px;padding:4px 10px;
font-size:11.5px;font-weight:700}
.micro{width:52px;height:52px;border-radius:50%;background:var(--prio-bloque);color:#fff;display:flex;
align-items:center;justify-content:center;font-size:20px;align-self:center}
.onde{display:flex;gap:3px;align-items:center;justify-content:center;height:26px}
.onde i{width:3px;border-radius:2px;background:var(--primaire)}
</style>
<header class="revue">
<b>SIOP · Maquettes R5 — IA</b>
<nav class="onglets" role="tablist" aria-label="Écrans">
<button role="tab" aria-selected="true" data-cible="assistant">1 · Assistant sourcé</button>
<button role="tab" aria-selected="false" data-cible="sans-source">2 · Sans source = refus</button>
<button role="tab" aria-selected="false" data-cible="suggestion-bilan">3 · Suggestion de bilan (web)</button>
<button role="tab" aria-selected="false" data-cible="suggestion-mobile">4 · Suggestion (mobile)</button>
<button role="tab" aria-selected="false" data-cible="corpus">5 · Corpus & ingestion</button>
<button role="tab" aria-selected="false" data-cible="voix">6 · Voix (option)</button>
</nav>
<div class="droite"><button class="theme" id="btn-theme">Thème : auto</button></div>
</header>
<!-- ═══ 1 · ASSISTANT SOURCÉ ═══ -->
<p class="note-ecran" data-note="assistant"><b>Intention :</b> la recette type du cadrage, à l'écran.
Chaque affirmation porte ses <b>citations numérotées</b> ; chaque source montre le document (bibliothèque
R3), la page et l'<b>extrait exact</b>, avec « Ouvrir » vers le document. L'avertissement « l'IA propose »
est permanent, pas un disclaimer caché. L'assistant vit dans la sidebar (groupe Pilotage).</p>
<section class="ecran actif" id="assistant">
<div class="app">
<aside class="nav">
<div class="logo"><i></i> SIOP</div>
<div class="groupe">Pilotage</div>
<a href="#">Statistiques</a>
<a class="actif" href="#">Assistant</a>
<a href="#">Personnes</a>
</aside>
<div class="contenu">
<div class="entete">
<h2>Assistant</h2>
<span class="fin">répond UNIQUEMENT depuis votre bibliothèque et vos historiques</span>
</div>
<div class="chat">
<div class="msg-q">Quel couple de serrage pour les coulisseaux de guides du Gen2 ?</div>
<div class="msg-r">
<p>Pour l'Otis <b>Gen2 Premier</b>, la notice prescrit un couple de serrage de
<b>25 N·m</b> pour les vis de fixation des coulisseaux de guides
<span class="cite">1</span>, avec contrôle du jeu latéral à 0,5 mm maximum
<span class="cite">1</span>. Sur votre parc, ce réglage a été appliqué lors du
remplacement des coulisseaux de l'ascenseur A1 le 17 juillet
<span class="cite">2</span>.</p>
<div class="sources">
<div class="source">
<span class="no">1</span>
<div>
<b>Notice Otis Gen2 Premier.pdf</b>
<div class="ou">Bibliothèque · Asc. A1 · page 42, § « Guidage cabine »</div>
<div class="extrait">« Serrer les vis de fixation des coulisseaux au couple de 25 N·m ;
jeu latéral maximal admissible : 0,5 mm. »</div>
</div>
<a class="ouvrir" href="#">Ouvrir p. 42</a>
</div>
<div class="source">
<span class="no">2</span>
<div>
<b>OT-2026-0341 — Bruit anormal en gaine</b>
<div class="ou">Historique · clôturé le 17/07/2026 · bilan : Guides / Remplacement pièce</div>
<div class="extrait">« Coulisseau de guide 16 mm × 2 — frottement guides, remplacement effectué. »</div>
</div>
<a class="ouvrir" href="#">Ouvrir l'OT</a>
</div>
</div>
<div class="avert">⚠ L'IA propose, vous validez : vérifiez la notice avant d'agir sur l'appareil.</div>
</div>
</div>
<div class="saisie-chat">
<input placeholder="Poser une question (notices, historiques, procédures)…">
<button class="btn prim">Envoyer</button>
</div>
</div>
</div>
</section>
<!-- ═══ 2 · SANS SOURCE = REFUS ═══ -->
<p class="note-ecran" data-note="sans-source" hidden><b>Intention :</b> l'anti-hallucination rendue
VISIBLE : quand le corpus ne porte pas la réponse, l'assistant le dit, montre ce qu'il a cherché, et
propose l'action utile (téléverser la notice manquante dans la bibliothèque R3). Jamais de réponse
inventée « pour faire plaisir ».</p>
<section class="ecran" id="sans-source">
<div class="app">
<aside class="nav">
<div class="logo"><i></i> SIOP</div>
<div class="groupe">Pilotage</div>
<a href="#">Statistiques</a>
<a class="actif" href="#">Assistant</a>
<a href="#">Personnes</a>
</aside>
<div class="contenu">
<div class="entete"><h2>Assistant</h2></div>
<div class="chat">
<div class="msg-q">Procédure de remplacement du variateur de fréquence du monte-charge KONE ?</div>
<div class="refus">
<b>Je ne trouve pas de source fiable dans votre bibliothèque — je préfère ne pas inventer.</b>
<div class="pourquoi">J'ai cherché dans 6 documents indexés et 214 bilans d'intervention :
aucune notice KONE, aucun historique de variateur sur le monte-charge MC-1.</div>
<div class="actions-sug">
<button class="btn prim">Téléverser la notice KONE dans la bibliothèque</button>
<button class="btn">Reformuler ma question</button>
</div>
</div>
</div>
<div class="saisie-chat">
<input placeholder="Poser une question…">
<button class="btn prim">Envoyer</button>
</div>
</div>
</div>
</section>
<!-- ═══ 3 · SUGGESTION DE BILAN (WEB) ═══ -->
<p class="note-ecran" data-note="suggestion-bilan" hidden><b>Intention :</b> le technicien (ou le
dispatcher) décrit la panne en français libre — l'IA propose les codes du bilan R2 avec sa
<b>justification</b> et sa confiance. « Appliquer » PRÉ-REMPLIT les sélecteurs (liseré « suggéré ») —
rien n'est enregistré tant que l'humain n'a pas cliqué « Enregistrer le bilan ». Les référentiels
restent la seule vérité : l'IA ne peut suggérer QUE des codes existants.</p>
<section class="ecran" id="suggestion-bilan">
<div class="app">
<aside class="nav">
<div class="logo"><i></i> SIOP</div>
<div class="groupe">Exploitation</div>
<a class="actif" href="#">Ordres de travail</a>
<a href="#">Demandes</a>
</aside>
<div class="contenu">
<div class="entete">
<h2>OT-2026-0352 — Portes qui rebondissent au 3ᵉ</h2>
<span class="fin">fiche OT · carte Bilan d'intervention</span>
</div>
<div class="carte">
<h3>Décrire pour suggérer (optionnel)</h3>
<textarea class="zone-libre">La porte cabine rebondissait à la fermeture au 3e étage, cellule encrassée, j'ai nettoyé la barrière et réglé le contact NC-31, essais OK sur 10 cycles.</textarea>
<div class="actions-sug">
<button class="btn prim">✨ Suggérer les codes</button>
<span style="font-size:11.5px;color:var(--encre-3);align-self:center">
La description reste dans l'OT — elle n'écrit rien toute seule.
</span>
</div>
</div>
<div class="carte">
<h3>3 suggestions — rien n'est enregistré sans vous</h3>
<div style="display:flex;flex-direction:column;gap:8px">
<div class="suggestion"><span class="ia"></span>
<div><b>Anomalie constatée → « Cellule/barrière encrassée »</b>
<div class="just">« cellule encrassée », « nettoyé la barrière » dans votre description</div></div>
<span class="confiance">confiance forte</span>
</div>
<div class="suggestion"><span class="ia"></span>
<div><b>Action réalisée → « Nettoyage + réglage »</b>
<div class="just">« j'ai nettoyé… et réglé le contact »</div></div>
<span class="confiance">confiance forte</span>
</div>
<div class="suggestion"><span class="ia"></span>
<div><b>Élément concerné → « Portes »</b>
<div class="just">« porte cabine », « contact NC-31 » — 9 bilans similaires sur ce parc</div></div>
<span class="confiance">confiance moyenne</span>
</div>
</div>
<div class="actions-sug">
<button class="btn prim">Appliquer les 3 (pré-remplir)</button>
<button class="btn">Ignorer</button>
</div>
</div>
<div class="carte">
<h3>Bilan d'intervention — requis pour clôturer</h3>
<div class="grille-2">
<div class="champ"><label>État des portes <em>*</em></label>
<div class="select vide">Sélectionner…</div></div>
<div class="champ"><label>Anomalie constatée</label>
<div class="select pre">Cellule/barrière encrassée</div></div>
<div class="champ"><label>Action réalisée <em>*</em></label>
<div class="select pre">Nettoyage + réglage</div></div>
<div class="champ"><label>Élément concerné <em>*</em></label>
<div class="select pre">Portes</div></div>
</div>
<div class="actions-sug" style="margin-top:10px">
<button class="btn prim">Enregistrer le bilan</button>
<span style="font-size:11.5px;color:var(--alerte);align-self:center;font-weight:600">
⚠ « État des portes » reste à choisir — l'IA ne l'a pas deviné, elle ne devine pas.
</span>
</div>
</div>
</div>
</div>
</section>
<!-- ═══ 4 · SUGGESTION (MOBILE) ═══ -->
<p class="note-ecran" data-note="suggestion-mobile" hidden><b>Intention :</b> la même capacité au pouce,
dans l'écran de clôture R4 : décrire (ou dicter, écran 6), recevoir des <b>chips suggérées</b>, les
appliquer d'un geste — les sélecteurs restent la vérité et la garde de clôture ne change pas.
Hors-ligne : la suggestion attend le réseau (l'IA est un service serveur), la clôture en file R4
fonctionne sans elle.</p>
<section class="ecran" id="suggestion-mobile">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Clôture — suggestion depuis la description</div>
<div class="ecran-tel">
<div class="entete-tel"><i></i> Clôturer OT-2026-0352</div>
<div class="carte-tel">
<h4>Décrire pour suggérer</h4>
<div style="border:1.5px solid var(--bordure-forte);border-radius:9px;background:var(--surface);padding:9px;color:var(--encre);font-size:12.5px">
Porte cabine qui rebondit, cellule encrassée, nettoyage + réglage du contact, essais OK.
</div>
<div class="btn-tel contour">✨ Suggérer les codes</div>
</div>
<div class="carte-tel">
<h4>Suggestions — appuyez pour appliquer</h4>
<div style="display:flex;flex-wrap:wrap;gap:6px">
<span class="chip-sug">✨ Anomalie : Cellule encrassée</span>
<span class="chip-sug">✨ Action : Nettoyage + réglage</span>
<span class="chip-sug">✨ Élément : Portes</span>
</div>
<div style="font-size:11px;color:var(--encre-3)">Rien ne s'enregistre sans votre geste —
les chips pré-remplissent les sélecteurs ci-dessous.</div>
</div>
<div class="carte-tel">
<h4>Bilan d'intervention</h4>
<div style="display:flex;flex-direction:column;gap:6px;font-size:12.5px">
<div>État des portes * : <b style="color:var(--encre-3)">à choisir</b></div>
<div>Anomalie : <b style="color:var(--primaire)">Cellule encrassée (suggéré)</b></div>
<div>Action * : <b style="color:var(--primaire)">Nettoyage + réglage (suggéré)</b></div>
<div>Élément * : <b style="color:var(--primaire)">Portes (suggéré)</b></div>
</div>
</div>
<div class="btn-tel" style="background:var(--bordure-forte)">Clôturer (bilan incomplet)</div>
</div>
</div>
</div>
</section>
<!-- ═══ 5 · CORPUS & INGESTION ═══ -->
<p class="note-ecran" data-note="corpus" hidden><b>Intention :</b> le corpus est la bibliothèque R3 +
les bilans codés — <b>rien d'externe</b>, et c'est VISIBLE : chaque document montre son statut
d'indexation, un interrupteur l'exclut du corpus, « Réindexer » est un geste explicite. Bandeau
loi 09-08 : l'anonymisation à l'ingestion est dite, pas cachée dans une CGU.</p>
<section class="ecran" id="corpus">
<div class="app">
<aside class="nav">
<div class="logo"><i></i> SIOP</div>
<div class="groupe">Ressources</div>
<a href="#">Stock & achats</a>
<a href="#">Tiers</a>
<a class="actif" href="#">Fichiers</a>
</aside>
<div class="contenu">
<div class="entete">
<h2>Bibliothèque — corpus de l'assistant</h2>
<span class="fin">6 documents · 5 indexés · 214 bilans codés inclus</span>
<button class="btn" style="margin-left:12px">Réindexer tout</button>
</div>
<div class="avert">🛡 Loi 09-08 — anonymisation à l'ingestion : noms, téléphones et e-mails des
personnes ne sont JAMAIS envoyés dans les index ni aux modèles.</div>
<div class="carte" style="padding:0">
<table>
<thead><tr><th>Document</th><th>Rattaché à</th><th>Indexation</th><th>Corpus</th></tr></thead>
<tbody>
<tr><td><b>Notice Otis Gen2 Premier.pdf</b></td><td>Asc. A1</td>
<td><span class="st ok">indexé · 17 juil. 09:12 · 38 extraits</span></td>
<td><span class="interrupteur"></span></td></tr>
<tr><td><b>Schindler 3300 — manuel.pdf</b></td><td>Asc. B1 · B2</td>
<td><span class="st ok">indexé · 17 juil. 09:12 · 51 extraits</span></td>
<td><span class="interrupteur"></span></td></tr>
<tr><td><b>Certificat parachute 2026.pdf</b></td><td>Asc. A1</td>
<td><span class="st ok">indexé · 17 juil. 09:13 · 4 extraits</span></td>
<td><span class="interrupteur"></span></td></tr>
<tr><td><b>Notice KONE MonoSpace.pdf</b></td><td>MC-1</td>
<td><span class="st encours">indexation en cours…</span></td>
<td><span class="interrupteur"></span></td></tr>
<tr><td><b>photo-guide-frottement.jpg</b></td><td>OT-2026-0341</td>
<td><span class="st exclu">image — non indexable</span></td>
<td><span class="interrupteur off"></span></td></tr>
<tr><td><b>Contrat cadre SPELEV 2026.pdf</b></td><td>Tour Atlas</td>
<td><span class="st exclu">exclu par l'admin</span></td>
<td><span class="interrupteur off"></span></td></tr>
</tbody>
</table>
</div>
<div class="carte">
<h3>Historiques inclus</h3>
<div style="font-size:13px;color:var(--encre-2)">214 bilans d'intervention codés (R2→R4),
anonymisés — c'est ce qui permet « sur votre parc, ce réglage a déjà été appliqué… ».</div>
</div>
</div>
</div>
</section>
<!-- ═══ 6 · VOIX (OPTION) ═══ -->
<p class="note-ecran" data-note="voix" hidden><b>Intention :</b> l'option « si budget temps » du
cadrage : dicter au lieu de taper, mains sales sur le palier. L'audio est transcrit puis
<b>PURGÉ immédiatement</b> (loi 09-08) — le bandeau le dit au moment même. La transcription devient la
description libre de l'écran 4 : même circuit, même validation humaine.</p>
<section class="ecran" id="voix">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Dictée — pendant l'enregistrement</div>
<div class="ecran-tel">
<div class="entete-tel"><i></i> Décrire l'intervention</div>
<div class="carte-tel" style="align-items:center;gap:12px;padding:22px 12px">
<div class="micro">🎙</div>
<div class="onde">
<i style="height:8px"></i><i style="height:18px"></i><i style="height:12px"></i>
<i style="height:22px"></i><i style="height:10px"></i><i style="height:16px"></i>
<i style="height:7px"></i><i style="height:20px"></i><i style="height:11px"></i>
</div>
<div style="font-size:13px;color:var(--encre-2);text-align:center">« …cellule encrassée,
j'ai nettoyé la barrière et réglé le contact… »</div>
<div class="btn-tel" style="background:var(--danger);width:100%">■ Terminer la dictée</div>
</div>
<div class="carte-tel">
<h4>Confidentialité (loi 09-08)</h4>
<div style="font-size:12px;color:var(--encre-2)">🛡 L'audio est transcrit puis
<b style="color:var(--encre)">supprimé immédiatement</b> — seule la transcription (que vous
relisez) est conservée, dans l'OT. Dictée <b style="color:var(--encre)">opt-in</b> :
jamais d'écoute sans ce bouton.</div>
</div>
</div>
</div>
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Après — transcription relue, audio purgé</div>
<div class="ecran-tel">
<div class="entete-tel"><i></i> Décrire l'intervention</div>
<div class="carte-tel">
<h4>Transcription — relisez avant d'envoyer</h4>
<div style="border:1.5px solid var(--bordure-forte);border-radius:9px;background:var(--surface);padding:9px;font-size:12.5px">
Porte cabine qui rebondissait à la fermeture au 3ᵉ, cellule encrassée, nettoyage de la
barrière et réglage du contact NC-31, essais concluants sur dix cycles.
</div>
<div style="font-size:11px;color:var(--st-termine);font-weight:700">✓ Audio purgé (2,4 s après transcription)</div>
</div>
<div class="carte-tel">
<h4>Et ensuite</h4>
<div style="display:flex;flex-direction:column;gap:8px">
<div class="btn-tel contour">✨ Suggérer les codes depuis ce texte</div>
<div class="btn-tel">Joindre la description à l'OT</div>
</div>
</div>
</div>
</div>
</div>
</section>
<script>
(function(){
var onglets=document.querySelectorAll('.revue .onglets button');
var ecrans=document.querySelectorAll('.ecran');
var notes=document.querySelectorAll('.note-ecran');
onglets.forEach(function(b){b.addEventListener('click',function(){
onglets.forEach(function(x){x.setAttribute('aria-selected','false')});
b.setAttribute('aria-selected','true');
var cible=b.dataset.cible;
ecrans.forEach(function(e){e.classList.toggle('actif',e.id===cible)});
notes.forEach(function(n){n.hidden=(n.dataset.note!==cible)});
window.scrollTo({top:0});
})});
var ordre=['auto','light','dark'];var i=0;
var bt=document.getElementById('btn-theme');
bt.addEventListener('click',function(){
i=(i+1)%3;var m=ordre[i];
if(m==='auto'){document.documentElement.removeAttribute('data-theme')}
else{document.documentElement.setAttribute('data-theme',m)}
bt.textContent='Thème : '+(m==='auto'?'auto':(m==='light'?'clair':'sombre'));
});
})();
</script>
</body>
</html>

View File

@@ -4,6 +4,21 @@ Trace chronologique des sessions (la plus récente en premier). Le **playbook**
---
## 2026-07-17 — Pr. Daaif (+ Claude) — R5 ouverte : maquettes IA (design d'abord)
**Actions**
- **`maquette-r5.html`** (docs/02-design/maquettes) : 6 écrans — **Assistant sourcé** (recette type du cadrage : « couple de serrage des guides Gen2 ? » → réponse à citations numérotées, sources document/page/**extrait exact** ouvrables), **Sans source = refus** (l'anti-hallucination visible : « je préfère ne pas inventer » + ce qui a été cherché + action utile), **Suggestion de bilan** web et mobile (description libre → codes EXISTANTS des référentiels, justification + confiance, « Appliquer » pré-remplit avec liseré « suggéré », rien d'enregistré sans le geste humain), **Corpus & ingestion** (bibliothèque R3 + bilans codés, statut par document, exclusion réversible, bandeau 09-08), **Voix** (option « si budget » : dictée opt-in, transcription relue, audio purgé immédiatement). Bi-thème, tokens répliqués, vérifiée en navigateur (6 onglets + sombre, zéro erreur console).
- Artefact de validation publié (6 écrans + preuve bi-thème + **5 décisions à acter** : D1 aucune écriture automatique, D2 sourcé ou silencieux, D3 corpus fermé et visible, D4 anonymisation à l'ingestion 09-08, D5 voix opt-in avec purge).
**Décisions**
- Aucune actée — les 5 décisions **attendent la validation du référent avec les écrans**. Aucune ligne de code `apps/ai` avant (principe n°1). L'architecture (pgvector, choix des modèles) se tranchera en **ADR-004** au lancement du socle R5.1.
**Prochaine étape** : validation référent (maquettes + décisions) → R5.1 socle `apps/ai` (FastAPI/uv, ingestion + ADR-004). Restes : recette R4 sur appareil, redéploiement Dokploy de `release/r3`.
---
## 2026-07-17 — Pr. Daaif (+ Claude) — R4 CLOSE : tag `release/r4` (recette téléphone reportée)
**Actions**