Files
OPENCLAW_ARCHIVE3_17/handoffs/HANDOFF-2026-06-09.md
Tallagrand Thierry 5363f99b76 Gmail Phase E/F + HANDOFF global + cleanup cron/root
- Réécriture HANDOFF.md dashboard multi-domaines

- Mise à jour MEMORY.md / TOOLS.md / AGENTS.md

- Cleanup fichiers cron obsolètes + fichiers root

- Gmail Phase E : audit, 18 filtres natifs, labels Promos/Dev-Tools/Social

- Gmail Phase F : archive Philippot + Ulys terminée
2026-06-26 00:28:07 +02:00

553 lines
26 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# HANDOFF — OpenClaw + Qwen3-VL Production
**Dernière mise à jour : 2026-06-09 ~17:45 UTC+2** (post-debug session WhatsApp DM stalled)
> Document de transition entre sessions de production. À lire en premier dans toute
> nouvelle session de travail. Stocké hors workspace pour ne pas polluer le bootstrap.
---
## 1. Stack actuelle (état stable)
### Infrastructure
- **DGX Spark (10.10.10.8)** : vLLM Qwen3-VL-30B-A3B-Instruct-FP8 sur port 8000, Watchtower DÉSACTIVÉ
- **NAS ARCHIVE3 (192.168.144.2)** : OpenClaw 2026.6.1 sur port 18789, image `openclaw-custom:latest` (build local)
- **NAS ARCHIVE2** : sandbox stoppée, en attente
### OpenClaw (ARCHIVE3)
- Compose : `/volume1/docker/openclaw/compose.yaml`
- Volume bind : `/volume1/docker/openclaw-data` → `/home/node/.openclaw` (container)
- Container WORKDIR : `/app` (le `dist/index.js` est à `/app/dist/index.js`)
- Dashboard : http://192.168.144.2:18789/ (paired, 2 devices)
- Container uid : `1000:1000` (`node`) — **tout fichier écrit en root sera invisible côté agent**
### Modèles configurés
- `vllm/qwen3-vl` (primary) — 200k ctx déclaré, mais sessions plafonnées à 66k pour la plupart
- `vllm/qwen3.6` (fallback / legacy)
### Multimodal WhatsApp
- Activé via `tools.media.image.enabled = true` (config set + restart gateway)
- AUCUNE modification de models.json nécessaire pour l'activer
- Pipeline : WhatsApp inbound → resize auto → tool-images → Qwen3-VL → réponse
- Latences mesurées : cron text-only 14-21s, multimodal photo 5-13s, DM text simple ~30s
- Tests OK historiques : Bernard-l'ermite, Hippocampe ×2 photos
- Limite identifiée : Qwen3-VL imprécis en taxonomie spécialisée (crabe → Euphausiidae au lieu de Majidae)
---
## 2. Cron jobs Orange (production)
| ID | Nom | Horaire | Action | Notification |
|---|---|---|---|---|
| `d1f3041c` | orange-ouverture | 09:10 | Mesure d'ouverture | WhatsApp +33607148216 |
| `8cd988b1` | orange-intraday | 10:00→17:00 (8x) | Mesure horaire silencieuse | Aucune |
| `1a0d98b7` | orange-cloture | 17:40 | Mesure de clôture | WhatsApp +33607148216 |
| `7d4bbd3d` | orange-chart-update | 17:45 | Génère le SVG du jour | Aucune |
Tous : modèle `vllm/qwen3-vl`, runtime `OpenClaw Default` (light-context), jours mardi→vendredi.
Source données : Yahoo Finance via `curl + jq` (cf. AGENTS.md). Premier cycle complet : 4 juin 2026.
---
## 3. Outils créés par l'utilisateur (NE PAS recréer ni modifier)
### `generate_chart.py` (alias `gen_chart.py`)
- Localisation : `/home/node/.openclaw/workspace/scripts/generate_chart.py`
- Rôle : génère `orange_chart.svg` à partir de `orange-bourse.md`
- Stack : Python stdlib uniquement (PAS matplotlib, PAS yfinance)
- Validé en production le 4/6/2026
- Règles d'usage dans **TOOLS.md** + **AGENTS.md** (HARD CONSTRAINTS)
### Pattern global
> "Agent pour la sémantique, script pour la mécanique"
- L'agent : récup données via `curl`, lecture HEARTBEAT, formatage, décision WhatsApp
- Les scripts : génération SVG, parsing Gmail, calculs déterministes
---
## 4. Décisions techniques notables
- **Heartbeat désactivé** (`agents.defaults.heartbeat.every = "0"`) — évite la dérive de fréquence (voulait 1h, recevait 30 min). **Conséquence acceptée** : pas de recovery auto en cas de stall (cf. §6 TODO).
- **NODE_OPTIONS** = `--max-old-space-size=1536` (à passer à 4096 après upgrade RAM 20GB)
- **mem_limit** = 2g, **mem_reservation** = 512m (à passer à 6g/1g après upgrade)
- **Provider timeout** : 300s, **Job timeout** : 600s
- **Hard constraints renforcés** dans AGENTS.md suite à incident où l'agent a tenté matplotlib + yfinance + scraping Yahoo en parallèle au lieu de `generate_chart.py` (47% du contexte consommé en cascade d'outils).
---
## 5. Backups
- `/volume1/backups/openclaw/YYYYMMDD-HHMM/` (à créer **manuellement**, aucun cron orchestre actuellement)
- `/volume1/docker/openclaw-data/openclaw.json.last-good` (auto par OpenClaw)
- `/volume1/docker/openclaw-data/openclaw.json.bak` (auto par OpenClaw)
- `/volume1/docker/openclaw-data/workspace/MEMORY.md.bak-2026-06-09` (snapshot avant split du 9/6, 21117 chars)
- `/volume1/docker/openclaw-data/workspace/*.bak-20260604-*` (snapshots du round précédent du 4/6)
---
## 6. Bug du 2026-06-09 — Session WhatsApp DM stalled (RÉSOLU)
### Symptôme
Session `agent:main:whatsapp:direct:+33607148216` (id `cfb27376-d71a-4406-80aa-4a3e9ed5ced5`)
en state=processing, `lastProgressAge` ~6h43, aucune réponse aux messages WhatsApp.
### Cause racine identifiée
`MEMORY.md` = 21117 chars > `bootstrapMaxChars` = 20000 (défaut)
→ troncature côté bootstrap (`per-file-limit`)
→ silent fail de l'`embedded_run` sans réponse modèle ni delivery
→ état `processing` non libéré, payload contenant un champ string `undefined`
(qui faisait crasher `sessions tail` sur `.trim()` of undefined)
### Méthodologie de diagnostic appliquée
1. `sessions list` + `sessions tail` + `health` → 3 sources concordantes
2. **Aucune commande mutative sans avoir lu son `--help`** (règle d'or — à conserver)
3. `doctor --lint --json` → finding `core/doctor/bootstrap-size` confirmant la cause
4. Inspection du payload JSONL → `truncated: true` sur MEMORY.md confirmé
### Fix appliqué (sans restart gateway)
1. Backup : `cp MEMORY.md MEMORY.md.bak-2026-06-09`
2. Split MEMORY.md en :
- `MEMORY.md` réduit à **7453 chars** (essentiel always-in-prompt : outils, workflows, config, prefs user, runbook bref)
- `memory/2026-06-09.md` (**871 chars** : note du jour avec multimodal + bug stalled)
3. Suppression d'une duplication CONFIG-PRODUCTION qui s'était infiltrée
4. Vérification ownership `1000:1000` sur les 2 fichiers (sinon agent ne peut pas lire)
5. `doctor --lint --only core/doctor/bootstrap-size` → `{"ok":true,"findings":[]}`
6. **Test WhatsApp réel** : "Test post-fix" envoyé à 17:39:29 → "OK" reçu à 17:40:01 (32s, normal)
### Tailles bootstrap finales
| Fichier | Chars | Limite |
|---|---|---|
| MEMORY.md | 7453 | 20000 |
| AGENTS.md | 12259 | 20000 |
| TOOLS.md | 7522 | 20000 |
| SOUL.md | 1806 | 20000 |
| USER.md | 1489 | 20000 |
| IDENTITY.md | 1341 | 20000 |
| HEARTBEAT.md | 344 | 20000 |
| **Total bootstrap** | **40995** (+ workspace `.md` minuscules) | **60000** |
---
## 7. TODO / Différé
### Priorité haute
- [ ] **Décision OAuth Gmail** avant 12/6/2026 (token `gmail.modify` expire) :
Publish OAuth app GCP **vs** re-auth weekly via cron
- [ ] Phase E Gmail reportée : filtres natifs, vague 2 (Archive Philippot+Ulys), 2ème passe Q8 newsletters tech
### Priorité moyenne
- [ ] **Investiguer fichiers `gmail-audit.md` / `gmail-housekeeping.md`** créés en `root:root` mode 600
→ l'agent (uid 1000) ne peut pas les lire
→ probablement un cron-host qui `docker exec` en root au lieu d'un cron OpenClaw natif
- [ ] **`orange-chart-update` du 4/6 17h45** = `error` dans `cron list` → vérifier la cause
- [ ] **Activer `memorySearch`** (différé faute de provider d'embeddings local) :
- Pas d'Ollama installé sur ARCHIVE3 (curl localhost:11434 → no answer)
- Pas de `.gguf` dans `workspace/tools/models/`
- vLLM actuel sert le chat Qwen3-VL, pas les embeddings
- 3 options à arbitrer : (a) installer Ollama+nomic-embed-text, (b) ajouter endpoint
embedding sur DGX, (c) télécharger un .gguf local. Aucune urgente.
### Priorité basse
- [ ] **Pollution workspace** : fichiers parasites `-a`, `--max`, `--force`, `--query` à supprimer
(créés par flags shell mal échappés en sessions précédentes)
- [ ] **Backups OpenClaw** : aucune orchestration en place malgré la mention dans MEMORY.md
→ créer un cron host hebdo qui copie `/volume1/docker/openclaw-data/*` vers
`/volume1/backups/openclaw/$(date +%Y%m%d-%H%M)/`
- [ ] **Fragilité structurelle** : `Heartbeat disabled` empêche toute recovery auto.
Toute future panne d'un `embedded_run` (coupure WhatsApp, crash modèle, etc.) reproduira
le pattern stalled. Pas un bug en soi, mais à documenter pour la prochaine fois.
---
## 8. Préférences utilisateur (à respecter par l'agent et les sessions IA)
- L'utilisateur travaille **en vacances** → temps disponible pour expérimenter
(sinon sessions nocturnes courtes)
- Préfère la **transparence** : "tu as raison" plutôt que justifier une erreur
- N'aime PAS les solutions cloud payantes (Claude API, OpenAI, Groq) → **tout doit rester local**
- A tendance à **attaquer avant de lire** → être bref et structuré, ordre clair des actions
- Aime **challenger** les propositions : on lit toujours `--help` ou `config schema` avant
de proposer une commande mutative
- Convention de communication établie : ne pas inventer de référence externe sans recherche
vérifiable, préférer raisonner sur les sorties locales réelles
---
## 9. Convention pour la prochaine session
### Reprise de production
1. Lire ce HANDOFF en entier
2. `sudo docker exec openclaw-gateway node /app/dist/index.js health` (état général)
3. `sudo docker exec openclaw-gateway node /app/dist/index.js sessions list | head -10` (sessions actives)
4. `sudo docker exec openclaw-gateway node /app/dist/index.js doctor --lint --json` (findings)
### Si nouveau debug
- **Aucune commande mutative sans `--help` lu au préalable**
- **Lire toujours d'abord** : `health`, `sessions list`, `doctor --lint --json`
- Pour mutation config : `config patch --stdin --dry-run` puis sans `--dry-run`
- Pour cleanup sessions : `cleanup --dry-run` puis `cleanup --enforce`
- Penser à `chown 1000:1000` après tout `sudo tee`/`sudo cp` dans workspace
### Append-only sur ce HANDOFF
À chaque session significative, ajouter une entrée dans **§6** (sous forme de nouvelle
sous-section "Bug du YYYY-MM-DD" ou "Évolution du YYYY-MM-DD") plutôt que d'écraser.
---
_Fin du HANDOFF — 2026-06-09 17:45 UTC+2_
## 10 juin 2026 ~01:00-01:45 UTC+2 — Persistance OAuth gog (pattern réutilisable)
### Contexte général
Découverte que les tools CLI (gog, et probablement d'autres) stockent leurs
credentials/tokens dans la couche writable du container par défaut, donc PERDUS à
chaque `compose down/up` ou `--force-recreate`. Pattern à corriger pour tout outil
qui aura besoin d'auth persistée (gog, future MCP avec OAuth, etc.).
### Modification compose.yaml (mutation #1 infra)
Ajout dans la section `environment:` du service openclaw-gateway :
GOG_HOME: /home/node/.openclaw/gogcli
→ Redirige toute l'arborescence gog (credentials + keyring + config + cache) sous
le volume Synology persisté `/volume1/docker/openclaw-data:/home/node/.openclaw`.
→ Pattern applicable à d'autres outils via leur env var équivalente (XDG_DATA_HOME,
HOME custom, ou env-var-spécifique).
### Migration manuelle des fichiers gog (one-shot)
Structure attendue par gog avec GOG_HOME :
$GOG_HOME/data/credentials.json
$GOG_HOME/data/keyring/_gogcli_key_v1_<base64>...
$GOG_HOME/config/config.json (créé à la demande)
Migration chronologique :
1. mkdir /volume1/docker/openclaw-data/gogcli (uid 1000, mode 700)
2. compose up -d → gog crée data/keyring/.lock
3. mv credentials.json + keyring/ vers data/ (préservation des 4 _gogcli_key_v1_*)
4. chown -R 1000:1000, find -type f -exec chmod 600, dirs chmod 700
### Test de persistance validé
- `compose down` puis `compose up -d` (recreate complet container) — 60s
- Container Up healthy après ~60s (start_period: 120s dans healthcheck)
- `gog auth list` : compte tallagrand.thierry@gmail.com survit ✅
- `gog gmail labels list` : retourne INBOX/SENT/IMPORTANT/CHAT comme avant ✅
- OpenClaw `health` : WhatsApp linked (auth age 1m), 33 sessions store
### Sessions store état après nuit
- 33 entries (vs 32 avant purge cfb27376 + 1 nouvelle session WhatsApp + 1 dashboard)
- Plus de session ruinée à 87% saturation
- Compaction `mode=safeguard, reserveTokens=8192` actif (cf. config patch précédent)
### Backups préservés (à purger après ~2 semaines de stabilité)
- /volume1/docker/openclaw/compose.yaml.bak-pre-goghome-20260610-*
- /volume1/docker/openclaw-data/gogcli.bak-pre-mv-20260610-0132/
- /volume1/docker/openclaw-data/agents/main/sessions/sessions.json.bak-pre-purge-*
- /volume1/docker/openclaw-data/openclaw.json.bak-pre-restart-20260609
### TODO infra (reportés, non critiques)
- Pattern XDG_*_HOME pour autres outils CLI futurs (réflexe à appliquer
systématiquement pour tout outil qui stocke des credentials)
- Investiguer warning gog `config.path missing` (gogcli/config/config.json)
- Mettre à jour scripts/generate_gmail_token.sh (la commande `gog auth generate-token`
utilisée n'existe pas — la vraie procédure est `gog auth credentials set` puis
`gog auth add ... --manual --gmail-scope=full --force-consent`)
- Surveiller latence cron Orange après tuning compaction (potentiel impact +overhead
via `mode=safeguard`)
- Bug Qwen3-VL boucle de répétition sur prompts longs : reproduit en prod, pas en
API directe ≤300 tokens. Cause suspectée : tool catalog volumineux + tool error
qui dégrade attention. Mitigations à explorer : réduire AGENTS.md de 12259 chars,
désactiver dir_list sur runtime dashboard, ou repetition_penalty (non exposé en
config OpenClaw 2026.6.1)
### Changement comportemental notable
Avant cette session, l'agent ne pouvait pas répondre aux questions Gmail via
WhatsApp ou dashboard (auth absente → tool errors → boucle Qwen3). Maintenant :
- Gmail accessible via gog gmail search/trash/archive/labels
- Doc syntaxe + hard constraints dans MEMORY.md (section "Gmail (gog CLI v0.21.0)")
- Référence au HANDOFF Gmail pour la doc opérationnelle complète
## Validation 10 juin 2026 ~02:13 UTC+2 — Découvertes
### Commande /new dans WhatsApp DM
Le plugin OpenClaw WhatsApp supporte la commande slash /new qui crée une nouvelle
session sans toucher à l'ancienne. **C'est la méthode privilégiée** pour
redémarrer une conversation WhatsApp DM saturée — préférable à la purge manuelle
de sessions.json pour les cas non corrompus.
Quand utiliser :
- Session WhatsApp DM avec context overflow (> 60k tokens)
- Bouclage suspect après plusieurs heures de discussion
- Reset volontaire pour démarrer un nouveau sujet
Quand NE PAS utiliser (préférer purge manuelle) :
- JSONL corrompu (assistant content: [] empty array)
- Session avec compactionCheckpoints=7+ (irrécupérable)
- abortedLastRun=true persistant
### Hot-reload config compaction validé
agents.defaults.compaction.* est correctement hot-reloaded après compose restart.
Pas besoin de docker compose down/up pour ces changements.
### Bug observable mais sans gravité
effectiveReserveTokens plafonne à 16384 même avec reserveTokensFloor configuré
à 20000. Le système gère via fallback compaction multiple. À reporter upstream
OpenClaw si récurrent.
## 10/6/2026 mercredi ~15:00-15:03 UTC+2 — Fix bug "OK au lieu du cours" cron orange-intraday
### Cause racine
Le cron `orange-intraday` (id `8cd988b1-d91e-4ecb-8719-c1c72efb0d87`) :
- prompt terminait par "Réponds par 'OK' une fois fini. PAS de WhatsApp pour l'intraday."
- delivery configuré en mode=announce, channel=whatsapp, to=+33607148216
- → l'agent répondait "OK" en signal de fin, et le mode `announce` envoyait
systématiquement la dernière réponse à WhatsApp = donc "OK" partait à chaque heure.
- L'instruction "PAS de WhatsApp pour l'intraday" dans le prompt était ignorée
(delivery est piloté par config, pas par prompt).
### Fix appliqué
Édition du prompt via :
`cron edit 8cd988b1-... --message "<nouveau prompt>"`
Remplacement final :
AVANT : "Réponds par 'OK' une fois fini. PAS de WhatsApp pour l'intraday."
APRÈS : "Une fois fini, réponds avec UNIQUEMENT cette ligne au format strict :
'ORA.PA : <prix>€ (<variation>%)' OU 'ORA.PA : indisponible'
PAS de 'OK', PAS d'autre texte, PAS de tableau, PAS de commentaire."
### Validation
- 15:00 : cron horaire avec ancien prompt → envoi "OK" (état pré-fix)
- 15:03 : `cron run` manuel avec nouveau prompt → envoi "ORA.PA : 17,83€ (+0,99%)" ✅
- ✅ format conforme, valeur cohérente (vendredi 6/6 clôture 17,66 → +0,99% = 17,83 OK)
- À surveiller : prochains crons auto 16:00 et 17:00 mercredi
### Backup
/volume1/docker/openclaw-data/handoffs/cron-orange-intraday-before-20260610-0303.json
### Apprentissages
- `cron edit <id> --message "<text>"` est la méthode propre pour modifier un prompt
- `cron run <id>` permet un test immédiat (debug, ne respecte pas le schedule)
- Le delivery mode `announce` envoie automatiquement la dernière réponse de l'agent
→ écrire le prompt pour que la dernière réponse soit le format souhaité
- Les autres cron Orange (orange-cloture, orange-ouverture) utilisent un pattern
similaire, à monitorer mais pas à modifier (semblent OK structurellement)
## 10/6/2026 nuit (~22:00-23:48 Paris) — Session marathon résolution amnésie agent
### Phases réussies
- A. Audit complet (versions, dette technique, ressources)
- B. Backup pré-MAJ (156 MB préservés, image pre-maj-20260610-2237)
- C. MAJ OpenClaw 2026.6.1 → 2026.6.5 (sans régression)
- D. Tests baseline 6/6 pass
- F. TOOLS.md + MEMORY.md complets avec convention exec
### Découverte majeure — Bug structurel résolu
Le bug "amnésie Gmail" n'était PAS une vraie amnésie LLM.
L'agent essayait d'invoquer `gog` comme tool natif (10 fois !).
La cause : TOOLS.md documentait `gog gmail send --to ...` sans préciser
que `gog` doit passer par le tool natif `exec` (ou `bash`).
Fix : ajout section 1.0 dans TOOLS.md + section 7 hard constraint :
"Toute commande CLI (gog, python3, curl, jq, git, node) DOIT être
invoquée via `exec` ou `bash`."
### Test validation 23:46 ✅
Question : "Envoie un mail à tallagrand.thierry@gmail.com..."
Agent : appelle `tool=exec` avec `gog gmail send -a ... --to ... --subject ... --body ...`
Résultat : Mail reçu (ID 19eb38051276d01e), agent confirme avec détails.
### Pattern réutilisable (à appliquer aux futures capacités)
1. Identifier la commande exacte (--help)
2. Documenter EXPLICITEMENT que ça passe par exec
3. Donner un exemple concret avec arguments
4. Mapping question→action
5. Hard constraint anti-amnésie
6. Test immédiat après modification
### Reste pour Phase E (en cours dans la nuit)
- E.1 Refactor generate_chart.py (PNG + tri chronologique)
- E.2 Reconstruction orange-bourse.md propre
- E.3-E.5 Test pipeline + cron + WhatsApp PNG
### Backups préservés
- /volume1/docker/openclaw-backups-pre-maj-20260610-2237/ (compose + data)
- Image Docker openclaw-gateway:pre-maj-20260610-2237 (rollback ULTIME)
- TOOLS.md.bak-pre-skills-fix-* (avant tee)
- TOOLS.md.bak-pre-exec-fix-* (avant section 1.0)
- MEMORY.md.bak-pre-skills-fix-*
## 11/6/2026 nuit (~00:30-01:45 Paris) — Phase E pipeline PNG complet
### Phase E.1 (infra cairosvg) ✅
- Dockerfile patché : ajout libcairo2/libpango/libgdk-pixbuf/libffi-dev/shared-mime-info + cairosvg==2.7.1
- Build OK (~33s) → openclaw-custom:latest sha256:8164c3ae04793...
- Container UP healthy 5 min après recreate
- Test cairosvg : PNG 15933 bytes généré
- Test gog auth list : tallagrand.thierry@gmail.com préservé (3e validation persistance)
- Patch generate_chart.py : conversion SVG→PNG + horodatage charts/ora-YYYY-MM-DD-HHMM.png + symlink ora-latest.png
### Phase E.2 (reconstruction orange-bourse.md) ✅
- Script clean_bourse_md.py créé (parse + dédup + tri + retire pollution YAML)
- Avant : 44 lignes, 5 sections désordonnées avec double 06-05, 10 polluants YAML
- Après : 34 lignes propres, 4 sections triées (06-05, 06-07, 06-09, 06-10), 0 pollution
- Régénération graphe 06-10 : 10 mesures, courbe LISSE chronologique (vs zigzag avant)
- Visualisation PNG validée : 46519 bytes, charte graphique Orange parfaite
### Reste pour Phase E (demain en condition réelle)
- E.4 : Update prompt cron orange-intraday (ajouter étape send WhatsApp + image PNG)
- E.5 : Test cron run + validation WhatsApp avec image attachée
### Fichiers ajoutés cette nuit
- /workspace/scripts/clean_bourse_md.py (nouveau, ~140 lignes)
- /workspace/charts/ (nouveau dossier)
- /workspace/charts/ora-2026-06-11-0143.png + symlink ora-latest.png
### Backups préservés
- Dockerfile.bak-pre-cairosvg-20260611-0014
- generate_chart.py.bak-pre-png-patch-20260611-XXXX
- orange-bourse.md.bak-pre-clean-20260611-0140
- orange-bourse.md.bak-pre-apply-20260611-XXXX
## 11/6/2026 (~01:55-02:10 Paris) — Phase E.4 prompt cron mis à jour
### Cron run manuel à 01:55 — preuve que ancien prompt fonctionne
- Run "ok" 31.5s, WhatsApp delivered "ORA.PA : 18,02€ (+2,07%)" (capture validée)
- Note : Yahoo retourne le last close + variation hors séance, normal
### Phase E.4 — Update prompt cron orange-intraday
- Backup pré-E4 : cron-orange-intraday-pre-E4-XXXX.json
- Nouveau prompt : 4 étapes (ajout étape 4 message+attachment PNG)
- Précisions : heure Paris explicite, valeurs cohérentes 10:00-17:30, ora-latest.png comme attachment
- Cleanup data fictives 11/06 : restauration depuis backup pré-fake
- Phase E.5 différée à 11/6 matin avant 10h (avant cron auto)
### Phase E.5 faite
- cron run manuel test → vérifier WhatsApp reçoit texte + image PNG
- a vérifier et faire si besoin cron auto utilise nouveau prompt → 2e validation
- Si KO : revert via backup .bak-pre-E4-XXXX
- Si OK : Phase E entièrement validée, fin Phase E
## 23 juin 2026 ~01:15-01:30 UTC+2 — Migration cron email horaire vers rapport quotidien 8h30
### Contexte
L’utilisateur souhaitait abandonner le rapport Gmail horaire (`hourly-email-check`) au
profit d’un unique résumé quotidien à 8h30 Europe/Paris, tous les jours (week-end inclus),
sur WhatsApp.
### Source de vérité identifiée
Le cron actif n’était PAS dans les fichiers JSON obsolètes (`cron/jobs.json*`) mais dans
la base SQLite :
- Path : `/volume1/docker/openclaw-data/state/openclaw.sqlite`
- Table : `cron_jobs`
- Job ID : `9d43dc31-f6ee-445e-a085-753ca65bc0b0`
### Actions réalisées
1. **Backup** de `state/openclaw.sqlite`, `workspace/MEMORY.md`, `workspace/TOOLS.md`
(timestamp `.bak-20260623-01...`).
2. **UPDATE SQLite** :
- `name` : `hourly-email-check` → `daily-email-report`
- `schedule_expr` : `0 * * * *` → `30 8 * * *`
- `payload_message` : résumé 24h, format court global + détail important (max 5)
- `job_json` : resynchronisé avec les nouvelles valeurs
- `next_run_at_ms` : recalculé (OpenClaw applique un `staggerMs` de 5 min max,
donc exécution réelle entre 8h30 et 8h35).
3. **Mise à jour `workspace/MEMORY.md`** :
- TODO courant modifié
- Apprentissage structurant du 23/6/2026 ajouté
4. **Mise à jour `workspace/TOOLS.md`** :
- Nouvelle section 9 « Gmail daily cron » (schedule, canal, format, source de vérité)
5. **Archivage** des fichiers JSON obsolètes dans `cron/archived-20260623/` :
- `jobs.json.migrated`
- `jobs.json.bak`
- `jobs-state.json.migrated`
- `runs/*.jsonl.migrated` (12 fichiers)
### Validation utilisateur (challenge pré-build)
- ✅ Tous les jours (week-end inclus)
- ✅ Résumé des dernières 24h
- ✅ Renommage en `daily-email-report`
- ✅ Canal WhatsApp conservé (`+33607148216`)
- ✅ Format court global + détail important avec date/heure
- ✅ Mise à jour MEMORY.md / TOOLS.md
- ✅ Archivage des JSON obsolètes (option B)
- ✅ Backup SQLite avant mutation
- ✅ Forçage de `next_run_at_ms`
- ✅ StaggerMs conservé (exécution 8h30–8h35, acceptable)
### Fichiers impactés
- `state/openclaw.sqlite` (mutation du job)
- `workspace/MEMORY.md`
- `workspace/TOOLS.md`
- `cron/jobs.json.migrated` → `cron/archived-20260623/`
- `cron/jobs.json.bak` → `cron/archived-20260623/`
- `cron/jobs-state.json.migrated` → `cron/archived-20260623/`
- `cron/runs/*.jsonl.migrated` → `cron/archived-20260623/runs/`
### Prochaine validation attendue
Vérifier demain matin (~8h30–8h35) que WhatsApp reçoit bien le résumé quotidien avec
le format convenu. Si format incorrect : ajuster `payload_message` dans SQLite.
## 23 juin 2026 ~01:15-01:30 UTC+2 — Migration cron email horaire vers rapport quotidien 8h30
### Contexte
L’utilisateur souhaitait abandonner le rapport Gmail horaire (`hourly-email-check`) au
profit d’un unique résumé quotidien à 8h30 Europe/Paris, tous les jours (week-end inclus),
sur WhatsApp.
### Source de vérité identifiée
Le cron actif n’était PAS dans les fichiers JSON obsolètes (`cron/jobs.json*`) mais dans
la base SQLite :
- Path : `/volume1/docker/openclaw-data/state/openclaw.sqlite`
- Table : `cron_jobs`
- Job ID : `9d43dc31-f6ee-445e-a085-753ca65bc0b0`
### Actions réalisées
1. **Backup** de `state/openclaw.sqlite`, `workspace/MEMORY.md`, `workspace/TOOLS.md`
(timestamp `.bak-20260623-01...`).
2. **UPDATE SQLite** :
- `name` : `hourly-email-check` → `daily-email-report`
- `schedule_expr` : `0 * * * *` → `30 8 * * *`
- `payload_message` : résumé 24h, format court global + détail important (max 5)
- `job_json` : resynchronisé avec les nouvelles valeurs
- `next_run_at_ms` : recalculé (OpenClaw applique un `staggerMs` de 5 min max,
donc exécution réelle entre 8h30 et 8h35).
3. **Mise à jour `workspace/MEMORY.md`** :
- TODO courant modifié
- Apprentissage structurant du 23/6/2026 ajouté
4. **Mise à jour `workspace/TOOLS.md`** :
- Nouvelle section 9 « Gmail daily cron » (schedule, canal, format, source de vérité)
5. **Archivage** des fichiers JSON obsolètes dans `cron/archived-20260623/` :
- `jobs.json.migrated`
- `jobs.json.bak`
- `jobs-state.json.migrated`
- `runs/*.jsonl.migrated` (12 fichiers)
### Validation utilisateur (challenge pré-build)
- ✅ Tous les jours (week-end inclus)
- ✅ Résumé des dernières 24h
- ✅ Renommage en `daily-email-report`
- ✅ Canal WhatsApp conservé (`+33607148216`)
- ✅ Format court global + détail important avec date/heure
- ✅ Mise à jour MEMORY.md / TOOLS.md
- ✅ Archivage des JSON obsolètes (option B)
- ✅ Backup SQLite avant mutation
- ✅ Forçage de `next_run_at_ms`
- ✅ StaggerMs conservé (exécution 8h30–8h35, acceptable)
### Fichiers impactés
- `state/openclaw.sqlite` (mutation du job)
- `workspace/MEMORY.md`
- `workspace/TOOLS.md`
- `cron/jobs.json.migrated` → `cron/archived-20260623/`
- `cron/jobs.json.bak` → `cron/archived-20260623/`
- `cron/jobs-state.json.migrated` → `cron/archived-20260623/`
- `cron/runs/*.jsonl.migrated` → `cron/archived-20260623/runs/`
### Prochaine validation attendue
Vérifier demain matin (~8h30–8h35) que WhatsApp reçoit bien le résumé quotidien avec
le format convenu. Si format incorrect : ajuster `payload_message` dans SQLite.