Les agents de coding écrivent vite. Les ledgers, eux, doivent rester append-only et honnêtes. Fil (Chronowflow) s'est construit autour d'une contrainte simple : il lit Chronos, il ne le mute jamais. Ce billet détaille cette hygiène — privacy bornée, vues locales, scores expliqués — et pourquoi elle protège à la fois l'humain et les agents suivants.
Le contrat en une ligne
Fil lit, il n'écrit pas. Chronos est le seul store durable de la chaîne captation. Fil ne réinjecte rien dans le ledger.
Tout le reste — masquer, concentrer, plafonner, journaliser — est une vue ou un dérivé. Pas une réécriture de l'histoire.
Masquer ≠ supprimer
| Action UI | Effet réel | Persistance |
|---|---|---|
| Dismiss agent (X) | Vue locale fil.agent.dismiss.v1 | Navigateur / workspace Fil |
| « Supprimer tout » | Marqueur cleared + purge vue | Empêche la résurrection démo ; ne touche pas Chronos |
| Hide terminal | Après finished / failed / interrupted + rétention | Toujours vue Fil |
| Silence non-terminal | Passe stale visible | Voulu : ne pas faire disparaître un agent muet |
Conséquence pour un POC de présence : si la session n'apparaît pas dans Fil alors que Chronos l'a ingérée, vérifier d'abord un dismiss local — le serveur ne peut pas le savoir.
Replier ≠ masquer
Le journal et Flux replient noise / ambient pour que le bilan de travail soit lisible. Mais :
- les compteurs
excluded/byCategoryrestent exposés ; - la ligne budget (surplus par source) est épinglée et exemptée du filtre catégorie par défaut ;
- un plafond Top-N sans compteur visible serait un mensonge d'interface.
Mesure citée (session captation) : journée « 141 / 68 / dispersion 10 » → après repli « 4 items de travail, 137 repliés, 3 projets, dispersion 3 ». Rien n'a été détruit.
Le bruit n'est pas une poubelle
Changement de comportement majeur du plan captation : plus rien n'est détruit à la captation. Un acte bruyant devient category: "noise", tagué, plafonné (ex. ≤ 18/100), dé-priorisé. Mesure : 201 items auparavant jetés, conservés sur un échantillon réel.
Pourquoi c'est de l'hygiène agentique : un agent suivant peut auditer pourquoi la journée était bruyante. Un hard-drop rendait cette preuve impossible.
Privacy bornée (sanitizeFlowPayload)
Non conservés / non rendus dans les payloads de flux :
- prompt intégral
- diff
- presse-papiers
- corps de message (
message_content) - keystrokes / screenshot /
raw_url(liste STATUS captation)
Titres : 120 caractères max.
Git : git log seul — jamais le contenu. La racine du dépôt est exigée pour éviter l'attribution parent (bogue réel corrigé en WP3 : public/ renvoyait 11 commits du parent).
Aucune donnée fabriquée si une source est absente ou illisible.
Un score s'explique
Contrat produit :
- chaque score porte des
reasons[]; - une raison de pénalité n'est jamais tronquée et passe en tête (
reasonLine) ; - la pénalité
hors-focusn'est jamais masquante — elle explique, elle ne censure pas.
Preuve navigateur WP8 : focus actif → score 50 → 40 avec hors-focus en tête de ligne.
Hypothèse non mesurée ici : le ressenti humain « est-ce que je comprends assez vite ? » — non instrumenté ; seuls les garde-fous techniques sont prouvés.
Présence fail-open
Si VFGate ou Chronos est indisponible :
- Signaler (bandeau santé, source
down). - Continuer (autres sources, UI utilisable).
Un 200 ok:true VFGate ne prouve pas une livraison (mock-only / no-adapter / erreur avalée restent possibles). Fil observe la présence via Chronos ; il ne « valide » pas le hub.
Pureté et tests : l'hygiène du code
| Zone | Règle |
|---|---|
src/lib/flows/** | Pur : pas de réseau, pas de React, pas de global navigateur |
flows/server/** | Seule zone I/O de collecte |
Script npm test | Liste explicite de fichiers — un test oublié ne tourne jamais (piège silencieux) |
| Lint | Pas de Date.now() dans un useMemo ; pas de setState dans le corps d'un effet |
Un agent qui ajoute un fichier de test sans l'inscrire dans package.json croit avoir prouvé quelque chose : il n'a rien prouvé.
Ce que cette hygiène refuse aux agents
- Muter le ledger Chronos « pour nettoyer ».
- Inventer des commits, des minutes actives, ou un journal « complet » parce que la page est courte (pagination Chronos partielle : un journal court ne prouve pas l'absence de travail).
- Coller un secret, un token, ou un prompt intégral dans un titre, un log, un commit ou un handoff.
- Présenter une source
declaredcomme live.
Preuves vs non exécuté
Preuve (documentée STATUS / DERNIERE-INFO / WP)
- Invariants formalisés dans
AGENTS.md. - Privacy et non-fabrication couvertes par la suite captation (compteurs historiques 185 puis 197 puis 213 puis 228 puis 246 tests selon les tranches WP).
- Navigateur WP8 : cohérence journal, pénalité visible, fail-open JS.
Non exécuté dans ce billet
- Audit privacy exhaustif de toutes les routes hors Flux.
- Preuve que zéro prompt fuit jamais via un autre chemin UI (hypothèse de couverture : centrée
sanitizeFlowPayload+ adaptateurs Flux). - Rejeu de la suite au moment de la rédaction.
Une phrase pour la suite
L'hygiène de Fil, c'est de laisser Chronos être la mémoire et Fil être le regard — un regard qui peut se tromper d'interprétation, mais qui n'a pas le droit de réécrire ni d'inventer.
Sources : AGENTS.md, STATUS.md, DERNIERE-INFO.md, handoffs captation WP0–WP8, docs/DEV-ENVIRONNEMENT.md. Miroir : Chronowflow/docs/devblog/.