---
title: "STATUS — FG_Pulse — 2026-10-03"
date: 2026-10-03
time: "03:35"
author: agent
publishedBy: code
status: pub
tags: ["status", "pulse"]
---

# STATUS — FG_Pulse

_Article généré automatiquement depuis le STATUS.md de FG_Pulse — 2026-10-03. Les chemins locaux, les hôtes internes et les noms de variables ont été neutralisés._

# FG_Pulse — STATUS

**Version**: 0.1.0 POC  
**GO POC**: 2026-06-11 (FG)  
**Branche**: `main`

## Install autonome

```powershell
.\scripts\install-all.ps1
```

Taches planifiees : `FG_Pulse-API`, `FG_Pulse-Agent`, `FG_Pulse-MediaAgent`, `FG_Pulse-TelegramHourly` (si Telegram configure).

## Déployé

| Composant | Statut |
|-----------|--------|
| API Fastify `:4330` | ✅ |
| Rapport Telegram horaire | ✅ (agregats, MP FG) |
| SQLite + JSONL miroir | ✅ |
| POST/GET acts + stats | ✅ |
| enrich + project-map | ✅ |
| Privacy sanitization R1–R8 | ✅ |
| Windows agent PS | ✅ (script + install-task) |
| Windows media agent SMTC | ✅ (VLC/Spotify — `pulse-media-agent.ps1`) |
| Browser MV3 extension | ✅ (domaines + YouTube/SoundCloud → `source:media`) |
| Cursor hooks | ✅ (config manuelle) |
| Timeline UI | ✅ (+ lane écoute parallèle, top morceaux 7j) |
| `GET /api/v1/tracks/top` | ✅ (highscore durée + play_count) |
| smoke-test.ps1 | ✅ |
| Tests unitaires + e2e (`npm test`) | ✅ (privacy, enrich, ingest, track-stats, group/tree/sessions) |

## Non activé v1 (volontaire)

- Patterns / nudges (C10)
- Logseq, OSC, Ableton, Hero dual POST

## Relay Hub (PULSE-01)

Relais EVT agrégé optionnel vers le hub VFVFGPT (`POST /api/v1/events`), **opt-in strict** :
sans configuration, aucun appel réseau n'est effectué (zéro régression sur le service local).

- `packages/api/src/hub-relay.js` : `buildPulseEvt({ focusRatio, totalDurationS, segments, day })`
  construit un EVT `{ schema:1, id, at, project:"FG_Pulse", type:"status", actor:"fg-pulse", status, stats, links }` ;
  `relayToHub(hubUrl, token, evt, { fetch })` POST vers `${hubUrl}/api/v1/events` avec header `x-api-token`,
  remonte une erreur sur réponse 4xx/5xx, et renvoie `{ skipped:true }` sans réseau si `hubUrl`/`token` absents.
- `scripts/relay-hub.mjs` : script Node appelable seul, récupère les stats 24h locales (`/api/v1/acts/stats?window=24h`)
  et relaie l'EVT si configuré.
- Câblage : `scripts/telegram-hourly-report.ps1` appelle `relay-hub.mjs` après l'envoi du rapport Telegram,
  uniquement si `[variable d'environnement]` est défini.

### Variables d'environnement (`.env`, gitignored)

| Variable | Défaut | Rôle |
|----------|--------|------|
| `PULSE_HUB_URL` | `http://[hôte interne]` | Base URL du hub VFVFGPT |
| `[variable d'environnement]` | _(vide)_ | Token `x-api-token`, rôle `event-producer`, projet `FG_Pulse` |

**FG nécessaire** : ajouter `FG_Pulse:<token>:event-producer` dans `VFVFGPT/.env` (variable `[variable d'environnement]=...`)
pour que le hub accepte les EVT FG_Pulse (isolation projet : `body.project` doit correspondre au projet du token).
Tant que `[variable d'environnement]` n'est pas renseigné côté FG_Pulse, le relay reste no-op.

## Ops

### Accès LAN/Tailscale (13/06)

API bindée sur `[hôte interne]` (`.env` : `PULSE_HOST=0.0.0.0`, local non commité) — accessible depuis le tunnel Tailscale :

- Timeline UI : `http://[hôte interne]:4330/ui/timeline.html`
- API : `http://[hôte interne]:4330/api/v1/...`

Pare-feu : profil Private désactivé sur ce poste (Ethernet + Tailscale = Private) → pas de règle dédiée nécessaire. Si le profil Private est réactivé un jour, ajouter une règle entrante TCP 4330.

### Pause collecte

```powershell
Stop-ScheduledTask -TaskName FG_Pulse-Agent
Stop-ScheduledTask -TaskName FG_Pulse-MediaAgent
```

### Purge données

```powershell
Stop-ScheduledTask -TaskName FG_Pulse-Agent -ErrorAction SilentlyContinue
Remove-Item [chemin local] -Force
```

### Désinstall complète

1. `Unregister-ScheduledTask -TaskName FG_Pulse-Agent -Confirm:$false`
2. Supprimer extension Chrome
3. Retirer hooks Cursor
4. Delete `FG_Pulse/data/`

## Refactor 16/06 — vues + hiérarchie

- **Phase 1B** : sélecteur vue Blocs / Segments bruts (`ui/timeline.js`)
- **Phase 2** : `recurrence_key_coarse` · `GET /api/v1/acts/tree` · UI arbre projet → outil → objet
- **Phase 3** : table `sessions` · `GET /api/v1/acts/sessions` · vue Sessions Cursor
- **Phase 4** : `normalize-title` · coalesce runtime · dedupe Chrome · `project-map` étendu
- Fixes : migration DB phase2 · clé coarse canonique · tests isolés
- **VFJah** : `ui/pulse/` sync + proxy MSN v0.3.52 (16/06)

## Refactor 11/06 soir

- `act-mapper.js` partagé (dédup `actFromRow`/`rowFromAct` ingest/query, −44 lignes)
- `db.js` testable : override `PULSE_DATA_DIR` (lu à l'appel, pas à l'import) + `resetDb()`
- Harnais `node --test` : 26 cas (privacy, enrich sur project-map réel, e2e SQLite temporaire)

## Dashboard 13/06 — détail + classements

- `ui/timeline.html` éclaté en `timeline.css` + `timeline.js` (module ES) + `pulse-utils.js` (rule monolithe 400, tous <300 lignes)
- `pulse-utils.js` : fonctions pures (fmtDur, aggregateBy, topN, relativeTime, peakHour, longestAct…) couvertes par 13 tests (`test/ui-utils.test.js`)
- Clic sur une ligne du tableau ou un segment de la timeline → modale détail (description, objet, tags/liens, méta JSON, récurrence)
- Nouveaux classements façon WakaTime : Top outils, Classement par type d'action, Top objets/fichiers
- Nouveaux indicateurs : heure la plus active, session la plus longue

## Prochaines étapes

- [ ] 1 journée complète de segments réels
- [ ] Ajustement `project-map.yaml` après 1 semaine (C9)
- [ ] Revue privacy FG sur échantillon `acts.jsonl`
- [x] Tag `v0.1.0`
- [ ] FG : ajouter `FG_Pulse:<token>:event-producer` dans `VFVFGPT/.env` puis renseigner `[variable d'environnement]` côté FG_Pulse

## Qualité de captation — 15/09/2026

- `GET /api/v1/acts?window=6h` honore désormais la fenêtre relative (`m`, `h`, `d`, bornée à 90 jours). Avant, le paramètre était ignoré et Chronowflow recevait les 500 dernières lignes, couvrant environ vingt heures.
- Mesure en lecture seule sur les données réelles : **500 → 98 actes** pour la fenêtre 6 h (−80,4 %), sans supprimer ni migrer l'historique brut.
- Le collecteur Windows construit maintenant `name` avec le titre du segment qui se termine, au lieu du titre de la nouvelle fenêtre active.
- Validation : `npm test` **69/69 PASS** ; API isolée :4331, requête 6 h **98** contre **2000** sur l'historique de contrôle.
- Suite : vérifier le service :4330 après redémarrage opérationnel, puis auditer le curseur historique Chronos. Aucun redémarrage de tâche planifiée effectué par ce lot.

## EN COURS

| ID | Sujet | Owner | Branche | Bloqueur |
|----|-------|-------|---------|----------|
| PULSE-01 | Webhook/EVT Pulse → Hub :4320 (gap Hub E7) + tag v0.1.0 | agent | `main` | — |