---
title: "Fil : ce que la captation voit, ce qu'elle refuse de fabriquer"
subtitle: "Comment Chronowflow range, score et journalise des flux déjà émis — sans inventer une journée de travail"
date: 2026-09-30
time: "19:59"
author: VFG / Fil (Chronowflow)
publishedBy: code
status: pub
tags: ["fil", "chronowflow", "devblog", "captation", "flux", "journal", "invariants"]
---

Fil (Chronowflow) n'est pas un second ledger. C'est un **hub de captation** : il lit ce que Chronos, Pulse, git et quelques ponts ont déjà produit, puis range · catégorise · score · tague · journalise · surveille. Ce billet raconte la valeur produit après le plan captation WP0–WP8 et le plan prioritaire P0/P1 — avec les chiffres réellement mesurés, et les limites assumées.

## Le problème qu'il fallait résoudre

Sans captation disciplinée, trois symptômes se cumulent :

1. **Le bruit passe pour du travail.** Titres de fenêtre OS, idle, DevTools : s'ils comptent comme items « actifs », le journal ment.
2. **Le silence passe pour une panne.** Un ledger vide n'est pas un serveur mort ; les confondre dégrade le badge et panique l'opérateur.
3. **Le score n'explique rien.** Une pénalité tronquée ou invisible n'aide personne à décider où concentrer l'attention.

Le plan maître `docs/PLAN-CAPTATION-FLUX.md` a livré WP0 → WP8 le 15 septembre 2026. Le [plan prioritaire](https://github.com/FGDidou/Chronowflow/blob/main/docs/PLAN-PRIORITAIRE-2026-09-15.md) a ensuite fiabilisé la cohérence Flux / Journal / Santé (P0) et la qualité Pulse + couverture Chronos (P1).

## Ce que Fil voit

| Source | Rôle | État registre | Fraîcheur |
| --- | --- | --- | --- |
| **Chronos** (`:4344`) | Ledger principal : `agent.turn`, `act`, `presence` | `live` | `archive` |
| **Pulse** (`:4330`) | Humeur / session | `live` | `archive` |
| **git** | `git log` des dépôts enregistrés (jamais de diff) | `live` | local |
| **blog** | Distant `blog.vfg.lol` | `live` (souvent non interrogé par la collecte Flux) | remote |
| **telegram** / **ideapit** | Promesses | `declared` | — |

Règle absolue du registre : une source **`declared` n'est jamais présentée comme fonctionnelle**. C'est une intention, pas un service up.

Fil démarre même si tout l'amont est éteint : il affiche `down` / `empty` plutôt que de planter. Un Fil « vide » est presque toujours un amont éteint — pas un bug Fil.

## Ce que Fil refuse de voir (ou de garder)

La captation est volontairement bornée :

- **Pas de prompt intégral, pas de diff, pas de presse-papiers, pas de corps de message** dans les payloads conservés (`sanitizeFlowPayload`).
- **Titres bornés à 120 caractères.**
- **`git log` seul** — jamais le contenu des fichiers. Une racine de dépôt est exigée : `git -C` sur un sous-dossier remonterait au parent et **attribuerait faussement** ses commits.
- **Aucune donnée fabriquée.** Dépôt illisible → erreur explicite. Aucun dépôt déclaré → `empty`, zéro commit inventé.
- **Fil ne mute pas Chronos.** Masquer un agent (`fil.agent.dismiss.v1`) est une vue locale.

## Correction de conception : le bruit n'est plus détruit

Avant la captation disciplinée, le filtre Pulse jetait massivement. Mesure sur flux réels (STATUS / DERNIERE-INFO, session captation) :

| Moment | Mesure |
| --- | --- |
| Après adaptateurs Chronos + Pulse | **234 items** (233 Chronos + 1 Pulse) → `work` 30 · `ambient` 3 · **`noise` 201** |
| Avec git branché | **245 items** (`work` 41 · `ambient` 3 · `noise` 201) |
| Bruit auparavant « détruit » | **201** items conservés, tagués, plafonnés à **18/100** |
| Commits git scorés | **45/100** (preuve dépôt réel, 11 commits) |

Le bruit devient `category: "noise"` : dé-priorisé, compté, **jamais perdu**. Replier n'est pas masquer : le journal expose `excluded` et `byCategory`.

## Journal : replier le papier peint

Premier jet du journal : il comptait le bruit. Une journée réelle affichait « **141 items / 68 projets / dispersion 10** ». Après repli de `noise` / `ambient` : « **4 items de travail**, 137 repliés, 3 projets, dispersion 3 ».

Invariant : `folded + rolled = total` pour chaque jour (vérifié par le scénario navigateur WP8).

Minutes actives : **mesurées uniquement** (`act.duration_s`, durées agent, présence). Un item sans durée contribue 0 — un journal sur-compté est pire qu'un journal prudent.

## Anti-dispersion (WP7)

Trois leviers dans `flows/discipline.ts` :

1. **Focus projet** — pénalité `hors-focus`, jamais masquante.
2. **Budget par source** — surplus → **une ligne compteur**, jamais un mur ni une perte silencieuse.
3. **`suggestFocusSlug`** — projet le plus **actif**, pas celui qui émet le plus de bruit.

Deux pièges évités (tous deux silencieux) :

- La ligne compteur, catégorisée `noise`, aurait été **masquée par le filtre par défaut** — exactement le plafond silencieux à empêcher. Elle est exemptée et **épinglée en haut**.
- `hors-focus` en 5ᵉ raison était **coupée** par l'ancienne troncature à 3. `reasonLine` ne tronque plus jamais une raison de pénalité.

### Preuve (navigateur, WP8)

| Contrôle | Résultat déclaré |
| --- | --- |
| Focus actif | score **50 → 40**, `hors-focus` en tête de ligne |
| Volume | **235** items classés / tagués / scorés / expliqués |
| Upstream coupé | **0** erreur JS |
| Mobile 390 px | sans débordement |
| Suite unitaire (clôture WP7–WP8) | `npm test` **246/246** · build · eslint 0/0 |

**Limite honnête :** le budget 60/h **ne s'est pas déclenché** sur les données du jour de test (aucun item dans la dernière heure). Testé en code, **non observé** en réel ce jour-là.

## Santé : `empty` ≠ `down`

| État | Signification | Dégrade le badge ? |
| --- | --- | --- |
| `up` | source répond avec des items | non |
| `empty` | silencieuse / non interrogée / vide | **non** |
| `stale` | fraîcheur `stream` dépassée | oui |
| `down` | panne observée | oui |

Une source `archive` ne devient jamais `stale` : un ledger silencieux n'est pas une panne. Fail-open prouvé : Chronos coupé → `down`, Pulse reste `up`.

## Pureté du cœur

`src/lib/flows/**` reste importable par `node --experimental-strip-types` : **pas de réseau, pas de React, pas d'effet**. Le réseau vit dans `flows/server/**`. Casser cette frontière casse la testabilité.

## État produit au 15 septembre 2026

| Élément | Valeur documentée |
| --- | --- |
| Package | `fil@0.4.0` · tag `v0.4.0` |
| Port UI | **4477** |
| Plan captation | WP0–WP8 **livrés** |
| Plan prioritaire | P0 + P1-A/P1-B **livrés** (STATUS) |
| Compteur tests (STATUS courant) | **279** (après fils nestés) — ne pas confondre avec **246** de la clôture WP7–WP8 |

Les chiffres « 201 / 245 / 234 » sont des **mesures de session** captation ; le plan prioritaire rappelle qu'ils méritent un échantillon frais avant d'être cités comme vérité permanente.

### Non exécuté dans ce billet

- Rejeu `npm test` / build / Playwright au moment de la rédaction éditoriale.
- Certification de l'état live Chronos / Pulse / VFGate au moment de la publication.
- Digests `fil.journal.v1` (non livrés).

## Une phrase pour la suite

Fil transforme « trop d'événements » en **travail lisible** sans détruire le bruit ni inventer une journée — la prochaine valeur produit est de figer les bilans (digests) et de traiter le bruit Pulse **à la source**, pas d'ajouter une source de plus.

---

*Sources : `STATUS.md`, `DERNIERE-INFO.md`, `docs/PLAN-CAPTATION-FLUX.md`, `docs/PLAN-PRIORITAIRE-2026-09-15.md`, `docs/DEV-ENVIRONNEMENT.md`, `AGENTS.md`. Miroir local : `Chronowflow/docs/devblog/`.*