blog.vfg.lol

Des flux aux fils nestés : anti-doublon inter-sources sur la Carte

Comment les FlowItem deviennent projet → session → items, pourquoi un doublon fusionné n’est pas une pénalité, et ce que 279 tests ont verrouillé

L’attente « voir des fils nestés se créer automatiquement » ne pouvait pas être satisfaite tant que trois blocages structurels restaient en place. Ce billet raconte le diagnostic, les décisions explicites du lot du 15 septembre 2026, et les preuves réellement exécutées — y compris ce qui a été volontairement sauté.

Trois blocages vérifiés dans le code

  1. Les adaptateurs Chronos / Pulse / Telegram repliaient au lieu de construire un arbre : un tableau d’un seul nœud plat (parentId: null), body du type « N tours · M outils ». Seul le chemin blog imbriquait déjà.
  2. Le pipeline Flux n’atteignait pas la Carte. La mindmap était alimentée exclusivement par AgentGrid.onSnapshot → buildFilPatchFromChronos. Les onglets Flux / Journal voyaient les items ; la Carte non.
  3. L’anti-doublon était partiel. dedupeRelayedActs couvre le même enregistrement relayé deux fois. ctx.duplicateNearby (pénalité -10) n’avait aucun appelant en production — code mort. Correction d’errata du handoff : il n’est pas vrai qu’il n’existait « aucun » dédoublonnage ; il ne couvrait simplement pas « même travail, deux sources, pas d’id commun ».

Décisions (aucune par défaut)

DécisionPourquoi
Espace d’ids fil:flow:Éviter le clignotement avec le legacy fil:event: / fil:agent: (deux parentId concurrents)
Zéro pénalité de score sur un doublon fusionnéVu par deux sources = mieux attesté, pas suspect ; -10 reste pour duplicateNearby
Clustering ancré (fenêtre 5 min depuis la première ancre)Le chaînage aurait fusionné une heure de titres récurrents
Priorité totale chronos > git > pulse > telegram > blogSans ordre total, l’item survivant clignote entre polls
Session = représentant le plus récent ; enfants = le resteÉvite le même titre parent et enfant
Parents et enfants émis ensembleflattenTree part de childrenOf(null,…) : parent absent = nœud invisible
Fusion visible dans le bandeauUne suppression silencieuse est exactement ce qu’on refuse

Imbrication volontaire à deux niveaux : projet → session → item. Les tours d’une session restent repliés dans le body via collapseChronosTurns (non modifié dans ce lot).

Livrables

ModuleRôle
src/lib/flows/dedup.tsAnti-doublon titre normalisé + fenêtre
src/lib/flows/to-nodes.tsItems → arbre projet → session → items
src/components/flow-map-sync.tsxPont Flux → Carte
capture.ts + /api/flowsDédoublonnage ; mergedDuplicates dans le bandeau santé
Testsdedupe.test.ts, flows-to-nodes.test.ts (+20)

Prérequis découvert : imports relatifs sans extension dans src/lib cassaient node --experimental-strip-types (ERR_MODULE_NOT_FOUND). Next tolérait ; les tests non. Corrigé dans le même lot — règle pour la suite : toujours .ts / .tsx dans un import relatif de src/lib.

Limites honnêtes

  • Ponts Inbox historiques (fil:pulse: / fil:telegram: / fil:blog:) restent hors Carte ; leurs items y arrivent via le nouveau chemin Flux. Deux représentations de Pulse (Inbox + Carte) coexistent — à trancher plus tard.
  • Log console [FlowMapSync] laissé volontairement (demande utilisateur) ; à retirer après stabilisation.
  • Alerte profondeur Carte (DEPTH_WARN 4 / CRITICAL 5) : le lot ajoute jusqu’à 2 niveaux sur des données auparavant plates — l’alerte s’allumera plus souvent ; seuils à arbitrer.

Preuve (handoff fils nestés)

ContrôleRésultat déclaré
npx tsc --noEmitexit 0
npx eslint src tests0 erreur / 0 warning
npm test279/279 PASS (259 → +20)
npm run buildPASS
/api/flows?days=7200 · 19 items · mergedDuplicates: 4
Navigateur (bandeau)flux 3/3 · chronos 22 · pulse 1 · git 26 · 4 doublons fusionnés
Navigateur (Carte)branche projet → session · 69 nœuds observés
Console[FlowMapSync] 45 items → 56 nœuds, 10 racines, 18 sessions

Non exécuté (volontaire dans ce lot)

  • tests/capture.browser.mjs non rejoué (demande « skip all full test »).
  • Mesure de performance non faite.
  • Arbitrage seuils de profondeur / retrait du log / fusion des deux représentations Pulse — hors périmètre.

Une phrase pour la suite

La Carte ne « invente » plus de branches : elle matérialise les flux déjà scorés, sans masquer les fusions — la prochaine irritation visible est la profondeur, pas l’absence de fils.


Sources : handoffs/2026-09-15-handoff-fils-nestes-antidoublon.md, STATUS.md, DERNIERE-INFO.md. Miroir : Chronowflow/docs/devblog/.

source markdown

Concepts de cet article

Pulsehandoff

Partage le plus de concepts avec