Skip to content

docs: nettoyage de structure — racine allégée, dossiers composants renommés, filtre ADR - #531

Merged
donovan-dev-web merged 100 commits into
mainfrom
docs/nettoyage-structure
Oct 12, 2026
Merged

donovan-dev-web merged 100 commits into
mainfrom
docs/nettoyage-structure

Conversation

@donovan-dev-web

Copy link
Copy Markdown
Owner

Contexte

Exécution partielle du PLAN-REFONTE-DOCUMENTATION (annexe §8) : la documentation vient d'être réalignée sur le code (PR #528–#530), donc on réorganise sans réécrire, et on applique le filtre ADR validé avec le mainteneur.

Ce que change

Racine — seuls restent les 7 fichiers reconnus par GitHub (README, LICENSE, CONTRIBUTING, CODE_OF_CONDUCT, SECURITY, CHANGELOG, VERSIONING) + le snapshot monographie :

Avant (racine) Après
ARCHITECTURE.md, COMMUNICATION.md, INSTALLATION.md, CI_CD.md, NAMING_CONVENTIONS.md docs/
VISION.md, FAQ.md, GLOSSARY.md (+ docs/ETHICS_AND_SCOPE.md) docs/presentation/
ROADMAP.md, LIVEX-STATUS.md, GITFLOW.md, PLAN-REFONTE-…md docs/governance/

Dossiers composants — préfixe redondant supprimé : docs-syne/echos/launcher/prism/installer → docs/syne/ etc.

Filtre ADR — ADR-010 (intentions partagées) et ADR-011 (institutionnalisation), classés Reporté V2 sans aucune implémentation, retranchés (historique Git) ; statut de l'ADR-001 Launcher corrigé Proposed → Accepted (Avalonia est implémenté depuis longtemps).

docs/installer/ conservé avec bandeau « spécification — aucun code à ce jour » (composant documenté mais absent du code).

Écarts assumés par rapport au plan initial (détaillés dans l'annexe §8) : pas de DocsOld/ (l'historique Git suffit), pas de découpage reference/+composants/ (les contrats vivent chez le composant), changelogs par composant conservés.

Vérifications

  • Liens : réécriture scriptée (~150 fichiers) puis vérification par comparaison avant/après : aucun lien Markdown cassé (les mentions restantes en backtick sont du prose : ports, noms d'actions GitHub, branches, exemples de nommage).
  • Build Launcher Release --warnaserror : 0 avertissement / 0 erreur.
  • Tests Launcher : 164 unitaires + 20 intégration, 0 échec (le panneau Documentation embarqué énumère les chemins dynamiquement, aucun chemin codé en dur ; le stub de test a été aligné).
  • Snapshot monographie (.md/.pdf) : intact à la racine, non réécrit.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff noreply@codebuff.com

donovan-dev-web and others added 30 commits September 21, 2026 07:06
* feat(governance): jalon U0 — socle git flow, CI remaniée, gouvernance GitHub

- branches Git Flow : develop créée depuis main
- milestones dédupliqués (série canonique par composant), labels normalisés
- CI: jobs filtrés par paths (syne/**, echos/**) via détection git diff,
  validation transverse toujours verte ; conteneurisation Docker reportée
- release.yml: aligné (pas de GHCR tant que pas de conteneurisation)
- ajout .gitignore/.editorconfig ; maj README, INSTALLATION, CHANGELOG

* fix(governance): resserre l'heuristique anti-secrets (auto-correspondance du motif)
…erministe, ADR-012 (#410)

- Syne.sln + Simulation.Core/Simulation.Console/Simulation.Core.Tests séparés (SYNE-001)
- SimulationOptions (Annexe H) + loader JSON générique (fichier partiel préservant
  les défauts), validation des plages, priorité défauts -> --config -> flags CLI (SYNE-006)
- CliOptions.Parse : --seed/--max-ticks/--world-size/--headless/--config, erreur explicite rc=2
- PRNG xoshiro256** + splitmix64 (System.Random interdit) : vecteurs de référence
  épinglés depuis une implémentation indépendante (SYNE-005 via déterminisme)
- ADR-012 (config JSON + CLI) fusionnée ; ARCHITECTURE.md/§4§6 + CHANGELOG SYNE à jour
- 28 tests xUnit verts, build Release sans avertissement
…tés typées + traits (#411)

- SimulationLoop : 1 tick = 1 minute simulée, maxTicks respecté, PRNG ancré au tick
  (tête/queue affichées par la Console) — SYNE-002
- World : plan continu non-toroidal (positions clampées [0,W]x[0,H]), SpatialGrid
  uniforme à rayon configurable (requêtes déterministes ligne-par-ligne) — SYNE-003
- Entity : identité séquentielle, espèce, position, 8 traits [0,2] hérités d'un
  paramétrage (plages), validation des invariants ; fabrique déterministe —
  valeurs épinglées calculées par implémentation indépendante — SYNE-004
- namespace Loop (évite l'ombre portée de Simulation.Core.Simulation)
- ARCHITECTURE.md + CHANGELOG SYNE à jour ; 62 tests xUnit verts
- paquet Python echos : API FastAPI create_app() (/health), registre des
  7 moteurs de métriques (METRICS_SPEC) + placeholder ingestion
- echos-ui : Vite + React + TypeScript (lint, build, tests vitest/jsdom)
- 13 tests pytest, couverture 100 %, flake8 (max-line-length=100)
- CI : job echos-python recalé sur 'flake8 echos', echos-ui npm ci actif
- docs : CHANGELOG/ARCHITECTURE ECHOS + CHANGELOG racine à jour
…iles (U0) (#413)

- modèles pydantic WorldSnapshot/ExternalEvent (JSON camelCase,
  API_CONTRACTS.md §2) : aliases ingress, sortie by_alias, parse_message
  déterministe + InvalidMessageError stable
- WsClient :5180 (transport injectable, réception rejouée déterministe)
  et ControlClient :5181 (start/pause/resume/reset, corps vérifiés)
- golden files versionnés (fixtures/ + golden/) : double garde
  non-régression (contrat camelCase + vue interne snake_case)
- deps runtime : httpx + websockets ajoutés
- 43 tests pytest (couverture 98 %), flake8 propre, docs à jour
- Perception : rayon 50 (déc. 6), confiance 1−(d/r)×0.3, rotation id%4,
  ligne de vue obstacle cercle (ADR-013), micro-benchmark grille (< 10 ms)
- Mémoire : salience exponentielle, éviction, rappel ordonné (SYNE-013)
- Croyances : révision alignement/conflit/moyenne, expiration (SYNE-014)
- BDI + utilité : pipeline 10/15 étapes branché, U = (b−c−r)×conf×persona+urg,
  mouvements déterministes sans consommation PRNG (SYNE-010)
- Déterminisme : hash FNV-1a épinglé de la trajectoire (SYNE-015)
- Tests : 62 → 122 (toutes catégories nouvelles), build warnaserror vert
- Landing de présentation (docs/site/index.md) + TOC DocFX
- Docs clés synchronisées par sync-docs.sh (source unique monorepo)
- API Simulation.Core générée par DocFX depuis le XML (Simulation.Core uniquement)
- XML .NET activé sur Simulation.Core + Simulation.Console (NoWarn 1591)
- Workflow docs-pages : push develop -> build XML + docfx -> gh-pages
- Branche gh-pages initialisée, source Pages basculée, .nojekyll
- Badge Documentation + entrée CHANGELOG

Co-authored-by: DevOps LIVE X <devops@livex.local>
…ns, conflits de priorités, utilité alignement + hystérésis (#SYNE-030→033) (#422)
…énomènes, complexité/imprévisibilité, disclaimer) + preuve J3 (#ECHOS-030→033) (#423)
…mique, actions terminales Eat/Drink + réserves globales (seuils ≥ 50), déclencheur d'interruption centralisé (#SYNE-040→043) (#424)
…cache, export JSON/CSV reproductible, croyances/relations, groupes, phénomènes) + stockage v2 (tick_metrics, tick_contexts) + preuve J5 (#ECHOS-040→045) (#425)
…ue + interception, coûts émission/réception hérités configurables, relais avec dégradation de confiance ×0.9/hop), événements message_sent/message_received, engineVersion 0.4.0 (#SYNE-050→054) (#426)
…e tag SSE-V2, traces decision_traces schéma v3 + endpoint /decisions, profilage bit-à-bit des 8 moteurs), SCHÉMA SCHEMA_VERSION 3, preuve J5 étendue 181 tests (#ECHOS-050→052) (#427)
…ffinité et composantes, leader par confiance entrante, décisions collectives pondérées, LOD 10 ticks, turnover), naissance par fusion consentie (paire d'id minimal, enfant médian, mind Born), héritage fin (dominance/mutation SplitMix64, salience configurable), événements group_formed/dissolved/decision + agent_spawned, snapshot groups[], transmissionRange 55 (§ calibration ph6), engineVersion 0.5.0 (#SYNE-060→063) (#428)
…ction←Intention←Objectif←Besoin←Croyance←Mémoire←Perception depuis decision_traces/events_log/agents, cycles récurrents + profondeur bornée [1,12], CausalCache LRU invalidé sur ingest_version, endpoint GET /api/runs/{id}/causal-chains/{agentId}) (#ECHOS-060→063) (#429)
…tem + agent_died, naissance consentie fidèle Qualifies/LOS/énergie/critique, décision collective → objectifs membres GroupObjective/PropagateObjectives + bonus alignement, cheminement A* déterministe grille rasterisée/voisinage ordonné/tie-break/repli sur place + PathCache LRU), preuves anti-triche SYNE-081/082, engineVersion 0.6.0 + checksum doré ré-épinglé 0x27fad50065d8c4a4 (#SYNE-074→077, #SYNE-081→082) (#430)
…POINTS (auto-description ), + test registre ECHOS-051 — alignement inventaire API_REST.md §2 (11 endpoints) (#431)
…CHOS ph6 ; U8 = ph7 + ph11 + 120-131 + packaging), tickets SYNE-074→077 livrés (jalon ph7b), agent_died documenté (payload {cause,species}, engineVersion 0.6.0), régularisation API_CONTRACTS/DETERMINISM/TESTING/CHANGELOG + épinglage checksum 0x27fad50065d8c4a4 (#432)
…API — PAS de shell Electron en V0.1 (ADR-001 ECHOS, ARCHITECTURE ECHOS/racine, CHANGELOG, FRONTEND_VISION, ISSUES, README, ROADMAP, PRISM ; résidu Electron = contexte d'abandon uniquement) (#433)
…udgetCollector budgets 7 sous-systèmes + part computation ≥30 %, CLI --benchmark cibles 50/500/1000 + checksum d'état FNV-1a, ObjectPool sur buffer de tri de perception pour réduire l'allocation GC, déterminisme conservé — checksum doré inchangé 0x27fad50065d8c4a4) ; tests +12 (ObjectPool 5, TickBudget 3, ScaleTargets 4) → 273 Core + 6 Console (#SYNE-090→093) (#434)
…k ≥2720/1187/505 t/s, part computation 35-68%, machine de référence, convention CI planchers 120/30/20×\~7), ISSUES.md SYNE-090→093 LIVRÉ, CHANGELOG, ROADMAP racine+docs (U7/ph9), TESTING.md (+12 → 279, planchers, §5/§6) — checksum doré inchangé 0x27fad50065d8c4a4 (#435)
…config 100%, déterminisme d'état complet) ; intégration boucle complète sans perte data; observabilité étendue ExternalEvent (#436)
…#438)

* feat(echos): jalon ph7 — comparaison expérimentale ECHOS-070→072 (GET /api/compare, méta-métriques reproductibilité ReproducibilityScore 1-(CognitiveDiff+SocialDiff)/2, empreinte SHA-256 canonique, exports json/csv alignés) ; tests +11 → 208, couverture 97,97%

* style(echos): lignes test_compare.py ≤ 100 caractères (flake8 echos .flake8 max-line-length=100) — CI Python verte
…,19%, baseline d'état 0x072a488aa18c05eb épinglée DETERMINISM §7), ROADMAP/TESTING/CHANGELOG/ISSUES+racine U7 (#437)
donovan-dev-web and others added 23 commits September 30, 2026 16:20
* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* chore(echos): ingestion 0.3.0, stockage et calibrage|Champs optionnels inventory/commitments dans les modèles d'ingestion (rétro-compat 0.2.1 conservée), routes et service UI (echos-serve), invalidation inter-processus du cache de séries via PRAGMA data_version, calibrage de fin de run et viabilité. Suite ECHOS verte, couverture 93,16 %. Closes #485

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

---------

Co-authored-by: Codebuff <noreply@codebuff.com>
…Live/Actualiser (#498)

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* chore(echos): ingestion 0.3.0, stockage et calibrage|Champs optionnels inventory/commitments dans les modèles d'ingestion (rétro-compat 0.2.1 conservée), routes et service UI (echos-serve), invalidation inter-processus du cache de séries via PRAGMA data_version, calibrage de fin de run et viabilité. Suite ECHOS verte, couverture 93,16 %. Closes #485

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* fix(echos-ui): écrans d'analyse gelés, retard croissant et contrôles Live/Actualiser|Trois causes racines corrigées : cache de séries jamais invalidé entre processus (retard croissant 155→494 ticks), liste des runs chargée une seule fois (le run démarré n'apparaissait jamais), et refetch complet à chaque tick WS (tempête de requêtes). Ajout des boutons Actualiser et bascule Live/Figé. Validation réelle sur un run de 7 600 ticks : retard stable 14-35 ticks, 1 req/2 s mesurée. 62/62 tests UI. Closes #480

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

---------

Co-authored-by: Codebuff <noreply@codebuff.com>
* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* chore(echos): ingestion 0.3.0, stockage et calibrage|Champs optionnels inventory/commitments dans les modèles d'ingestion (rétro-compat 0.2.1 conservée), routes et service UI (echos-serve), invalidation inter-processus du cache de séries via PRAGMA data_version, calibrage de fin de run et viabilité. Suite ECHOS verte, couverture 93,16 %. Closes #485

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* fix(echos-ui): écrans d'analyse gelés, retard croissant et contrôles Live/Actualiser|Trois causes racines corrigées : cache de séries jamais invalidé entre processus (retard croissant 155→494 ticks), liste des runs chargée une seule fois (le run démarré n'apparaissait jamais), et refetch complet à chaque tick WS (tempête de requêtes). Ajout des boutons Actualiser et bascule Live/Figé. Validation réelle sur un run de 7 600 ticks : retard stable 14-35 ticks, 1 req/2 s mesurée. 62/62 tests UI. Closes #480

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* feat(echos): shell de bureau Electron (ADR-003), packaging et CI|Backend Python enfant démarré par le shell (port libre, attente /health, SIGTERM→SIGKILL), UI servie même origine (zéro CORS), PyInstaller onedir avec collect_submodules('echos') (les moteurs importlib étaient invisibles de l'analyse statique), postinst Debian posant le setuid chrome-sandbox, packaging .deb/NSIS et workflow echos-desktop.yml avec smoke test. Closes #479

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

---------

Co-authored-by: Codebuff <noreply@codebuff.com>
…500)

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* chore(echos): ingestion 0.3.0, stockage et calibrage|Champs optionnels inventory/commitments dans les modèles d'ingestion (rétro-compat 0.2.1 conservée), routes et service UI (echos-serve), invalidation inter-processus du cache de séries via PRAGMA data_version, calibrage de fin de run et viabilité. Suite ECHOS verte, couverture 93,16 %. Closes #485

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* fix(echos-ui): écrans d'analyse gelés, retard croissant et contrôles Live/Actualiser|Trois causes racines corrigées : cache de séries jamais invalidé entre processus (retard croissant 155→494 ticks), liste des runs chargée une seule fois (le run démarré n'apparaissait jamais), et refetch complet à chaque tick WS (tempête de requêtes). Ajout des boutons Actualiser et bascule Live/Figé. Validation réelle sur un run de 7 600 ticks : retard stable 14-35 ticks, 1 req/2 s mesurée. 62/62 tests UI. Closes #480

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* feat(echos): shell de bureau Electron (ADR-003), packaging et CI|Backend Python enfant démarré par le shell (port libre, attente /health, SIGTERM→SIGKILL), UI servie même origine (zéro CORS), PyInstaller onedir avec collect_submodules('echos') (les moteurs importlib étaient invisibles de l'analyse statique), postinst Debian posant le setuid chrome-sandbox, packaging .deb/NSIS et workflow echos-desktop.yml avec smoke test. Closes #479

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* feat(dev-stack): script de développement Electron pour la pile ECHOS|Variante bureau de dev-stack.sh : SYNE + ingestion + fenêtre Electron partageant la base d'analyse via ECHOS_ANALYTICS_DB ; arrêt par Ctrl+C ou fermeture de la fenêtre (le backend enfant ne survit jamais à la fenêtre). Deux modes documentés dans README et INSTALLATION. Closes #482

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

---------

Co-authored-by: Codebuff <noreply@codebuff.com>
* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* chore(echos): ingestion 0.3.0, stockage et calibrage|Champs optionnels inventory/commitments dans les modèles d'ingestion (rétro-compat 0.2.1 conservée), routes et service UI (echos-serve), invalidation inter-processus du cache de séries via PRAGMA data_version, calibrage de fin de run et viabilité. Suite ECHOS verte, couverture 93,16 %. Closes #485

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* fix(echos-ui): écrans d'analyse gelés, retard croissant et contrôles Live/Actualiser|Trois causes racines corrigées : cache de séries jamais invalidé entre processus (retard croissant 155→494 ticks), liste des runs chargée une seule fois (le run démarré n'apparaissait jamais), et refetch complet à chaque tick WS (tempête de requêtes). Ajout des boutons Actualiser et bascule Live/Figé. Validation réelle sur un run de 7 600 ticks : retard stable 14-35 ticks, 1 req/2 s mesurée. 62/62 tests UI. Closes #480

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* feat(echos): shell de bureau Electron (ADR-003), packaging et CI|Backend Python enfant démarré par le shell (port libre, attente /health, SIGTERM→SIGKILL), UI servie même origine (zéro CORS), PyInstaller onedir avec collect_submodules('echos') (les moteurs importlib étaient invisibles de l'analyse statique), postinst Debian posant le setuid chrome-sandbox, packaging .deb/NSIS et workflow echos-desktop.yml avec smoke test. Closes #479

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* feat(dev-stack): script de développement Electron pour la pile ECHOS|Variante bureau de dev-stack.sh : SYNE + ingestion + fenêtre Electron partageant la base d'analyse via ECHOS_ANALYTICS_DB ; arrêt par Ctrl+C ou fermeture de la fenêtre (le backend enfant ne survit jamais à la fenêtre). Deux modes documentés dans README et INSTALLATION. Closes #482

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* fix(syne-mock): run_id canonique run-<seed>-<12hex>|Deux runs de même seed se partageaient le même run_id côté stockage ECHOS. Format canonique aligné sur API_CONTRACTS.md §3 avec suffixe d'unicité, seed transporté dans le snapshot. Closes #483

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

---------

Co-authored-by: Codebuff <noreply@codebuff.com>
* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* chore(echos): ingestion 0.3.0, stockage et calibrage|Champs optionnels inventory/commitments dans les modèles d'ingestion (rétro-compat 0.2.1 conservée), routes et service UI (echos-serve), invalidation inter-processus du cache de séries via PRAGMA data_version, calibrage de fin de run et viabilité. Suite ECHOS verte, couverture 93,16 %. Closes #485

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* fix(echos-ui): écrans d'analyse gelés, retard croissant et contrôles Live/Actualiser|Trois causes racines corrigées : cache de séries jamais invalidé entre processus (retard croissant 155→494 ticks), liste des runs chargée une seule fois (le run démarré n'apparaissait jamais), et refetch complet à chaque tick WS (tempête de requêtes). Ajout des boutons Actualiser et bascule Live/Figé. Validation réelle sur un run de 7 600 ticks : retard stable 14-35 ticks, 1 req/2 s mesurée. 62/62 tests UI. Closes #480

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* feat(echos): shell de bureau Electron (ADR-003), packaging et CI|Backend Python enfant démarré par le shell (port libre, attente /health, SIGTERM→SIGKILL), UI servie même origine (zéro CORS), PyInstaller onedir avec collect_submodules('echos') (les moteurs importlib étaient invisibles de l'analyse statique), postinst Debian posant le setuid chrome-sandbox, packaging .deb/NSIS et workflow echos-desktop.yml avec smoke test. Closes #479

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* feat(dev-stack): script de développement Electron pour la pile ECHOS|Variante bureau de dev-stack.sh : SYNE + ingestion + fenêtre Electron partageant la base d'analyse via ECHOS_ANALYTICS_DB ; arrêt par Ctrl+C ou fermeture de la fenêtre (le backend enfant ne survit jamais à la fenêtre). Deux modes documentés dans README et INSTALLATION. Closes #482

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* fix(syne-mock): run_id canonique run-<seed>-<12hex>|Deux runs de même seed se partageaient le même run_id côté stockage ECHOS. Format canonique aligné sur API_CONTRACTS.md §3 avec suffixe d'unicité, seed transporté dans le snapshot. Closes #483

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* docs: revue documentaire V0.1 transverse et élection de source|Rapport des éléments ouverts (arbitrage 5 acceptés / 2 reportés), création de docs/docs-launcher (18 documents + 6 ADR), retrait des docs prototype remplacés (47 fichiers), ADR cognitifs marqués implémentés, docs SYNE (contrat 0.3.0, 14 clés catalogue, jalon déterminisme 0.14.0) et ECHOS (ADR-003, correctifs). Closes #484

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

---------

Co-authored-by: Codebuff <noreply@codebuff.com>
L'audit de parité SYNE ↔ syne-mock a révélé huit écarts : versions de
contrat obsolètes (0.2.0/0.11.0 au lieu de 0.3.0/0.14.0), runId absent
du monde préparé (SYNE l'épingle dès le prepare), start accepté sur un
run terminé (409 run_finished chez SYNE), erreurs HTTP sans la clé
detail, réponses de contrôle sans l'enveloppe {action, runId, state,
tick, aliveCount, seed}, obstacles de world_initialized exposant la
représentation interne (type/shape/cells) au lieu de la géométrie
{id, x, y, radius} de WorldDescription, événement world.book_written
sans cost ni targetId, et simulatedTimeMinutes confondu avec le tick.

Le mock reste une reproduction simplifiée et déterministe, mais il
parle désormais exactement le contrat HTTP :5181 et WS :5180 du moteur
0.14.0 — PRISM et ECHOS passent de l'un à l'autre sans adaptation.

Tests : 39/39 Node, intégration ECHOS↔mock verte (LIVEX_MOCK_E2E=1).

🤖 Generated with Codebuff

Co-authored-by: Codebuff <noreply@codebuff.com>
…quette (#504)

Établit la spécification pixel de l'interface du Launcher par mesure directe
de la maquette de référence 1536x1024, et réconcilie le document fonctionnel
avec ce qu'elle montre réellement.

GUI.md (nouveau, 15 sections) : grille à trois colonnes vérifiée
(16+222+17+924+17+321+19 = 1536), bornes pixel de chaque zone, palette,
typographie, composants, états, interactions, ordre de priorité de
reproduction et points ouverts.

USER_INTERFACE.md : ajout du découpage de portée avec GUI.md ; réécriture du
§2 autour de la sidebar à sept entrées réellement présente dans la maquette,
avec la correspondance aux trois modes et le conflit de navigation signalé
comme décision à trancher ; §6 révisé, le principe « aucun dégradé » étant
contredit par la maquette — les dégradés sont admis comme traitement de fond,
jamais comme signal ; §6.2 fixe le couple typographique Montserrat/Inter.

Écart mesuré et documenté (GUI.md §12) : un rendu navigateur du prototype à
1536x1024 ne reproduit pas la maquette — hero 205 px contre 185 px, fond médian
#071017 contre #0d0f15, grain absent. Le prototype est structurellement
fidèle mais visuellement faux ; le PNG fait foi.

Maquettes versionnées (maquettes/) : le PNG est la source de vérité citée par
GUI.md et le prototype sert de référence de comportement ; ces références
étaient mortes tant que les fichiers n'étaient pas suivis.

Aucun impact contrat : ni WorldSnapshot, ni ExternalEvent, ni API REST ECHOS,
ni format de persistance, ni déterminisme SYNE.
…506)

Ajoute dans NETWORK.md la cartographie complète des flux — trois canaux :
contrôle via le Launcher, données directes SYNE <-> ECHOS/PRISM, restitution
ECHOS -> Launcher — et la cartographie des sous-espaces orchestrés par le
Launcher (blocs d'adressage internes par instance). DATA_FLOW.md reçoit la
cartographie équivalente (direct vs via le Launcher) et la règle du single
writer.

Corrige la taxonomie des modes (§9) pour s'aligner sur COMPONENTS.md §8,
lève la contradiction « analyse hors ligne » avec VISION.md, corrige le faux
flux SYNE -> Launcher de la séquence DATA_FLOW §7 (les instantanés et
événements partent en direct vers ECHOS/PRISM ; le Launcher ne prélève que
des métriques), propage le statut « forme de sortie » de la Gateway.

Répare les références de section cassées (PACKAGE_FORMAT, ROADMAP, PACKAGING,
ADR-004/006, TESTING, USER_INTERFACE, ISSUES, ARCHITECTURE), la ligne G0
dupliquée du ROADMAP, la réconciliation §5/§6 d'ISSUES, les pipes non
échappés d'INTEGRATION_CONTRACT et les coquilles du corpus.

Aucun impact contrat : documentation seule, aucun contrat de transport ni
format modifié.
Deliver the Launcher V1 desktop app, supervised Linux component adapters, unified real/emulated SYNE role, CI coverage, and aligned documentation.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…508)

listen() attend désormais l'erreur de bind du port WebSocket avant de
résoudre : un port occupé ferme le serveur HTTP au lieu de laisser une
instance à moitié démarrée qui répond sur un seul port.

- SIGINT rejoint SIGTERM pour l'arrêt propre (test dédié) ;
- le test d'arrêt authenticated ouvre un client WebSocket et attend sa
  fermeture : l'arrêt ne laisse aucun client suspendu ;
- README : 46 tests, et le mock n'est jamais présenté comme équivalent
  scientifique de SYNE (CONTRIBUTING.md §4).

Contrôle de transport non modifié : seule la mise en écoute et le cycle
de vie changent, la surface HTTP/WebSocket reste celle documentée dans
COMMUNICATION_PROTOCOL.md.
…cher (#511)

* feat(syne): export de stream batch et supervision de run pour le Launcher (#509)

Mode supervisé : --control-port, --instance-id, --work-dir, --log-dir et
--correlation-id ouvrent le cycle de vie attendu par le Launcher
(INTEGRATION_CONTRACT.md) — readiness, start/pause/stop/reset, arrêt
authentifié et journal du workspace.

Export batch : --simulation, --ticks, --export-dir, --run-id,
--export-stream et --autostart écrivent result.json et stream.jsonl
alignés dans le dossier du run, sous une identité analytique
{campagne}-{run} réutilisable par ECHOS.

Observabilité composite : diffusion WebSocket et journal de fichiers
coexistent sans se disputer le même événement (CompositeObservabilitySink).

Contrat v1 : syne/component.json décrit exécutable, endpoints, capacités
health/timeouts pour le validateur de manifests du Launcher.

Aucun argument existant n'est modifié et les nouveaux ne s'activent que
s'ils sont fournis : la trajectoire de référence et ses checksums de
persistance restent identiques (514 tests Core + 75 Console verts).

* docs(syne): décrit l export batch, la supervision et le manifeste de composant (#510)

README : mode supervisé, arguments densjaillement du run, export
result.json/stream.jsonl sous identité analytique, et le manifeste
component.json que le Launcher consomme.

COMMUNICATION_PROTOCOL : les chemins batch (run_id, fenêtre détats alignés,
arrêt contrôlé) rejoignent la description des canaux existants.

Aucune règle de comportement nest changée : lexecutable, les routes et le
format des trames sont ceux déjà livrés par la branche.
* feat(launcher): valide les manifests de composant v1 en CI

Schema JSON Schema (draft 2020-12) decrivant le manifeste component.json
dun composant LIVEX : identite, version, executable, endpoints, health,
timeouts et capacites. Le validateur verifie le schema, lexemple valide,
la rejection de lexemple invalide et lintegralite des component.json du
depot (git ls-files), ce qui refuse tout manifeste qui departage de la
regle depuis la racine.

Le job CI component-manifests se declenche quand un composant bouge, ce
qui empeche dajouter un composant dont le contrat nexiste pas.

Sonde : 3 manifests valides dans le workspace.

* docs(launcher): documente le contrat d'intégration des manifests v1
* feat(launcher): orchestre les campagnes multi-runs de bout en bout (#513)

* feat(launcher): orchestre les campagnes multi-runs de bout en bout

Identite de run deterministe (RunIdentity, SeedDeriver) : chaque run dun
groupe derive sa graine de la campagne, ce qui rend le groupe reproductible
sans semence globale. RunEngineProfile porte le profil densjaillement
(mono ou multi-run, cadence, ticks) lu depuis ExperimentDefinition.

Le cycle de vie va plus loin que le demarrage : les runs peuvent tre
pilotes (start/pause/stop/reset), les journaux de composant sont buffers
(ComponentLogBuffer) puis exportes avec le paquet, et les sondes de sante
respectent les timeouts du manifeste (HealthProber).

Le paquet Livex applique des regles dentree verifiees (PackageEntryRules)
: index, journal et fichiers de run concordent avant scellement. La surface
HTTP expose registre et metriques sans exposer de commande critique.

EchosAnalysisService devient consommable hors interface (telemetrie
cote ECHOS), ce qui conditionne le mode publication reel.

Interfaces de test : Stub.Syne et Stub.Echos refletent le contrat v1
(manifeste, endpoints, cycle de vie), ce qui permet aux tests end-to-end
d'exercer le vrai chemin dun poste sans installation.

125 tests unitaires, 15 dintegration et 27 end-to-end verts.

* docs(launcher): documente les flux de donnees, le format de paquet et le reseau

DATA_FLOW suit une donnee du profil dexperience jusquau paquet scelle ;
PACKAGE_FORMAT et PACKAGING decrivent lentree verifiee, lindex et le
scellement; EXPERIMENTS et INTEGRATION_CONTRACT alignent le vocabulaire
des profils, des runs et des capacites; NETWORK expose les plages de ports
et la surface HTTP; le README du projet reprend la structure et les
commandes de developpement.

Aucune regle de comportement nest changee : ces pages decrivent
lexistant et les ajouts livres dans le commit precedent.

* test(launcher): exerce la campagne sur le moteur SYNE publié + publication en CI (#514)

* test(launcher): exerce la campagne sur le moteur SYNE publié

Le banc passe desolecution dinstances stub a lexecution reelle de
Simulation.Console publie : la campagne est creee, deux runs partent du
vrai moteur avec des graines derivees, la progression du run est lue sur
le tic rapporte par le moteur, puis le paquet est scelle et relu.

La variable LIVEX_SYNE_PUBLISHED_ROOT rend le test conditionnel : sans
elle, il signale sa presence plutot que de pretendre avoir couvert le
chemin reel.

* ci(launcher): publie SYNE avant les tests bout en bout

Sans publication, le test dacception du moteur reel se signale comme
ignore et le job passe sans avoir rien verifie. Lexetape publish produit
lexecutable dans bin/Release/net10.0/publish et le test le localise par
LIVEX_SYNE_PUBLISHED_ROOT.

* fix(launcher): mesure la progression du run sur les échantillons en cours (#515)

Lintegration exigeait MaxTicks == 1000 sur tous les echantillons, alors
que la premiere sonde peut arriver pendant que le moteur attend encore
son start : le run en est a letat ready, aucun tic nest ouvert et
lhorizon nenst pas encore publie. Le contrainte nest donc verifiee que
sur les echantillons dun run effectif (Tick > 0), ou ControlServer a
bien transmis son horizont depuis StartAsync.

Le comportement reste celui voulu par Abstractions.cs : sans horizon,
la barre reste indeterminee plut que dafficher un faux pourcentage.

* feat(launcher): ouvre les consoles de composant et la fenêtre d'analyse natives (#516)

* feat(launcher): ouvre les consoles de composant et la fenetre d analyse natives

Une fenetre native par instance supervisee (ConsoleWindow + ConsoleViewModel)
: les journaux buffers du moteur y defilent en direct a l ouverture, a la
demande depuis les cartes et automatiquement au demarrage d un composant.
Aucune commande ny transite, elle reste un canal dobservation.

Une fenetre d analyse unique (AnalysisWindow, ~2300 lignes de ViewModel)
remplace le panneau web retire d ECHOS : courbes de KPI, graphe de confiance,
graphe de groupes et vue du monde separent depuis l API REST d ECHOS, sans
serveur ni bundle front.

Les controles dessines (WorldView, TrustGraph, GroupsGraph) et le package
LiveChartsCore ne servent qu a la presentation : ils naffectent ni le
cycle de vie ni les contrats.

tools/UiScreenshot capture ces fenetres pour illustrer la documentation.

161 tests unitaires (dont les deux suites deViewModel de fenetre), 15
dintegration et 29 end-to-end verts.

* docs(launcher): acte les fenetres natives, l ADR-007 et la matrice de capacites

ADR-007 enregistre le choix des consoles et de la fenetre d analyse natives
apres le retrait de l interface web, avec ses alternatives rejetees. USER_INTERFACE
decrit la disposition, les entrees et les raccourcis; ARCHITECTURE,
COMPONENTS, NETWORK, ROADMAP, TESTING, VISION, ISSUES, CHANGELOG et le
README suivent, ainsi que le sommaire des ADR.

ROADMAP-V1 et V1-CAPABILITY-MATRIX suivent l avancement reel : chaque
capacite de la V1 est rattachee au code ou au test qui la couvre.

Aucune regle de comportement nest changee : la documentation decrit les
fenetres livrees dans le commit precedent.
…terface (#522)

* feat(echos): catalogue versionné, provenance par état, analyse headless et ingestion par lot (#518)

* feat(echos): catalogue versionne des metriques, provenance par etat et analyse headless

catalog.py est la source unique de verite documentaire des metriques :
identite, unite, formule, population, fenetre, direction, statut
(measured/exploratory/suspended), etats de provenance possibles,
avertissement, forme visuelle et historique des renommages. CATALOG_VERSION
suit le semver : toute formule ou unite changee le fait monter.

La provenance nest plus un booleen seul : chaque point porte un etat
(explicitement observe, fenetre vide, couverture insuffisante, absente,
repli neutre, censuree) de sorte quun 0.0 observe ne se confonde plus
avec un repli.

headless.py rejoue lanalyse hors serveur depuis un run archive, ce qui
permet au Launcher de produire un rapport sans API REST ni bundle front.

Les modules existants adoptent le vocabulaire : chaque metrique declare
son statut, ses etats possibles et son avertissement depuis le catalogue
plutot que depuis une chaine en dur.

Scenarios de reference et dore contredisent lanalyse de tete : les formules
sont verifiees sur des mondes connus plutot que sur des tirages aleatoires.

* feat(echos): expose le catalogue, ingere par lot et aligne le serveur

/api/metrics/catalog publie le contrat du catalogue (formatage, axes,
filtrage) sans jamais recalculer un score : le Launcher restore, ECHOS
reste proprietaire du calcul.

Lingestion par lot lit un run archive (manifeste, flux aligne, resultats)
et le rejoue dans une base neuve : meme archive, meme analyse, que le
flux vienne dun WebSocket ou dun fichier. file_client refuse un champ
inconnu au lieu de laisser passer une donnee qui ny aurait pas sa place.

Les routes exposent valeur ET drapeau de provenance cote a cote, ce qui
permet a linterface de distinguer un 0.0 mesure dun repli.

Le serveur, le reporting et le contrat Launcher suivent le catalogue :
identifiants stables, statuts declares, etats de donnees rendus tels quels.

Ensemble vert avec la branche de lanalyse : flake8 sans faute, 94 % de
couverture (seuil 80 %), scenarios de reference et determinisme J2 verts.

* fix(echos): borne la liste des métriques non mesurables sur les tirs courts (#519)

Les deux integrations (SYNE reel et mock) exigeaient que toutes les
metriques soient mesurees sur un run reel : lanalyse V2 refuse desormais
dinventer une valeur quand la condition de mesure nenst pas reunie, et
six metriques tombent en non mesure sur ce tir de 3 ticks / 9 agents
(BeliefDiversityNorm dont le denominateur repose sur les categories
observees, plus cinq metriques declarees exploratoires au catalogue).

La liste blanche vit dans provenance_expectations.py, partagee par les
deux tests, et ne peut que retrecir : une metrique non mesuree qui ny
figure pas est une regression de provenance, et une metrique redevenue
mesurable doit en sortir pour que la liste ne devienne pas un sac de
recharge silencieux.

Verifie sur les deux integrations (LIVEX_SYNE_E2E=1, LIVEX_MOCK_E2E=1),
lintegralite de la suite et flake8 : 0 faute, couverture 93,49 %.

* docs(echos): fondements analytiques, métriques, scénarios de référence et API (#520)

ANALYSIS_FOUNDATIONS pose les equations, les hypotheses et les limites de
chaque moteur plutot que denoncer un resultat sans contexte. METRICS_SPEC
et METRICS_DICTIONARY donnent formule, unite et matrice metrique vers API
vers vue, avec lexplicite de ce qui est retire et de pourquoi.

REFERENCE_SCENARIOS fournit les cas etalons et les baselines, ce qui rend
les ors des scenarios opposables et non plus indicatifs. DYNAMIC_VIABILITY_INDEX
enregistre le successeur conceptuel demergenceScore, documente mais pas
encore implemente.

API_REST documente le catalogue, la provenance fournie avec chaque valeur
et les nouvelles routes d analyse; le README du composant décrit lingestion
par lot et lanalyse headless, qui nen dependent denservir de fenetre.

TESTING et EMERGENCE_INDICATORS suivent le nombre de tests (365) et les
identifiants renomes. Aucune regle de comportement nest changee.

* refactor(echos)!: retire l'interface web et le shell Electron (ADR-007) (#521)

* refactor(echos): retire linterface web et le shell Electron (ADR-007)

ECHOS redevient un moteur : echos-ui (React + Vite) et echos-desktop
(Electron, PyInstaller ondir) sont supprimes, de meme que la CI qui les
construisait (job echos-ui de ci.yml, workflow echos-desktop.yml sur
matrice ubuntu/windows et release.yml) et le lancement de linterface
dans dev-stack.sh et dev-stack-electron.sh.

Lintroduction de lanalyse headless la veille a rendu cette separation
possible : API et analyse ne dependent denservir de fenetres, et la
presentation est portee par les fenetres natives du Launcher (consoles
de logs, fenetre d analyse) qui sondent lAPI locale.

Suppression de 62 fichiers, aucun fichier code Python ou TypeScript
conservant de reference a ces chemins : server.py et create_app() ne
desservent plus de statique depuis lanalyse V2.

* docs(echos): archive linterface retiree et recale ADR-001 et ADR-003

Les documents qui affirment lexistence de linterface web sont
recalibres sur le retrait : README index, ARCHITECTURE, ROADMAP,
ISSUES et CHANGELOG mentionnent ADR-007 et renvoient vers les
fenetres natives du Launcher.

FRONTEND_VISION et USER_STORIES basculent en statut historique, le
design system reste comme trace de lintention. ADR-001 (stack
applicative) et ADR-003 (shell Electron) portent la decision du
5 octobre 2026 avec le lien vers lADR-007 du Launcher.

Aucun document analytique ni contrat API nest modifie ici : la
documentation d analyse a ete livree avec la branche dadaptation
analytique, seule la couche qui decrit linterface change.

* fix(echos): rattache l'ingestion batch au job U8 et gate le vrai moteur (#523)

Le job echos-python est Python pur : pas de dotnet, pas de build Release.
test_batch_ingestion.py declenchait pourtant le binaire SYNE et plantait
la CI de la PR parente (echos-python en rouge, integrations vertes).

A l'image de l'integration WebSocket, la fixture `syne_run` est sautee
sans `LIVEX_SYNE_E2E=1` ; les tests qui ne touchent pas au moteur
(lecture de flux, `inspect`, routes de refus) restent actifs partout. Le
job U8, qui compile SYNE Release, execute desormais aussi le fichier avec
le vrai moteur.

Verifie : flake8 sans faute, suite complete verte (couverture 91,86%,
seuil 80%), U8 etendue verte (WebSocket + batch sur le moteur reel).

* fix(echos): saute l'écriture des runs moteur quand le binaire SYNE est absent (#524)

La premiere garde ne couvrait que la fixture `syne_run` : le test du
flux tronque appelle `_write_run` en direct et plantait encore le job
Python pur (CI #522 rouge, 12:49). La garde remonte dans `_write_run`,
unique point de depart dun processus SYNE : 11 tests sautes sans
`LIVEX_SYNE_E2E=1`, aucun appel au moteur dans le job echos-python.

Le job U8, qui compile SYNE Release, execute toujours les 16 tests avec
le vrai moteur. flake8 sans faute, suite complete verte (couverture
91,23%, seuil 80%).
#525)

README, ARCHITECTURE, INSTALLATION et VERSIONING recadrent la pile :
ECHOS est un moteur sans interface, la presentation vit dans les
fenetres natives du Launcher, et dev-stack-electron.sh a disparu.
INSTALLATION gere le demarrage sans navigateur ni Electron.

Livex-status.md rejoint le depot : c'est le bilan de l'etat de la
campagne d'integrer, nouveau frontiere de ce qui a ete livre (SYNE,
SYNE-MOCK, ECHOS, Launcher) et de ce qui reste ouvert.
* fix(launcher): archive les runs au-delà de 2 Gio et fiabilise l'analyse de campagne

- RunDataFile : source fichier lue en flux, jamais chargée en byte[] (un stream.jsonl
  de 2500 ticks × 50 agents = 2,34 Gio dépasse int.MaxValue) ; LivexPackageWriter écrit
  en mode Create avec échange atomique et hachage d'intégrité en flux, Seal en Read → Create,
  plafond d'entrée du lecteur relevé de 4 à 16 Gio (PACKAGE_FORMAT §9).
- Ensemble vide de runIds détecté côté Campagne : avertissement explicite au lieu d'un 422 opaque.
- Délai d'analyse ECHOS posé par requête : 30 min pour ingest/run et analysis/* (5 m 30 s
  mesurées pour ingérer 2500 ticks × 50 agents), 30 s pour les appels ordinaires.
- Tests : régression > 2 Gio, archivage du vrai stream.jsonl 2,34 Gio, campagne SYNE publié,
  analyse ECHOS ; docs PACKAGE_FORMAT / EXPERIMENTS / CHANGELOG à jour.

* feat(syne): calibration B1 des défauts intégrés — stabilité 2500 ticks (ADR-016)

Défauts du moteur recalibrés pour tenir 2500 ticks à 50 et 100 agents (6/6 runs,
0 extinction, 0 mort, |pente| ≤ 0,0037/tick < 0,005) : réserves food/water 20 000
avec régénération nette 20/10 (degradationTick null), moveEnergyCost 0,05 → 0,03,
gains Eat/Drink 2,0/1,0, Rest 1,5/2,0, dérives social/curiosité 0,001/0,002 →
0,0002/0,0005, coûts de communication neutres. engineVersion 0.14.0 → 0.15.0,
goldens re-pinnés (DETERMINISM §7), 27 tests adaptés.

Accompagnement : reference.json corrigé (chemin catalog.entries) et rejouant B1 ;
ComputationShare rapportée en temps/tick ; rejet 413 fiabilisé (vidange bornée du
corps avant réponse, fini le broken pipe) ; script rejouable scripts/calibration-campaign.py.

* docs(prism): fixe l'échelle et la cadence SYNE ↔ Unreal (ADR-003)

Convention d'échelle arrêtée : k = 100 uu/unité, ticksPerSecond 6, monde 2240 × 2240
(5 km²), worldCellSize 32 uu = case de grille WP 3200 uu (défaut UE, MaxWalkSpeed
600 uu/s). Ajout de SCALE_AND_CADENCE_SPEC.md (11 sections, checklist de validation)
et de l'ADR-003 [Proposed] ; README, CHANGELOG, index ADR et PRISM_UNREAL_IMPLEMENTATION
mises en cohérence (formule de conversion UnrealX = SyneX × k, tableaux de cadence).
… les 4 suites (#527)

Étapes 4 et 5 de ROADMAP-V01 : validations Windows de bout en bout (apphost natif,
Job Object, journaux de session partagés, --check, E2E contre SYNE publié win-x64 et
ECHOS réel) ; suite Launcher 214 tests verts, build --warnaserror 0/0.

CI : 4 nouveaux jobs windows-latest, 13/13 verts (Linux + Windows). Cinq défauts
trouvés et corrigés au passage : glob shell non étendu par PowerShell, saut dynamique
xunit non converti en « ignoré », verrou mortel CloseAsync/ReceiveAsync du serveur
d'observabilité SYNE, plancher de débit mesuré sous contention entre assemblées de
tests, et archivage des journaux de run en violation de partage (RunLogArchive,
lecture FileShare.ReadWrite).

Docs : ROADMAP-V01, CHANGELOG, Livex-status alignés sur le constat CI.
…auncher) (#528)

SYNE (ADR-017, échelle/cadence PRISM):
- Clé simulation.simulatedSecondsPerTick (défaut 60, neutre par défaut, plage
  [1,3600]) et clé informative world.metersPerUnit ; ratio R = TPS × s/tick.
- Horloge instanciée SimulationClock + mise à l'échelle déterministe en trois
  classes (TemporalScale) ; profil prism (monde 2240, 6 TPS, 5 s/tick, R=30)
  via --simulation prism + configs/simulation/prism.json.
- Contrats additifs : observabilité 0.4.0, world_initialized 1.1
  (simulatedSecondsPerTick/metersPerUnit), snapshot + simulatedTimeSeconds,
  /api/control/status + simulatedSecondsPerTick.

syne-mock: aligné sur le nouveau contrat temporel et le profil prism.

Launcher (mode PRISM / refonte du parcours):
- Posture pilotée EnginePosture (sans --autostart, --simulation prism,
  --observe-port) : le projet Unreal pilote via prepare/ready/start.
- Écran PRISM dédié (navigation) : démarrage/arrêt + URLs de contrôle (HTTP)
  et d'observation (WS) à rejoindre.
- Modes Expérience et PRISM mutuellement exclusifs : PRISM actif verrouille
  l'écran Expériences (bandeau + CanCreateCampaign).
- Nettoyage : retrait du champ Mode Mono/MultiRun (runs + vitesse explicites).

Tests: SYNE 634 verts, Launcher 164 unit + 20 int + E2E piloted, syne-mock 22.

🤖 Generated with Codebuff

Co-authored-by: protection-test <protection-test@example.com>
Co-authored-by: Codebuff <noreply@codebuff.com>
…ructure (#529)

* docs(naming): conformité NAMING_CONVENTIONS — en-têtes, renvois et structure

- En-tête de fichier conforme §9.2 dans les 353 fichiers de code : docstring de
  module (Python, bandeau # redondant supprimé), bloc JSDoc (JavaScript),
  bandeau // en tête (C# et C++ — écart « /// » documenté : un commentaire XML
  avant les using déclenche CS1587 dès que GenerateDocumentationFile=true).
- Rôles tronqués (…) réécrits depuis les blocs de doc natifs des fichiers
  (199 bandeaux C# touchés).
- Références à des documents et paragraphes retirées des commentaires et
  docstrings (X.md, §n, Annexe, ADR, Monographie, noms de documents sans
  extension) ; les références d'issue (SYNE-nnn, ECHOS-nnn…) sont conservées.
- Nommage : scripts Python en snake_case, ADR transverses numérotés
  (ADR-005 → ADR-011 + index docs/adr/README.md), Livex-status.md →
  LIVEX-STATUS.md.
- 11 documents obsolètes retirés du dépôt (ROADMAP-V01, RAPPORT-ELEMENTS-OUVERTS,
  UI_DESIGN, USER_STORIES, FRONTEND_VISION, MIGRATION_MORPHOLOGY, DECISIONS_V01,
  ADR-001 Godot, ADR-003 Electron, ADR Perception, Note Couche Affective) ; les
  renvois qui les citaient sont neutralisés (« document retiré du dépôt ») dans
  les changelogs, ADR et ISSUES ; métadonnées §10 complétées sur les documents
  PRISM et docs/README.md ; docstring de batch_analysis.py traduite en français.

Vérifié : builds Release --warnaserror 0/0 (syne + launcher), tests SYNE 548 +
86, tests Launcher, npm test syne-mock 46 ✓, flake8 à parité avec HEAD
(38 E501 préexistants, 0 nouvel écart), compileall exit 0.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* fix(echos): restaure le DDL et les INSERT corrompus par la passe de conformité

La passe de suppression des renvois avait retiré la parenthèse ouvrante de
8 `CREATE TABLE` (DDL de `storage/sqlite.py`), de 5 `INSERT` inline et du
schéma de test de `test_sqlite_store.py` : les suites ECHOS tombaient en
`sqlite3.OperationalError: near "key"/"run_id"` (4 jobs CI en échec). Le
diff AST hors docstrings contre develop ne révèle aucune autre altération de
code ; quatre artefacts de docstring résiduels sont aussi nettoyés (crochet
vide, « cf., » orphelin, espace perdu en début de ligne, reflow).

Vérifié : pytest complet vert (couverture 90,55 % ≥ 80 %), flake8 à parité
avec develop (38 E501 préexistants), compileall exit 0.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

---------

Co-authored-by: protection-test <protection-test@example.com>
Co-authored-by: Codebuff <noreply@codebuff.com>
…, badges et LIVEX-STATUS (#530)

* fix(launcher): fenêtre sans chrome et carte composant — coins arrondis, débordement corrigé

- Fenêtre : CornerRadius 16 + ClipToBounds, fond déplacé du Window vers la
  Border principale pour que le dégradé radial soit découpé aux coins.
- Carte composant : rangée « pastille d'état + Console » puis rangée
  « Démarrer/Arrêter + Configurer » — le Grid à rangées implicites
  débordait de la carte.
- Boutons de fenêtre 40 → 32 px, padding 0 → 10.

Vérifié : build Release --warnaserror 0/0, suites Launcher 164 unitaires +
20 intégration verts.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* docs(livex): cohérence doc/code — versions, badges de tests et LIVEX-STATUS au 12/10

- LIVEX-STATUS : réécriture avec suites rejouées (1 258 tests, 16 ignorés,
  0 échec), couverture ECHOS 90,55 % et SYNE 87,41 % (union coverlet),
  inventaire 640 fichiers / 65 142 lignes tokei ; renvois « étapes »
  réalignés sur ROADMAP.md + launcher/ROADMAP-V1.md (le plan ROADMAP-V01 a
  été retiré par la PR #529) ; CI develop 13/13 jobs au 11/10.
- VERSIONING §8 : lignes composants manquantes — Launcher 0.1.0,
  syne-mock 0.1.0, ECHOS 0.1.0, PRISM sans version propre (DRAFT).
- Badges : CI + Tests 1 258 + Couverture ≥ 80 % (README racine, ancre §5),
  contrat obs. 0.2.1 → 0.4.0, docs-syne 634 / 87,4 %, docs-echos 361 /
  90,5 %, ligne Launcher ajoutée à la table des composants.
- API_CONTRACTS : « implémentation actuelle, contrat 0.2.1 » → contrat
  courant 0.4.0 ; en-têtes VERSIONING / docs-syne / docs-prism au 12/10.
- Lignes de version dans syne/README, echos/README, launcher/README,
  syne-mock/README (48 tests) ; docs-launcher dans l'arborescence README.

Vérifié le 12/10 : suites SYNE 634, Launcher 217, ECHOS 361+14 ignorés,
syne-mock 46+2 ignorés, tokei 13.0.0 sur les fichiers suivis.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

---------

Co-authored-by: protection-test <protection-test@example.com>
Co-authored-by: Codebuff <noreply@codebuff.com>
…nommés, filtre ADR

Exécution partielle du PLAN-REFONTE-DOCUMENTATION (annexe §8) :

- Racine limitée aux 7 fichiers conventions GitHub + snapshot monographie ;
  ARCHITECTURE/COMMUNICATION/INSTALLATION/CI_CD/NAMING → docs/,
  VISION/FAQ/GLOSSARY/ETHICS → docs/presentation/,
  ROADMAP/LIVEX-STATUS/GITFLOW/PLAN-REFONTE → docs/governance/.
- Dossiers composants renommés : docs-syne/echos/launcher/prism/installer.
- Filtre ADR : ADR-010 et ADR-011 (Reporté V2, aucune implémentation)
  retranchés (historique Git) ; statut ADR-001 Launcher corrigé
  Proposed → Accepted (Avalonia implémenté).
- docs/installer/ conservé avec bandeau « spécification — aucun code ».
- ~150 fichiers de liens réécrits par script + vérification par
  comparaison avant/après : aucun lien Markdown cassé.
- Code : commentaires et stub de test alignés sur les nouveaux chemins.

Build Release --warnaserror : 0/0. Tests Launcher : 164 unitaires +
20 intégration, 0 échec.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
- SUPPORT.md : canaux d'assistance (issues GitHub avec les 4 modèles
  existants + page contact du portfolio), périmètre hors support.
- AUTHORS : contributeur unique d'après l'historique Git.
- CITATION.cff : citation du logiciel LIVEX V0.1 au format CFF 1.2.0
  (validé : YAML + clés requêtes), bouton « Cite this repository ».
- README : mention du canal d'assistance dans la section Contribuer.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@donovan-dev-web
donovan-dev-web merged commit 2cc28bd into main Oct 12, 2026
13 checks passed
@donovan-dev-web
donovan-dev-web deleted the docs/nettoyage-structure branch October 12, 2026 10:52
donovan-dev-web added a commit that referenced this pull request Oct 12, 2026
…nommés, filtre ADR (#531) (#533)

* [GOVERNANCE] Jalon U0 — socle git flow, CI, gouvernance GitHub (#409)

* feat(governance): jalon U0 — socle git flow, CI remaniée, gouvernance GitHub

- branches Git Flow : develop créée depuis main
- milestones dédupliqués (série canonique par composant), labels normalisés
- CI: jobs filtrés par paths (syne/**, echos/**) via détection git diff,
  validation transverse toujours verte ; conteneurisation Docker reportée
- release.yml: aligné (pas de GHCR tant que pas de conteneurisation)
- ajout .gitignore/.editorconfig ; maj README, INSTALLATION, CHANGELOG

* fix(governance): resserre l'heuristique anti-secrets (auto-correspondance du motif)

* feat(syne): socle U0 — solution .NET, config Annexe H + CLI, PRNG déterministe, ADR-012 (#410)

- Syne.sln + Simulation.Core/Simulation.Console/Simulation.Core.Tests séparés (SYNE-001)
- SimulationOptions (Annexe H) + loader JSON générique (fichier partiel préservant
  les défauts), validation des plages, priorité défauts -> --config -> flags CLI (SYNE-006)
- CliOptions.Parse : --seed/--max-ticks/--world-size/--headless/--config, erreur explicite rc=2
- PRNG xoshiro256** + splitmix64 (System.Random interdit) : vecteurs de référence
  épinglés depuis une implémentation indépendante (SYNE-005 via déterminisme)
- ADR-012 (config JSON + CLI) fusionnée ; ARCHITECTURE.md/§4§6 + CHANGELOG SYNE à jour
- 28 tests xUnit verts, build Release sans avertissement

* feat(syne): noyau U0 — boucle minimale, monde + grille spatiale, entités typées + traits (#411)

- SimulationLoop : 1 tick = 1 minute simulée, maxTicks respecté, PRNG ancré au tick
  (tête/queue affichées par la Console) — SYNE-002
- World : plan continu non-toroidal (positions clampées [0,W]x[0,H]), SpatialGrid
  uniforme à rayon configurable (requêtes déterministes ligne-par-ligne) — SYNE-003
- Entity : identité séquentielle, espèce, position, 8 traits [0,2] hérités d'un
  paramétrage (plages), validation des invariants ; fabrique déterministe —
  valeurs épinglées calculées par implémentation indépendante — SYNE-004
- namespace Loop (évite l'ombre portée de Simulation.Core.Simulation)
- ARCHITECTURE.md + CHANGELOG SYNE à jour ; 62 tests xUnit verts

* feat(echos): livraison ECHOS-1 — structure du monorepo (U0) (#412)

- paquet Python echos : API FastAPI create_app() (/health), registre des
  7 moteurs de métriques (METRICS_SPEC) + placeholder ingestion
- echos-ui : Vite + React + TypeScript (lint, build, tests vitest/jsdom)
- 13 tests pytest, couverture 100 %, flake8 (max-line-length=100)
- CI : job echos-python recalé sur 'flake8 echos', echos-ui npm ci actif
- docs : CHANGELOG/ARCHITECTURE ECHOS + CHANGELOG racine à jour

* feat(echos): livraison ECHOS-2 — contrats d'ingestion SYNE + golden files (U0) (#413)

- modèles pydantic WorldSnapshot/ExternalEvent (JSON camelCase,
  API_CONTRACTS.md §2) : aliases ingress, sortie by_alias, parse_message
  déterministe + InvalidMessageError stable
- WsClient :5180 (transport injectable, réception rejouée déterministe)
  et ControlClient :5181 (start/pause/resume/reset, corps vérifiés)
- golden files versionnés (fixtures/ + golden/) : double garde
  non-régression (contrat camelCase + vue interne snake_case)
- deps runtime : httpx + websockets ajoutés
- 43 tests pytest (couverture 98 %), flake8 propre, docs à jour

* feat(syne): jalon ph1 — BDI + perception (SYNE-010 à SYNE-015) (#414)

- Perception : rayon 50 (déc. 6), confiance 1−(d/r)×0.3, rotation id%4,
  ligne de vue obstacle cercle (ADR-013), micro-benchmark grille (< 10 ms)
- Mémoire : salience exponentielle, éviction, rappel ordonné (SYNE-013)
- Croyances : révision alignement/conflit/moyenne, expiration (SYNE-014)
- BDI + utilité : pipeline 10/15 étapes branché, U = (b−c−r)×conf×persona+urg,
  mouvements déterministes sans consommation PRNG (SYNE-010)
- Déterminisme : hash FNV-1a épinglé de la trajectoire (SYNE-015)
- Tests : 62 → 122 (toutes catégories nouvelles), build warnaserror vert

* feat(syne): émetteur WebSocket d'observabilité (SYNE-080) — snapshots + événements typés par tick (#415)

* feat(echos): ECHOS-010 — consommation du flux alignée par tick (snapshots V0.1 + serveur in-process) (#416)

* feat(echos): ECHOS-011/012/013 — stockage d'analyse (agrégation, SQLite, Parquet, pipeline) (#417)

* docs(echos): preuve du déterminisme J1 (2 runs seed 7 → 0 divergence sur 443 ticks + 44 300 séries) (#418)

* docs: site GitHub Pages DocFX + XML SYNE (#docs-site) (#419)

- Landing de présentation (docs/site/index.md) + TOC DocFX
- Docs clés synchronisées par sync-docs.sh (source unique monorepo)
- API Simulation.Core générée par DocFX depuis le XML (Simulation.Core uniquement)
- XML .NET activé sur Simulation.Core + Simulation.Console (NoWarn 1591)
- Workflow docs-pages : push develop -> build XML + docfx -> gh-pages
- Branche gh-pages initialisée, source Pages basculée, .nojekyll
- Badge Documentation + entrée CHANGELOG



* feat(syne): SYNE ph2 — mémoire intergénérationnelle, trustDecay, éviction 1000 + observabilité étendue (#420)

* feat(echos): ECHOS-020→027 — 7 moteurs de métriques déterministes + golden files + preuve J2 (#421)

* feat(syne): SYNE ph3 — délibération (fréquence/holdover), interruptions, conflits de priorités, utilité alignement + hystérésis (#SYNE-030→033) (#422)

* feat(echos): ECHOS ph3 — indicateurs d'émergence (score composite, phénomènes, complexité/imprévisibilité, disclaimer) + preuve J3 (#ECHOS-030→033) (#423)

* feat(syne): SYNE ph4 — catalogue d'actions déclaratif + exécuteur atomique, actions terminales Eat/Drink + réserves globales (seuils ≥ 50), déclencheur d'interruption centralisé (#SYNE-040→043) (#424)

* feat(echos): ECHOS ph4 — API REST (runs, métriques/séries ?every=N + cache, export JSON/CSV reproductible, croyances/relations, groupes, phénomènes) + stockage v2 (tick_metrics, tick_contexts) + preuve J5 (#ECHOS-040→045) (#425)

* feat(syne): SYNE ph5 — communication par pulsations (diffusion publique + interception, coûts émission/réception hérités configurables, relais avec dégradation de confiance ×0.9/hop), événements message_sent/message_received, engineVersion 0.4.0 (#SYNE-050→054) (#426)

* feat(echos): ECHOS ph5 — logging & instrumentation (JSONL déterministe tag SSE-V2, traces decision_traces schéma v3 + endpoint /decisions, profilage bit-à-bit des 8 moteurs), SCHÉMA SCHEMA_VERSION 3, preuve J5 étendue 181 tests (#ECHOS-050→052) (#427)

* feat(syne): SYNE ph6 — réseau social émergent (cohésion confiance × affinité et composantes, leader par confiance entrante, décisions collectives pondérées, LOD 10 ticks, turnover), naissance par fusion consentie (paire d'id minimal, enfant médian, mind Born), héritage fin (dominance/mutation SplitMix64, salience configurable), événements group_formed/dissolved/decision + agent_spawned, snapshot groups[], transmissionRange 55 (§ calibration ph6), engineVersion 0.5.0 (#SYNE-060→063) (#428)

* feat(echos): ECHOS ph6 — analyse causale hors ligne (reconstruction Action←Intention←Objectif←Besoin←Croyance←Mémoire←Perception depuis decision_traces/events_log/agents, cycles récurrents + profondeur bornée [1,12], CausalCache LRU invalidé sur ingest_version, endpoint GET /api/runs/{id}/causal-chains/{agentId}) (#ECHOS-060→063) (#429)

* feat(syne): SYNE ph7b — fidélités V0.1 (mortalité épuisement DeathSystem + agent_died, naissance consentie fidèle Qualifies/LOS/énergie/critique, décision collective → objectifs membres GroupObjective/PropagateObjectives + bonus alignement, cheminement A* déterministe grille rasterisée/voisinage ordonné/tie-break/repli sur place + PathCache LRU), preuves anti-triche SYNE-081/082, engineVersion 0.6.0 + checksum doré ré-épinglé 0x27fad50065d8c4a4 (#SYNE-074→077, #SYNE-081→082) (#430)

* fix(echos): publie GET /api/runs/{id}/decisions dans le registre _ENDPOINTS (auto-description ), + test registre ECHOS-051 — alignement inventaire API_REST.md §2 (11 endpoints) (#431)

* docs(syne): resegmentation U5/U6/U8 (U6 = ph8 + ph7b SYNE-074-077 + ECHOS ph6 ; U8 = ph7 + ph11 + 120-131 + packaging), tickets SYNE-074→077 livrés (jalon ph7b), agent_died documenté (payload {cause,species}, engineVersion 0.6.0), régularisation API_CONTRACTS/DETERMINISM/TESTING/CHANGELOG + épinglage checksum 0x27fad50065d8c4a4 (#432)

* docs(echos): décision interface web locale React/Vite servie par FastAPI — PAS de shell Electron en V0.1 (ADR-001 ECHOS, ARCHITECTURE ECHOS/racine, CHANGELOG, FRONTEND_VISION, ISSUES, README, ROADMAP, PRISM ; résidu Electron = contexte d'abandon uniquement) (#433)

* feat(syne): jalon ph9 — performance & scalabilité SYNE-090→093 (TickBudgetCollector budgets 7 sous-systèmes + part computation ≥30 %, CLI --benchmark cibles 50/500/1000 + checksum d'état FNV-1a, ObjectPool sur buffer de tri de perception pour réduire l'allocation GC, déterminisme conservé — checksum doré inchangé 0x27fad50065d8c4a4) ; tests +12 (ObjectPool 5, TickBudget 3, ScaleTargets 4) → 273 Core + 6 Console (#SYNE-090→093) (#434)

* docs(syne): jalon ph9 livré — PERFORMANCE.md §9 (résultats --benchmark ≥2720/1187/505 t/s, part computation 35-68%, machine de référence, convention CI planchers 120/30/20×\~7), ISSUES.md SYNE-090→093 LIVRÉ, CHANGELOG, ROADMAP racine+docs (U7/ph9), TESTING.md (+12 → 279, planchers, §5/§6) — checksum doré inchangé 0x27fad50065d8c4a4 (#435)

* feat(syne): jalon ph10 — tests & couverture SYNE-100→102 (validateur config 100%, déterminisme d'état complet) ; intégration boucle complète sans perte data; observabilité étendue ExternalEvent (#436)

* feat(echos): jalon ph7 — comparaison expérimentale ECHOS-070→072 (U7) (#438)

* feat(echos): jalon ph7 — comparaison expérimentale ECHOS-070→072 (GET /api/compare, méta-métriques reproductibilité ReproducibilityScore 1-(CognitiveDiff+SocialDiff)/2, empreinte SHA-256 canonique, exports json/csv alignés) ; tests +11 → 208, couverture 97,97%

* style(echos): lignes test_compare.py ≤ 100 caractères (flake8 echos .flake8 max-line-length=100) — CI Python verte

* docs(syne): jalon ph10 livré — SYNE-100→102 (324 tests, couverture 96,19%, baseline d'état 0x072a488aa18c05eb épinglée DETERMINISM §7), ROADMAP/TESTING/CHANGELOG/ISSUES+racine U7 (#437)

* docs(echos): jalon ph7 livré — comparaison expérimentale ECHOS-070→072 (API_REST §3.9 +registre 12 endpoints, EXPERIMENT_COMPARISON §4 implémenté, METRICS_SPEC §10, ISSUES LIVRÉ, CHANGELOG, ROADMAP, TESTING +11→208/97,97%) ; ROADMAP racine U7 complet livré (#439)

* docs(echos): correction Electron — conservé, implémentation différée post-V0.1 (#440)

Reformulation 'PAS de shell Electron' → 'shell Electron conservé, implémentation différée à un horizon ultérieur' (décision 23/09/2026 corrigée) dans ADR-001 ECHOS (décision + log correctif), ARCHITECTURE (ECHOS + racine), FRONTEND_VISION, README, ROADMAP (phase 10 'Shell Electron'), ISSUES (ECHOS-001/080 + intro), CHANGELOG (ECHOS + racine), TRANSPORT_API (PRISM). Monographie non modifiée (snapshot figé).

* feat(echos): jalon ph8 — échos-ui, les 6 Écrans (A→F) (#441)

- stack : react-router-dom (routes A→F), echarts+echarts-for-react,
  lucide-react, zustand ; Vite proxy /api+/health → :5000 (dév.) ;
  code-splitting par écran + chunks vendor echarts/react.
- src/api/ : client REST typé sur API_REST.md §3 (runs, métriques
  ?every=, export, décisions, causal-chains, croyances/relations,
  groups, phenomena, compare) ; 503/404 gérés ; controlClient =
  relais ECHOS→SYNE :5181 (jamais en direct).
- src/ws/realtime.ts : client WS :5180 (reconnexion, tick, état SYNE).
- src/store/ (zustand) : runs, KPI live, run sélectionné, état WS.
- Écrans A→F : Dashboard (KPICards+gauges+timeline+phénomènes),
  Explore (Entités/Groupes/Communications, heatmap « à venir »),
  SocialGraph (graphe force-directed /relationships + inspecteur),
  Analysis (Métriques 8 moteurs / Causale profondeur ≤12 / Comparaison
  /compare), Control (pilotage relais + calibration + runs/export WS),
  Log (console 3 niveaux + limites de validité).
- vues sans calcul de métrique ; 13 tests vitest/RTL verts
  (mock fetch+WS) ; eslint + tsc -b + build verts.
- docs ECHOS : CHANGELOG ph8 + ISSUES ECHOS-080→085 → LIVRÉ (statuts).

* docs(site): refonte GitHub Pages — landing LIVEX, thème DocFX surchargé (palette LIVEX, logo/favicon), Écrans A→F & FRONTEND_VISION publiés dans la navigation (#442)

* docs(site): refonte GitHub Pages — landing LIVEX, thème DocFX surchargé (palette LIVEX, logo/favicon), docs Écrans A→F & FRONTEND_VISION publiées dans la navigation

### Landing (index.md)
- Hero sombre  + badge « Monorepo dotnet + python + typescript »,
  tagline, description, 3 CTA (README / API REST ECHOS / Interface web pour
  echos-ui), **3 cartes modules** (SYNE sémantique — Simulation.Core ; ECHOS
  analyse ; PRISM rendu) en overlay  (HTML dans le markdown DocFX),
  bandeau « Fonctionnalités » (6 lignes : déterminisme bit-à-bit, observation
  non intrusive, 7+8 moteurs de métriques, adéquation SYNE↔ECHOS, lien
  doc principes).

### Thème DocFX — overlay
- **** : palette LIVEX () appliquée au thème
   DocFX (docfx.css Bootstrap) — variable-couples , fond
  /surface /bordure /texte /accent
  , navbar sombre, cartes , hero, badges, tableaux,
  code, footer ; police Inter + JetBrains Mono (chevauche cohérent avec
  ).
- ** + ** (overlay : remplace  DocFX par la
  marque LIVEX — 2 cercles reliés, palette ECHOS) ;  multi-taille
  généré (16/32/48/64).
- ** non requis** (le  fournit la navbar) ; overlay
  appliqué via  → .

### Navigation ()
- Section ECHOS enrichie : **FEATURE VISION orbitale & UI Désign** (les 6
  Écrans A→F) publiées dans la nav, + rubriques Métriques/API REST/Tests ;
  section Transverse inchangée (docs clés) —  étendu avec
   et  dans le tableau ECHOS.

### Build
- DocFX local :  (Simulation.Core.xml → API .NET) puis error: FatalError: System.IO.FileNotFoundException: Cannot find config file /home/devops/Documents/Code/LIVEX/docfx.json
   at Docfx.Docset.GetConfig(String configFile) in /_/src/Docfx.App/Docset.cs:line 73
   at Docfx.BuildCommand.<>c__DisplayClass0_0.<<ExecuteAsync>b__0>d.MoveNext() in /_/src/docfx/Models/BuildCommand.cs:line 25
--- End of stack trace from previous location ---
   at Docfx.CommandHelper.RunAsync(LogOptions options, Func`1 run) in /_/src/docfx/Models/CommandHelper.cs:line 42
   at Spectre.Console.Cli.CommandExecutor.ExecuteAsync(CommandTree leaf, CommandTree tree, CommandContext context, ITypeResolver resolver, IConfiguration configuration, CancellationToken cancellationToken) in /_/src/Spectre.Console.Cli/Internal/CommandExecutor.cs:line 257
  (0 erreur) ;  vérifiés : index hero + 3 cards, toc.html, chaîne
  bootstrap clean, favicon/logo overlay au bon chemin.

* docs(echos): FRONTEND_VISION — front-matter DocFX (title • accent paragraphe jalon ph8) ; aligne le h1 unique doc site ESLint conformité

* docs(site): refonte complète GitHub Pages en landing SaaS — landing sur mesure hors DocFX (racine), branding LIVEX (logo, favicon, palette UI_DESIGN), sections Modules/Fonctionnalités/Performances/Roadmap/FAQ, responsive + animations JS ; document DocFX DocFX sous /docs/, assemblage assemble-pages.sh + workflow assemble-pages (landing racine + docs/) (#443)

* docs(roadmap): cadrage Jalon U8 — assainissement du backlog (#444)

Plage ECHOS fictive (080…093) rectifiée en 080…085 (ph8, livrés U7) +
090…092 (ph9) ; carte manquante SYNE-113 ajoutée (serveur de contrôle
HTTP :5181, cible réelle du relais controlClient ECHOS) ; SYNE-110
précisé (hooks autoSaveEveryNTicks/maxBackups à brancher) ; ECHOS-085
annoté (livré côté UI, finalisation contre SYNE-113 en U8).

* feat(syne): jalon U8 — persistance SQLite bit-à-bit (SYNE-110→112) (#445)

- SqlitePersistenceStore : schéma V2.0 (11 tables, PRAGMA user_version=2), transactions atomiques, rotation maxBackups=5, reprise au dernier tick_states ;
- SimulationSnapshot/Codec : capture déterministe monde+cognition+PRNG 4×64 (JSON stable, hash FNV-1a) ;
- SimulationSnapshotRestorer : reprise exacte au tick N sans re-jouage, holdover LastDecision + réserves restaurées en place ;
- Hook autoSaveEveryNTicks (défaut 1000) câblé dans SimulationLoop.AdvanceOneTick — aucun tirage PRNG ⇒ checksums épinglés inchangés ;
- 5 PersistenceTests (320 Core, 329 totaux — reprise bit-à-bit, état RNG, reprise post-crash, schéma 11 tables, rotation) ;
- docs : PERSISTENCE §3 recalé (health→energy/hunger/thirst/fatigue), TESTING 324→329, CHANGELOG, ISSUES SYNE-110/112 LIVRÉ

* feat(syne): serveur de contrôle HTTP :5181 (SYNE-113) (#446)

Serveur de contrôle non intrusif du moteur SYNE, contrat API_CONTRACTS §3
(ADR-002/003) :
- SimulationFactory : résolution options (défauts → surcouche config → seed)
  + construction monde/entités/PRNG/boucle, identique au mode batch (bit-à-bit) ;
- SimulationController : machine à états idle→running⇋paused→finished, boucle
  d'arrière-plan (ManualResetEventSlim + CancellationToken par run) — 0 tirage
  PRNG ajouté ⇒ trajectoire inaltérée (SYNE-081, DETERMINISM §3) ;
- ControlServer : HttpListener BCL 127.0.0.1:5181, POST
  /api/control/start|pause|resume|reset + GET /status, erreurs JSON structurées ;
- mode CLI --serve / --serve-port (défaut 5181) ; interop vérifiée contre le
  ControlClient ECHOS (finalise ECHOS-085) ;
- 6 ControlServerWireTests (335 tests au total : 320 Core + 15 Console).

* feat(syne): cycle des ressources — minéraux + régénération/dégradation (SYNE-070) (#447)

- ResourceKind.Mineral (4e type, initial 0) + ResourceSettings enum-driven (ToStocks/Spec)
- ResourceStocks.ApplyLifecycle(tick, settings) appliqué en fin de tick par
  SimulationLoop.AdvanceOneTick (ordre causal strict, 0 tirage PRNG) : régénération
  + regenerationRate/tick, dégradation périodique -regenerationRate x degradationTick
  a chaque degradationTick (clamp >= 0, inerte sans taux)
- Persistance etendue : WorldSnapshotDto.MineralStock, codec Capture, restorer,
  SQLite WriteResources (4 types), observabilité resources[] (4 types)
- engineVersion 0.7.0 ; checksums dores (perception + baseline ph10) inchangees,
  re-epingles pour pin contractuel (DETERMINISM §7)
- Validation bornes resources.* (initial >= 0, regenerationRate >= 0, degradationTick > 0)
- Tests : ResourceStocksTests +5, SimulationOptionsValidatorTests +1,
  PersistenceTests +1 (4 reserves dont mineral perseveres, regeneration restauree),
  assertions CognitionPipeline/Observability adaptees aux bornes de regeneration
- Docs : DETERMINISM, CONFIGURATION §6.7, DATA_MODEL §8.1, SYSTEMS_SPEC §4,
  API_CONTRACTS §2.1, DECISIONS_V01 §2.4, ISSUES SYNE-070 LIVRE, TESTING (342),
  CHANGELOG (racine + SYNE), ROADMAP (racine + SYNE)

Suite totale : 342 tests (327 Core + 15 Console)

* feat(syne): constructions — obstacles statiques configurables + modification d'environnement tracée (SYNE-071) (#448)

* test(syne): jalons de validation moteur T0-T5 (SYNE-122) (#449)

T0 50 ent./1000 ticks sans crash + état valide déterministe ; T1 50/2000
croyances divergentes ; T2 traits -> décisions différentes en situation
identique (curiosité [0,0] vs [2,2], divergence portée par Explore) ;
T3 information locale (jamais hors portée) ; T4 reproductibilité
benchmark ; T5 suite > 160 tests (370). Carte purement test : 0 tirage
PRNG, engineVersion inchangé (0.8.0). MilestoneT0T5Tests (+8), suite
370 tests (353 Core + 17 Console), couverture 94.01 %.

* feat(syne): cycle de saisons world.seasons (SYNE-072) (#450)

world.seasons: ancien booléen mort -> bloc actif (enabled, seasonLengthTicks 360, initialSeason spring, cycle[] 4 saisons × facteurs/réserve). Saison = fonction pure du tick (0 tirage PRNG) ; SeasonFactors module régénération/dégradation (ResourceStocks.ApplyLifecycle, fin de tick) ; basculement tracé + drainé world.season_changed (tick exact) ; snapshot season/seasonIndex (additif) ; validation §6. engineVersion 0.9.0, checksums dorés inchangés (désactivé par défaut). +19 tests (SeasonTests, ObservabilitySeasonTests) — suite 389 (369 Core + 20 Console).

* feat(syne): territoires world.territory_membership_changed (SYNE-073) (#451)

* feat(livex): finalise le jalon U8 (#452)

* feat(livex): complete U8 milestone

* docs(livex): refresh project overview and setup guide

* fix(ci): disable full coverage on isolated U8 smoke test

* fix(echos): correction démarrage/contrôle + documentation (bundle existant) (#453)

* Refactor echos startup and control mechanisms

- Update installation and README documentation.
- Create V0.1 audit roadmap.
- Enhance API and frontend documentation.
- Improve control client and ingestion logic.
- Add new dev stack script for easier setup.
- Update tests for analysis, API routes, and control client.

* Fix startup and control issues in Echos module and update documentation

- Improve CI workflow and enhance installation instructions.
- Add new simulation configuration files and update related tests.
- Refactor Echos API and ingestion logic for better performance.
- Introduce new reporting functionality and tests for validation.
- Update various components in the Echos UI for better integration.

* fix(echos-ui): alignement des écrans sur le contrat snapshot SYNE (position imbriquée, ressources type/quantity, LiveAgent, garde anti-stale) (#454)

* feat(echos): trace parquet dans le batch, scheduler d'analyse périodique et benchmark SYNE vs SYNE+ECHOS (#455)

* fix(syne): repair test baselines and sqlite cleanup

Refresh the deterministic golden values to match the reproducible current trajectory, and release pooled SQLite connections before deleting temporary databases on Windows.



* fix(syne): normalize deterministic logs across platforms

Use explicit LF separators for hashed test logs so the pinned simulation checksums match on Windows and Linux.



* feat(syne): expose prepared world and global snapshots

Publish a versioned initial world with agents, cells, obstacles, resources, and tick rate; add the explicit prepare/ready control flow and include complete per-tick actions and world changes in the global snapshot.



* fix(echos): handle SYNE world initialization frames

Validate and ignore the world_initialized prelude while aligning tick segments so the ECHOS ingestion pipeline can connect to the updated SYNE stream.



* feat(syne-mock): simulate contracts with modular services

Split world generation, agent decisions, destination selection, movement, and snapshots into services; preserve the HTTP/WebSocket contract and add deterministic scenarios and integration tests.



* fix(git): répare la ligne .gitignore cassée et ignore les artefacts Unreal (#459)

fix(git): répare la ligne .gitignore cassée et ignore les artefacts Unreal

La ligne `*.logdocs/pages-dist/` supprimait d'un coup la règle `*.log` et
l'exclusion du site DocFX généré : les logs n'étaient plus ignorés et le build
de `docs-pages` réapparaissait dans `git status` à chaque publication.

Ajoute aussi les exclusions des répertoires produits par Unreal (`Binaries`,
`DerivedDataCache`, `Intermediate`, `Saved`, `Replays`, `StagedBuilds`, `.vs`,
solutions Visual Studio) afin que l'hôte technique `prism/LDK/` puisse être
versionné sans traîner ses ~10 Go de fichiers générés.

* feat(prism): ajoute le plugin Unreal PRISM-LDK (PrismLdk) et son hôte technique de build (#460)

feat(prism): ajoute le plugin Unreal PRISM-LDK (PrismLdk) et son hôte technique de build

Première implémentation exécutable de PRISM. Le plugin `PrismLdk` expose à
Blueprint le cycle de contrôle HTTP (5181) et la réception des contrats SYNE en
WebSocket (5180) : `Prepare`/`Ready`/`Start`/`Pause`/`Resume`/`Stop`/`Reset`,
`world_initialized`, snapshot global, deltas et événements.

SYNE reste le moteur décisionnel et l'autorité de l'état ; le C++ du plugin se
limite au transport, au parsing et à la conversion en types Blueprint.

- `prism/LDK/` : hôte technique `LDK.uproject` (Unreal 5.8), `Config/`, module
  `LDK` et assets Blueprint de test.
- `prism/LDK/Plugins/PrismLdk/` : module `PrismLdk` (Runtime, phase Default),
  `UPrismLdkSubsystem` + bibliothèque Blueprint + types de contrat.
- `EngineAssociation` positionné à `5.8` : la valeur GUID d'origine (build
  source) empêchait l'ouverture sur une installation Unreal Launcher.
- `.gitattributes` : `*.uasset`/`*.umap` déclarés binaires, une conversion de
  fin de ligne automatique corromprait ces assets ; LF garanti pour `*.sh`.
- `docs/docs-prism/PRISM_UNREAL_IMPLEMENTATION.md` : guide d'intégration.

Non validé : aucun runner Unreal 5.8 n'est disponible, la compilation du plugin
reste à confirmer sur une installation Unreal locale.

* docs(prism): acte l'adoption d'Unreal (ADR-002) et supersède l'ADR Godot (#461)

docs(prism): acte l'adoption d'Unreal (ADR-002) et supersède l'ADR Godot

L'ADR-001 (prototype Godot) était marquée « historique » sans qu'aucun ADR
successeur ne prenne le relais : le choix du moteur définitif restait donc non
tranché en gouvernance, alors même qu'un socle de code Unreal était livré
(PR #460).

- Nouvel `docs/docs-prism/adr/ADR-002-choix-unreal-prism-ldk.md` [Accepted] :
  contexte, décision, conséquences, risques, alternatives (Godot, Unity, non
  décision maintenue, ECHOS seul) et conditions de validation/réouverture.
- ADR-001 marquée [Superseded] avec renvoi vers l'ADR-002 ; l'argument « Unity
  et Unreal surdimensionnés » est explicitement rattaché au périmètre du
  prototype.
- Index ADR du composant mis à jour (nouveaux statuts par ADR).
- ADR-003 / ADR-004 : la liste des routes et des formats est désormais
  explicitement celle de la proposition d'origine de la Monographie, avec renvoi
  vers le contrat courant. ADR-004 acte la diffusion multi-consommateur.
- `ARCHITECTURE.md`, `VISION.md`, `GLOSSARY.md` : PRISM décrit comme projet
  Unreal final intégrant le plugin PRISM-LDK ; `prism/LDK/LDK.uproject`
  documenté comme hôte technique de build/test et non comme un second produit.
- `CHANGELOG.md` racine : entrée de la décision d'architecture.

* docs(prism): réécrit le dossier PRISM pour le projet Unreal et son plugin (#462)

docs(prism): réécrit le dossier PRISM pour le projet Unreal et son plugin

Le dossier `docs-prism` décrivait un prototype Godot sans rapport avec l'état
réel du dépôt. Réaligné sur l'ADR-002 et sur le code livré en PR #460.

- `README.md`, `ARCHITECTURE.md`, `VISION.md` : PRISM = projet Unreal final
  intégrant le plugin PRISM-LDK ; frontière explicite entre le plugin
  (interopérabilité Blueprint) et le projet PRISM (expérience et rendu) ; SYNE
  reste l'autorité de l'état.
- `TRANSPORT_API.md` : contrats selon l'état courant — `world_initialized`,
  snapshot global par tick, deltas/événements, cycle
  `prepare`/`ready`/`start`/`pause`/`resume`/`stop`/`reset`, 5180/5181 par
  défaut.
- `SCENE_SPEC.md`, `RENDERING_SPEC.md`, `VISUALIZATION_SPEC.md`,
  `UX_INTERACTION.md`, `ASSETS_CONVENTIONS.md` : spécifications recadrées en
  objectifs de présentation, sans prétendre que les fonctions sont livrées.
- `TESTING.md` : stratégie de validation, avec la distinction explicite entre
  contrat (testable sans moteur) et rendu (non couvert en CI, aucun runner
  Unreal).
- `ROADMAP.md` : 6 étapes d'évolution orientées intégration et validation, avec
  section de risques et réponses.
- `CHANGELOG.md` du composant : réécrit en conservant les entrées plugin
  (PR #460) et ADR-002 (PR #461) et en restaurant la table de mises à jour.
- `CHANGELOG.md` racine : entrée de la réécriture du dossier.

Vérifié : aucun lien interne mort dans `docs/docs-prism/`.

* docs(livex): réaligne la documentation transverse sur PRISM-Unreal et cadre syne-mock (#463)

docs(livex): réaligne la documentation transverse sur PRISM-Unreal et cadre syne-mock

Dernier volet documentaire de l'adoption d'Unreal (PR #461 et #462) : cohérence
transverse et honnêteté sur ce qui est réellement implémenté.

- `README.md`, `ARCHITECTURE.md`, `VISION.md`, `ROADMAP.md`, `FAQ.md`,
  `INSTALLATION.md`, `COMMUNICATION.md`, `SECURITY.md`, `CI_CD.md`,
  `CONTRIBUTING.md` : PRISM décrit comme projet Unreal final intégrant le
  plugin PRISM-LDK ; `prism/` et `syne-mock/` apparaissent dans l'arborescence ;
  `ARCHITECTURE.md` gagne une §2.4 (syne-mock) et une §6 réécrite.
- `syne-mock` cadré explicitement comme outil de développement des contrats,
  pas un moteur : README, ARCHITECTURE §2.4, CONTRIBUTING §4 (checklist
  `npm test --prefix syne-mock`), CI_CD §2 et §5, ETHICS_AND_SCOPE §4.1.
- `docs/docs-echos/{ISSUES,ROADMAP,TESTING}.md` : ECHOS-091 restreint à
  SYNE→ECHOS ; la validation PRISM-LDK et du projet Unreal relève d'un chantier
  distinct. Finit la contradiction « le runtime PRISM commence après U8 ».
- `docs/docs_prototype/README.md` : bandeau d'archive.
- `LIVEX-Monographie_SnapV0-1.md` : note de statut explicitant que la
  monographie est une référence conceptuelle historique et non prescriptive.
- `docs/README.md` (nouveau) : portail séparant références courantes et
  archives, avec la règle de préséance en cas de divergence.
- `FAQ.md` : §9 remplace « Pourquoi pas Unreal/Unity ? » par la distinction
  LIVEX/PRISM/PRISM-LDK, avec renvoi vers l'ADR-002 pour la justification ;
  §10 explique le mock ; renumérotation 1→13.
- `docs/site/index.md` : carte PRISM en « Visualisation Unreal ».
- `CHANGELOG.md` racine : entrées transverse et portail, sans écraser celles des
  PR #461 et #462.

Vérifié : aucun lien interne mort hors gabarits Liquid `{{_rel}}` de
`docs/site/index.md` (préexistants) ; les occurrences restantes de « Godot »
sont dans des archives explicitement signalées (ADR-001, `docs_prototype`,
Monographie, DECISIONS_V01 §2.28) ou dans le contexte historique de l'ADR-002.

* chore(echos): verrouille les dépendances Python (uv.lock) (#464)

chore(echos): verrouille les dépendances Python (uv.lock)

Le lockfile était présent dans le checkout mais non suivi, ce qui rendait les
résolutions locales non reproductibles alors que `echos-ui/package-lock.json`
est versionné depuis le début.

- 36 paquets épinglés avec empreintes SHA-256.
- `requires-python = ">=3.11"`, cohérent avec `pyproject.toml`.
- Le groupe de développement (flake8, pytest, pytest-cov) est verrouillé, donc
  les mêmes versions que celles qu'installe la CI via `requirements-dev.txt`.

La CI continue d'utiliser `pip install -r requirements-dev.txt` : le lockfile
sert la reproductibilité du développement local. Le passage de la CI à `uv`
est hors périmètre.

* fix(syne-mock): libère les ressources du test et aligne les assertions (#465)

fix(syne-mock): libère les ressources du test et aligne les assertions

`npm test --prefix syne-mock` ne se terminait jamais : après la fin des
assertions, 2 serveurs TCP et 3 sockets restaient ouverts, si bien que
`node --test` ne rendait jamais la main. La commande était donc inutilisable
et masquait 4 échecs réellement présents sur `develop`.

- `createServer().close()` termine les clients WebSocket connectés, purge les
  connexions HTTP en keep-alive et chaîne les rappels de fermeture, afin que
  `close()` ne promette que lorsque les sockets sont réellement libérés ;
- les tests de serveur libèrent leur instance via `t.after()` (y compris en cas
  d'échec d'assertion) et attendent la fermeture du client WebSocket ;
- les assertions d'obstacles attendent le champ `type`, que `WorldDescription`
  publie déjà.

* fix(syne-mock): pose les agents sur les cases publiées comme franchissables (#466)

fix(syne-mock): pose les agents sur les cases publiées comme franchissables

`createInitialAgents` ne validait ses positions candidates que contre les
obstacles, jamais contre le relief : un agent pouvait apparaître sur une cellule
`sea` (`walkable: false`). La fonction évaluait aussi la position brute alors
que le monde publie la position arrondie, si bien que l'arrondi pouvait faire
basculer l'agent dans une case voisine bloquée.

Deux critères de test disjoints faisaient désaccord :

- le placement utilisait `isPositionBlocked`, qui compare le point au cercle ;
- la grille publiée utilisait `isCellBlocked`, qui compare le centre de case au
  cercle augmenté de la demi-cellule.

Un agent pouvait donc être validé au placement et déclaré non franchissable par
`WorldDescription`, ce qu'exprime exactement le test
`world generation places resources and agents only on walkable cells`.

Le placement s'appuie désormais sur `cells[].walkable`, indicateur publié par
`WorldDescription` : obstacles et mer passent par la règle exposée, et aucune
divergence entre les deux n'est plus possible. `obstacles` n'est plus requis par
la fonction, et la grille de terrain n'a jamais eu besoin d'être passée.

Vérification : 300 graines x 5 densités x 2 configurations d'obstacles
(324 600 positions) : 3 452 agents sur case non franchissable avant, 0 après,
génération toujours déterministe. Test de non-régression ajouté sur 5 graines,
vérifié en échec sur l'état précédent.

* ci: exécute la suite syne-mock et publie le guide d'intégration Unreal (#467)

ci: exécute la suite syne-mock et publie le guide d'intégration Unreal

`CI_CD.md` §2 annonce un job CI `syne-mock` et `CONTRIBUTING.md` §4 rend
`npm test --prefix syne-mock` obligatoire pour toute modification du
composant. Aucun des deux n'était exécuté. Le job peut désormais l'être : la
commande se termine (PR #465) et la suite est verte (PR #466).

- `ci.yml` : `syne-mock/` rejoint la boucle de détection des composants, avec
  sortie `syne_mock` (le `-` est converti en `_`, une clé de sortie ne pouvant
  pas contenir de tiret dans une expression) ; nouveau job
  `Tests (SYNE-MOCK Node)` sur `ubuntu-latest`, `npm ci` puis `npm test`, avec
  `timeout-minutes: 5` en garde-fou contre une régression de type fuite de
  descripteurs ;
- `sync-docs.sh` : `PRISM_UNREAL_IMPLEMENTATION.md` publié dans `articles/prism/`,
  et `toc.yml` l'expose sous « Intégration Unreal (PRISM-LDK) ». Le guide
  Blueprint du plugin, référencé par `ARCHITECTURE.md`, était inaccessible sur
  le site ;
- `docs-pages.yml` : `prism/**` déclenche désormais le build du site, la
  documentation contractuelle étant écrite contre ce code ;
- `syne-mock/README.md` : la commande de test renvoie vers le job CI.

Au passage, la section `## [Unreleased]` du CHANGELOG cumulait des
sous-sections dupliquées (`### Changed` x3, `### Added` x2) et une ligne blanche
parasite ; sections regroupées et ordonnées `Added` -> `Changed` -> `Fixed` ->
`Deprecated`, et coquille « formality » corrigée en « formalise ».

Vérifié : `ci.yml`, `docs-pages.yml` et `toc.yml` parsent, `bash -n
sync-docs.sh` passe, le script publie bien le guide, et la commande exacte du
job (`node --test test/*.test.js` dans `syne-mock/`) sort en 0 avec 12 tests
verts.

* ci: declenche la CI sur les PR visant main (#468)

La CI ne se declenchait que sur develop. La protection de branche « branche a
jour + CI verte » de main ne peut donc pas etre appliquee : une PR de release
ou de hotfix n-executerait aucun check, et le merge resterait bloque sur un
status attendu qui n'arrive jamais.

`main` est ajoute aux branches de `pull_request` et de `push`, ce qui rend la
regle enforceable. Les jobs restent filtres par composant, donc une PR de
release ne construit que ce qu'elle touche.

Aucun changement de job ni de condition.

* docs(ci-cd): documente les protections de branche actives (#469)

`main` et `develop` sont desormais couverts par les rulesets `mainRules` et
`developRules`, en enforcement active. Le document annoncait « echec =
blocage (protection de branche) » sans jamais dire de quelle protection il
s'agissait, ni quels checks sont exiges.

La nouvelle section 2.1 detaille les cinq regles en vigueur, les deux checks
exiges et pourquoi les jobs par composant ne le sont pas (ils rapportent
`skipped` hors perimetre), ainsi que le retrait de `required_signatures` et sa
raison.

Consigne de maintenance ajoutee : renommer `Composants modifies` ou
`Structure & conventions (transverse)` bloque tous les merges jusqu'a mise a
jour du ruleset.

* fix(adr-001): corrige la coquille « formality » et ajoute le saut de ligne final (#470)

L'entree de CHANGELOG.md qui annoncait la correction de « qui formality ce
choix » decrivait en realite la coquille du CHANGELOG lui-meme. Le fichier ADR
vise, docs/docs-prism/adr/ADR-001-choix-godot.md, portait toujours « formality »
et n'avait jamais ete corrige.

Corrige en « formalise », et ajoute le saut de ligne final manquant sur cet ADR
et sur docs/docs-prism/adr/README.md, tous deux sans terminaison.

Detecte en comparant le stash de securite stash@{0} (wip-prism-unreal) aux
fichiers merges sur develop : le stash est un sous-ensemble strict de develop,
donc rien d'utile n'y est encore, et le rapprochement a fait ressortir la
coquille.



* fix(syne-mock): applique la carte publiee au deplacement des agents (#471)

Le deploiement deplace les agents sans jamais consulter la carte que
WorldDescription publie. Quatre defauts distincts :

- isPositionBlocked etait appele sans cellSize, donc la branche `shape`
  comparait des coordonnees NaN et laissait traverser les sept formes
  d'obstacle, alors que la version circulaire bloquait ;
- canEnter ignorait cells[].walkable, donc les agents traversaient la mer ;
- le cout de terrain etait ignore : une riviere (movementCost 4) se
  traversait a la vitesse de la plaine ;
- un deplacement refuse etait facture : l'energie baissait de
  moveEnergyCost meme quand l'agent n'avait pas bouge.

cell-grid.js centralise l'indexation de cells[] (y * cellCountX + x),
partagee par le placement et le deplacement. L'inversion x * cellCountX + y
etait auto-coherente sur une carte carree mais faisait chevaucher des cles
sur une carte rectangulaire. L'arrondi est desormais applique avant le test,
pour que la position validee soit celle que le snapshot publie.

Le cout retenu pour borner le pas est le plus eleve entre la case de depart
et la case visee : entrer dans une riviere ralentit, en sortir aussi. Une
case non franchissable donne un budget nul. Seul un mouvement effectif est
facture ; un blocage est reporte via outcome: 'blocked'.

La generation du monde est inchangee : empreintes SHA-256 identiques avant
et apres sur 5 graines x 4 configurations, dont une carte rectangulaire
300x180. movement.test.js ajoute 10 tests (12 -> 22).



* fix(syne-mock): rend le demarrage transactionnel, borne le journal et corrige l age des objectifs (#472)

Trois defauts de cycle de vie, sans rapport entre eux mais tous visibles
par un client de controle.

1. start() laissait un run actif apres un echec. `loadReplay` leve sur un
   fichier absent ou une ligne JSON malformee ; il etait appele apres
   `state = 'running'` mais avant `startTimer()`. Le resultat etait un run
   declare actif sans timer : rien ne tickait, et tout appel ulterieur a
   start() etait rejete au motif que le run etait deja actif. Le chargement
   du replay precede desormais l'entree en running, et tout ce qui le
   precede est reecritable sans consequence. Apres un echec, le monde reste
   prepare et acquitte, et un nouvel appel se comporte comme le premier.

2. `this.events` n'etait pas borne. Deux evenements par agent et par tick
   etaient conserves pendant toute la duree du run : 202 200 evenements sur
   2 000 ticks x 50 agents, heap 66 Mo. `diagnostics.maxEvents` (defaut
   2 000) borne le tampon a 2 000 evenements, soit heap 18 Mo sur le meme
   run. La troncature vide jusqu'a mi-capacite plutot que d'un seul
   element, pour ne pas decaler tout le tampon a chaque emission. Le flux
   diffuse (WebSocket) reste la source faisant autorite : ce tampon est un
   diagnostic, pas l'historique.

3. `goals[].age` valait le tick absolu. La liste etant reconstruite a chaque
   tick, `age` etait toujours egal au tick courant et ne disait rien de la
   duree d'un but. `intentionSince` suit le dernier changement d'intention
   et `age` devient le nombre de ticks ecoules depuis : 15 a 24 au tick
   2 000 d'un run de reference, au lieu de 2 000. Le marqueur reste interne,
   le snapshot publiant une liste de champs explicite.

lifecycle.test.js ajoute 8 tests (22 -> 30).



* docs(syne-mock): rectifie le contrat consomme et liste les simplifications assumees (#473)

Le contrat decrit ce que le mock publie, donc ce qu'un client PRISM ou
ECHOS branche dessus. Deux de ses affirmations etaient fausses ou
incompletes, et un consommateur pouvait s'y fier.

- Le document annoncait que le mock n'expose pas de type de terrain et que
  les cellules utilisent `terrainType: "plains"`. C'est faux : le mock publie
  trois profils, `plains` (cout 1), `river` (cout 4) et `sea`
  (`walkable: false`, cout infini), et le pas est borne par le cout de
  terrain. Le tableau des profils est ajoute, avec la regle d'entree et de
  sortie de riviere et la frontiere mer, en distinguant ce qui appartient au
  mock de ce qui appartient a SYNE.
- La liste des actions a mapper en `UENUM` n'en citait que 5 sur 9 :
  `SeekFood`, `SeekWater`, `Flee` et `Socialize` manquaient, alors que le
  contrat les publie des qu'elles se produisent. Les 9 sont listees, avec pour
  chacune sa condition de candidature et son premier tick de production,
  mesure sur la graine 42 avec 50 agents et non deduit du code. Deux
  impossibilites sont explicites : `Flee` est structurellement inatteignable,
  car `safetyDriftRate` est positif alors que `safety` demarre a sa borne
  haute et ne peut donc jamais passer sous 0.5 ; `Socialize` n'est produite
  qu'au tick 943, donc hors du `maxTicks: 400` par defaut.
- Nouvelle section « Perimetre reel et simplifications assumees » : la mort,
  la perception, le contenu des communications, la decision de groupe, les
  livres, les territoires, les ressources locales, l'echelle temporelle et le
  pathfinding sont des elements decoratifs, et `simulation.events` un tampon de
  diagnostic borne. Ces elements sont publies dans le contrat comme s'ils
  portaient du sens ; la section dit desormais ce qu'un client ne doit pas
  encore interpreter.
- Le comportement d'un `start` refuse est documente dans la section HTTP : le
  monde reste `ready` et reutilisable, donc un client peut reessayer sans
  appeler `stop`.



* feat(syne-mock): besoins de depart configurables, fini les 15 s d'Idle initial (#474)

Les agents passaient 146 ticks sans rien faire au debut d'un run. Les besoins
de depart etaient codes en dur dans createInitialAgents et curiosity partait
de 0 : il fallait que curiosityDriftRate (0.002) amène la valeur au seuil
d'exploration de 0.3, soit 150 ticks, ou 15 s a ticksPerSecond 10.

- agentSimulation.needs.initial rend les six besoins de depart configurables,
  avec les domaines qu'ils bornent deja (0..100 pour hunger/thirst/fatigue,
  0..1 pour safety/social/curiosity). Une valeur absente retombe sur l'etat
  historique du mock, une valeur hors domaine est refusee a la generation du
  monde, comme les autres cles de configuration.
- curiosity passe de 0 a 0.3 par defaut, exactement le seuil d'exploration :
  les agents se mettent en mouvement au tick 1 et plus aucun Idle n'est produit.
  Eat 100, Drink 72, Rest 234 et Socialize 943 sont inchanges.
- curiosityDriftRate passe de 0.002 a 0.001, le cout de ce decalage : explorer
  des le premier tick sature curiosity plus vite, et un besoin sature garde une
  utilite superieure a celle de Rest, qui devient alors jamais produit. Mesure
  sur 2000 ticks, 0.002 supprime Rest du flux alors que 0.001 conserve le
  repertoire complet d'actions.

Le placement des agents ne lit que la graine et la carte : les besoins de depart
decalent la trajectoire d'un agent, pas l'endroit ou il apparait. Generation du
monde byte-identique avant/apres sur 5 graines x 2 tailles dont 300x180, run
deterministe a l'identique sur 2 processus distincts.

+4 tests dans test/server.test.js, suite verte.



* fix(syne-mock): diffuser le snapshot avant les evenements du tick (#475)

Le mock emettait les evenements du tick avant son snapshot. SYNE
(ObservabilityTickEmitter) et API_CONTRACTS.md §2 imposent l'inverse, et tout
consommateur qui aligne le flux sur les ticks le refuse : ECHOS rejetait le
mock des la premiere trame avec

  TickAlignmentError: message event invalide (conforme API_CONTRACTS.md) :
  evenement decision_made recu avant le premier snapshot

step() regroupe desormais les evenements du tick, diffuse le snapshot puis
tick_summary, puis les evenements de ce tick. L'ordre des evenements entre eux
et le tampon de diagnostics sont inchanges, stepReplay() n'est pas touche, et le
contenu par tick reste identique (hash canonique inchange sur 120 ticks) :
seul l'ordonnancement change.

Verrouille par deux tests qui echouent tous deux sur l'ancien code :
- syne-mock/test/stream-order.test.js : ordre exact des trames, invariant
  d'alignement et invariance du tampon de diagnostics ;
- echos/echos/tests/test_syne_mock_integration.py : le vrai client ECHOS
  ingere le mock de bout en bout (controle HTTP, WebSocket, SQLite, Parquet,
  API REST, calibration), sans build .NET.

Le mock devient donc utilisable pour travailler sur ECHOS : pointage par
SYNE_OBSERVABILITY_URL / SYNE_CONTROL_URL, procedure documentee dans
syne-mock/README.md, limites de simulation assumees (beliefs/trust vides).
Nouveau job CI "Integration mock -> ECHOS" sur toute PR touchant syne-mock/
ou echos/, distinct du job U8 qui reste sur le moteur .NET.



* fix(echos): revue complète du composant (moteurs, provenance, API, interface) (#477)

Deux bugs rendaient des fonctions centrales inopérantes : `/api/compare`
renvoyait 500 sur tout run contenant un événement (la décompression décomptait
six colonnes pour un zip de sept), donc la comparaison de reproductibilité
était inaccessible sur tout run réel ; et `AnalyticsStore.runs()` levait
`int(None)` sur un run sans tick, ce qui rendait l'API entière inopérante sur
une base fraîche ou un run en cours d'acquisition.

Sept métriques restaient à 0 sur tout run réel parce que le snapshot ne
portait que le tick courant, jamais `history` ni `communityHistory` — la
fixture de test les fournissait artificiellement, ce qui masquait le
problème. `_RollingContext` construit et borne désormais trois fenêtres
glissantes. Le dénominateur des taux de groupe ne dépend plus de la charge
(il valait 1000 ticks sur un run calme et 20 sur un tick chargé, soit un
facteur 50 sur la même métrique) : la fenêtre est bornée en ticks et sa durée
réellement observée est publiée dans le snapshot.

Les singletons n'étaient plus comptés comme communautés, `DecisionDiversity`
était calculée sur les objectifs, `SystemComplexity` n'était pas borné,
`_availability(100, None, 0)` renvoyait 1e11 et contaminait la moyenne du
moteur de durabilité, et un cycle d'import existait entre `emergence` et le
registre des moteurs.

Ajout de la provenance `measured` : `analysis.provenance()` calcule par couple
(moteur, métrique) si la valeur servie est une mesure ou le repli neutre du
moteur faute de fenêtre, depuis les mêmes entrées que le calcul lui-même. Sans
ce signal, l'interface ne pouvait pas distinguer un `0` observé d'un repli.
Persisté par tick (`tick_metrics.measured`, schéma SQLite v5, migration
additive) et publié par `/api/runs/{id}/metrics` et `/api/runs/{id}`. Évol
adhésion MINOR : champ ajouté, aucun consommateur existant n'est cassé.

Robustesse : cadences nulles qui levaient `ZeroDivisionError` ou étaient
silencieusement ignorées, fuite de descripteurs (`EchosLogger` sans `close()`),
reconnexion toutes les 100 ms quand SYNE est arrêté, fin de flux détectée par
préfixe de libellé d'erreur, et `pyarrow` importé mais non déclaré dans
`pyproject.toml` (un `pip install echos` produisait un paquet qui ne démarrait
pas). `dev_ingest` valide désormais sa configuration avant toute I/O, avec
sortie 2 distincte.

Les identifiants de groupe (`members`, `leaderId`, entiers côté transport)
sont normalisés en chaînes, sinon ils ne pouvaient jamais être joints à
`Agent.id` — `"3" != 3`. Même normalisation pour `Territory.members` et
`Book.author_id`/`readers`.

Interface `echos-ui` : l'export « CSV » téléchargeait une enveloppe JSON
illisible par tout tableur ; `beliefs`/`relationships`/`phenomena` appelaient
l'API sans `run_id` et affichaient donc les données du run le plus récent sous
le nom du run sélectionné ; le cache de métriques ignorait la cadence dans sa
clé et fusionnait des séries d'échantillonnages différents, produisant des
`NaN` rendus comme des zéros ; le graphe social relançait une requête par
membre en série à chaque tick ; la jauge de vitesse de diffusion alertait en
rouge un monde qui propageait bien ; `disconnect()` se reconnectait 2 s plus
tard et `usePhenomena` affichait « aucun phénomène détecté » sur un échec
réseau. `npm test` lance `vitest run` : le mode interactif ne termine jamais et
accrochait la CI.

Tests : 233 → 283 (couverture 93 %, seuil 80 %), flake8 propre ; interface
18 → 61 tests sur 14 fichiers, eslint et `tsc` propres. Les deux scénarios
d'intégration (SYNE réel et syne-mock) passent et vérifient désormais la
provenance et la normalisation des groupes contre les émetteurs réels.

Rapport complet dans `echos/ECHOS-REVIEW.md`, qui arbitrage aussi les points
laissés ouverts et leurs raisons.

* chore(docs): supprime DocFX et la publication GitHub Pages (#478)

Retire docs/site/ (source DocFX), docs/landing/ (landing SaaS),
docs/pages-dist/ (artefact d'assemblage commite malgre .gitignore) et le
workflow .github/workflows/docs-pages.yml. 51 fichiers suivis supprimes.

- .gitignore : entree docs/pages-dist/ devenue inutile retiree
- CHANGELOG.md : section Removed + entrees [Unreleased] obsoletes retirees
- echos/ECHOS-REVIEW.md : la note sur docs/pages-dist/ est replacee dans
  son contexte historique

Les documents markdown ecrits a la main (docs-syne, docs-echos, docs-prism,
adr, governance) sont conserves : ce sont les sources, pas des artefacts.

* fix(syne): revue complète du moteur (déterminisme, cycle de vie, observabilité, HTTP) (#476)

Revue et refactor du moteur SYNE. Les défauts ci-dessous sont groupés par
famille. Chacun est couvert par un test vérifié détecteur : le défaut est
réintroduit temporairement dans le code, le test doit devenir rouge, puis le
correctif est restauré. Ce que je n'ai pas su reproduire est dit comme tel
plutôt que présenté comme couvert.

1. DETERMINISME

SplitMix64.Gamma/Avalanche et l'implémentation FNV-1a étaient dupliqués sur
six sites, constantes recopiées : une divergence future aurait produit deux
hachages pour la même valeur. Centralisés dans SplitMix64 et le nouveau
Fnv1a64, sans effet sur les trajectoires.

La cause unique de l'écart de trajectoire était neutralisée : la garde de
rejeu de la communication existait mais n'était jamais appliquée. Le
destinataire d'un message le relaye donc une seconde fois. CanRelay applique
désormais HasRelayed, et la file de messages devient bornée (« plus récent
gagne ») au lieu de croître sans limite.

Réépinglage selon DETERMINISM.md §7 : percepts 0x27fad50065d8c4a4 ->
0xdb57f58566418f5d, état Ph10 0x072a488aa18c05eb -> 0x88bbc67950002bab,
EngineVersion 0.11.0 -> 0.12.0.

Piège de déterminisme : la cellule de SpatialGrid était dimensionnée par
agents.perception.radius. Or QueryCircle renvoie les voisins dans l'ordre de
parcours des cellules, qui décide de l'ordre de considération des perceptions.
Régler la portée de la perception modifiait donc silencieusement l'évolution
du monde. agents.perception.spatialCellSize devient un paramètre explicite,
défaut 50 (égal au rayon par défaut : trajectoire de référence inchangée, ce
qui évite un réépinglage supplémentaire).

2. VALIDATION

Les contrôles de plage s'écrivent « value is < 0.0 or > 1.0 ». En IEEE-754
toute comparaison avec NaN est fausse : « NaN is < 0.0 or > 1.0 » vaut false,
donc un NaN franchissait la validation puis se propageait dans les distances,
l'énergie et la Barclay, corrompant le monde sans lever d'erreur. Le
validateur balaie maintenant tout le graphe d'options par réflexion, ce qui
couvre aussi les champs ajoutés ultérieurement, et tolerate les chemins en
camelCase comme le contrat de configuration.

worldCellSize et le nouveau spatialCellSize n'étaient pas validés du tout.

3. CYCLE DE VIE DU CONTRÔLEUR

La boucle de tick était lancée en « feu et forget » : la tâche n'était jamais
conservée. Un second StartAsync superimposait une deuxième boucle sur le même
monde, Stop n'annulait que la dernière CancellationTokenSource en laissant
l'ancienne boucle active, cette ancienne boucle pouvait ensuite repasser
l'état à Finished par-dessus un run plus récent, et DisposeAsync simulait
l'attente avec Task.Delay(20). La tâche est maintenant conservée, une
génération de run est vérifiée avant toute écriture d'état partagé, un second
démarrage est refusé sur run actif, et StopAsync/ResetAsync/DisposeAsync
attendent réellement la fin de boucle. ControlServer répond 200 sur stop
après l'arrêt effectif.

4. HTTP DE CONTRÔLE

RootElement était renvoyé sans Clone() ni Dispose() : propriété invalide dès
la fin de vie du JsonDocument, une fuite par requête. Aucun plafond de taille
n'existait : un Content-Length ou un transfert par blocs arbitrairement grand
était lu intégralement en mémoire (1 Mio, 413 payload_too_large, lecture bornée
pour les blocs). Un JSON malformé ou un type de configuration incompatible
remontait en 500 au lieu de 400.

5. OBSERVABILITÉ

Un WebSocket n'accepte qu'un SendAsync à la fois : deux diffusions
concurrentes levaient InvalidOperationException, non rattrapée, et tuaient le
processus. Sérialisation par client, envois bornés dans le temps, retrait des
clients dans le finally du drain (auparavant un client déconnecté restait au
dictionnaire et son socket n'était jamais fermé), fermeture réellement
attendue, Start/DisposeAsync idempotents.

L'émetteur ne faisait pas confiance au sink pour être borné : un client lent
figeait la simulation, sans plafond. La capture est sautée quand aucun client
n'est connecté, mais les tampons du tick sont toujours vidés : la couche
d'observabilité en est le seul consommateur, sans quoi ils croissent sans
borne et rejouent des événements obsolètes.

6. CONFIGURATION ET AUTRES

La fusion de configuration sparse était destructive : le corps était
désérialisé en SimulationOptions avant fusion, donc chaque clé absente
prenait la valeur par défaut du type et un client ne pouvait surcharger un
champ sans détruire silencieusement tous les autres réglages. MergeJson fusionne
récursivement, et le JSON brut est transporté jusqu'à la fusion.

ResourceStocks consommait partiellement face à un stock insuffisant ;
ActionExecutor appliquait les bénéfices avant l'échec d'une réserve ; la
grille confondait les comptes et bornes X/Y ; les IDs de naissance n'étaient
pas uniques ; les territoires n'étaient pas persistés, donc une restauration
perdait toutes les zones et réassignait « Communes » (SchemaVersion 4).
A* autorisait une diagonale alors que les deux orthogonales étaient bloquées :
le pas rase le point d'appui entre deux cellules solides. PhaseCount valait 8
pour une énumération de 7 phases. `--seed -1` produisait une trace d'appels
plutôt qu'un message.

7. LE PIÈGE QUE SEUL LE TEST D'INTÉGRATION A VU

Une première version de la validation CLI refusait « --observe-port sans
--observe ». C'est faux : en mode --serve, Program démarre l'observability sur
--observe-port, et le contrat d'intégration SYNE → ECHOS lance exactement
« --serve --serve-port P --observe-port Q ». Le job CI
syne-echos-u8-integration échouait alors sur un défaut de validation, pas de
moteur, et SYNE refusait ses arguments sans ouvrir aucun port. Une suite
unitaire entièrement verte ne prouve pas qu'un contrat transverse est préservé.

Ce que j'avais laissé passer en commit est ce piège, pas un bug du moteur : la
validation est correcte, c'est ma règle qui était fausse, parce que j'avais
supposé que le port d'observation n'avait qu'un seul mode consommateur sans
avoir vérifié qui le consommait. Corrigé, avec un test qui verrouille les deux
combinaisons. C'est aussi ce qui m'a fait suspecter un auto-blocage possible du
chemin stop (le client ECHOS appelle stop alors qu'il ne lit plus le WebSocket,
et la requête HTTP a un timeout de 2 s) : vérifié empiriquement, 5 exécutions
consécutives vertes.

132 tests ajoutés (466 -> 598) ; suite SYNE à 553 tests, verte en Release avec
--warnaserror. Trois tests détectaient d'abord le bon bug pour la mauvaise
raison et ont été réécrits ; deux correctifs sont défensifs et le disent
(disparition intra-tick de groupe, culture invariante sur drapeaux entiers) ;
aucun n'est présenté comme vérifié par mutation quand il ne l'est pas.

REVIEW-REFACTOR-REPORT.md détaille chaque point.

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481 (#495)

🤖 Generated with Codebuff



* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs (#496)

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

🤖 Generated with Codebuff


* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

🤖 Generated with Codebuff


---------



* chore(echos): ingestion 0.3.0, stockage et calibrage (#497)

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

🤖 Generated with Codebuff


* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

🤖 Generated with Codebuff


* chore(echos): ingestion 0.3.0, stockage et calibrage|Champs optionnels inventory/commitments dans les modèles d'ingestion (rétro-compat 0.2.1 conservée), routes et service UI (echos-serve), invalidation inter-processus du cache de séries via PRAGMA data_version, calibrage de fin de run et viabilité. Suite ECHOS verte, couverture 93,16 %. Closes #485

🤖 Generated with Codebuff


---------



* fix(echos-ui): écrans d'analyse gelés, retard croissant et contrôles Live/Actualiser (#498)

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

🤖 Generated with Codebuff


* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

🤖 Generated with Codebuff


* chore(echos): ingestion 0.3.0, stockage et calibrage|Champs optionnels inventory/commitments dans les modèles d'ingestion (rétro-compat 0.2.1 conservée), routes et service UI (echos-serve), invalidation inter-processus du cache de séries via PRAGMA data_version, calibrage de fin de run et viabilité. Suite ECHOS verte, couverture 93,16 %. Closes #485

🤖 Generated with Codebuff


* fix(echos-ui): écrans d'analyse gelés, retard croissant et contrôles Live/Actualiser|Trois causes racines corrigées : cache de séries jamais invalidé entre processus (retard croissant 155→494 ticks), liste des runs chargée une seule fois (le run démarré n'apparaissait jamais), et refetch complet à chaque tick WS (tempête de requêtes). Ajout des boutons Actualiser et bascule Live/Figé. Validation réelle sur un run de 7 600 ticks : retard stable 14-35 ticks, 1 req/2 s mesurée. 62/62 tests UI. Closes #480

🤖 Generated with Codebuff


---------



* feat(echos): shell de bureau Electron (ADR-003), packaging et CI (#499)

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

…

Co-authored-by: DevOps LIVE X <devops@livex.local>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: protection-test <protection-test@example.com>
Co-authored-by: Codebuff <noreply@codebuff.com>
donovan-dev-web added a commit that referenced this pull request Oct 12, 2026
…nommés, filtre ADR (#531)

* [GOVERNANCE] Jalon U0 — socle git flow, CI, gouvernance GitHub (#409)

* feat(governance): jalon U0 — socle git flow, CI remaniée, gouvernance GitHub

- branches Git Flow : develop créée depuis main
- milestones dédupliqués (série canonique par composant), labels normalisés
- CI: jobs filtrés par paths (syne/**, echos/**) via détection git diff,
  validation transverse toujours verte ; conteneurisation Docker reportée
- release.yml: aligné (pas de GHCR tant que pas de conteneurisation)
- ajout .gitignore/.editorconfig ; maj README, INSTALLATION, CHANGELOG

* fix(governance): resserre l'heuristique anti-secrets (auto-correspondance du motif)

* feat(syne): socle U0 — solution .NET, config Annexe H + CLI, PRNG déterministe, ADR-012 (#410)

- Syne.sln + Simulation.Core/Simulation.Console/Simulation.Core.Tests séparés (SYNE-001)
- SimulationOptions (Annexe H) + loader JSON générique (fichier partiel préservant
  les défauts), validation des plages, priorité défauts -> --config -> flags CLI (SYNE-006)
- CliOptions.Parse : --seed/--max-ticks/--world-size/--headless/--config, erreur explicite rc=2
- PRNG xoshiro256** + splitmix64 (System.Random interdit) : vecteurs de référence
  épinglés depuis une implémentation indépendante (SYNE-005 via déterminisme)
- ADR-012 (config JSON + CLI) fusionnée ; ARCHITECTURE.md/§4§6 + CHANGELOG SYNE à jour
- 28 tests xUnit verts, build Release sans avertissement

* feat(syne): noyau U0 — boucle minimale, monde + grille spatiale, entités typées + traits (#411)

- SimulationLoop : 1 tick = 1 minute simulée, maxTicks respecté, PRNG ancré au tick
  (tête/queue affichées par la Console) — SYNE-002
- World : plan continu non-toroidal (positions clampées [0,W]x[0,H]), SpatialGrid
  uniforme à rayon configurable (requêtes déterministes ligne-par-ligne) — SYNE-003
- Entity : identité séquentielle, espèce, position, 8 traits [0,2] hérités d'un
  paramétrage (plages), validation des invariants ; fabrique déterministe —
  valeurs épinglées calculées par implémentation indépendante — SYNE-004
- namespace Loop (évite l'ombre portée de Simulation.Core.Simulation)
- ARCHITECTURE.md + CHANGELOG SYNE à jour ; 62 tests xUnit verts

* feat(echos): livraison ECHOS-1 — structure du monorepo (U0) (#412)

- paquet Python echos : API FastAPI create_app() (/health), registre des
  7 moteurs de métriques (METRICS_SPEC) + placeholder ingestion
- echos-ui : Vite + React + TypeScript (lint, build, tests vitest/jsdom)
- 13 tests pytest, couverture 100 %, flake8 (max-line-length=100)
- CI : job echos-python recalé sur 'flake8 echos', echos-ui npm ci actif
- docs : CHANGELOG/ARCHITECTURE ECHOS + CHANGELOG racine à jour

* feat(echos): livraison ECHOS-2 — contrats d'ingestion SYNE + golden files (U0) (#413)

- modèles pydantic WorldSnapshot/ExternalEvent (JSON camelCase,
  API_CONTRACTS.md §2) : aliases ingress, sortie by_alias, parse_message
  déterministe + InvalidMessageError stable
- WsClient :5180 (transport injectable, réception rejouée déterministe)
  et ControlClient :5181 (start/pause/resume/reset, corps vérifiés)
- golden files versionnés (fixtures/ + golden/) : double garde
  non-régression (contrat camelCase + vue interne snake_case)
- deps runtime : httpx + websockets ajoutés
- 43 tests pytest (couverture 98 %), flake8 propre, docs à jour

* feat(syne): jalon ph1 — BDI + perception (SYNE-010 à SYNE-015) (#414)

- Perception : rayon 50 (déc. 6), confiance 1−(d/r)×0.3, rotation id%4,
  ligne de vue obstacle cercle (ADR-013), micro-benchmark grille (< 10 ms)
- Mémoire : salience exponentielle, éviction, rappel ordonné (SYNE-013)
- Croyances : révision alignement/conflit/moyenne, expiration (SYNE-014)
- BDI + utilité : pipeline 10/15 étapes branché, U = (b−c−r)×conf×persona+urg,
  mouvements déterministes sans consommation PRNG (SYNE-010)
- Déterminisme : hash FNV-1a épinglé de la trajectoire (SYNE-015)
- Tests : 62 → 122 (toutes catégories nouvelles), build warnaserror vert

* feat(syne): émetteur WebSocket d'observabilité (SYNE-080) — snapshots + événements typés par tick (#415)

* feat(echos): ECHOS-010 — consommation du flux alignée par tick (snapshots V0.1 + serveur in-process) (#416)

* feat(echos): ECHOS-011/012/013 — stockage d'analyse (agrégation, SQLite, Parquet, pipeline) (#417)

* docs(echos): preuve du déterminisme J1 (2 runs seed 7 → 0 divergence sur 443 ticks + 44 300 séries) (#418)

* docs: site GitHub Pages DocFX + XML SYNE (#docs-site) (#419)

- Landing de présentation (docs/site/index.md) + TOC DocFX
- Docs clés synchronisées par sync-docs.sh (source unique monorepo)
- API Simulation.Core générée par DocFX depuis le XML (Simulation.Core uniquement)
- XML .NET activé sur Simulation.Core + Simulation.Console (NoWarn 1591)
- Workflow docs-pages : push develop -> build XML + docfx -> gh-pages
- Branche gh-pages initialisée, source Pages basculée, .nojekyll
- Badge Documentation + entrée CHANGELOG

* feat(syne): SYNE ph2 — mémoire intergénérationnelle, trustDecay, éviction 1000 + observabilité étendue (#420)

* feat(echos): ECHOS-020→027 — 7 moteurs de métriques déterministes + golden files + preuve J2 (#421)

* feat(syne): SYNE ph3 — délibération (fréquence/holdover), interruptions, conflits de priorités, utilité alignement + hystérésis (#SYNE-030→033) (#422)

* feat(echos): ECHOS ph3 — indicateurs d'émergence (score composite, phénomènes, complexité/imprévisibilité, disclaimer) + preuve J3 (#ECHOS-030→033) (#423)

* feat(syne): SYNE ph4 — catalogue d'actions déclaratif + exécuteur atomique, actions terminales Eat/Drink + réserves globales (seuils ≥ 50), déclencheur d'interruption centralisé (#SYNE-040→043) (#424)

* feat(echos): ECHOS ph4 — API REST (runs, métriques/séries ?every=N + cache, export JSON/CSV reproductible, croyances/relations, groupes, phénomènes) + stockage v2 (tick_metrics, tick_contexts) + preuve J5 (#ECHOS-040→045) (#425)

* feat(syne): SYNE ph5 — communication par pulsations (diffusion publique + interception, coûts émission/réception hérités configurables, relais avec dégradation de confiance ×0.9/hop), événements message_sent/message_received, engineVersion 0.4.0 (#SYNE-050→054) (#426)

* feat(echos): ECHOS ph5 — logging & instrumentation (JSONL déterministe tag SSE-V2, traces decision_traces schéma v3 + endpoint /decisions, profilage bit-à-bit des 8 moteurs), SCHÉMA SCHEMA_VERSION 3, preuve J5 étendue 181 tests (#ECHOS-050→052) (#427)

* feat(syne): SYNE ph6 — réseau social émergent (cohésion confiance × affinité et composantes, leader par confiance entrante, décisions collectives pondérées, LOD 10 ticks, turnover), naissance par fusion consentie (paire d'id minimal, enfant médian, mind Born), héritage fin (dominance/mutation SplitMix64, salience configurable), événements group_formed/dissolved/decision + agent_spawned, snapshot groups[], transmissionRange 55 (§ calibration ph6), engineVersion 0.5.0 (#SYNE-060→063) (#428)

* feat(echos): ECHOS ph6 — analyse causale hors ligne (reconstruction Action←Intention←Objectif←Besoin←Croyance←Mémoire←Perception depuis decision_traces/events_log/agents, cycles récurrents + profondeur bornée [1,12], CausalCache LRU invalidé sur ingest_version, endpoint GET /api/runs/{id}/causal-chains/{agentId}) (#ECHOS-060→063) (#429)

* feat(syne): SYNE ph7b — fidélités V0.1 (mortalité épuisement DeathSystem + agent_died, naissance consentie fidèle Qualifies/LOS/énergie/critique, décision collective → objectifs membres GroupObjective/PropagateObjectives + bonus alignement, cheminement A* déterministe grille rasterisée/voisinage ordonné/tie-break/repli sur place + PathCache LRU), preuves anti-triche SYNE-081/082, engineVersion 0.6.0 + checksum doré ré-épinglé 0x27fad50065d8c4a4 (#SYNE-074→077, #SYNE-081→082) (#430)

* fix(echos): publie GET /api/runs/{id}/decisions dans le registre _ENDPOINTS (auto-description ), + test registre ECHOS-051 — alignement inventaire API_REST.md §2 (11 endpoints) (#431)

* docs(syne): resegmentation U5/U6/U8 (U6 = ph8 + ph7b SYNE-074-077 + ECHOS ph6 ; U8 = ph7 + ph11 + 120-131 + packaging), tickets SYNE-074→077 livrés (jalon ph7b), agent_died documenté (payload {cause,species}, engineVersion 0.6.0), régularisation API_CONTRACTS/DETERMINISM/TESTING/CHANGELOG + épinglage checksum 0x27fad50065d8c4a4 (#432)

* docs(echos): décision interface web locale React/Vite servie par FastAPI — PAS de shell Electron en V0.1 (ADR-001 ECHOS, ARCHITECTURE ECHOS/racine, CHANGELOG, FRONTEND_VISION, ISSUES, README, ROADMAP, PRISM ; résidu Electron = contexte d'abandon uniquement) (#433)

* feat(syne): jalon ph9 — performance & scalabilité SYNE-090→093 (TickBudgetCollector budgets 7 sous-systèmes + part computation ≥30 %, CLI --benchmark cibles 50/500/1000 + checksum d'état FNV-1a, ObjectPool sur buffer de tri de perception pour réduire l'allocation GC, déterminisme conservé — checksum doré inchangé 0x27fad50065d8c4a4) ; tests +12 (ObjectPool 5, TickBudget 3, ScaleTargets 4) → 273 Core + 6 Console (#SYNE-090→093) (#434)

* docs(syne): jalon ph9 livré — PERFORMANCE.md §9 (résultats --benchmark ≥2720/1187/505 t/s, part computation 35-68%, machine de référence, convention CI planchers 120/30/20×\~7), ISSUES.md SYNE-090→093 LIVRÉ, CHANGELOG, ROADMAP racine+docs (U7/ph9), TESTING.md (+12 → 279, planchers, §5/§6) — checksum doré inchangé 0x27fad50065d8c4a4 (#435)

* feat(syne): jalon ph10 — tests & couverture SYNE-100→102 (validateur config 100%, déterminisme d'état complet) ; intégration boucle complète sans perte data; observabilité étendue ExternalEvent (#436)

* feat(echos): jalon ph7 — comparaison expérimentale ECHOS-070→072 (U7) (#438)

* feat(echos): jalon ph7 — comparaison expérimentale ECHOS-070→072 (GET /api/compare, méta-métriques reproductibilité ReproducibilityScore 1-(CognitiveDiff+SocialDiff)/2, empreinte SHA-256 canonique, exports json/csv alignés) ; tests +11 → 208, couverture 97,97%

* style(echos): lignes test_compare.py ≤ 100 caractères (flake8 echos .flake8 max-line-length=100) — CI Python verte

* docs(syne): jalon ph10 livré — SYNE-100→102 (324 tests, couverture 96,19%, baseline d'état 0x072a488aa18c05eb épinglée DETERMINISM §7), ROADMAP/TESTING/CHANGELOG/ISSUES+racine U7 (#437)

* docs(echos): jalon ph7 livré — comparaison expérimentale ECHOS-070→072 (API_REST §3.9 +registre 12 endpoints, EXPERIMENT_COMPARISON §4 implémenté, METRICS_SPEC §10, ISSUES LIVRÉ, CHANGELOG, ROADMAP, TESTING +11→208/97,97%) ; ROADMAP racine U7 complet livré (#439)

* docs(echos): correction Electron — conservé, implémentation différée post-V0.1 (#440)

Reformulation 'PAS de shell Electron' → 'shell Electron conservé, implémentation différée à un horizon ultérieur' (décision 23/09/2026 corrigée) dans ADR-001 ECHOS (décision + log correctif), ARCHITECTURE (ECHOS + racine), FRONTEND_VISION, README, ROADMAP (phase 10 'Shell Electron'), ISSUES (ECHOS-001/080 + intro), CHANGELOG (ECHOS + racine), TRANSPORT_API (PRISM). Monographie non modifiée (snapshot figé).

* feat(echos): jalon ph8 — échos-ui, les 6 Écrans (A→F) (#441)

- stack : react-router-dom (routes A→F), echarts+echarts-for-react,
  lucide-react, zustand ; Vite proxy /api+/health → :5000 (dév.) ;
  code-splitting par écran + chunks vendor echarts/react.
- src/api/ : client REST typé sur API_REST.md §3 (runs, métriques
  ?every=, export, décisions, causal-chains, croyances/relations,
  groups, phenomena, compare) ; 503/404 gérés ; controlClient =
  relais ECHOS→SYNE :5181 (jamais en direct).
- src/ws/realtime.ts : client WS :5180 (reconnexion, tick, état SYNE).
- src/store/ (zustand) : runs, KPI live, run sélectionné, état WS.
- Écrans A→F : Dashboard (KPICards+gauges+timeline+phénomènes),
  Explore (Entités/Groupes/Communications, heatmap « à venir »),
  SocialGraph (graphe force-directed /relationships + inspecteur),
  Analysis (Métriques 8 moteurs / Causale profondeur ≤12 / Comparaison
  /compare), Control (pilotage relais + calibration + runs/export WS),
  Log (console 3 niveaux + limites de validité).
- vues sans calcul de métrique ; 13 tests vitest/RTL verts
  (mock fetch+WS) ; eslint + tsc -b + build verts.
- docs ECHOS : CHANGELOG ph8 + ISSUES ECHOS-080→085 → LIVRÉ (statuts).

* docs(site): refonte GitHub Pages — landing LIVEX, thème DocFX surchargé (palette LIVEX, logo/favicon), Écrans A→F & FRONTEND_VISION publiés dans la navigation (#442)

* docs(site): refonte GitHub Pages — landing LIVEX, thème DocFX surchargé (palette LIVEX, logo/favicon), docs Écrans A→F & FRONTEND_VISION publiées dans la navigation

### Landing (index.md)
- Hero sombre  + badge « Monorepo dotnet + python + typescript »,
  tagline, description, 3 CTA (README / API REST ECHOS / Interface web pour
  echos-ui), **3 cartes modules** (SYNE sémantique — Simulation.Core ; ECHOS
  analyse ; PRISM rendu) en overlay  (HTML dans le markdown DocFX),
  bandeau « Fonctionnalités » (6 lignes : déterminisme bit-à-bit, observation
  non intrusive, 7+8 moteurs de métriques, adéquation SYNE↔ECHOS, lien
  doc principes).

### Thème DocFX — overlay
- **** : palette LIVEX () appliquée au thème
   DocFX (docfx.css Bootstrap) — variable-couples , fond
  /surface /bordure /texte /accent
  , navbar sombre, cartes , hero, badges, tableaux,
  code, footer ; police Inter + JetBrains Mono (chevauche cohérent avec
  ).
- ** + ** (overlay : remplace  DocFX par la
  marque LIVEX — 2 cercles reliés, palette ECHOS) ;  multi-taille
  généré (16/32/48/64).
- ** non requis** (le  fournit la navbar) ; overlay
  appliqué via  → .

### Navigation ()
- Section ECHOS enrichie : **FEATURE VISION orbitale & UI Désign** (les 6
  Écrans A→F) publiées dans la nav, + rubriques Métriques/API REST/Tests ;
  section Transverse inchangée (docs clés) —  étendu avec
   et  dans le tableau ECHOS.

### Build
- DocFX local :  (Simulation.Core.xml → API .NET) puis error: FatalError: System.IO.FileNotFoundException: Cannot find config file /home/devops/Documents/Code/LIVEX/docfx.json
   at Docfx.Docset.GetConfig(String configFile) in /_/src/Docfx.App/Docset.cs:line 73
   at Docfx.BuildCommand.<>c__DisplayClass0_0.<<ExecuteAsync>b__0>d.MoveNext() in /_/src/docfx/Models/BuildCommand.cs:line 25
End of stack trace from previous location ---
   at Docfx.CommandHelper.RunAsync(LogOptions options, Func`1 run) in /_/src/docfx/Models/CommandHelper.cs:line 42
   at Spectre.Console.Cli.CommandExecutor.ExecuteAsync(CommandTree leaf, CommandTree tree, CommandContext context, ITypeResolver resolver, IConfiguration configuration, CancellationToken cancellationToken) in /_/src/Spectre.Console.Cli/Internal/CommandExecutor.cs:line 257
  (0 erreur) ;  vérifiés : index hero + 3 cards, toc.html, chaîne
  bootstrap clean, favicon/logo overlay au bon chemin.

* docs(echos): FRONTEND_VISION — front-matter DocFX (title • accent paragraphe jalon ph8) ; aligne le h1 unique doc site ESLint conformité

* docs(site): refonte complète GitHub Pages en landing SaaS — landing sur mesure hors DocFX (racine), branding LIVEX (logo, favicon, palette UI_DESIGN), sections Modules/Fonctionnalités/Performances/Roadmap/FAQ, responsive + animations JS ; document DocFX DocFX sous /docs/, assemblage assemble-pages.sh + workflow assemble-pages (landing racine + docs/) (#443)

* docs(roadmap): cadrage Jalon U8 — assainissement du backlog (#444)

Plage ECHOS fictive (080…093) rectifiée en 080…085 (ph8, livrés U7) +
090…092 (ph9) ; carte manquante SYNE-113 ajoutée (serveur de contrôle
HTTP :5181, cible réelle du relais controlClient ECHOS) ; SYNE-110
précisé (hooks autoSaveEveryNTicks/maxBackups à brancher) ; ECHOS-085
annoté (livré côté UI, finalisation contre SYNE-113 en U8).

* feat(syne): jalon U8 — persistance SQLite bit-à-bit (SYNE-110→112) (#445)

- SqlitePersistenceStore : schéma V2.0 (11 tables, PRAGMA user_version=2), transactions atomiques, rotation maxBackups=5, reprise au dernier tick_states ;
- SimulationSnapshot/Codec : capture déterministe monde+cognition+PRNG 4×64 (JSON stable, hash FNV-1a) ;
- SimulationSnapshotRestorer : reprise exacte au tick N sans re-jouage, holdover LastDecision + réserves restaurées en place ;
- Hook autoSaveEveryNTicks (défaut 1000) câblé dans SimulationLoop.AdvanceOneTick — aucun tirage PRNG ⇒ checksums épinglés inchangés ;
- 5 PersistenceTests (320 Core, 329 totaux — reprise bit-à-bit, état RNG, reprise post-crash, schéma 11 tables, rotation) ;
- docs : PERSISTENCE §3 recalé (health→energy/hunger/thirst/fatigue), TESTING 324→329, CHANGELOG, ISSUES SYNE-110/112 LIVRÉ

* feat(syne): serveur de contrôle HTTP :5181 (SYNE-113) (#446)

Serveur de contrôle non intrusif du moteur SYNE, contrat API_CONTRACTS §3
(ADR-002/003) :
- SimulationFactory : résolution options (défauts → surcouche config → seed)
  + construction monde/entités/PRNG/boucle, identique au mode batch (bit-à-bit) ;
- SimulationController : machine à états idle→running⇋paused→finished, boucle
  d'arrière-plan (ManualResetEventSlim + CancellationToken par run) — 0 tirage
  PRNG ajouté ⇒ trajectoire inaltérée (SYNE-081, DETERMINISM §3) ;
- ControlServer : HttpListener BCL 127.0.0.1:5181, POST
  /api/control/start|pause|resume|reset + GET /status, erreurs JSON structurées ;
- mode CLI --serve / --serve-port (défaut 5181) ; interop vérifiée contre le
  ControlClient ECHOS (finalise ECHOS-085) ;
- 6 ControlServerWireTests (335 tests au total : 320 Core + 15 Console).

* feat(syne): cycle des ressources — minéraux + régénération/dégradation (SYNE-070) (#447)

- ResourceKind.Mineral (4e type, initial 0) + ResourceSettings enum-driven (ToStocks/Spec)
- ResourceStocks.ApplyLifecycle(tick, settings) appliqué en fin de tick par
  SimulationLoop.AdvanceOneTick (ordre causal strict, 0 tirage PRNG) : régénération
  + regenerationRate/tick, dégradation périodique -regenerationRate x degradationTick
  a chaque degradationTick (clamp >= 0, inerte sans taux)
- Persistance etendue : WorldSnapshotDto.MineralStock, codec Capture, restorer,
  SQLite WriteResources (4 types), observabilité resources[] (4 types)
- engineVersion 0.7.0 ; checksums dores (perception + baseline ph10) inchangees,
  re-epingles pour pin contractuel (DETERMINISM §7)
- Validation bornes resources.* (initial >= 0, regenerationRate >= 0, degradationTick > 0)
- Tests : ResourceStocksTests +5, SimulationOptionsValidatorTests +1,
  PersistenceTests +1 (4 reserves dont mineral perseveres, regeneration restauree),
  assertions CognitionPipeline/Observability adaptees aux bornes de regeneration
- Docs : DETERMINISM, CONFIGURATION §6.7, DATA_MODEL §8.1, SYSTEMS_SPEC §4,
  API_CONTRACTS §2.1, DECISIONS_V01 §2.4, ISSUES SYNE-070 LIVRE, TESTING (342),
  CHANGELOG (racine + SYNE), ROADMAP (racine + SYNE)

Suite totale : 342 tests (327 Core + 15 Console)

* feat(syne): constructions — obstacles statiques configurables + modification d'environnement tracée (SYNE-071) (#448)

* test(syne): jalons de validation moteur T0-T5 (SYNE-122) (#449)

T0 50 ent./1000 ticks sans crash + état valide déterministe ; T1 50/2000
croyances divergentes ; T2 traits -> décisions différentes en situation
identique (curiosité [0,0] vs [2,2], divergence portée par Explore) ;
T3 information locale (jamais hors portée) ; T4 reproductibilité
benchmark ; T5 suite > 160 tests (370). Carte purement test : 0 tirage
PRNG, engineVersion inchangé (0.8.0). MilestoneT0T5Tests (+8), suite
370 tests (353 Core + 17 Console), couverture 94.01 %.

* feat(syne): cycle de saisons world.seasons (SYNE-072) (#450)

world.seasons: ancien booléen mort -> bloc actif (enabled, seasonLengthTicks 360, initialSeason spring, cycle[] 4 saisons × facteurs/réserve). Saison = fonction pure du tick (0 tirage PRNG) ; SeasonFactors module régénération/dégradation (ResourceStocks.ApplyLifecycle, fin de tick) ; basculement tracé + drainé world.season_changed (tick exact) ; snapshot season/seasonIndex (additif) ; validation §6. engineVersion 0.9.0, checksums dorés inchangés (désactivé par défaut). +19 tests (SeasonTests, ObservabilitySeasonTests) — suite 389 (369 Core + 20 Console).

* feat(syne): territoires world.territory_membership_changed (SYNE-073) (#451)

* feat(livex): finalise le jalon U8 (#452)

* feat(livex): complete U8 milestone

* docs(livex): refresh project overview and setup guide

* fix(ci): disable full coverage on isolated U8 smoke test

* fix(echos): correction démarrage/contrôle + documentation (bundle existant) (#453)

* Refactor echos startup and control mechanisms

- Update installation and README documentation.
- Create V0.1 audit roadmap.
- Enhance API and frontend documentation.
- Improve control client and ingestion logic.
- Add new dev stack script for easier setup.
- Update tests for analysis, API routes, and control client.

* Fix startup and control issues in Echos module and update documentation

- Improve CI workflow and enhance installation instructions.
- Add new simulation configuration files and update related tests.
- Refactor Echos API and ingestion logic for better performance.
- Introduce new reporting functionality and tests for validation.
- Update various components in the Echos UI for better integration.

* fix(echos-ui): alignement des écrans sur le contrat snapshot SYNE (position imbriquée, ressources type/quantity, LiveAgent, garde anti-stale) (#454)

* feat(echos): trace parquet dans le batch, scheduler d'analyse périodique et benchmark SYNE vs SYNE+ECHOS (#455)

* fix(syne): repair test baselines and sqlite cleanup

Refresh the deterministic golden values to match the reproducible current trajectory, and release pooled SQLite connections before deleting temporary databases on Windows.

* fix(syne): normalize deterministic logs across platforms

Use explicit LF separators for hashed test logs so the pinned simulation checksums match on Windows and Linux.

* feat(syne): expose prepared world and global snapshots

Publish a versioned initial world with agents, cells, obstacles, resources, and tick rate; add the explicit prepare/ready control flow and include complete per-tick actions and world changes in the global snapshot.

* fix(echos): handle SYNE world initialization frames

Validate and ignore the world_initialized prelude while aligning tick segments so the ECHOS ingestion pipeline can connect to the updated SYNE stream.

* feat(syne-mock): simulate contracts with modular services

Split world generation, agent decisions, destination selection, movement, and snapshots into services; preserve the HTTP/WebSocket contract and add deterministic scenarios and integration tests.

* fix(git): répare la ligne .gitignore cassée et ignore les artefacts Unreal (#459)

fix(git): répare la ligne .gitignore cassée et ignore les artefacts Unreal

La ligne `*.logdocs/pages-dist/` supprimait d'un coup la règle `*.log` et
l'exclusion du site DocFX généré : les logs n'étaient plus ignorés et le build
de `docs-pages` réapparaissait dans `git status` à chaque publication.

Ajoute aussi les exclusions des répertoires produits par Unreal (`Binaries`,
`DerivedDataCache`, `Intermediate`, `Saved`, `Replays`, `StagedBuilds`, `.vs`,
solutions Visual Studio) afin que l'hôte technique `prism/LDK/` puisse être
versionné sans traîner ses ~10 Go de fichiers générés.

* feat(prism): ajoute le plugin Unreal PRISM-LDK (PrismLdk) et son hôte technique de build (#460)

feat(prism): ajoute le plugin Unreal PRISM-LDK (PrismLdk) et son hôte technique de build

Première implémentation exécutable de PRISM. Le plugin `PrismLdk` expose à
Blueprint le cycle de contrôle HTTP (5181) et la réception des contrats SYNE en
WebSocket (5180) : `Prepare`/`Ready`/`Start`/`Pause`/`Resume`/`Stop`/`Reset`,
`world_initialized`, snapshot global, deltas et événements.

SYNE reste le moteur décisionnel et l'autorité de l'état ; le C++ du plugin se
limite au transport, au parsing et à la conversion en types Blueprint.

- `prism/LDK/` : hôte technique `LDK.uproject` (Unreal 5.8), `Config/`, module
  `LDK` et assets Blueprint de test.
- `prism/LDK/Plugins/PrismLdk/` : module `PrismLdk` (Runtime, phase Default),
  `UPrismLdkSubsystem` + bibliothèque Blueprint + types de contrat.
- `EngineAssociation` positionné à `5.8` : la valeur GUID d'origine (build
  source) empêchait l'ouverture sur une installation Unreal Launcher.
- `.gitattributes` : `*.uasset`/`*.umap` déclarés binaires, une conversion de
  fin de ligne automatique corromprait ces assets ; LF garanti pour `*.sh`.
- `docs/docs-prism/PRISM_UNREAL_IMPLEMENTATION.md` : guide d'intégration.

Non validé : aucun runner Unreal 5.8 n'est disponible, la compilation du plugin
reste à confirmer sur une installation Unreal locale.

* docs(prism): acte l'adoption d'Unreal (ADR-002) et supersède l'ADR Godot (#461)

docs(prism): acte l'adoption d'Unreal (ADR-002) et supersède l'ADR Godot

L'ADR-001 (prototype Godot) était marquée « historique » sans qu'aucun ADR
successeur ne prenne le relais : le choix du moteur définitif restait donc non
tranché en gouvernance, alors même qu'un socle de code Unreal était livré
(PR #460).

- Nouvel `docs/docs-prism/adr/ADR-002-choix-unreal-prism-ldk.md` [Accepted] :
  contexte, décision, conséquences, risques, alternatives (Godot, Unity, non
  décision maintenue, ECHOS seul) et conditions de validation/réouverture.
- ADR-001 marquée [Superseded] avec renvoi vers l'ADR-002 ; l'argument « Unity
  et Unreal surdimensionnés » est explicitement rattaché au périmètre du
  prototype.
- Index ADR du composant mis à jour (nouveaux statuts par ADR).
- ADR-003 / ADR-004 : la liste des routes et des formats est désormais
  explicitement celle de la proposition d'origine de la Monographie, avec renvoi
  vers le contrat courant. ADR-004 acte la diffusion multi-consommateur.
- `ARCHITECTURE.md`, `VISION.md`, `GLOSSARY.md` : PRISM décrit comme projet
  Unreal final intégrant le plugin PRISM-LDK ; `prism/LDK/LDK.uproject`
  documenté comme hôte technique de build/test et non comme un second produit.
- `CHANGELOG.md` racine : entrée de la décision d'architecture.

* docs(prism): réécrit le dossier PRISM pour le projet Unreal et son plugin (#462)

docs(prism): réécrit le dossier PRISM pour le projet Unreal et son plugin

Le dossier `docs-prism` décrivait un prototype Godot sans rapport avec l'état
réel du dépôt. Réaligné sur l'ADR-002 et sur le code livré en PR #460.

- `README.md`, `ARCHITECTURE.md`, `VISION.md` : PRISM = projet Unreal final
  intégrant le plugin PRISM-LDK ; frontière explicite entre le plugin
  (interopérabilité Blueprint) et le projet PRISM (expérience et rendu) ; SYNE
  reste l'autorité de l'état.
- `TRANSPORT_API.md` : contrats selon l'état courant — `world_initialized`,
  snapshot global par tick, deltas/événements, cycle
  `prepare`/`ready`/`start`/`pause`/`resume`/`stop`/`reset`, 5180/5181 par
  défaut.
- `SCENE_SPEC.md`, `RENDERING_SPEC.md`, `VISUALIZATION_SPEC.md`,
  `UX_INTERACTION.md`, `ASSETS_CONVENTIONS.md` : spécifications recadrées en
  objectifs de présentation, sans prétendre que les fonctions sont livrées.
- `TESTING.md` : stratégie de validation, avec la distinction explicite entre
  contrat (testable sans moteur) et rendu (non couvert en CI, aucun runner
  Unreal).
- `ROADMAP.md` : 6 étapes d'évolution orientées intégration et validation, avec
  section de risques et réponses.
- `CHANGELOG.md` du composant : réécrit en conservant les entrées plugin
  (PR #460) et ADR-002 (PR #461) et en restaurant la table de mises à jour.
- `CHANGELOG.md` racine : entrée de la réécriture du dossier.

Vérifié : aucun lien interne mort dans `docs/docs-prism/`.

* docs(livex): réaligne la documentation transverse sur PRISM-Unreal et cadre syne-mock (#463)

docs(livex): réaligne la documentation transverse sur PRISM-Unreal et cadre syne-mock

Dernier volet documentaire de l'adoption d'Unreal (PR #461 et #462) : cohérence
transverse et honnêteté sur ce qui est réellement implémenté.

- `README.md`, `ARCHITECTURE.md`, `VISION.md`, `ROADMAP.md`, `FAQ.md`,
  `INSTALLATION.md`, `COMMUNICATION.md`, `SECURITY.md`, `CI_CD.md`,
  `CONTRIBUTING.md` : PRISM décrit comme projet Unreal final intégrant le
  plugin PRISM-LDK ; `prism/` et `syne-mock/` apparaissent dans l'arborescence ;
  `ARCHITECTURE.md` gagne une §2.4 (syne-mock) et une §6 réécrite.
- `syne-mock` cadré explicitement comme outil de développement des contrats,
  pas un moteur : README, ARCHITECTURE §2.4, CONTRIBUTING §4 (checklist
  `npm test --prefix syne-mock`), CI_CD §2 et §5, ETHICS_AND_SCOPE §4.1.
- `docs/docs-echos/{ISSUES,ROADMAP,TESTING}.md` : ECHOS-091 restreint à
  SYNE→ECHOS ; la validation PRISM-LDK et du projet Unreal relève d'un chantier
  distinct. Finit la contradiction « le runtime PRISM commence après U8 ».
- `docs/docs_prototype/README.md` : bandeau d'archive.
- `LIVEX-Monographie_SnapV0-1.md` : note de statut explicitant que la
  monographie est une référence conceptuelle historique et non prescriptive.
- `docs/README.md` (nouveau) : portail séparant références courantes et
  archives, avec la règle de préséance en cas de divergence.
- `FAQ.md` : §9 remplace « Pourquoi pas Unreal/Unity ? » par la distinction
  LIVEX/PRISM/PRISM-LDK, avec renvoi vers l'ADR-002 pour la justification ;
  §10 explique le mock ; renumérotation 1→13.
- `docs/site/index.md` : carte PRISM en « Visualisation Unreal ».
- `CHANGELOG.md` racine : entrées transverse et portail, sans écraser celles des
  PR #461 et #462.

Vérifié : aucun lien interne mort hors gabarits Liquid `{{_rel}}` de
`docs/site/index.md` (préexistants) ; les occurrences restantes de « Godot »
sont dans des archives explicitement signalées (ADR-001, `docs_prototype`,
Monographie, DECISIONS_V01 §2.28) ou dans le contexte historique de l'ADR-002.

* chore(echos): verrouille les dépendances Python (uv.lock) (#464)

chore(echos): verrouille les dépendances Python (uv.lock)

Le lockfile était présent dans le checkout mais non suivi, ce qui rendait les
résolutions locales non reproductibles alors que `echos-ui/package-lock.json`
est versionné depuis le début.

- 36 paquets épinglés avec empreintes SHA-256.
- `requires-python = ">=3.11"`, cohérent avec `pyproject.toml`.
- Le groupe de développement (flake8, pytest, pytest-cov) est verrouillé, donc
  les mêmes versions que celles qu'installe la CI via `requirements-dev.txt`.

La CI continue d'utiliser `pip install -r requirements-dev.txt` : le lockfile
sert la reproductibilité du développement local. Le passage de la CI à `uv`
est hors périmètre.

* fix(syne-mock): libère les ressources du test et aligne les assertions (#465)

fix(syne-mock): libère les ressources du test et aligne les assertions

`npm test --prefix syne-mock` ne se terminait jamais : après la fin des
assertions, 2 serveurs TCP et 3 sockets restaient ouverts, si bien que
`node --test` ne rendait jamais la main. La commande était donc inutilisable
et masquait 4 échecs réellement présents sur `develop`.

- `createServer().close()` termine les clients WebSocket connectés, purge les
  connexions HTTP en keep-alive et chaîne les rappels de fermeture, afin que
  `close()` ne promette que lorsque les sockets sont réellement libérés ;
- les tests de serveur libèrent leur instance via `t.after()` (y compris en cas
  d'échec d'assertion) et attendent la fermeture du client WebSocket ;
- les assertions d'obstacles attendent le champ `type`, que `WorldDescription`
  publie déjà.

* fix(syne-mock): pose les agents sur les cases publiées comme franchissables (#466)

fix(syne-mock): pose les agents sur les cases publiées comme franchissables

`createInitialAgents` ne validait ses positions candidates que contre les
obstacles, jamais contre le relief : un agent pouvait apparaître sur une cellule
`sea` (`walkable: false`). La fonction évaluait aussi la position brute alors
que le monde publie la position arrondie, si bien que l'arrondi pouvait faire
basculer l'agent dans une case voisine bloquée.

Deux critères de test disjoints faisaient désaccord :

- le placement utilisait `isPositionBlocked`, qui compare le point au cercle ;
- la grille publiée utilisait `isCellBlocked`, qui compare le centre de case au
  cercle augmenté de la demi-cellule.

Un agent pouvait donc être validé au placement et déclaré non franchissable par
`WorldDescription`, ce qu'exprime exactement le test
`world generation places resources and agents only on walkable cells`.

Le placement s'appuie désormais sur `cells[].walkable`, indicateur publié par
`WorldDescription` : obstacles et mer passent par la règle exposée, et aucune
divergence entre les deux n'est plus possible. `obstacles` n'est plus requis par
la fonction, et la grille de terrain n'a jamais eu besoin d'être passée.

Vérification : 300 graines x 5 densités x 2 configurations d'obstacles
(324 600 positions) : 3 452 agents sur case non franchissable avant, 0 après,
génération toujours déterministe. Test de non-régression ajouté sur 5 graines,
vérifié en échec sur l'état précédent.

* ci: exécute la suite syne-mock et publie le guide d'intégration Unreal (#467)

ci: exécute la suite syne-mock et publie le guide d'intégration Unreal

`CI_CD.md` §2 annonce un job CI `syne-mock` et `CONTRIBUTING.md` §4 rend
`npm test --prefix syne-mock` obligatoire pour toute modification du
composant. Aucun des deux n'était exécuté. Le job peut désormais l'être : la
commande se termine (PR #465) et la suite est verte (PR #466).

- `ci.yml` : `syne-mock/` rejoint la boucle de détection des composants, avec
  sortie `syne_mock` (le `-` est converti en `_`, une clé de sortie ne pouvant
  pas contenir de tiret dans une expression) ; nouveau job
  `Tests (SYNE-MOCK Node)` sur `ubuntu-latest`, `npm ci` puis `npm test`, avec
  `timeout-minutes: 5` en garde-fou contre une régression de type fuite de
  descripteurs ;
- `sync-docs.sh` : `PRISM_UNREAL_IMPLEMENTATION.md` publié dans `articles/prism/`,
  et `toc.yml` l'expose sous « Intégration Unreal (PRISM-LDK) ». Le guide
  Blueprint du plugin, référencé par `ARCHITECTURE.md`, était inaccessible sur
  le site ;
- `docs-pages.yml` : `prism/**` déclenche désormais le build du site, la
  documentation contractuelle étant écrite contre ce code ;
- `syne-mock/README.md` : la commande de test renvoie vers le job CI.

Au passage, la section `## [Unreleased]` du CHANGELOG cumulait des
sous-sections dupliquées (`### Changed` x3, `### Added` x2) et une ligne blanche
parasite ; sections regroupées et ordonnées `Added` -> `Changed` -> `Fixed` ->
`Deprecated`, et coquille « formality » corrigée en « formalise ».

Vérifié : `ci.yml`, `docs-pages.yml` et `toc.yml` parsent, `bash -n
sync-docs.sh` passe, le script publie bien le guide, et la commande exacte du
job (`node --test test/*.test.js` dans `syne-mock/`) sort en 0 avec 12 tests
verts.

* ci: declenche la CI sur les PR visant main (#468)

La CI ne se declenchait que sur develop. La protection de branche « branche a
jour + CI verte » de main ne peut donc pas etre appliquee : une PR de release
ou de hotfix n-executerait aucun check, et le merge resterait bloque sur un
status attendu qui n'arrive jamais.

`main` est ajoute aux branches de `pull_request` et de `push`, ce qui rend la
regle enforceable. Les jobs restent filtres par composant, donc une PR de
release ne construit que ce qu'elle touche.

Aucun changement de job ni de condition.

* docs(ci-cd): documente les protections de branche actives (#469)

`main` et `develop` sont desormais couverts par les rulesets `mainRules` et
`developRules`, en enforcement active. Le document annoncait « echec =
blocage (protection de branche) » sans jamais dire de quelle protection il
s'agissait, ni quels checks sont exiges.

La nouvelle section 2.1 detaille les cinq regles en vigueur, les deux checks
exiges et pourquoi les jobs par composant ne le sont pas (ils rapportent
`skipped` hors perimetre), ainsi que le retrait de `required_signatures` et sa
raison.

Consigne de maintenance ajoutee : renommer `Composants modifies` ou
`Structure & conventions (transverse)` bloque tous les merges jusqu'a mise a
jour du ruleset.

* fix(adr-001): corrige la coquille « formality » et ajoute le saut de ligne final (#470)

L'entree de CHANGELOG.md qui annoncait la correction de « qui formality ce
choix » decrivait en realite la coquille du CHANGELOG lui-meme. Le fichier ADR
vise, docs/docs-prism/adr/ADR-001-choix-godot.md, portait toujours « formality »
et n'avait jamais ete corrige.

Corrige en « formalise », et ajoute le saut de ligne final manquant sur cet ADR
et sur docs/docs-prism/adr/README.md, tous deux sans terminaison.

Detecte en comparant le stash de securite stash@{0} (wip-prism-unreal) aux
fichiers merges sur develop : le stash est un sous-ensemble strict de develop,
donc rien d'utile n'y est encore, et le rapprochement a fait ressortir la
coquille.

* fix(syne-mock): applique la carte publiee au deplacement des agents (#471)

Le deploiement deplace les agents sans jamais consulter la carte que
WorldDescription publie. Quatre defauts distincts :

- isPositionBlocked etait appele sans cellSize, donc la branche `shape`
  comparait des coordonnees NaN et laissait traverser les sept formes
  d'obstacle, alors que la version circulaire bloquait ;
- canEnter ignorait cells[].walkable, donc les agents traversaient la mer ;
- le cout de terrain etait ignore : une riviere (movementCost 4) se
  traversait a la vitesse de la plaine ;
- un deplacement refuse etait facture : l'energie baissait de
  moveEnergyCost meme quand l'agent n'avait pas bouge.

cell-grid.js centralise l'indexation de cells[] (y * cellCountX + x),
partagee par le placement et le deplacement. L'inversion x * cellCountX + y
etait auto-coherente sur une carte carree mais faisait chevaucher des cles
sur une carte rectangulaire. L'arrondi est desormais applique avant le test,
pour que la position validee soit celle que le snapshot publie.

Le cout retenu pour borner le pas est le plus eleve entre la case de depart
et la case visee : entrer dans une riviere ralentit, en sortir aussi. Une
case non franchissable donne un budget nul. Seul un mouvement effectif est
facture ; un blocage est reporte via outcome: 'blocked'.

La generation du monde est inchangee : empreintes SHA-256 identiques avant
et apres sur 5 graines x 4 configurations, dont une carte rectangulaire
300x180. movement.test.js ajoute 10 tests (12 -> 22).

* fix(syne-mock): rend le demarrage transactionnel, borne le journal et corrige l age des objectifs (#472)

Trois defauts de cycle de vie, sans rapport entre eux mais tous visibles
par un client de controle.

1. start() laissait un run actif apres un echec. `loadReplay` leve sur un
   fichier absent ou une ligne JSON malformee ; il etait appele apres
   `state = 'running'` mais avant `startTimer()`. Le resultat etait un run
   declare actif sans timer : rien ne tickait, et tout appel ulterieur a
   start() etait rejete au motif que le run etait deja actif. Le chargement
   du replay precede desormais l'entree en running, et tout ce qui le
   precede est reecritable sans consequence. Apres un echec, le monde reste
   prepare et acquitte, et un nouvel appel se comporte comme le premier.

2. `this.events` n'etait pas borne. Deux evenements par agent et par tick
   etaient conserves pendant toute la duree du run : 202 200 evenements sur
   2 000 ticks x 50 agents, heap 66 Mo. `diagnostics.maxEvents` (defaut
   2 000) borne le tampon a 2 000 evenements, soit heap 18 Mo sur le meme
   run. La troncature vide jusqu'a mi-capacite plutot que d'un seul
   element, pour ne pas decaler tout le tampon a chaque emission. Le flux
   diffuse (WebSocket) reste la source faisant autorite : ce tampon est un
   diagnostic, pas l'historique.

3. `goals[].age` valait le tick absolu. La liste etant reconstruite a chaque
   tick, `age` etait toujours egal au tick courant et ne disait rien de la
   duree d'un but. `intentionSince` suit le dernier changement d'intention
   et `age` devient le nombre de ticks ecoules depuis : 15 a 24 au tick
   2 000 d'un run de reference, au lieu de 2 000. Le marqueur reste interne,
   le snapshot publiant une liste de champs explicite.

lifecycle.test.js ajoute 8 tests (22 -> 30).

* docs(syne-mock): rectifie le contrat consomme et liste les simplifications assumees (#473)

Le contrat decrit ce que le mock publie, donc ce qu'un client PRISM ou
ECHOS branche dessus. Deux de ses affirmations etaient fausses ou
incompletes, et un consommateur pouvait s'y fier.

- Le document annoncait que le mock n'expose pas de type de terrain et que
  les cellules utilisent `terrainType: "plains"`. C'est faux : le mock publie
  trois profils, `plains` (cout 1), `river` (cout 4) et `sea`
  (`walkable: false`, cout infini), et le pas est borne par le cout de
  terrain. Le tableau des profils est ajoute, avec la regle d'entree et de
  sortie de riviere et la frontiere mer, en distinguant ce qui appartient au
  mock de ce qui appartient a SYNE.
- La liste des actions a mapper en `UENUM` n'en citait que 5 sur 9 :
  `SeekFood`, `SeekWater`, `Flee` et `Socialize` manquaient, alors que le
  contrat les publie des qu'elles se produisent. Les 9 sont listees, avec pour
  chacune sa condition de candidature et son premier tick de production,
  mesure sur la graine 42 avec 50 agents et non deduit du code. Deux
  impossibilites sont explicites : `Flee` est structurellement inatteignable,
  car `safetyDriftRate` est positif alors que `safety` demarre a sa borne
  haute et ne peut donc jamais passer sous 0.5 ; `Socialize` n'est produite
  qu'au tick 943, donc hors du `maxTicks: 400` par defaut.
- Nouvelle section « Perimetre reel et simplifications assumees » : la mort,
  la perception, le contenu des communications, la decision de groupe, les
  livres, les territoires, les ressources locales, l'echelle temporelle et le
  pathfinding sont des elements decoratifs, et `simulation.events` un tampon de
  diagnostic borne. Ces elements sont publies dans le contrat comme s'ils
  portaient du sens ; la section dit desormais ce qu'un client ne doit pas
  encore interpreter.
- Le comportement d'un `start` refuse est documente dans la section HTTP : le
  monde reste `ready` et reutilisable, donc un client peut reessayer sans
  appeler `stop`.

* feat(syne-mock): besoins de depart configurables, fini les 15 s d'Idle initial (#474)

Les agents passaient 146 ticks sans rien faire au debut d'un run. Les besoins
de depart etaient codes en dur dans createInitialAgents et curiosity partait
de 0 : il fallait que curiosityDriftRate (0.002) amène la valeur au seuil
d'exploration de 0.3, soit 150 ticks, ou 15 s a ticksPerSecond 10.

- agentSimulation.needs.initial rend les six besoins de depart configurables,
  avec les domaines qu'ils bornent deja (0..100 pour hunger/thirst/fatigue,
  0..1 pour safety/social/curiosity). Une valeur absente retombe sur l'etat
  historique du mock, une valeur hors domaine est refusee a la generation du
  monde, comme les autres cles de configuration.
- curiosity passe de 0 a 0.3 par defaut, exactement le seuil d'exploration :
  les agents se mettent en mouvement au tick 1 et plus aucun Idle n'est produit.
  Eat 100, Drink 72, Rest 234 et Socialize 943 sont inchanges.
- curiosityDriftRate passe de 0.002 a 0.001, le cout de ce decalage : explorer
  des le premier tick sature curiosity plus vite, et un besoin sature garde une
  utilite superieure a celle de Rest, qui devient alors jamais produit. Mesure
  sur 2000 ticks, 0.002 supprime Rest du flux alors que 0.001 conserve le
  repertoire complet d'actions.

Le placement des agents ne lit que la graine et la carte : les besoins de depart
decalent la trajectoire d'un agent, pas l'endroit ou il apparait. Generation du
monde byte-identique avant/apres sur 5 graines x 2 tailles dont 300x180, run
deterministe a l'identique sur 2 processus distincts.

+4 tests dans test/server.test.js, suite verte.

* fix(syne-mock): diffuser le snapshot avant les evenements du tick (#475)

Le mock emettait les evenements du tick avant son snapshot. SYNE
(ObservabilityTickEmitter) et API_CONTRACTS.md §2 imposent l'inverse, et tout
consommateur qui aligne le flux sur les ticks le refuse : ECHOS rejetait le
mock des la premiere trame avec

  TickAlignmentError: message event invalide (conforme API_CONTRACTS.md) :
  evenement decision_made recu avant le premier snapshot

step() regroupe desormais les evenements du tick, diffuse le snapshot puis
tick_summary, puis les evenements de ce tick. L'ordre des evenements entre eux
et le tampon de diagnostics sont inchanges, stepReplay() n'est pas touche, et le
contenu par tick reste identique (hash canonique inchange sur 120 ticks) :
seul l'ordonnancement change.

Verrouille par deux tests qui echouent tous deux sur l'ancien code :
- syne-mock/test/stream-order.test.js : ordre exact des trames, invariant
  d'alignement et invariance du tampon de diagnostics ;
- echos/echos/tests/test_syne_mock_integration.py : le vrai client ECHOS
  ingere le mock de bout en bout (controle HTTP, WebSocket, SQLite, Parquet,
  API REST, calibration), sans build .NET.

Le mock devient donc utilisable pour travailler sur ECHOS : pointage par
SYNE_OBSERVABILITY_URL / SYNE_CONTROL_URL, procedure documentee dans
syne-mock/README.md, limites de simulation assumees (beliefs/trust vides).
Nouveau job CI "Integration mock -> ECHOS" sur toute PR touchant syne-mock/
ou echos/, distinct du job U8 qui reste sur le moteur .NET.

* fix(echos): revue complète du composant (moteurs, provenance, API, interface) (#477)

Deux bugs rendaient des fonctions centrales inopérantes : `/api/compare`
renvoyait 500 sur tout run contenant un événement (la décompression décomptait
six colonnes pour un zip de sept), donc la comparaison de reproductibilité
était inaccessible sur tout run réel ; et `AnalyticsStore.runs()` levait
`int(None)` sur un run sans tick, ce qui rendait l'API entière inopérante sur
une base fraîche ou un run en cours d'acquisition.

Sept métriques restaient à 0 sur tout run réel parce que le snapshot ne
portait que le tick courant, jamais `history` ni `communityHistory` — la
fixture de test les fournissait artificiellement, ce qui masquait le
problème. `_RollingContext` construit et borne désormais trois fenêtres
glissantes. Le dénominateur des taux de groupe ne dépend plus de la charge
(il valait 1000 ticks sur un run calme et 20 sur un tick chargé, soit un
facteur 50 sur la même métrique) : la fenêtre est bornée en ticks et sa durée
réellement observée est publiée dans le snapshot.

Les singletons n'étaient plus comptés comme communautés, `DecisionDiversity`
était calculée sur les objectifs, `SystemComplexity` n'était pas borné,
`_availability(100, None, 0)` renvoyait 1e11 et contaminait la moyenne du
moteur de durabilité, et un cycle d'import existait entre `emergence` et le
registre des moteurs.

Ajout de la provenance `measured` : `analysis.provenance()` calcule par couple
(moteur, métrique) si la valeur servie est une mesure ou le repli neutre du
moteur faute de fenêtre, depuis les mêmes entrées que le calcul lui-même. Sans
ce signal, l'interface ne pouvait pas distinguer un `0` observé d'un repli.
Persisté par tick (`tick_metrics.measured`, schéma SQLite v5, migration
additive) et publié par `/api/runs/{id}/metrics` et `/api/runs/{id}`. Évol
adhésion MINOR : champ ajouté, aucun consommateur existant n'est cassé.

Robustesse : cadences nulles qui levaient `ZeroDivisionError` ou étaient
silencieusement ignorées, fuite de descripteurs (`EchosLogger` sans `close()`),
reconnexion toutes les 100 ms quand SYNE est arrêté, fin de flux détectée par
préfixe de libellé d'erreur, et `pyarrow` importé mais non déclaré dans
`pyproject.toml` (un `pip install echos` produisait un paquet qui ne démarrait
pas). `dev_ingest` valide désormais sa configuration avant toute I/O, avec
sortie 2 distincte.

Les identifiants de groupe (`members`, `leaderId`, entiers côté transport)
sont normalisés en chaînes, sinon ils ne pouvaient jamais être joints à
`Agent.id` — `"3" != 3`. Même normalisation pour `Territory.members` et
`Book.author_id`/`readers`.

Interface `echos-ui` : l'export « CSV » téléchargeait une enveloppe JSON
illisible par tout tableur ; `beliefs`/`relationships`/`phenomena` appelaient
l'API sans `run_id` et affichaient donc les données du run le plus récent sous
le nom du run sélectionné ; le cache de métriques ignorait la cadence dans sa
clé et fusionnait des séries d'échantillonnages différents, produisant des
`NaN` rendus comme des zéros ; le graphe social relançait une requête par
membre en série à chaque tick ; la jauge de vitesse de diffusion alertait en
rouge un monde qui propageait bien ; `disconnect()` se reconnectait 2 s plus
tard et `usePhenomena` affichait « aucun phénomène détecté » sur un échec
réseau. `npm test` lance `vitest run` : le mode interactif ne termine jamais et
accrochait la CI.

Tests : 233 → 283 (couverture 93 %, seuil 80 %), flake8 propre ; interface
18 → 61 tests sur 14 fichiers, eslint et `tsc` propres. Les deux scénarios
d'intégration (SYNE réel et syne-mock) passent et vérifient désormais la
provenance et la normalisation des groupes contre les émetteurs réels.

Rapport complet dans `echos/ECHOS-REVIEW.md`, qui arbitrage aussi les points
laissés ouverts et leurs raisons.

* chore(docs): supprime DocFX et la publication GitHub Pages (#478)

Retire docs/site/ (source DocFX), docs/landing/ (landing SaaS),
docs/pages-dist/ (artefact d'assemblage commite malgre .gitignore) et le
workflow .github/workflows/docs-pages.yml. 51 fichiers suivis supprimes.

- .gitignore : entree docs/pages-dist/ devenue inutile retiree
- CHANGELOG.md : section Removed + entrees [Unreleased] obsoletes retirees
- echos/ECHOS-REVIEW.md : la note sur docs/pages-dist/ est replacee dans
  son contexte historique

Les documents markdown ecrits a la main (docs-syne, docs-echos, docs-prism,
adr, governance) sont conserves : ce sont les sources, pas des artefacts.

* fix(syne): revue complète du moteur (déterminisme, cycle de vie, observabilité, HTTP) (#476)

Revue et refactor du moteur SYNE. Les défauts ci-dessous sont groupés par
famille. Chacun est couvert par un test vérifié détecteur : le défaut est
réintroduit temporairement dans le code, le test doit devenir rouge, puis le
correctif est restauré. Ce que je n'ai pas su reproduire est dit comme tel
plutôt que présenté comme couvert.

1. DETERMINISME

SplitMix64.Gamma/Avalanche et l'implémentation FNV-1a étaient dupliqués sur
six sites, constantes recopiées : une divergence future aurait produit deux
hachages pour la même valeur. Centralisés dans SplitMix64 et le nouveau
Fnv1a64, sans effet sur les trajectoires.

La cause unique de l'écart de trajectoire était neutralisée : la garde de
rejeu de la communication existait mais n'était jamais appliquée. Le
destinataire d'un message le relaye donc une seconde fois. CanRelay applique
désormais HasRelayed, et la file de messages devient bornée (« plus récent
gagne ») au lieu de croître sans limite.

Réépinglage selon DETERMINISM.md §7 : percepts 0x27fad50065d8c4a4 ->
0xdb57f58566418f5d, état Ph10 0x072a488aa18c05eb -> 0x88bbc67950002bab,
EngineVersion 0.11.0 -> 0.12.0.

Piège de déterminisme : la cellule de SpatialGrid était dimensionnée par
agents.perception.radius. Or QueryCircle renvoie les voisins dans l'ordre de
parcours des cellules, qui décide de l'ordre de considération des perceptions.
Régler la portée de la perception modifiait donc silencieusement l'évolution
du monde. agents.perception.spatialCellSize devient un paramètre explicite,
défaut 50 (égal au rayon par défaut : trajectoire de référence inchangée, ce
qui évite un réépinglage supplémentaire).

2. VALIDATION

Les contrôles de plage s'écrivent « value is < 0.0 or > 1.0 ». En IEEE-754
toute comparaison avec NaN est fausse : « NaN is < 0.0 or > 1.0 » vaut false,
donc un NaN franchissait la validation puis se propageait dans les distances,
l'énergie et la Barclay, corrompant le monde sans lever d'erreur. Le
validateur balaie maintenant tout le graphe d'options par réflexion, ce qui
couvre aussi les champs ajoutés ultérieurement, et tolerate les chemins en
camelCase comme le contrat de configuration.

worldCellSize et le nouveau spatialCellSize n'étaient pas validés du tout.

3. CYCLE DE VIE DU CONTRÔLEUR

La boucle de tick était lancée en « feu et forget » : la tâche n'était jamais
conservée. Un second StartAsync superimposait une deuxième boucle sur le même
monde, Stop n'annulait que la dernière CancellationTokenSource en laissant
l'ancienne boucle active, cette ancienne boucle pouvait ensuite repasser
l'état à Finished par-dessus un run plus récent, et DisposeAsync simulait
l'attente avec Task.Delay(20). La tâche est maintenant conservée, une
génération de run est vérifiée avant toute écriture d'état partagé, un second
démarrage est refusé sur run actif, et StopAsync/ResetAsync/DisposeAsync
attendent réellement la fin de boucle. ControlServer répond 200 sur stop
après l'arrêt effectif.

4. HTTP DE CONTRÔLE

RootElement était renvoyé sans Clone() ni Dispose() : propriété invalide dès
la fin de vie du JsonDocument, une fuite par requête. Aucun plafond de taille
n'existait : un Content-Length ou un transfert par blocs arbitrairement grand
était lu intégralement en mémoire (1 Mio, 413 payload_too_large, lecture bornée
pour les blocs). Un JSON malformé ou un type de configuration incompatible
remontait en 500 au lieu de 400.

5. OBSERVABILITÉ

Un WebSocket n'accepte qu'un SendAsync à la fois : deux diffusions
concurrentes levaient InvalidOperationException, non rattrapée, et tuaient le
processus. Sérialisation par client, envois bornés dans le temps, retrait des
clients dans le finally du drain (auparavant un client déconnecté restait au
dictionnaire et son socket n'était jamais fermé), fermeture réellement
attendue, Start/DisposeAsync idempotents.

L'émetteur ne faisait pas confiance au sink pour être borné : un client lent
figeait la simulation, sans plafond. La capture est sautée quand aucun client
n'est connecté, mais les tampons du tick sont toujours vidés : la couche
d'observabilité en est le seul consommateur, sans quoi ils croissent sans
borne et rejouent des événements obsolètes.

6. CONFIGURATION ET AUTRES

La fusion de configuration sparse était destructive : le corps était
désérialisé en SimulationOptions avant fusion, donc chaque clé absente
prenait la valeur par défaut du type et un client ne pouvait surcharger un
champ sans détruire silencieusement tous les autres réglages. MergeJson fusionne
récursivement, et le JSON brut est transporté jusqu'à la fusion.

ResourceStocks consommait partiellement face à un stock insuffisant ;
ActionExecutor appliquait les bénéfices avant l'échec d'une réserve ; la
grille confondait les comptes et bornes X/Y ; les IDs de naissance n'étaient
pas uniques ; les territoires n'étaient pas persistés, donc une restauration
perdait toutes les zones et réassignait « Communes » (SchemaVersion 4).
A* autorisait une diagonale alors que les deux orthogonales étaient bloquées :
le pas rase le point d'appui entre deux cellules solides. PhaseCount valait 8
pour une énumération de 7 phases. `--seed -1` produisait une trace d'appels
plutôt qu'un message.

7. LE PIÈGE QUE SEUL LE TEST D'INTÉGRATION A VU

Une première version de la validation CLI refusait « --observe-port sans
--observe ». C'est faux : en mode --serve, Program démarre l'observability sur
--observe-port, et le contrat d'intégration SYNE → ECHOS lance exactement
« --serve --serve-port P --observe-port Q ». Le job CI
syne-echos-u8-integration échouait alors sur un défaut de validation, pas de
moteur, et SYNE refusait ses arguments sans ouvrir aucun port. Une suite
unitaire entièrement verte ne prouve pas qu'un contrat transverse est préservé.

Ce que j'avais laissé passer en commit est ce piège, pas un bug du moteur : la
validation est correcte, c'est ma règle qui était fausse, parce que j'avais
supposé que le port d'observation n'avait qu'un seul mode consommateur sans
avoir vérifié qui le consommait. Corrigé, avec un test qui verrouille les deux
combinaisons. C'est aussi ce qui m'a fait suspecter un auto-blocage possible du
chemin stop (le client ECHOS appelle stop alors qu'il ne lit plus le WebSocket,
et la requête HTTP a un timeout de 2 s) : vérifié empiriquement, 5 exécutions
consécutives vertes.

132 tests ajoutés (466 -> 598) ; suite SYNE à 553 tests, verte en Release avec
--warnaserror. Trois tests détectaient d'abord le bon bug pour la mauvaise
raison et ont été réécrits ; deux correctifs sont défensifs et le disent
(disparition intra-tick de groupe, culture invariante sur drapeaux entiers) ;
aucun n'est présenté comme vérifié par mutation quand il ne l'est pas.

REVIEW-REFACTOR-REPORT.md détaille chaque point.

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481 (#495)

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs (#496)

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

* chore(echos): ingestion 0.3.0, stockage et calibrage (#497)

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

* chore(echos): ingestion 0.3.0, stockage et calibrage|Champs optionnels inventory/commitments dans les modèles d'ingestion (rétro-compat 0.2.1 conservée), routes et service UI (echos-serve), invalidation inter-processus du cache de séries via PRAGMA data_version, calibrage de fin de run et viabilité. Suite ECHOS verte, couverture 93,16 %. Closes #485

* fix(echos-ui): écrans d'analyse gelés, retard croissant et contrôles Live/Actualiser (#498)

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

* chore(echos): ingestion 0.3.0, stockage et calibrage|Champs optionnels inventory/commitments dans les modèles d'ingestion (rétro-compat 0.2.1 conservée), routes et service UI (echos-serve), invalidation inter-processus du cache de séries via PRAGMA data_version, calibrage de fin de run et viabilité. Suite ECHOS verte, couverture 93,16 %. Closes #485

* fix(echos-ui): écrans d'analyse gelés, retard croissant et contrôles Live/Actualiser|Trois causes racines corrigées : cache de séries jamais invalidé entre processus (retard croissant 155→494 ticks), liste des runs chargée une seule fois (le run démarré n'apparaissait jamais), et refetch complet à chaque tick WS (tempête de requêtes). Ajout des boutons Actualiser et bascule Live/Figé. Validation réelle sur un run de 7 600 ticks : retard stable 14-35 ticks, 1 req/2 s mesurée. 62/62 tests UI. Closes #480

* feat(echos): shell de bureau Electron (ADR-003), packaging et CI (#499)

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

* chore(echos): ingestion 0.3.0, stockage et calibrage|Champs optionnels inventory/commitments dans les modèles d'ingestion (rétro-compat 0.2.1 conservée), routes et service UI (echos-serve), invalidation inter-processus du cache de séries via PRAGMA data_version, calibrage de fin de run et viabilité. Suite ECHOS verte, couverture 93,16 %. Closes #485

* fix(echos-ui): écrans d'analyse gelés, retard croissant et contrôles Live/Actualiser|Trois causes racines corrigées : cache de séries jamais invalidé entre processus (retard croissant 155→494 ticks), liste des runs chargée une seule fois (le run démarré n'apparaissait jamais), et refetch complet à chaque tick WS (tempête de requêtes). Ajout des boutons Actualiser et bascule Live/Figé. Validation réelle sur un run de 7 600 ticks : retard stable 14-35 ticks, 1 req/2 s mesurée. 62/62 tests UI. Closes #480

* feat(echos): shell de bureau Electron (ADR-003), packaging et CI|Backend Python enfant démarré par le shell (port libre, attente /health, SIGTERM→SIGKILL), UI servie même origine (zéro CORS), PyInstaller onedir avec collect_submodules('echos') (les moteurs importlib étaient invisibles de l'analyse statique), postinst Debian posant le setuid chrome-sandbox, packaging …
donovan-dev-web added a commit that referenced this pull request Oct 12, 2026
…nommés, filtre ADR (#531) (#533)

* [GOVERNANCE] Jalon U0 — socle git flow, CI, gouvernance GitHub (#409)

* feat(governance): jalon U0 — socle git flow, CI remaniée, gouvernance GitHub

- branches Git Flow : develop créée depuis main
- milestones dédupliqués (série canonique par composant), labels normalisés
- CI: jobs filtrés par paths (syne/**, echos/**) via détection git diff,
  validation transverse toujours verte ; conteneurisation Docker reportée
- release.yml: aligné (pas de GHCR tant que pas de conteneurisation)
- ajout .gitignore/.editorconfig ; maj README, INSTALLATION, CHANGELOG

* fix(governance): resserre l'heuristique anti-secrets (auto-correspondance du motif)

* feat(syne): socle U0 — solution .NET, config Annexe H + CLI, PRNG déterministe, ADR-012 (#410)

- Syne.sln + Simulation.Core/Simulation.Console/Simulation.Core.Tests séparés (SYNE-001)
- SimulationOptions (Annexe H) + loader JSON générique (fichier partiel préservant
  les défauts), validation des plages, priorité défauts -> --config -> flags CLI (SYNE-006)
- CliOptions.Parse : --seed/--max-ticks/--world-size/--headless/--config, erreur explicite rc=2
- PRNG xoshiro256** + splitmix64 (System.Random interdit) : vecteurs de référence
  épinglés depuis une implémentation indépendante (SYNE-005 via déterminisme)
- ADR-012 (config JSON + CLI) fusionnée ; ARCHITECTURE.md/§4§6 + CHANGELOG SYNE à jour
- 28 tests xUnit verts, build Release sans avertissement

* feat(syne): noyau U0 — boucle minimale, monde + grille spatiale, entités typées + traits (#411)

- SimulationLoop : 1 tick = 1 minute simulée, maxTicks respecté, PRNG ancré au tick
  (tête/queue affichées par la Console) — SYNE-002
- World : plan continu non-toroidal (positions clampées [0,W]x[0,H]), SpatialGrid
  uniforme à rayon configurable (requêtes déterministes ligne-par-ligne) — SYNE-003
- Entity : identité séquentielle, espèce, position, 8 traits [0,2] hérités d'un
  paramétrage (plages), validation des invariants ; fabrique déterministe —
  valeurs épinglées calculées par implémentation indépendante — SYNE-004
- namespace Loop (évite l'ombre portée de Simulation.Core.Simulation)
- ARCHITECTURE.md + CHANGELOG SYNE à jour ; 62 tests xUnit verts

* feat(echos): livraison ECHOS-1 — structure du monorepo (U0) (#412)

- paquet Python echos : API FastAPI create_app() (/health), registre des
  7 moteurs de métriques (METRICS_SPEC) + placeholder ingestion
- echos-ui : Vite + React + TypeScript (lint, build, tests vitest/jsdom)
- 13 tests pytest, couverture 100 %, flake8 (max-line-length=100)
- CI : job echos-python recalé sur 'flake8 echos', echos-ui npm ci actif
- docs : CHANGELOG/ARCHITECTURE ECHOS + CHANGELOG racine à jour

* feat(echos): livraison ECHOS-2 — contrats d'ingestion SYNE + golden files (U0) (#413)

- modèles pydantic WorldSnapshot/ExternalEvent (JSON camelCase,
  API_CONTRACTS.md §2) : aliases ingress, sortie by_alias, parse_message
  déterministe + InvalidMessageError stable
- WsClient :5180 (transport injectable, réception rejouée déterministe)
  et ControlClient :5181 (start/pause/resume/reset, corps vérifiés)
- golden files versionnés (fixtures/ + golden/) : double garde
  non-régression (contrat camelCase + vue interne snake_case)
- deps runtime : httpx + websockets ajoutés
- 43 tests pytest (couverture 98 %), flake8 propre, docs à jour

* feat(syne): jalon ph1 — BDI + perception (SYNE-010 à SYNE-015) (#414)

- Perception : rayon 50 (déc. 6), confiance 1−(d/r)×0.3, rotation id%4,
  ligne de vue obstacle cercle (ADR-013), micro-benchmark grille (< 10 ms)
- Mémoire : salience exponentielle, éviction, rappel ordonné (SYNE-013)
- Croyances : révision alignement/conflit/moyenne, expiration (SYNE-014)
- BDI + utilité : pipeline 10/15 étapes branché, U = (b−c−r)×conf×persona+urg,
  mouvements déterministes sans consommation PRNG (SYNE-010)
- Déterminisme : hash FNV-1a épinglé de la trajectoire (SYNE-015)
- Tests : 62 → 122 (toutes catégories nouvelles), build warnaserror vert

* feat(syne): émetteur WebSocket d'observabilité (SYNE-080) — snapshots + événements typés par tick (#415)

* feat(echos): ECHOS-010 — consommation du flux alignée par tick (snapshots V0.1 + serveur in-process) (#416)

* feat(echos): ECHOS-011/012/013 — stockage d'analyse (agrégation, SQLite, Parquet, pipeline) (#417)

* docs(echos): preuve du déterminisme J1 (2 runs seed 7 → 0 divergence sur 443 ticks + 44 300 séries) (#418)

* docs: site GitHub Pages DocFX + XML SYNE (#docs-site) (#419)

- Landing de présentation (docs/site/index.md) + TOC DocFX
- Docs clés synchronisées par sync-docs.sh (source unique monorepo)
- API Simulation.Core générée par DocFX depuis le XML (Simulation.Core uniquement)
- XML .NET activé sur Simulation.Core + Simulation.Console (NoWarn 1591)
- Workflow docs-pages : push develop -> build XML + docfx -> gh-pages
- Branche gh-pages initialisée, source Pages basculée, .nojekyll
- Badge Documentation + entrée CHANGELOG

* feat(syne): SYNE ph2 — mémoire intergénérationnelle, trustDecay, éviction 1000 + observabilité étendue (#420)

* feat(echos): ECHOS-020→027 — 7 moteurs de métriques déterministes + golden files + preuve J2 (#421)

* feat(syne): SYNE ph3 — délibération (fréquence/holdover), interruptions, conflits de priorités, utilité alignement + hystérésis (#SYNE-030→033) (#422)

* feat(echos): ECHOS ph3 — indicateurs d'émergence (score composite, phénomènes, complexité/imprévisibilité, disclaimer) + preuve J3 (#ECHOS-030→033) (#423)

* feat(syne): SYNE ph4 — catalogue d'actions déclaratif + exécuteur atomique, actions terminales Eat/Drink + réserves globales (seuils ≥ 50), déclencheur d'interruption centralisé (#SYNE-040→043) (#424)

* feat(echos): ECHOS ph4 — API REST (runs, métriques/séries ?every=N + cache, export JSON/CSV reproductible, croyances/relations, groupes, phénomènes) + stockage v2 (tick_metrics, tick_contexts) + preuve J5 (#ECHOS-040→045) (#425)

* feat(syne): SYNE ph5 — communication par pulsations (diffusion publique + interception, coûts émission/réception hérités configurables, relais avec dégradation de confiance ×0.9/hop), événements message_sent/message_received, engineVersion 0.4.0 (#SYNE-050→054) (#426)

* feat(echos): ECHOS ph5 — logging & instrumentation (JSONL déterministe tag SSE-V2, traces decision_traces schéma v3 + endpoint /decisions, profilage bit-à-bit des 8 moteurs), SCHÉMA SCHEMA_VERSION 3, preuve J5 étendue 181 tests (#ECHOS-050→052) (#427)

* feat(syne): SYNE ph6 — réseau social émergent (cohésion confiance × affinité et composantes, leader par confiance entrante, décisions collectives pondérées, LOD 10 ticks, turnover), naissance par fusion consentie (paire d'id minimal, enfant médian, mind Born), héritage fin (dominance/mutation SplitMix64, salience configurable), événements group_formed/dissolved/decision + agent_spawned, snapshot groups[], transmissionRange 55 (§ calibration ph6), engineVersion 0.5.0 (#SYNE-060→063) (#428)

* feat(echos): ECHOS ph6 — analyse causale hors ligne (reconstruction Action←Intention←Objectif←Besoin←Croyance←Mémoire←Perception depuis decision_traces/events_log/agents, cycles récurrents + profondeur bornée [1,12], CausalCache LRU invalidé sur ingest_version, endpoint GET /api/runs/{id}/causal-chains/{agentId}) (#ECHOS-060→063) (#429)

* feat(syne): SYNE ph7b — fidélités V0.1 (mortalité épuisement DeathSystem + agent_died, naissance consentie fidèle Qualifies/LOS/énergie/critique, décision collective → objectifs membres GroupObjective/PropagateObjectives + bonus alignement, cheminement A* déterministe grille rasterisée/voisinage ordonné/tie-break/repli sur place + PathCache LRU), preuves anti-triche SYNE-081/082, engineVersion 0.6.0 + checksum doré ré-épinglé 0x27fad50065d8c4a4 (#SYNE-074→077, #SYNE-081→082) (#430)

* fix(echos): publie GET /api/runs/{id}/decisions dans le registre _ENDPOINTS (auto-description ), + test registre ECHOS-051 — alignement inventaire API_REST.md §2 (11 endpoints) (#431)

* docs(syne): resegmentation U5/U6/U8 (U6 = ph8 + ph7b SYNE-074-077 + ECHOS ph6 ; U8 = ph7 + ph11 + 120-131 + packaging), tickets SYNE-074→077 livrés (jalon ph7b), agent_died documenté (payload {cause,species}, engineVersion 0.6.0), régularisation API_CONTRACTS/DETERMINISM/TESTING/CHANGELOG + épinglage checksum 0x27fad50065d8c4a4 (#432)

* docs(echos): décision interface web locale React/Vite servie par FastAPI — PAS de shell Electron en V0.1 (ADR-001 ECHOS, ARCHITECTURE ECHOS/racine, CHANGELOG, FRONTEND_VISION, ISSUES, README, ROADMAP, PRISM ; résidu Electron = contexte d'abandon uniquement) (#433)

* feat(syne): jalon ph9 — performance & scalabilité SYNE-090→093 (TickBudgetCollector budgets 7 sous-systèmes + part computation ≥30 %, CLI --benchmark cibles 50/500/1000 + checksum d'état FNV-1a, ObjectPool sur buffer de tri de perception pour réduire l'allocation GC, déterminisme conservé — checksum doré inchangé 0x27fad50065d8c4a4) ; tests +12 (ObjectPool 5, TickBudget 3, ScaleTargets 4) → 273 Core + 6 Console (#SYNE-090→093) (#434)

* docs(syne): jalon ph9 livré — PERFORMANCE.md §9 (résultats --benchmark ≥2720/1187/505 t/s, part computation 35-68%, machine de référence, convention CI planchers 120/30/20×\~7), ISSUES.md SYNE-090→093 LIVRÉ, CHANGELOG, ROADMAP racine+docs (U7/ph9), TESTING.md (+12 → 279, planchers, §5/§6) — checksum doré inchangé 0x27fad50065d8c4a4 (#435)

* feat(syne): jalon ph10 — tests & couverture SYNE-100→102 (validateur config 100%, déterminisme d'état complet) ; intégration boucle complète sans perte data; observabilité étendue ExternalEvent (#436)

* feat(echos): jalon ph7 — comparaison expérimentale ECHOS-070→072 (U7) (#438)

* feat(echos): jalon ph7 — comparaison expérimentale ECHOS-070→072 (GET /api/compare, méta-métriques reproductibilité ReproducibilityScore 1-(CognitiveDiff+SocialDiff)/2, empreinte SHA-256 canonique, exports json/csv alignés) ; tests +11 → 208, couverture 97,97%

* style(echos): lignes test_compare.py ≤ 100 caractères (flake8 echos .flake8 max-line-length=100) — CI Python verte

* docs(syne): jalon ph10 livré — SYNE-100→102 (324 tests, couverture 96,19%, baseline d'état 0x072a488aa18c05eb épinglée DETERMINISM §7), ROADMAP/TESTING/CHANGELOG/ISSUES+racine U7 (#437)

* docs(echos): jalon ph7 livré — comparaison expérimentale ECHOS-070→072 (API_REST §3.9 +registre 12 endpoints, EXPERIMENT_COMPARISON §4 implémenté, METRICS_SPEC §10, ISSUES LIVRÉ, CHANGELOG, ROADMAP, TESTING +11→208/97,97%) ; ROADMAP racine U7 complet livré (#439)

* docs(echos): correction Electron — conservé, implémentation différée post-V0.1 (#440)

Reformulation 'PAS de shell Electron' → 'shell Electron conservé, implémentation différée à un horizon ultérieur' (décision 23/09/2026 corrigée) dans ADR-001 ECHOS (décision + log correctif), ARCHITECTURE (ECHOS + racine), FRONTEND_VISION, README, ROADMAP (phase 10 'Shell Electron'), ISSUES (ECHOS-001/080 + intro), CHANGELOG (ECHOS + racine), TRANSPORT_API (PRISM). Monographie non modifiée (snapshot figé).

* feat(echos): jalon ph8 — échos-ui, les 6 Écrans (A→F) (#441)

- stack : react-router-dom (routes A→F), echarts+echarts-for-react,
  lucide-react, zustand ; Vite proxy /api+/health → :5000 (dév.) ;
  code-splitting par écran + chunks vendor echarts/react.
- src/api/ : client REST typé sur API_REST.md §3 (runs, métriques
  ?every=, export, décisions, causal-chains, croyances/relations,
  groups, phenomena, compare) ; 503/404 gérés ; controlClient =
  relais ECHOS→SYNE :5181 (jamais en direct).
- src/ws/realtime.ts : client WS :5180 (reconnexion, tick, état SYNE).
- src/store/ (zustand) : runs, KPI live, run sélectionné, état WS.
- Écrans A→F : Dashboard (KPICards+gauges+timeline+phénomènes),
  Explore (Entités/Groupes/Communications, heatmap « à venir »),
  SocialGraph (graphe force-directed /relationships + inspecteur),
  Analysis (Métriques 8 moteurs / Causale profondeur ≤12 / Comparaison
  /compare), Control (pilotage relais + calibration + runs/export WS),
  Log (console 3 niveaux + limites de validité).
- vues sans calcul de métrique ; 13 tests vitest/RTL verts
  (mock fetch+WS) ; eslint + tsc -b + build verts.
- docs ECHOS : CHANGELOG ph8 + ISSUES ECHOS-080→085 → LIVRÉ (statuts).

* docs(site): refonte GitHub Pages — landing LIVEX, thème DocFX surchargé (palette LIVEX, logo/favicon), Écrans A→F & FRONTEND_VISION publiés dans la navigation (#442)

* docs(site): refonte GitHub Pages — landing LIVEX, thème DocFX surchargé (palette LIVEX, logo/favicon), docs Écrans A→F & FRONTEND_VISION publiées dans la navigation

### Landing (index.md)
- Hero sombre  + badge « Monorepo dotnet + python + typescript »,
  tagline, description, 3 CTA (README / API REST ECHOS / Interface web pour
  echos-ui), **3 cartes modules** (SYNE sémantique — Simulation.Core ; ECHOS
  analyse ; PRISM rendu) en overlay  (HTML dans le markdown DocFX),
  bandeau « Fonctionnalités » (6 lignes : déterminisme bit-à-bit, observation
  non intrusive, 7+8 moteurs de métriques, adéquation SYNE↔ECHOS, lien
  doc principes).

### Thème DocFX — overlay
- **** : palette LIVEX () appliquée au thème
   DocFX (docfx.css Bootstrap) — variable-couples , fond
  /surface /bordure /texte /accent
  , navbar sombre, cartes , hero, badges, tableaux,
  code, footer ; police Inter + JetBrains Mono (chevauche cohérent avec
  ).
- ** + ** (overlay : remplace  DocFX par la
  marque LIVEX — 2 cercles reliés, palette ECHOS) ;  multi-taille
  généré (16/32/48/64).
- ** non requis** (le  fournit la navbar) ; overlay
  appliqué via  → .

### Navigation ()
- Section ECHOS enrichie : **FEATURE VISION orbitale & UI Désign** (les 6
  Écrans A→F) publiées dans la nav, + rubriques Métriques/API REST/Tests ;
  section Transverse inchangée (docs clés) —  étendu avec
   et  dans le tableau ECHOS.

### Build
- DocFX local :  (Simulation.Core.xml → API .NET) puis error: FatalError: System.IO.FileNotFoundException: Cannot find config file /home/devops/Documents/Code/LIVEX/docfx.json
   at Docfx.Docset.GetConfig(String configFile) in /_/src/Docfx.App/Docset.cs:line 73
   at Docfx.BuildCommand.<>c__DisplayClass0_0.<<ExecuteAsync>b__0>d.MoveNext() in /_/src/docfx/Models/BuildCommand.cs:line 25
End of stack trace from previous location ---
   at Docfx.CommandHelper.RunAsync(LogOptions options, Func`1 run) in /_/src/docfx/Models/CommandHelper.cs:line 42
   at Spectre.Console.Cli.CommandExecutor.ExecuteAsync(CommandTree leaf, CommandTree tree, CommandContext context, ITypeResolver resolver, IConfiguration configuration, CancellationToken cancellationToken) in /_/src/Spectre.Console.Cli/Internal/CommandExecutor.cs:line 257
  (0 erreur) ;  vérifiés : index hero + 3 cards, toc.html, chaîne
  bootstrap clean, favicon/logo overlay au bon chemin.

* docs(echos): FRONTEND_VISION — front-matter DocFX (title • accent paragraphe jalon ph8) ; aligne le h1 unique doc site ESLint conformité

* docs(site): refonte complète GitHub Pages en landing SaaS — landing sur mesure hors DocFX (racine), branding LIVEX (logo, favicon, palette UI_DESIGN), sections Modules/Fonctionnalités/Performances/Roadmap/FAQ, responsive + animations JS ; document DocFX DocFX sous /docs/, assemblage assemble-pages.sh + workflow assemble-pages (landing racine + docs/) (#443)

* docs(roadmap): cadrage Jalon U8 — assainissement du backlog (#444)

Plage ECHOS fictive (080…093) rectifiée en 080…085 (ph8, livrés U7) +
090…092 (ph9) ; carte manquante SYNE-113 ajoutée (serveur de contrôle
HTTP :5181, cible réelle du relais controlClient ECHOS) ; SYNE-110
précisé (hooks autoSaveEveryNTicks/maxBackups à brancher) ; ECHOS-085
annoté (livré côté UI, finalisation contre SYNE-113 en U8).

* feat(syne): jalon U8 — persistance SQLite bit-à-bit (SYNE-110→112) (#445)

- SqlitePersistenceStore : schéma V2.0 (11 tables, PRAGMA user_version=2), transactions atomiques, rotation maxBackups=5, reprise au dernier tick_states ;
- SimulationSnapshot/Codec : capture déterministe monde+cognition+PRNG 4×64 (JSON stable, hash FNV-1a) ;
- SimulationSnapshotRestorer : reprise exacte au tick N sans re-jouage, holdover LastDecision + réserves restaurées en place ;
- Hook autoSaveEveryNTicks (défaut 1000) câblé dans SimulationLoop.AdvanceOneTick — aucun tirage PRNG ⇒ checksums épinglés inchangés ;
- 5 PersistenceTests (320 Core, 329 totaux — reprise bit-à-bit, état RNG, reprise post-crash, schéma 11 tables, rotation) ;
- docs : PERSISTENCE §3 recalé (health→energy/hunger/thirst/fatigue), TESTING 324→329, CHANGELOG, ISSUES SYNE-110/112 LIVRÉ

* feat(syne): serveur de contrôle HTTP :5181 (SYNE-113) (#446)

Serveur de contrôle non intrusif du moteur SYNE, contrat API_CONTRACTS §3
(ADR-002/003) :
- SimulationFactory : résolution options (défauts → surcouche config → seed)
  + construction monde/entités/PRNG/boucle, identique au mode batch (bit-à-bit) ;
- SimulationController : machine à états idle→running⇋paused→finished, boucle
  d'arrière-plan (ManualResetEventSlim + CancellationToken par run) — 0 tirage
  PRNG ajouté ⇒ trajectoire inaltérée (SYNE-081, DETERMINISM §3) ;
- ControlServer : HttpListener BCL 127.0.0.1:5181, POST
  /api/control/start|pause|resume|reset + GET /status, erreurs JSON structurées ;
- mode CLI --serve / --serve-port (défaut 5181) ; interop vérifiée contre le
  ControlClient ECHOS (finalise ECHOS-085) ;
- 6 ControlServerWireTests (335 tests au total : 320 Core + 15 Console).

* feat(syne): cycle des ressources — minéraux + régénération/dégradation (SYNE-070) (#447)

- ResourceKind.Mineral (4e type, initial 0) + ResourceSettings enum-driven (ToStocks/Spec)
- ResourceStocks.ApplyLifecycle(tick, settings) appliqué en fin de tick par
  SimulationLoop.AdvanceOneTick (ordre causal strict, 0 tirage PRNG) : régénération
  + regenerationRate/tick, dégradation périodique -regenerationRate x degradationTick
  a chaque degradationTick (clamp >= 0, inerte sans taux)
- Persistance etendue : WorldSnapshotDto.MineralStock, codec Capture, restorer,
  SQLite WriteResources (4 types), observabilité resources[] (4 types)
- engineVersion 0.7.0 ; checksums dores (perception + baseline ph10) inchangees,
  re-epingles pour pin contractuel (DETERMINISM §7)
- Validation bornes resources.* (initial >= 0, regenerationRate >= 0, degradationTick > 0)
- Tests : ResourceStocksTests +5, SimulationOptionsValidatorTests +1,
  PersistenceTests +1 (4 reserves dont mineral perseveres, regeneration restauree),
  assertions CognitionPipeline/Observability adaptees aux bornes de regeneration
- Docs : DETERMINISM, CONFIGURATION §6.7, DATA_MODEL §8.1, SYSTEMS_SPEC §4,
  API_CONTRACTS §2.1, DECISIONS_V01 §2.4, ISSUES SYNE-070 LIVRE, TESTING (342),
  CHANGELOG (racine + SYNE), ROADMAP (racine + SYNE)

Suite totale : 342 tests (327 Core + 15 Console)

* feat(syne): constructions — obstacles statiques configurables + modification d'environnement tracée (SYNE-071) (#448)

* test(syne): jalons de validation moteur T0-T5 (SYNE-122) (#449)

T0 50 ent./1000 ticks sans crash + état valide déterministe ; T1 50/2000
croyances divergentes ; T2 traits -> décisions différentes en situation
identique (curiosité [0,0] vs [2,2], divergence portée par Explore) ;
T3 information locale (jamais hors portée) ; T4 reproductibilité
benchmark ; T5 suite > 160 tests (370). Carte purement test : 0 tirage
PRNG, engineVersion inchangé (0.8.0). MilestoneT0T5Tests (+8), suite
370 tests (353 Core + 17 Console), couverture 94.01 %.

* feat(syne): cycle de saisons world.seasons (SYNE-072) (#450)

world.seasons: ancien booléen mort -> bloc actif (enabled, seasonLengthTicks 360, initialSeason spring, cycle[] 4 saisons × facteurs/réserve). Saison = fonction pure du tick (0 tirage PRNG) ; SeasonFactors module régénération/dégradation (ResourceStocks.ApplyLifecycle, fin de tick) ; basculement tracé + drainé world.season_changed (tick exact) ; snapshot season/seasonIndex (additif) ; validation §6. engineVersion 0.9.0, checksums dorés inchangés (désactivé par défaut). +19 tests (SeasonTests, ObservabilitySeasonTests) — suite 389 (369 Core + 20 Console).

* feat(syne): territoires world.territory_membership_changed (SYNE-073) (#451)

* feat(livex): finalise le jalon U8 (#452)

* feat(livex): complete U8 milestone

* docs(livex): refresh project overview and setup guide

* fix(ci): disable full coverage on isolated U8 smoke test

* fix(echos): correction démarrage/contrôle + documentation (bundle existant) (#453)

* Refactor echos startup and control mechanisms

- Update installation and README documentation.
- Create V0.1 audit roadmap.
- Enhance API and frontend documentation.
- Improve control client and ingestion logic.
- Add new dev stack script for easier setup.
- Update tests for analysis, API routes, and control client.

* Fix startup and control issues in Echos module and update documentation

- Improve CI workflow and enhance installation instructions.
- Add new simulation configuration files and update related tests.
- Refactor Echos API and ingestion logic for better performance.
- Introduce new reporting functionality and tests for validation.
- Update various components in the Echos UI for better integration.

* fix(echos-ui): alignement des écrans sur le contrat snapshot SYNE (position imbriquée, ressources type/quantity, LiveAgent, garde anti-stale) (#454)

* feat(echos): trace parquet dans le batch, scheduler d'analyse périodique et benchmark SYNE vs SYNE+ECHOS (#455)

* fix(syne): repair test baselines and sqlite cleanup

Refresh the deterministic golden values to match the reproducible current trajectory, and release pooled SQLite connections before deleting temporary databases on Windows.

* fix(syne): normalize deterministic logs across platforms

Use explicit LF separators for hashed test logs so the pinned simulation checksums match on Windows and Linux.

* feat(syne): expose prepared world and global snapshots

Publish a versioned initial world with agents, cells, obstacles, resources, and tick rate; add the explicit prepare/ready control flow and include complete per-tick actions and world changes in the global snapshot.

* fix(echos): handle SYNE world initialization frames

Validate and ignore the world_initialized prelude while aligning tick segments so the ECHOS ingestion pipeline can connect to the updated SYNE stream.

* feat(syne-mock): simulate contracts with modular services

Split world generation, agent decisions, destination selection, movement, and snapshots into services; preserve the HTTP/WebSocket contract and add deterministic scenarios and integration tests.

* fix(git): répare la ligne .gitignore cassée et ignore les artefacts Unreal (#459)

fix(git): répare la ligne .gitignore cassée et ignore les artefacts Unreal

La ligne `*.logdocs/pages-dist/` supprimait d'un coup la règle `*.log` et
l'exclusion du site DocFX généré : les logs n'étaient plus ignorés et le build
de `docs-pages` réapparaissait dans `git status` à chaque publication.

Ajoute aussi les exclusions des répertoires produits par Unreal (`Binaries`,
`DerivedDataCache`, `Intermediate`, `Saved`, `Replays`, `StagedBuilds`, `.vs`,
solutions Visual Studio) afin que l'hôte technique `prism/LDK/` puisse être
versionné sans traîner ses ~10 Go de fichiers générés.

* feat(prism): ajoute le plugin Unreal PRISM-LDK (PrismLdk) et son hôte technique de build (#460)

feat(prism): ajoute le plugin Unreal PRISM-LDK (PrismLdk) et son hôte technique de build

Première implémentation exécutable de PRISM. Le plugin `PrismLdk` expose à
Blueprint le cycle de contrôle HTTP (5181) et la réception des contrats SYNE en
WebSocket (5180) : `Prepare`/`Ready`/`Start`/`Pause`/`Resume`/`Stop`/`Reset`,
`world_initialized`, snapshot global, deltas et événements.

SYNE reste le moteur décisionnel et l'autorité de l'état ; le C++ du plugin se
limite au transport, au parsing et à la conversion en types Blueprint.

- `prism/LDK/` : hôte technique `LDK.uproject` (Unreal 5.8), `Config/`, module
  `LDK` et assets Blueprint de test.
- `prism/LDK/Plugins/PrismLdk/` : module `PrismLdk` (Runtime, phase Default),
  `UPrismLdkSubsystem` + bibliothèque Blueprint + types de contrat.
- `EngineAssociation` positionné à `5.8` : la valeur GUID d'origine (build
  source) empêchait l'ouverture sur une installation Unreal Launcher.
- `.gitattributes` : `*.uasset`/`*.umap` déclarés binaires, une conversion de
  fin de ligne automatique corromprait ces assets ; LF garanti pour `*.sh`.
- `docs/docs-prism/PRISM_UNREAL_IMPLEMENTATION.md` : guide d'intégration.

Non validé : aucun runner Unreal 5.8 n'est disponible, la compilation du plugin
reste à confirmer sur une installation Unreal locale.

* docs(prism): acte l'adoption d'Unreal (ADR-002) et supersède l'ADR Godot (#461)

docs(prism): acte l'adoption d'Unreal (ADR-002) et supersède l'ADR Godot

L'ADR-001 (prototype Godot) était marquée « historique » sans qu'aucun ADR
successeur ne prenne le relais : le choix du moteur définitif restait donc non
tranché en gouvernance, alors même qu'un socle de code Unreal était livré
(PR #460).

- Nouvel `docs/docs-prism/adr/ADR-002-choix-unreal-prism-ldk.md` [Accepted] :
  contexte, décision, conséquences, risques, alternatives (Godot, Unity, non
  décision maintenue, ECHOS seul) et conditions de validation/réouverture.
- ADR-001 marquée [Superseded] avec renvoi vers l'ADR-002 ; l'argument « Unity
  et Unreal surdimensionnés » est explicitement rattaché au périmètre du
  prototype.
- Index ADR du composant mis à jour (nouveaux statuts par ADR).
- ADR-003 / ADR-004 : la liste des routes et des formats est désormais
  explicitement celle de la proposition d'origine de la Monographie, avec renvoi
  vers le contrat courant. ADR-004 acte la diffusion multi-consommateur.
- `ARCHITECTURE.md`, `VISION.md`, `GLOSSARY.md` : PRISM décrit comme projet
  Unreal final intégrant le plugin PRISM-LDK ; `prism/LDK/LDK.uproject`
  documenté comme hôte technique de build/test et non comme un second produit.
- `CHANGELOG.md` racine : entrée de la décision d'architecture.

* docs(prism): réécrit le dossier PRISM pour le projet Unreal et son plugin (#462)

docs(prism): réécrit le dossier PRISM pour le projet Unreal et son plugin

Le dossier `docs-prism` décrivait un prototype Godot sans rapport avec l'état
réel du dépôt. Réaligné sur l'ADR-002 et sur le code livré en PR #460.

- `README.md`, `ARCHITECTURE.md`, `VISION.md` : PRISM = projet Unreal final
  intégrant le plugin PRISM-LDK ; frontière explicite entre le plugin
  (interopérabilité Blueprint) et le projet PRISM (expérience et rendu) ; SYNE
  reste l'autorité de l'état.
- `TRANSPORT_API.md` : contrats selon l'état courant — `world_initialized`,
  snapshot global par tick, deltas/événements, cycle
  `prepare`/`ready`/`start`/`pause`/`resume`/`stop`/`reset`, 5180/5181 par
  défaut.
- `SCENE_SPEC.md`, `RENDERING_SPEC.md`, `VISUALIZATION_SPEC.md`,
  `UX_INTERACTION.md`, `ASSETS_CONVENTIONS.md` : spécifications recadrées en
  objectifs de présentation, sans prétendre que les fonctions sont livrées.
- `TESTING.md` : stratégie de validation, avec la distinction explicite entre
  contrat (testable sans moteur) et rendu (non couvert en CI, aucun runner
  Unreal).
- `ROADMAP.md` : 6 étapes d'évolution orientées intégration et validation, avec
  section de risques et réponses.
- `CHANGELOG.md` du composant : réécrit en conservant les entrées plugin
  (PR #460) et ADR-002 (PR #461) et en restaurant la table de mises à jour.
- `CHANGELOG.md` racine : entrée de la réécriture du dossier.

Vérifié : aucun lien interne mort dans `docs/docs-prism/`.

* docs(livex): réaligne la documentation transverse sur PRISM-Unreal et cadre syne-mock (#463)

docs(livex): réaligne la documentation transverse sur PRISM-Unreal et cadre syne-mock

Dernier volet documentaire de l'adoption d'Unreal (PR #461 et #462) : cohérence
transverse et honnêteté sur ce qui est réellement implémenté.

- `README.md`, `ARCHITECTURE.md`, `VISION.md`, `ROADMAP.md`, `FAQ.md`,
  `INSTALLATION.md`, `COMMUNICATION.md`, `SECURITY.md`, `CI_CD.md`,
  `CONTRIBUTING.md` : PRISM décrit comme projet Unreal final intégrant le
  plugin PRISM-LDK ; `prism/` et `syne-mock/` apparaissent dans l'arborescence ;
  `ARCHITECTURE.md` gagne une §2.4 (syne-mock) et une §6 réécrite.
- `syne-mock` cadré explicitement comme outil de développement des contrats,
  pas un moteur : README, ARCHITECTURE §2.4, CONTRIBUTING §4 (checklist
  `npm test --prefix syne-mock`), CI_CD §2 et §5, ETHICS_AND_SCOPE §4.1.
- `docs/docs-echos/{ISSUES,ROADMAP,TESTING}.md` : ECHOS-091 restreint à
  SYNE→ECHOS ; la validation PRISM-LDK et du projet Unreal relève d'un chantier
  distinct. Finit la contradiction « le runtime PRISM commence après U8 ».
- `docs/docs_prototype/README.md` : bandeau d'archive.
- `LIVEX-Monographie_SnapV0-1.md` : note de statut explicitant que la
  monographie est une référence conceptuelle historique et non prescriptive.
- `docs/README.md` (nouveau) : portail séparant références courantes et
  archives, avec la règle de préséance en cas de divergence.
- `FAQ.md` : §9 remplace « Pourquoi pas Unreal/Unity ? » par la distinction
  LIVEX/PRISM/PRISM-LDK, avec renvoi vers l'ADR-002 pour la justification ;
  §10 explique le mock ; renumérotation 1→13.
- `docs/site/index.md` : carte PRISM en « Visualisation Unreal ».
- `CHANGELOG.md` racine : entrées transverse et portail, sans écraser celles des
  PR #461 et #462.

Vérifié : aucun lien interne mort hors gabarits Liquid `{{_rel}}` de
`docs/site/index.md` (préexistants) ; les occurrences restantes de « Godot »
sont dans des archives explicitement signalées (ADR-001, `docs_prototype`,
Monographie, DECISIONS_V01 §2.28) ou dans le contexte historique de l'ADR-002.

* chore(echos): verrouille les dépendances Python (uv.lock) (#464)

chore(echos): verrouille les dépendances Python (uv.lock)

Le lockfile était présent dans le checkout mais non suivi, ce qui rendait les
résolutions locales non reproductibles alors que `echos-ui/package-lock.json`
est versionné depuis le début.

- 36 paquets épinglés avec empreintes SHA-256.
- `requires-python = ">=3.11"`, cohérent avec `pyproject.toml`.
- Le groupe de développement (flake8, pytest, pytest-cov) est verrouillé, donc
  les mêmes versions que celles qu'installe la CI via `requirements-dev.txt`.

La CI continue d'utiliser `pip install -r requirements-dev.txt` : le lockfile
sert la reproductibilité du développement local. Le passage de la CI à `uv`
est hors périmètre.

* fix(syne-mock): libère les ressources du test et aligne les assertions (#465)

fix(syne-mock): libère les ressources du test et aligne les assertions

`npm test --prefix syne-mock` ne se terminait jamais : après la fin des
assertions, 2 serveurs TCP et 3 sockets restaient ouverts, si bien que
`node --test` ne rendait jamais la main. La commande était donc inutilisable
et masquait 4 échecs réellement présents sur `develop`.

- `createServer().close()` termine les clients WebSocket connectés, purge les
  connexions HTTP en keep-alive et chaîne les rappels de fermeture, afin que
  `close()` ne promette que lorsque les sockets sont réellement libérés ;
- les tests de serveur libèrent leur instance via `t.after()` (y compris en cas
  d'échec d'assertion) et attendent la fermeture du client WebSocket ;
- les assertions d'obstacles attendent le champ `type`, que `WorldDescription`
  publie déjà.

* fix(syne-mock): pose les agents sur les cases publiées comme franchissables (#466)

fix(syne-mock): pose les agents sur les cases publiées comme franchissables

`createInitialAgents` ne validait ses positions candidates que contre les
obstacles, jamais contre le relief : un agent pouvait apparaître sur une cellule
`sea` (`walkable: false`). La fonction évaluait aussi la position brute alors
que le monde publie la position arrondie, si bien que l'arrondi pouvait faire
basculer l'agent dans une case voisine bloquée.

Deux critères de test disjoints faisaient désaccord :

- le placement utilisait `isPositionBlocked`, qui compare le point au cercle ;
- la grille publiée utilisait `isCellBlocked`, qui compare le centre de case au
  cercle augmenté de la demi-cellule.

Un agent pouvait donc être validé au placement et déclaré non franchissable par
`WorldDescription`, ce qu'exprime exactement le test
`world generation places resources and agents only on walkable cells`.

Le placement s'appuie désormais sur `cells[].walkable`, indicateur publié par
`WorldDescription` : obstacles et mer passent par la règle exposée, et aucune
divergence entre les deux n'est plus possible. `obstacles` n'est plus requis par
la fonction, et la grille de terrain n'a jamais eu besoin d'être passée.

Vérification : 300 graines x 5 densités x 2 configurations d'obstacles
(324 600 positions) : 3 452 agents sur case non franchissable avant, 0 après,
génération toujours déterministe. Test de non-régression ajouté sur 5 graines,
vérifié en échec sur l'état précédent.

* ci: exécute la suite syne-mock et publie le guide d'intégration Unreal (#467)

ci: exécute la suite syne-mock et publie le guide d'intégration Unreal

`CI_CD.md` §2 annonce un job CI `syne-mock` et `CONTRIBUTING.md` §4 rend
`npm test --prefix syne-mock` obligatoire pour toute modification du
composant. Aucun des deux n'était exécuté. Le job peut désormais l'être : la
commande se termine (PR #465) et la suite est verte (PR #466).

- `ci.yml` : `syne-mock/` rejoint la boucle de détection des composants, avec
  sortie `syne_mock` (le `-` est converti en `_`, une clé de sortie ne pouvant
  pas contenir de tiret dans une expression) ; nouveau job
  `Tests (SYNE-MOCK Node)` sur `ubuntu-latest`, `npm ci` puis `npm test`, avec
  `timeout-minutes: 5` en garde-fou contre une régression de type fuite de
  descripteurs ;
- `sync-docs.sh` : `PRISM_UNREAL_IMPLEMENTATION.md` publié dans `articles/prism/`,
  et `toc.yml` l'expose sous « Intégration Unreal (PRISM-LDK) ». Le guide
  Blueprint du plugin, référencé par `ARCHITECTURE.md`, était inaccessible sur
  le site ;
- `docs-pages.yml` : `prism/**` déclenche désormais le build du site, la
  documentation contractuelle étant écrite contre ce code ;
- `syne-mock/README.md` : la commande de test renvoie vers le job CI.

Au passage, la section `## [Unreleased]` du CHANGELOG cumulait des
sous-sections dupliquées (`### Changed` x3, `### Added` x2) et une ligne blanche
parasite ; sections regroupées et ordonnées `Added` -> `Changed` -> `Fixed` ->
`Deprecated`, et coquille « formality » corrigée en « formalise ».

Vérifié : `ci.yml`, `docs-pages.yml` et `toc.yml` parsent, `bash -n
sync-docs.sh` passe, le script publie bien le guide, et la commande exacte du
job (`node --test test/*.test.js` dans `syne-mock/`) sort en 0 avec 12 tests
verts.

* ci: declenche la CI sur les PR visant main (#468)

La CI ne se declenchait que sur develop. La protection de branche « branche a
jour + CI verte » de main ne peut donc pas etre appliquee : une PR de release
ou de hotfix n-executerait aucun check, et le merge resterait bloque sur un
status attendu qui n'arrive jamais.

`main` est ajoute aux branches de `pull_request` et de `push`, ce qui rend la
regle enforceable. Les jobs restent filtres par composant, donc une PR de
release ne construit que ce qu'elle touche.

Aucun changement de job ni de condition.

* docs(ci-cd): documente les protections de branche actives (#469)

`main` et `develop` sont desormais couverts par les rulesets `mainRules` et
`developRules`, en enforcement active. Le document annoncait « echec =
blocage (protection de branche) » sans jamais dire de quelle protection il
s'agissait, ni quels checks sont exiges.

La nouvelle section 2.1 detaille les cinq regles en vigueur, les deux checks
exiges et pourquoi les jobs par composant ne le sont pas (ils rapportent
`skipped` hors perimetre), ainsi que le retrait de `required_signatures` et sa
raison.

Consigne de maintenance ajoutee : renommer `Composants modifies` ou
`Structure & conventions (transverse)` bloque tous les merges jusqu'a mise a
jour du ruleset.

* fix(adr-001): corrige la coquille « formality » et ajoute le saut de ligne final (#470)

L'entree de CHANGELOG.md qui annoncait la correction de « qui formality ce
choix » decrivait en realite la coquille du CHANGELOG lui-meme. Le fichier ADR
vise, docs/docs-prism/adr/ADR-001-choix-godot.md, portait toujours « formality »
et n'avait jamais ete corrige.

Corrige en « formalise », et ajoute le saut de ligne final manquant sur cet ADR
et sur docs/docs-prism/adr/README.md, tous deux sans terminaison.

Detecte en comparant le stash de securite stash@{0} (wip-prism-unreal) aux
fichiers merges sur develop : le stash est un sous-ensemble strict de develop,
donc rien d'utile n'y est encore, et le rapprochement a fait ressortir la
coquille.

* fix(syne-mock): applique la carte publiee au deplacement des agents (#471)

Le deploiement deplace les agents sans jamais consulter la carte que
WorldDescription publie. Quatre defauts distincts :

- isPositionBlocked etait appele sans cellSize, donc la branche `shape`
  comparait des coordonnees NaN et laissait traverser les sept formes
  d'obstacle, alors que la version circulaire bloquait ;
- canEnter ignorait cells[].walkable, donc les agents traversaient la mer ;
- le cout de terrain etait ignore : une riviere (movementCost 4) se
  traversait a la vitesse de la plaine ;
- un deplacement refuse etait facture : l'energie baissait de
  moveEnergyCost meme quand l'agent n'avait pas bouge.

cell-grid.js centralise l'indexation de cells[] (y * cellCountX + x),
partagee par le placement et le deplacement. L'inversion x * cellCountX + y
etait auto-coherente sur une carte carree mais faisait chevaucher des cles
sur une carte rectangulaire. L'arrondi est desormais applique avant le test,
pour que la position validee soit celle que le snapshot publie.

Le cout retenu pour borner le pas est le plus eleve entre la case de depart
et la case visee : entrer dans une riviere ralentit, en sortir aussi. Une
case non franchissable donne un budget nul. Seul un mouvement effectif est
facture ; un blocage est reporte via outcome: 'blocked'.

La generation du monde est inchangee : empreintes SHA-256 identiques avant
et apres sur 5 graines x 4 configurations, dont une carte rectangulaire
300x180. movement.test.js ajoute 10 tests (12 -> 22).

* fix(syne-mock): rend le demarrage transactionnel, borne le journal et corrige l age des objectifs (#472)

Trois defauts de cycle de vie, sans rapport entre eux mais tous visibles
par un client de controle.

1. start() laissait un run actif apres un echec. `loadReplay` leve sur un
   fichier absent ou une ligne JSON malformee ; il etait appele apres
   `state = 'running'` mais avant `startTimer()`. Le resultat etait un run
   declare actif sans timer : rien ne tickait, et tout appel ulterieur a
   start() etait rejete au motif que le run etait deja actif. Le chargement
   du replay precede desormais l'entree en running, et tout ce qui le
   precede est reecritable sans consequence. Apres un echec, le monde reste
   prepare et acquitte, et un nouvel appel se comporte comme le premier.

2. `this.events` n'etait pas borne. Deux evenements par agent et par tick
   etaient conserves pendant toute la duree du run : 202 200 evenements sur
   2 000 ticks x 50 agents, heap 66 Mo. `diagnostics.maxEvents` (defaut
   2 000) borne le tampon a 2 000 evenements, soit heap 18 Mo sur le meme
   run. La troncature vide jusqu'a mi-capacite plutot que d'un seul
   element, pour ne pas decaler tout le tampon a chaque emission. Le flux
   diffuse (WebSocket) reste la source faisant autorite : ce tampon est un
   diagnostic, pas l'historique.

3. `goals[].age` valait le tick absolu. La liste etant reconstruite a chaque
   tick, `age` etait toujours egal au tick courant et ne disait rien de la
   duree d'un but. `intentionSince` suit le dernier changement d'intention
   et `age` devient le nombre de ticks ecoules depuis : 15 a 24 au tick
   2 000 d'un run de reference, au lieu de 2 000. Le marqueur reste interne,
   le snapshot publiant une liste de champs explicite.

lifecycle.test.js ajoute 8 tests (22 -> 30).

* docs(syne-mock): rectifie le contrat consomme et liste les simplifications assumees (#473)

Le contrat decrit ce que le mock publie, donc ce qu'un client PRISM ou
ECHOS branche dessus. Deux de ses affirmations etaient fausses ou
incompletes, et un consommateur pouvait s'y fier.

- Le document annoncait que le mock n'expose pas de type de terrain et que
  les cellules utilisent `terrainType: "plains"`. C'est faux : le mock publie
  trois profils, `plains` (cout 1), `river` (cout 4) et `sea`
  (`walkable: false`, cout infini), et le pas est borne par le cout de
  terrain. Le tableau des profils est ajoute, avec la regle d'entree et de
  sortie de riviere et la frontiere mer, en distinguant ce qui appartient au
  mock de ce qui appartient a SYNE.
- La liste des actions a mapper en `UENUM` n'en citait que 5 sur 9 :
  `SeekFood`, `SeekWater`, `Flee` et `Socialize` manquaient, alors que le
  contrat les publie des qu'elles se produisent. Les 9 sont listees, avec pour
  chacune sa condition de candidature et son premier tick de production,
  mesure sur la graine 42 avec 50 agents et non deduit du code. Deux
  impossibilites sont explicites : `Flee` est structurellement inatteignable,
  car `safetyDriftRate` est positif alors que `safety` demarre a sa borne
  haute et ne peut donc jamais passer sous 0.5 ; `Socialize` n'est produite
  qu'au tick 943, donc hors du `maxTicks: 400` par defaut.
- Nouvelle section « Perimetre reel et simplifications assumees » : la mort,
  la perception, le contenu des communications, la decision de groupe, les
  livres, les territoires, les ressources locales, l'echelle temporelle et le
  pathfinding sont des elements decoratifs, et `simulation.events` un tampon de
  diagnostic borne. Ces elements sont publies dans le contrat comme s'ils
  portaient du sens ; la section dit desormais ce qu'un client ne doit pas
  encore interpreter.
- Le comportement d'un `start` refuse est documente dans la section HTTP : le
  monde reste `ready` et reutilisable, donc un client peut reessayer sans
  appeler `stop`.

* feat(syne-mock): besoins de depart configurables, fini les 15 s d'Idle initial (#474)

Les agents passaient 146 ticks sans rien faire au debut d'un run. Les besoins
de depart etaient codes en dur dans createInitialAgents et curiosity partait
de 0 : il fallait que curiosityDriftRate (0.002) amène la valeur au seuil
d'exploration de 0.3, soit 150 ticks, ou 15 s a ticksPerSecond 10.

- agentSimulation.needs.initial rend les six besoins de depart configurables,
  avec les domaines qu'ils bornent deja (0..100 pour hunger/thirst/fatigue,
  0..1 pour safety/social/curiosity). Une valeur absente retombe sur l'etat
  historique du mock, une valeur hors domaine est refusee a la generation du
  monde, comme les autres cles de configuration.
- curiosity passe de 0 a 0.3 par defaut, exactement le seuil d'exploration :
  les agents se mettent en mouvement au tick 1 et plus aucun Idle n'est produit.
  Eat 100, Drink 72, Rest 234 et Socialize 943 sont inchanges.
- curiosityDriftRate passe de 0.002 a 0.001, le cout de ce decalage : explorer
  des le premier tick sature curiosity plus vite, et un besoin sature garde une
  utilite superieure a celle de Rest, qui devient alors jamais produit. Mesure
  sur 2000 ticks, 0.002 supprime Rest du flux alors que 0.001 conserve le
  repertoire complet d'actions.

Le placement des agents ne lit que la graine et la carte : les besoins de depart
decalent la trajectoire d'un agent, pas l'endroit ou il apparait. Generation du
monde byte-identique avant/apres sur 5 graines x 2 tailles dont 300x180, run
deterministe a l'identique sur 2 processus distincts.

+4 tests dans test/server.test.js, suite verte.

* fix(syne-mock): diffuser le snapshot avant les evenements du tick (#475)

Le mock emettait les evenements du tick avant son snapshot. SYNE
(ObservabilityTickEmitter) et API_CONTRACTS.md §2 imposent l'inverse, et tout
consommateur qui aligne le flux sur les ticks le refuse : ECHOS rejetait le
mock des la premiere trame avec

  TickAlignmentError: message event invalide (conforme API_CONTRACTS.md) :
  evenement decision_made recu avant le premier snapshot

step() regroupe desormais les evenements du tick, diffuse le snapshot puis
tick_summary, puis les evenements de ce tick. L'ordre des evenements entre eux
et le tampon de diagnostics sont inchanges, stepReplay() n'est pas touche, et le
contenu par tick reste identique (hash canonique inchange sur 120 ticks) :
seul l'ordonnancement change.

Verrouille par deux tests qui echouent tous deux sur l'ancien code :
- syne-mock/test/stream-order.test.js : ordre exact des trames, invariant
  d'alignement et invariance du tampon de diagnostics ;
- echos/echos/tests/test_syne_mock_integration.py : le vrai client ECHOS
  ingere le mock de bout en bout (controle HTTP, WebSocket, SQLite, Parquet,
  API REST, calibration), sans build .NET.

Le mock devient donc utilisable pour travailler sur ECHOS : pointage par
SYNE_OBSERVABILITY_URL / SYNE_CONTROL_URL, procedure documentee dans
syne-mock/README.md, limites de simulation assumees (beliefs/trust vides).
Nouveau job CI "Integration mock -> ECHOS" sur toute PR touchant syne-mock/
ou echos/, distinct du job U8 qui reste sur le moteur .NET.

* fix(echos): revue complète du composant (moteurs, provenance, API, interface) (#477)

Deux bugs rendaient des fonctions centrales inopérantes : `/api/compare`
renvoyait 500 sur tout run contenant un événement (la décompression décomptait
six colonnes pour un zip de sept), donc la comparaison de reproductibilité
était inaccessible sur tout run réel ; et `AnalyticsStore.runs()` levait
`int(None)` sur un run sans tick, ce qui rendait l'API entière inopérante sur
une base fraîche ou un run en cours d'acquisition.

Sept métriques restaient à 0 sur tout run réel parce que le snapshot ne
portait que le tick courant, jamais `history` ni `communityHistory` — la
fixture de test les fournissait artificiellement, ce qui masquait le
problème. `_RollingContext` construit et borne désormais trois fenêtres
glissantes. Le dénominateur des taux de groupe ne dépend plus de la charge
(il valait 1000 ticks sur un run calme et 20 sur un tick chargé, soit un
facteur 50 sur la même métrique) : la fenêtre est bornée en ticks et sa durée
réellement observée est publiée dans le snapshot.

Les singletons n'étaient plus comptés comme communautés, `DecisionDiversity`
était calculée sur les objectifs, `SystemComplexity` n'était pas borné,
`_availability(100, None, 0)` renvoyait 1e11 et contaminait la moyenne du
moteur de durabilité, et un cycle d'import existait entre `emergence` et le
registre des moteurs.

Ajout de la provenance `measured` : `analysis.provenance()` calcule par couple
(moteur, métrique) si la valeur servie est une mesure ou le repli neutre du
moteur faute de fenêtre, depuis les mêmes entrées que le calcul lui-même. Sans
ce signal, l'interface ne pouvait pas distinguer un `0` observé d'un repli.
Persisté par tick (`tick_metrics.measured`, schéma SQLite v5, migration
additive) et publié par `/api/runs/{id}/metrics` et `/api/runs/{id}`. Évol
adhésion MINOR : champ ajouté, aucun consommateur existant n'est cassé.

Robustesse : cadences nulles qui levaient `ZeroDivisionError` ou étaient
silencieusement ignorées, fuite de descripteurs (`EchosLogger` sans `close()`),
reconnexion toutes les 100 ms quand SYNE est arrêté, fin de flux détectée par
préfixe de libellé d'erreur, et `pyarrow` importé mais non déclaré dans
`pyproject.toml` (un `pip install echos` produisait un paquet qui ne démarrait
pas). `dev_ingest` valide désormais sa configuration avant toute I/O, avec
sortie 2 distincte.

Les identifiants de groupe (`members`, `leaderId`, entiers côté transport)
sont normalisés en chaînes, sinon ils ne pouvaient jamais être joints à
`Agent.id` — `"3" != 3`. Même normalisation pour `Territory.members` et
`Book.author_id`/`readers`.

Interface `echos-ui` : l'export « CSV » téléchargeait une enveloppe JSON
illisible par tout tableur ; `beliefs`/`relationships`/`phenomena` appelaient
l'API sans `run_id` et affichaient donc les données du run le plus récent sous
le nom du run sélectionné ; le cache de métriques ignorait la cadence dans sa
clé et fusionnait des séries d'échantillonnages différents, produisant des
`NaN` rendus comme des zéros ; le graphe social relançait une requête par
membre en série à chaque tick ; la jauge de vitesse de diffusion alertait en
rouge un monde qui propageait bien ; `disconnect()` se reconnectait 2 s plus
tard et `usePhenomena` affichait « aucun phénomène détecté » sur un échec
réseau. `npm test` lance `vitest run` : le mode interactif ne termine jamais et
accrochait la CI.

Tests : 233 → 283 (couverture 93 %, seuil 80 %), flake8 propre ; interface
18 → 61 tests sur 14 fichiers, eslint et `tsc` propres. Les deux scénarios
d'intégration (SYNE réel et syne-mock) passent et vérifient désormais la
provenance et la normalisation des groupes contre les émetteurs réels.

Rapport complet dans `echos/ECHOS-REVIEW.md`, qui arbitrage aussi les points
laissés ouverts et leurs raisons.

* chore(docs): supprime DocFX et la publication GitHub Pages (#478)

Retire docs/site/ (source DocFX), docs/landing/ (landing SaaS),
docs/pages-dist/ (artefact d'assemblage commite malgre .gitignore) et le
workflow .github/workflows/docs-pages.yml. 51 fichiers suivis supprimes.

- .gitignore : entree docs/pages-dist/ devenue inutile retiree
- CHANGELOG.md : section Removed + entrees [Unreleased] obsoletes retirees
- echos/ECHOS-REVIEW.md : la note sur docs/pages-dist/ est replacee dans
  son contexte historique

Les documents markdown ecrits a la main (docs-syne, docs-echos, docs-prism,
adr, governance) sont conserves : ce sont les sources, pas des artefacts.

* fix(syne): revue complète du moteur (déterminisme, cycle de vie, observabilité, HTTP) (#476)

Revue et refactor du moteur SYNE. Les défauts ci-dessous sont groupés par
famille. Chacun est couvert par un test vérifié détecteur : le défaut est
réintroduit temporairement dans le code, le test doit devenir rouge, puis le
correctif est restauré. Ce que je n'ai pas su reproduire est dit comme tel
plutôt que présenté comme couvert.

1. DETERMINISME

SplitMix64.Gamma/Avalanche et l'implémentation FNV-1a étaient dupliqués sur
six sites, constantes recopiées : une divergence future aurait produit deux
hachages pour la même valeur. Centralisés dans SplitMix64 et le nouveau
Fnv1a64, sans effet sur les trajectoires.

La cause unique de l'écart de trajectoire était neutralisée : la garde de
rejeu de la communication existait mais n'était jamais appliquée. Le
destinataire d'un message le relaye donc une seconde fois. CanRelay applique
désormais HasRelayed, et la file de messages devient bornée (« plus récent
gagne ») au lieu de croître sans limite.

Réépinglage selon DETERMINISM.md §7 : percepts 0x27fad50065d8c4a4 ->
0xdb57f58566418f5d, état Ph10 0x072a488aa18c05eb -> 0x88bbc67950002bab,
EngineVersion 0.11.0 -> 0.12.0.

Piège de déterminisme : la cellule de SpatialGrid était dimensionnée par
agents.perception.radius. Or QueryCircle renvoie les voisins dans l'ordre de
parcours des cellules, qui décide de l'ordre de considération des perceptions.
Régler la portée de la perception modifiait donc silencieusement l'évolution
du monde. agents.perception.spatialCellSize devient un paramètre explicite,
défaut 50 (égal au rayon par défaut : trajectoire de référence inchangée, ce
qui évite un réépinglage supplémentaire).

2. VALIDATION

Les contrôles de plage s'écrivent « value is < 0.0 or > 1.0 ». En IEEE-754
toute comparaison avec NaN est fausse : « NaN is < 0.0 or > 1.0 » vaut false,
donc un NaN franchissait la validation puis se propageait dans les distances,
l'énergie et la Barclay, corrompant le monde sans lever d'erreur. Le
validateur balaie maintenant tout le graphe d'options par réflexion, ce qui
couvre aussi les champs ajoutés ultérieurement, et tolerate les chemins en
camelCase comme le contrat de configuration.

worldCellSize et le nouveau spatialCellSize n'étaient pas validés du tout.

3. CYCLE DE VIE DU CONTRÔLEUR

La boucle de tick était lancée en « feu et forget » : la tâche n'était jamais
conservée. Un second StartAsync superimposait une deuxième boucle sur le même
monde, Stop n'annulait que la dernière CancellationTokenSource en laissant
l'ancienne boucle active, cette ancienne boucle pouvait ensuite repasser
l'état à Finished par-dessus un run plus récent, et DisposeAsync simulait
l'attente avec Task.Delay(20). La tâche est maintenant conservée, une
génération de run est vérifiée avant toute écriture d'état partagé, un second
démarrage est refusé sur run actif, et StopAsync/ResetAsync/DisposeAsync
attendent réellement la fin de boucle. ControlServer répond 200 sur stop
après l'arrêt effectif.

4. HTTP DE CONTRÔLE

RootElement était renvoyé sans Clone() ni Dispose() : propriété invalide dès
la fin de vie du JsonDocument, une fuite par requête. Aucun plafond de taille
n'existait : un Content-Length ou un transfert par blocs arbitrairement grand
était lu intégralement en mémoire (1 Mio, 413 payload_too_large, lecture bornée
pour les blocs). Un JSON malformé ou un type de configuration incompatible
remontait en 500 au lieu de 400.

5. OBSERVABILITÉ

Un WebSocket n'accepte qu'un SendAsync à la fois : deux diffusions
concurrentes levaient InvalidOperationException, non rattrapée, et tuaient le
processus. Sérialisation par client, envois bornés dans le temps, retrait des
clients dans le finally du drain (auparavant un client déconnecté restait au
dictionnaire et son socket n'était jamais fermé), fermeture réellement
attendue, Start/DisposeAsync idempotents.

L'émetteur ne faisait pas confiance au sink pour être borné : un client lent
figeait la simulation, sans plafond. La capture est sautée quand aucun client
n'est connecté, mais les tampons du tick sont toujours vidés : la couche
d'observabilité en est le seul consommateur, sans quoi ils croissent sans
borne et rejouent des événements obsolètes.

6. CONFIGURATION ET AUTRES

La fusion de configuration sparse était destructive : le corps était
désérialisé en SimulationOptions avant fusion, donc chaque clé absente
prenait la valeur par défaut du type et un client ne pouvait surcharger un
champ sans détruire silencieusement tous les autres réglages. MergeJson fusionne
récursivement, et le JSON brut est transporté jusqu'à la fusion.

ResourceStocks consommait partiellement face à un stock insuffisant ;
ActionExecutor appliquait les bénéfices avant l'échec d'une réserve ; la
grille confondait les comptes et bornes X/Y ; les IDs de naissance n'étaient
pas uniques ; les territoires n'étaient pas persistés, donc une restauration
perdait toutes les zones et réassignait « Communes » (SchemaVersion 4).
A* autorisait une diagonale alors que les deux orthogonales étaient bloquées :
le pas rase le point d'appui entre deux cellules solides. PhaseCount valait 8
pour une énumération de 7 phases. `--seed -1` produisait une trace d'appels
plutôt qu'un message.

7. LE PIÈGE QUE SEUL LE TEST D'INTÉGRATION A VU

Une première version de la validation CLI refusait « --observe-port sans
--observe ». C'est faux : en mode --serve, Program démarre l'observability sur
--observe-port, et le contrat d'intégration SYNE → ECHOS lance exactement
« --serve --serve-port P --observe-port Q ». Le job CI
syne-echos-u8-integration échouait alors sur un défaut de validation, pas de
moteur, et SYNE refusait ses arguments sans ouvrir aucun port. Une suite
unitaire entièrement verte ne prouve pas qu'un contrat transverse est préservé.

Ce que j'avais laissé passer en commit est ce piège, pas un bug du moteur : la
validation est correcte, c'est ma règle qui était fausse, parce que j'avais
supposé que le port d'observation n'avait qu'un seul mode consommateur sans
avoir vérifié qui le consommait. Corrigé, avec un test qui verrouille les deux
combinaisons. C'est aussi ce qui m'a fait suspecter un auto-blocage possible du
chemin stop (le client ECHOS appelle stop alors qu'il ne lit plus le WebSocket,
et la requête HTTP a un timeout de 2 s) : vérifié empiriquement, 5 exécutions
consécutives vertes.

132 tests ajoutés (466 -> 598) ; suite SYNE à 553 tests, verte en Release avec
--warnaserror. Trois tests détectaient d'abord le bon bug pour la mauvaise
raison et ont été réécrits ; deux correctifs sont défensifs et le disent
(disparition intra-tick de groupe, culture invariante sur drapeaux entiers) ;
aucun n'est présenté comme vérifié par mutation quand il ne l'est pas.

REVIEW-REFACTOR-REPORT.md détaille chaque point.

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481 (#495)

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs (#496)

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

* chore(echos): ingestion 0.3.0, stockage et calibrage (#497)

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

* chore(echos): ingestion 0.3.0, stockage et calibrage|Champs optionnels inventory/commitments dans les modèles d'ingestion (rétro-compat 0.2.1 conservée), routes et service UI (echos-serve), invalidation inter-processus du cache de séries via PRAGMA data_version, calibrage de fin de run et viabilité. Suite ECHOS verte, couverture 93,16 %. Closes #485

* fix(echos-ui): écrans d'analyse gelés, retard croissant et contrôles Live/Actualiser (#498)

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

* fix(syne): observabilité 0.3.0, persistance additive et cycle de vie des runs|Le serveur de contrôle expose le seed et un cycle de vie durci ; le contrat d'observabilité passe à 0.3.0 (inventory/commitments sous drapeaux, sortie identique drapeaux éteints) ; la persistance devient additive sans rompre les hash de snapshots ; pins de version re-calés (0.14.0/0.3.0). 569/569 tests verts, checksums dorés 0x46769cfb11c8b3a7 / 0xe62395429b50b7c1 inchangés. Closes #486

* chore(echos): ingestion 0.3.0, stockage et calibrage|Champs optionnels inventory/commitments dans les modèles d'ingestion (rétro-compat 0.2.1 conservée), routes et service UI (echos-serve), invalidation inter-processus du cache de séries via PRAGMA data_version, calibrage de fin de run et viabilité. Suite ECHOS verte, couverture 93,16 %. Closes #485

* fix(echos-ui): écrans d'analyse gelés, retard croissant et contrôles Live/Actualiser|Trois causes racines corrigées : cache de séries jamais invalidé entre processus (retard croissant 155→494 ticks), liste des runs chargée une seule fois (le run démarré n'apparaissait jamais), et refetch complet à chaque tick WS (tempête de requêtes). Ajout des boutons Actualiser et bascule Live/Figé. Validation réelle sur un run de 7 600 ticks : retard stable 14-35 ticks, 1 req/2 s mesurée. 62/62 tests UI. Closes #480

* feat(echos): shell de bureau Electron (ADR-003), packaging et CI (#499)

* feat(syne): implémentation des 5 ADR cognitifs acceptés|Implémente les 5 ADR acceptés du rapport éléments ouverts V0.1 : primitives atomiques Take/Give/Trade/Attack/Defend (D7), inventaire à capacité pondérée (D8), bibliothèque de plans means-end (D3), engagements communicationnels Request/Response avec confiance (D5) et politique de saillance (D2). Catalogue Agents.Actions.* à drapeaux défaut-faux : la trajectoire de référence reste bit-à-bit identique (checksums dorés intacts), engineVersion 0.14.0. 13 nouveaux tests. Closes #481

…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant