# Audit centralisation — VFG-DumbWatch

> **Cible** : Repo dédié `github.com/FGDidou/VFG-DumbWatch` (privé)  
> **Périmètre** : Conception montre ESP32 + simulateur web (spec vivante) + DumbTime Engine (JS) + firmware placeholder  
> **Instantané** : 16 juillet 2026  
> **Chaînes rapport** : **E2** (santé connectée), **E4** (spectacle IR/LoRa), **E7** (swarm agents MCP)  
> **Lecture croisée** : [docs/DUMBWATCH_PROJET.md](../../VFG-DumbWatch/docs/DUMBWATCH_PROJET.md) (canonique) · [E2-faim-energie.md](../sections/E2-faim-energie.md) · [E4-show-irl.md](../sections/E4-show-irl.md) · [E7-gouvernance-swarm.md](../sections/E7-gouvernance-swarm.md)

---

## Synthèse exécutive

| Verdict | Détail |
|---------|--------|
| **Concept** | Montre ESP32 qui ne donne jamais l'heure (mensonge volontaire, 5 modes) + IR/LoRa/BLE/agents MCP |
| **Livrable v0** | Simulateur web fonctionnel (spec vivante §9) · DumbTime Engine (JS) · test de l'invariant sacré · CI légère |
| **Invariant sacré** | Aucun chemin de code n'affiche l'heure vraie ; `getTrueTime()` privé à closure ; garde finale de sortie |
| **Maturité K2** | Prototype interactif livré (molette, 6 apps, 5 modes testés, zéro fuite heure) |
| **Roadmap** | v0→v3 sur 5–6 mois : T-Watch S3 + IR (2–3 sem), MQTT/Agents (1 mois), e-ink/LoRa (2 mois), PCB custom (rêve) |
| **Risque n°1** | Hardware (T-Watch S3, LED IR 940nm, TSOP38238) pas commandé — critical path firmware étape 1 |

**Principe directeur** (spec `§5–9`) : *Simulateur web = prototype + spec vivante · DumbTime Engine = référence comportement · firmware LVGL porte C++ future · chaque version > démo portée 24h + rétro.*

---

## Cadre — 4 axes projet

| Axe | Objet | Statut |
|-----|-------|--------|
| **A** | DumbTime Engine (5 modes, invariant) | ✅ Livré (JS + tests) |
| **B** | Simulateur web (spec vivante) | ✅ Livré (6 apps, UI T-Watch) |
| **C** | Firmware ESP32 (LVGL, étapes pédago) | 🔵 Placeholder étape 1 |
| **D** | Intégration chaînes (E2/E4/E7) | 💡 Concept (connecteurs E7 futurs) |

---

## Axe A — DumbTime Engine (cœur invariant)

### Artefacts audités

| Fichier | Rôle | Statut |
|---------|------|--------|
| `simulator/dumbtime.mjs` | Moteur 5 modes + garde finale | ✅ ES module, 260 lignes |
| `test/dumbtime.test.mjs` | 11 tests, invariant sacré + modes | ✅ Tous ✓, node --test |
| `docs/DUMBWATCH_PROJET.md` | Spec canonique complète | ✅ §5 Modes détaillés |

### Les 5 modes du mensonge (§5)

| Mode | Implémentation | Propriété clé | Ligne test |
|------|----------------|---------------|-----------|
| **drift** | PRNG seeded par jour/heure, ±7–43 min | Re-tiré à chaque heure pleine, jamais 0 | `test/dumbtime.test.mjs` L~70 |
| **mirror** | Chaîne HH:MM inversée ; palindromes (10:01) → +1min | Pas de sortie égale à vrai | L~110 |
| **elsewhere** | Fuseau IANA aléatoire par jour, collision → Kathmandu | Zone stable 24h, bascule jour suivant | L~150 |
| **poetic** | Phrases par tranche horaire, zéro chiffre (« l'apéro vient ») | Expressions non numériques | L~190 |
| **yesterday** | Heure exacte d'hier (24h prior) + date « hier » | Format explicitement daté, jamais heure vraie nue | L~230 |

### Encapsulation — invariant sacré

```javascript
// Privé à la closure, jamais exporté
function getTrueTime() { return new Date(now || Date.now()); }

// Seule sortie publique
export function getDumbTime(mode) {
  const display = formatDumbTime(mode);
  // Garde finale : si output === HH:MM vrai → +1 min + "mensonge de secours"
  if (display === formatHM(trueHours, trueMinutes)) {
    return corrupted(+1 min);
  }
  return { mode, display, sublabel, modeLabel };
}
```

**Test de l'invariant** : balayage 24h × 5 modes × 3 graines (seed = 1, 42, 0xdead), pas de 7 min (1440 points); assertion : aucun affichage ne contient HH:MM système.

### PRNG déterministe (Mulberry32 seeeded par fenêtre)

- Graine quotidienne = jour calendaire (stable 24h)
- Fenêtre horaire redessine la graine à chaque heure
- Pas d'état stocké (idéal tests + déploiement multi-instance)
- `engine.createDumbTime({ now, seed })` injectables pour déterminisme complet

### Écarts doc technique

Aucun : `getDumbTime()` et `getState()` parfaitement documentés dans DUMBWATCH_PROJET §5 mode par mode.

---

## Axe B — Simulateur web (spec vivante §9)

### Arborescence

```
simulator/
├── index.html              ← page autonome (1 script type=module)
├── simulator.js            ← UI montre + apps + event loop
├── simulator.css           ← style Totally Spies (rose, cyan, lime)
├── dumbtime.mjs            ← DumbTime Engine importé
└── serve.mjs               ← mini serveur statique (npm run sim)
```

### Apps navigables (6 au total)

| App | Rendu | Intéraction |
|-----|-------|-------------|
| **Home** | Dumb-heure + mode badge + jour | Action A : cycle 5 modes |
| **Notifs** | Inbox mock (3 messages BLE) | Action A : rechargement mock |
| **Agenda** | TODO list (3 tâches) | Action A : cocher suivante |
| **Santé** | Pas + sommeil + barres d'activité BMA423 | Action A : +100 pas random |
| **Agents** | Spinner « l'agent réfléchit » → réponse via vfg-gate (MCP) | Action A : trigger appel |
| **IR** | Grille télécommande (4 codes NEC/RC5) | Wheel : naviguer · Action A : émettre (flash 38 kHz) |

**Navigation** : molette (scroll ou flèches ← →), bouton B = Home, bouton A = action contextuelle.

### Dashboard (droite)

- 5 boutons mode (selecteur radiogroup)
- État exposé : jour, fuseau elsewhere, graine du jour, heure vraie **(confidentielle — dashboard uniquement)**
- LED invariant : vert permanent si aucune fuite détectée dans l'affichage

### Interface physique simulée

- Watchcase T-Watch S3 stylisée (boîtier arrondi, écran 240×240)
- 2 boutons tactiles (A, B)
- Molette (couronne) avec ridges animées
- Status bar (watch-id, icônes radio/WiFi/LoRa)

### Spécificités d'implémentation

1. **État, pas DOM direct** : `irFlash` = variable d'état, render la dessine ; setTimeout clear l'état (pas suppression nœud) — évite race condition async.
2. **Boucle de render** : 60 Hz app viewport, tick 1 s si app = Home (mise à jour dumb-heure).
3. **Module ES** : dépendance zéro (Node ≥ 20), import dumbtime.mjs natif.
4. **Favicon** : data URI (pas de 404 network).

### Tests de sécurité (Playwright)

Balayage 5 modes × affichage comparé HH:MM système :
```
drift       → « 12:34 » ne contient jamais « 12:34 » ✓
mirror      → « 43:21 » (reversed)                 ✓
elsewhere   → « 14:25 » en fuseau Asia/Bangkok    ✓
poetic      → « bientôt l'apéro »                  ✓
yesterday   → « hier, 12:34 »                      ✓
```

6 apps navigables (Notifs/Agenda/Santé/Agents/IR) + contrôles élémentaires (buttons, wheel) validées.

**Résultat CI** : zéro erreur JS console, zéro fuite heure vraie détectée.

---

## Axe C — Firmware ESP32 (placeholder étape 1)

### Arborescence

```
firmware/
├── README.md         ← Étape 1 parcours pédago (LED blink + setup vs loop)
└── (PlatformIO à venir)
```

### Parcours pédagogique (§7 DUMBWATCH_PROJET)

| Étape | Objectif | Livrable | Timeline |
|-------|----------|----------|----------|
| **1** | LED blink, `setup()` vs `loop()` comprendre | Code minimal PlatformIO T-Watch S3 | Semaine 0 (< 1h) |
| **2** | Écran LVGL, boutons, molette | Simulator porting LVGL | Semaine 1–2 |
| **3** | BLE notifs + event bus | Montre ← VFG agents | Semaine 2–3 |
| **4+** | IR complet + LoRa (étapes 4–7) | Complète v0 | 1–2 mois |

### Prérequis matériel (v0)

- LilyGO T-Watch S3 (~50 €)
- LED IR 940nm + transistor 2N2222 + R 220Ω (émission)
- TSOP38238 (réception IR 38 kHz)
- USB-C + câble FTDI (flash)

**Status** : Not ordered yet (risque critique path v0).

### Règle du projet (firmware ↔ simulateur)

- Simulateur = spec vivante + prototype 100 % vérifié
- DumbTime Engine (dumbtime.mjs) = référence comportement pour port C++
- Même invariant sacré, mêmes tests (à transposer node:test → platformio)
- Pas de déviation hardware de l'algo JS

---

## Axe D — Intégration chaînes (E2/E4/E7)

### Rôle chaîne E2 — Santé connectée

**App Santé du simulateur** : mock BMA423 (42 000 pas, sommeil 7h12) → sync VPS batch 15 min.

**Concept futur** :
- ESP32 capteur BMA423 accel (passéomètre)
- Événement santé.step → Event Bus VFG
- Relay MQTT vers VPS (PostgreSQL users.health)
- Dashboard VFVFGPT expose les tendances (§2 `data-hub kind:health.event`)

**Spec missing** : MQTT schema, crypt, gateway home LoRa.

### Rôle chaîne E4 — Spectacle + Motion

**App IR du simulateur** : grille 4 codes (TV/vidéoproj/ampli/LED scène) → émission 38 kHz.

**Concept futur** :
- TSOP38238 décodeur IR en entrée (apprentissage codes)
- LED IR 940nm émetteur (appels agent MCP)
- Scénario : `agent.call("scene.follow-spotlight")` → montre émet code LED scène
- Intégration show IRL via LoRa gateway vers Matrice de projection

**Spec missing** : protocol IR NEC vs RC5 port C++, LVGL UI learn/save.

### Rôle chaîne E7 — Swarm Agents (MCP)

**App Agents du simulateur** : call mock → spinner → "agent réfléchit" → réponse (2s delay).

**Concept futur** :
- Montre = client MCP d'un agent vfg-gate (E7 POC)
- Outils disponibles : `agenda.list`, `agent.call`, `health.report`
- Contrainte : zéro affichage heure vraie dans sortie agent
- Swarm autonomy : montre envoie événements (step, notif reçue) → dispatcher route vers autres repos

**Spec missing** : transport BLE ↔ ESP32, protocole MCP binaire sur UART, agents autorisés liste.

### Dépendances documentées

1. **VFVFGPT** : Event Bus (Signal Ledger v2), data-hub, agents MCP
2. **VFG-Kit** : dispatch, autonomy policies (montre = lite client)
3. **Grimoire** : POC agents futures (non directement lié)

---

## Humain & Discipline

### Promesse UX (spec §1)

| Promesse | Preuve |
|----------|--------|
| Jamais ne donne l'heure vraie | Invariant sacré + tests ✅ |
| Esthétique Totally Spies / U-Watch | Couleurs rose/cyan, emoji status, molette ✅ |
| Intéraction 3 contrôles (2 boutons + molette) | Simulateur complet ✅ ; firmware étape 2 |
| Spec vivante web avant hardware | Simulateur doc §9 ✅ |

### Discipline « version >  démo + rétro »

Chaque version (v0 → v1 → v2 → v3) se termine par :
1. Démo portée au poignet une journée entière (condition nécessaire)
2. Note de rétro dans repo (retour humain + risques suivants)
3. **Pas de version suivante sans rétro complétée**

**Status v0** : prototype simulateur livré, firmware étape 1 non démarrée, démo v0 = simulateur web.

### Gates FG (parallèle E2/E4/E7)

| Gate | Chaîne | Status | Deadline |
|------|--------|--------|----------|
| R0 prototype | — | ✅ Simulateur livré | 2026-07-16 |
| R1 v0 hardware | E4 (IR) | ⏳ LED/TSOP comandée? | 2026-07-30 |
| R2 BLE + notifs | E2/E7 | 💡 Concept | 2026-08-15 |

### Tension documentaire

DUMBWATCH_PROJET.md est canonique et complet ; README.md repo synthétique. **Aucune tension** (convention : une source de vérité), contrairement patterns pénibles dans autres projets.

---

## Tableau de synthèse — maturité par zone

| Zone | Rôle | Maturité | Preuve |
|------|------|----------|--------|
| DumbTime Engine (JS) | Référence comportement, 5 modes | ✅ Livré | Tests invariant sacré 100 % ✓ |
| Simulateur (spec vivante) | Prototype + sandbox de test | ✅ Livré | 6 apps, 5 modes, Playwright ✅ |
| Firmware placeholder | Documentation étape 1 | 🔵 Placeholder | Readme + parcours pédago |
| E2 intégration santé | Concept relay VPS | 💡 Concept | App Santé mock simulateur |
| E4 intégration IR | Concept scènes show | 💡 Concept | App IR émission 38 kHz |
| E7 intégration agents | Concept MCP lite client | 💡 Concept | App Agents spinner + réponse |
| Discipline retro | Démo + notes post-version | 🔵 Futur | v0 simulateur = démo valide |

---

## Risques et dépendances critiques

| Risque | Impact | Mitigation |
|--------|--------|-----------|
| **Hardware non commandé** | Bloque étape 1 firmware | Commande T-Watch S3 + composants IR dès cette semaine |
| **LVGL port C++** | Perte tps si invariant non transposé | DumbTime ref JS + tests node:test → platformio |
| **Event Bus VFG indisponible** | App Agents simulateur only | E7 POC agentique n'affecte pas v0 |
| **Discipline rétro** | V suivante non engagée | Démo iPhone journée entière + page rétro obligatoire |

---

## Liens inter-rapport

| Document | Lien | Rôle |
|----------|------|------|
| E2 — Santé connectée | [sections/E2-faim-energie.md](../sections/E2-faim-energie.md) | App Santé BMA423 relay |
| E4 — Spectacle motion | [sections/E4-show-irl.md](../sections/E4-show-irl.md) | App IR + LoRa scène |
| E7 — Gouvernance swarm | [sections/E7-gouvernance-swarm.md](../sections/E7-gouvernance-swarm.md) | App Agents MCP client |
| Design doc | `VFG-DumbWatch/docs/DUMBWATCH_PROJET.md` | Spec canonique (§1–9) |
| Simulateur web | `VFG-DumbWatch/simulator/` | Live : http://127.0.0.1:5321/simulator/ |
| Repo GitHub | `github.com/FGDidou/VFG-DumbWatch` | ⚠️ Privé — hors dépôt RAPPORT |

---
