Les portées et les layers : un arbre peuplé, une descente qui n'existe pas
ouvrir la planche en plein écran → · 28 pièces · 30 traverses · 16 marges
L'emboîtement MONTE et il est vivant — 5216 lignes que j'ai reproduites moi-même, six appelants, un barreau fail-close ; il ne DESCEND sur l'arbre des portées jamais (mais il descend d'un cran sur le CADASTRE, et cette porte est montée) ; et trois mécanismes annoncés vivants sont en réalité muets : les quatre types de nœuds manquent à l'ORM autant qu'à la production (35 migrations en arrière), les trois membranes ne publient sur aucun bus, et les quatre niveaux L1–L4 n'ont plus aucun lecteur chargé.
Cette collecte n'a PAS vu la production. Aucune requête n'a été exécutée contre atom_db (hôte 138.197.132.63, conteneur compose-atom-db-1), ni aucune commande SSH : tout est lecture de fichiers au commit 8addf1c94 (branche integration/fondateur-p0), plus une reproduction Python locale sur data/countries/ (répertoire vérifié propre). Conséquences précises : (1) la révision de production v82_264_coquille_reglage et le fossé de 35 migrations reposent sur deux relevés DATÉS du 2026-09-04 et du 2026-09-07, vieux de 29 jours — le compte de 35 est confirmé par moi sur le graphe alembic, la RÉVISION ne l'est pas ; (2) les comptes de lignes que je cite — scope_membership 5216 (5215 commu / 1 civ / 0 indiv), atom_positions 4, community_relation 0, projection_nodes 0, 449 tables — viennent tous de fiches de mémoire datées, aucun n'a été re-mesuré ; le seul 5216 que j'atteste est celui de la SOURCE de données, pas celui de la base ; (3) « 3862 feuilles sur 3862 » reste non établi : il ne vit que dans un commentaire de 2026-08-09 ; (4) je n'ai pas pu vérifier si COUNTRY_SPINE_DATA_DIR ou ATOM_DATA_ROOT sont posées dans le conteneur de production, donc je ne peux pas dire si l'épine s'amorce ou échoue à chaque démarrage ; (5) je n'ai lancé AUCUN test et AUCUNE garde — rien ici n'est étiqueté « vert » ; (6) le code DÉPLOYÉ en production est plus ancien que le commit mesuré (memory/porte-connaissance-criteres-ancestraux.md:42 : « code très en retard »), donc tout raisonnement du genre « ce INSERT nomme node_kind, donc il casse en prod » est un raisonnement sur le COMMIT, pas sur le runtime, et je ne le présente pas autrement ; (7) les comptes d'appelants sont des git grep sur les deux arbres backend/app/ et les ~278 .py hors app/, plus frontend/ — ils voient les imports et les appels nommés, pas les appels par réflexion, par chaîne de caractères, ni par registre dynamique.
ne pas dessiner
| main.py:1093 (_amorcer_epine_lieu, démarrage) appelle | → | country_spine_importer.amorcer_epine_lieubackend/app/main.py:1093-1131 | |
| country_spine_importer.importer_epine:119 appelle | → | scope_membership_service.set_membershipbackend/app/services/country_spine_importer.py:118-127 | |
| set_membership:254 alimente | → | table scope_membership (+ node_kind)backend/app/services/scope_membership_service.py:254-261 | |
| person_position_membership_authority.insert_membership:641 alimente | → | table scope_membership (SANS node_kind)backend/app/services/person_position_membership_authority.py:641-652 ; table d'appui person_position_bindings absente de la production (relevé 2026-09-07) | |
| enclosure_place_membership_authority.insert:139 alimente | → | table scope_membership (SANS node_kind)0 appelant de production, 2 arbres fouillés ; backend/app/services/enclosure_place_membership_authority.py:139-157 | |
| table scope_membership contient | → | models/scope_membership_contract.ScopeMembershipRecordbackend/app/models/scope_membership_contract.py:24-48 — node_kind non mappé | |
| routers/fractale_communautaire.py (monté main.py:2007) appelle | → | resolve_ancestors / resolve_chainbackend/app/routers/fractale_communautaire.py:210-211, :296, :353 | |
| routers/babel/fractal_websocket_router.py (monté main.py:2001) appelle | → | resolve_ancestorsbackend/app/routers/babel/fractal_websocket_router.py:107 | |
| routers/canon_coherence_router.py:214 (monté main.py:2408) autorise | → | cran_suivant (le barreau)backend/app/routers/canon_coherence_router.py:214-270 — 4 états → 503/403/403/409 | |
| cran_suivant autorise | → | les humains, en production0 ligne de portée indiv en base (country_spine_importer n'écrit que civ+commu ; l'écrivain des personnes est sans table) → APPARTENANCE_ABSENTE → 403 membership_not_registered sur toute communauté | |
| projection_scope_context_service.read:61 et :75 appelle | → | resolve_ancestors_strict + relation_service.memberships_of_strictbackend/app/services/projection_scope_context_service.py:61, :75 — l'arbre répond, la maille est vide | |
| relation_service.add_relation alimente | → | table community_relationbackend/app/services/relation_service.py:132 — 0 appelant de production, 2 arbres fouillés | |
| routers/world_canon.py:1112 (monté main.py:2494) appelle | → | chemin_cadastre_service.enfants_de (DESCENTE, 1 cran)backend/app/routers/world_canon.py:1112-1133 — descend projection_nodes, pas scope_membership | |
| scope_membership_service.resolve_descendants appelle | → | n'importe quel appelantmur écrit backend/app/routers/world_canon.py:1107-1108 ; 0 appelant, 2 arbres fouillés | |
| main.py:853 (bio_tick_worker.start) appelle | → | fractal_bio_tick_worker → queue_upward_propagation → membrane Bbackend/app/main.py:853 ; backend/app/services/babel/fractal_bio_tick_worker.py:448, :378 | |
| fractal_bio_tick_worker traverse | → | le bus (émission de la montée)backend/app/main.py:856-860 — démarré SANS bus, motif fractal_causal_clock_unassigned ; et main.py:844-847 — antenne non abonnée, motif antenna_persistence_unavailable | |
| conduit_membranes.declarer (B et C) traverse | → | les 3 topics membrane.*.franchiebackend/app/core/conduit_membranes.py:138-140 déclare les topics ; declarer() rend un objet, le payload est inséré dans un dict de retour (fractal_pipeline.py:426, membrane_service.py:208) et jamais publié | |
| frontend/js/airway-conduction.js (membrane A, chargée governance-init.js:759) appelle | → | conduit_membranes.declarerbackend/app/core/conduit_membranes.py:108 désigne un organe JS pour une fonction Python — le trait est impossible par construction | |
| meshmap.html:15 / design-center.html:27 appelle | → | frontend/js/atom-meshmap.jsbalises <script defer> directes ; absent de GOVERNANCE_CONFIG.scripts | |
| governance-init.js TIER3_PATTERNS:1320 contient | → | '/js/atom-meshmap.js'frontend/js/governance-init.js:1320 — le motif de tier existe, le script n'est pas dans le tableau chargé | |
| atom-meshmap.js:1838 autorise | → | les 4 clés canoniques (node_id, world_id, point0_ref, fractal_address)frontend/js/atom-meshmap.js:1838-1845 — fail-close avec 3 refus nommés | |
| 911 modules frontend (MALLEABILITY_CONTRACT.level) alimente | → | boot-optimizer.js:195 (le seul lecteur)boot-optimizer.js n'est chargé par aucune page vivante : 0 occurrence dans governance-init.js, 1 seule balise dans frontend/archives/orphan-pages/test-v3-modules.html:142 | |
| 5 modules frontend alimente | → | MALLEABILITY_CONTRACT.level = … || 'L2'atom-mapping-engine.js:1063, donut-radar.js:829, i18n.js:717, narrative-notes.js:537, zama-engine.js:759 — la valeur est FABRIQUÉE quand elle manque | |
| routers/trinity_geo_router.py:167, :262 (monté main.py:2303) alimente | → | position_registry.enregistrer → atom_positionsbackend/app/services/position_registry.py:161-167 (INSERT … ON CONFLICT) | |
| tout chemin de NAISSANCE alimente | → | atom_positionsles 2 seuls écrivains sont des routes HTTP de géolocalisation ; aucune inscription n'y écrit — d'où 4 lignes qui sont des sondes de test (fiche datée, non re-vérifiée) | |
| world_blueprints contient | → | world_blueprints (parenté entre QG)backend/alembic/versions/v82_057_world_canon_projection_contract.py:32-48 — aucune colonne de parenté | |
| WorldBlueprintPositionAuthority (les 7 mondes) appelle | → | n'importe quel appelantbackend/app/services/world_blueprint_position_authority.py:5 — « deliberately no HTTP route » ; 0 appelant, 2 arbres fouillés ; sa table v82_297 postérieure à la production | |
| mcp_server.py:685 (handler monté main.py:2573) appelle | → | mcp_carte_tools.resolve_position → point0_debackend/app/services/mcp_carte_tools.py:194, :428 ; backend/app/services/fractal_position_resolver.py:548 | |
| point0_ref autorise | → | n'importe quelle décision de lecture0 WHERE / filter / GROUP BY sur point0_ref dans les deux arbres, hors les 2 UPDATE de remplissage de v82_057 (:168, :326) | |
| commit 8addf1c94 (tête v82_299) alimente | → | production atom_db (v82_264)35 migrations non appliquées — compte confirmé par marche du graphe alembic depuis v82_264 ; relevé de production datant du 2026-09-04/09-07 |
| 1 | scope_membership — la table de contenance durable (l'ARBRE)v82_253 est antérieure à la révision de production mesurée v82_264_coquille_reglage → la table EXISTE en production. Règle : marche du graphe alembic (304 révisions lues, 1 seule tête réelle = v82_299 après résolution de la fusion v82_259)backend/alembic/versions/v82_253_scope_membership_contract.py (DDL) ; backend/app/models/scope_membership_contract.py:24-48 (ORM) ; clé composite (entity_id, tree_scope) :42-47 · confirmé dans le code | |
| 2 | La racine unique civ:atom — parent NULL1 racine, 0 orphelin, 0 auto-parent — reproduit par moi sur les 5216 enregistrementsbackend/app/services/country_spine_importer.py:28 (CIV_ROOT = 'civ:atom') et :64 (add(CIV_ROOT, 'civ', None, node_kind=None)) ; contrôle d'intégrité :89-108 exige racines == [CIV_ROOT] · confirmé dans le code | |
| 3 | set_membership — l'écrivain canonique, celui qui porte node_kind1 appelant de production, 2 arbres fouillés (backend/app/ et les 278 .py hors app/) : git grep 'set_membership' hors tests → country_spine_importer uniquementbackend/app/services/scope_membership_service.py:219-281 ; appelé en production par backend/app/services/country_spine_importer.py:119-127, lui-même lancé au démarrage depuis backend/app/main.py:1093-1131 (tâche de fond _amorcer_epine_lieu) · confirmé dans le code | |
| 4 | LA MONTÉE — resolve_ancestors sur un CTE récursif6 appelants de resolve_ancestors + 1 de resolve_ancestors_strict, 2 arbres fouillés. Garde anti-runaway _MAX_DEPTH = 64 (:53), levée au-delà (:389-397)backend/app/services/scope_membership_service.py:57-118 (_SQL_ANCESTORS, WITH RECURSIVE) et :424-461 ; 6 appelants de production — backend/app/routers/fractale_communautaire.py:210, :296, :353 (routeur monté main.py:2007), backend/app/routers/babel/fractal_websocket_router.py:107 (monté main.py:2001), backend/app/services/fractal_scope_guard.py:103, backend/app/services/relation_mutuelle_service.py:202 ; + resolve_ancestors_strict depuis backend/app/services/projection_scope_context_service.py:61 · confirmé dans le code | |
| 5 | LE BARREAU — cran_suivant, et son énum qui ne confond pas racine, absence et panne1 appelant de production, 2 arbres fouillés. 4 états fermés, chacun mappé sur un code HTTP distinct (503 / 403 membership_root_has_no_container / 403 membership_not_registered / 409)backend/app/services/scope_membership_service.py:124-131 (CranSuivantEtat : PARENT_TROUVE · RACINE · APPARTENANCE_ABSENTE · LECTURE_DEGRADEE) + :134-150 (CranSuivantResultat, __post_init__ qui lève 'cran_suivant_resultat_incoherent') + :493-520 ; appelé par backend/app/routers/canon_coherence_router.py:214, routeur monté backend/app/main.py:2408 · confirmé dans le code | |
| 6 | THE_POINT_0 — la constante gravée dans le schémav82_057 est très antérieure à la production v82_264 → le DEFAULT est appliqué en base. 2 tables portent la colonne, 0 clé étrangère vers quoi que ce soitbackend/alembic/versions/v82_057_world_canon_projection_contract.py:37 (world_blueprints.point0_ref TEXT NOT NULL DEFAULT 'THE_POINT_0') et :64 (projection_nodes idem) ; ORM backend/app/models/world_canon_projection.py:26 et :58 ; défaut Pydantic backend/app/routers/world_canon.py:63 et :87 · confirmé dans le code | |
| 7 | Les 3 portées — énum fermée, SEPT représentations (pas cinq), et personne qui les réconcilie7 représentations indépendantes des 3 portées, mesurées au commit 8addf1c94 par git grep sur les deux arbres backend/ + hf-atom-tools/ ; règle = toute définition qui ÉNUMÈRE ou CONTRAINT indiv/commu/civ, une par site de définition (pas les usages)hf-atom-tools/atom_canon/primitives/trinity_scope.py:29-34 (ScopeTrinity) + backend/app/services/scope_membership_service.py:40-45 (_VALID_SCOPES, repli littéral) + backend/alembic/versions/v82_253_scope_membership_contract.py (tree_scope TEXT) + v82_057_world_canon_projection_contract.py:65 et :114 (scope_trinity JSONB, DEUX défauts différents) + backend/app/api/routes/atom_mapping_routes.py:172 (Literal) + backend/app/routers/world_canon.py:88 et :131 (Pydantic default_factory) + v82_260_atom_positions.py:57 (scope String(20), nullable, AUCUN CHECK) · confirmé dans le codeL'autorité centrale n'est lue par aucune des six autres : ScopeTrinity est importée UNE seule fois (scope_membership_service.py:40) et sous try/except, donc le repli littéral est le chemin réel si le paquet n'est pas sur le path. `atom_positions.scope` n'a aucun CHECK — cette colonne accepte n'importe quelle chaîne de 20 caractères. | |
| 8 | tree_scope — 3 portées déclarées, 2 peuplées, indiv à ZÉRO5216 total = 5215 commu + 1 civ + 0 indiv. Règle : reproduction en Python de extraire_epine() sur data/countries/{profiles,admin_divisions,major_cities}.json, dédup par entity_id, à l'arbre de travail PROPRE (identique au commit pour ce répertoire)backend/app/services/country_spine_importer.py:64-86 (seuls 'civ' et 'commu' sont écrits) ; reproduction indépendante sur data/countries/ (répertoire propre : git status --short data/countries → 0 fichier modifié) · confirmé dans le codeL'écrivain des personnes. La portée indiv ne peut être peuplée que par person_position_membership_authority.insert_membership — et sa table d'appui person_position_bindings (v82_291) est postérieure à la production (v82_264) et mesurée ABSENTE de la base le 2026-09-07. | |
| 9 | node_kind — les 4 types de nœuds (individu/lieu/agent/communauté)1 écrivain sur 3 porte node_kind. Les deux autres l'OMETTENT du INSERT : person_position_membership_authority.py:641-652 et enclosure_place_membership_authority.py:139-157. Règle : git grep 'INSERT INTO scope_membership' sur les deux arbres, hors tests → 3 sitesbackend/alembic/versions/v82_299_scope_membership_node_kind.py:24-33 (colonne + CHECK + index) ; backend/app/services/scope_membership_service.py:51 (NODE_KINDS frozenset) et :254-261 (le seul INSERT qui nomme la colonne) · confirmé dans le codeDeux maillons, pas un. (1) Les deux autres écrivains n'écrivent jamais le type : toute PERSONNE et tout LIEU qu'ils inscrivent arrive avec node_kind NULL. (2) 'agent' et 'communaute' sont dans l'énum NODE_KINDS et dans le CHECK, et AUCUN écrivain du dépôt ne les produit — seuls 'lieu' (×5215) et NULL (×1, la racine) sont écrits. | |
| 10 | ⚑ L'ÉCRIVAIN CANONIQUE TROUVE SES DONNÉES PAR COMPTAGE DE PARENTS — le patron que data_root.py a été écrit pour abolir0 import de app.core.data_root dans country_spine_importer.py (git grep → aucun). 1 échappatoire : la variable COUNTRY_SPINE_DATA_DIR (:37)backend/app/services/country_spine_importer.py:35 — `_ROOT = Path(__file__).resolve().parents[3]` ; l'organe de remplacement existe et n'est PAS utilisé ici : backend/app/core/data_root.py:1-28 (« on ne devine pas la racine en comptant des parents. On la CHERCHE ») · confirmé dans le codeL'appel à data_path(). Dans le conteneur, `COPY backend /app` supprime un niveau : parents[3] résout sur `/`, donc `/data/countries`. Sans COUNTRY_SPINE_DATA_DIR posée, extraire_epine() lève FileNotFoundError et main.py:1137 écrit country_spine_health = unhealthy. Je n'ai PAS pu vérifier si la variable est posée en production. | |
| 11 | person_position_membership_authority — l'écrivain des PERSONNES, qui contourne node_kind6 appelants de production, 2 arbres fouillés ; 0 des 6 ne porte node_kindbackend/app/services/person_position_membership_authority.py:637-652 (insert_membership, INSERT sans node_kind) ; 6 appelants de production : backend/app/api/v1/routes/auth_routes.py:44, backend/app/services/auth/auth_service.py:58, backend/app/routers/fractale_communautaire.py:155-161, backend/app/routers/canon_coherence_router.py:167-173, backend/app/routers/babel/fractal_websocket_router.py:99-103, backend/app/services/fractal_scope_guard.py:81-82 · confirmé dans le codeSa table d'appui. v82_291_person_position_membership_authority est POSTÉRIEURE à la révision de production v82_264, et person_position_bindings a été cherchée sur pg_class × pg_namespace, tous schémas, et déclarée ABSENTE de atom_db le 2026-09-07 (memory/sch0-trois-schemas-qui-divergent.md:160-166). Cet écrivain ne peut pas fonctionner en production aujourd'hui. | |
| 12 | LES TROIS MEMBRANES — A ingestion · B montée · C lecture2 membranes sur 3 déclarent. 0 publieur pour les 3 topics déclarés (conduit_membranes.py:138-140) : git grep 'membrane.a.ingestion.franchie|membrane.b.montee.franchie|membrane.c.lecture.franchie' sur backend/ + frontend/ hors tests → 3 occurrences, toutes dans le fichier de déclarationbackend/app/core/conduit_membranes.py:83-110 (les trois noms, leurs directions, leurs questions, leurs organes) ; appels à declarer() : backend/app/services/babel/fractal_pipeline.py:412-417 (B) et backend/app/services/membrane_service.py:200-202 (C) · confirmé dans le codeDeux maillons. (1) La membrane A ne déclare jamais : son organe désigné est frontend/js/airway-conduction.js (:108), un fichier JS — il ne peut pas appeler la fonction Python declarer(). (2) declarer() ne publie RIEN : elle rend un objet Franchissement (:234-242) dont .payload() est inséré dans un dict de retour (fractal_pipeline.py:426, membrane_service.py:208) et jamais mis sur un bus. Les trois topics nommés n'ont aucun émetteur. | |
| 13 | LA DESCENTE — elle existe, d'un cran, et PAS sur l'arbre des portées1 porte de descente montée, 1 seul cran par appel (le commentaire :1105-1108 le pose comme interdit : « UN SEUL NIVEAU, jamais le sous-arbre »)backend/app/routers/world_canon.py:1098-1133 — route GET /world/{world_id}/children, authentifiée (Depends(get_current_user)), appelant chemin_cadastre_service.enfants_de ; routeur monté backend/app/main.py:2494 · confirmé dans le code⚑ CORRECTION DE LA COLLECTE PRÉCÉDENTE, qui annonçait la descente ABSENTE. Elle n'est pas absente : elle est sur un AUTRE ARBRE. Elle descend projection_nodes (le cadastre world-canon), jamais scope_membership (l'arbre des portées). Le maillon manquant est donc précis : aucune descente de PORTÉE, et la table que cette porte lit est mesurée à 0 ligne dans atom_db (docstring world_canon.py:744, mesure 2026-08-15 — chiffre NON re-vérifié par moi). | |
| 14 | resolve_descendants — bâti, cycle-safe, et MURÉ PAR DÉCISION ÉCRITE0 appelant de production. Règle : git grep 'resolve_descendants' sur les deux arbres backend/, hors tests → 1 occurrence, et c'est le COMMENTAIRE du murbackend/app/services/scope_membership_service.py:565-578 ; le mur est écrit en clair dans backend/app/routers/world_canon.py:1107-1108 : « Le service porte déjà resolve_descendants récursif, sans appelant de production : il le reste » · confirmé dans le codeRien à construire : c'est un arbitrage assumé, pas un trou. Le mur a une raison nommée — « une descente récursive contournerait la Porte de la Connaissance par le VOLUME ». | |
| 15 | LA MONTÉE DE MATIÈRE — câblée, battante, et fermée par DEUX NON-ABONNEMENTS (pas par deux False)Seuil de la membrane : MEMBRANE_MIN_RECURRENCE = 3 (fractal_pipeline.py:78). 2 non-abonnements délibérés au démarragebackend/app/services/babel/fractal_pipeline.py:366-430 (evaluate_upward_propagation, membrane B) + :469-516 (queue_upward_propagation) + :695 (drain_and_materialize) ; appelés par backend/app/services/babel/fractal_bio_tick_worker.py:448 et :378 ; worker démarré backend/app/main.py:853 (await bio_tick_worker.start()) · confirmé dans le code⚑ CORRECTION : la collecte annonçait « fermée par deux False en dur ». Les deux False sont à fractal_pipeline.py:508-509, DANS un `except asyncio.QueueFull` — c'est un refus honnête sur file pleine, pas un mur. Les vraies fermetures sont deux non-abonnements écrits au démarrage : backend/app/main.py:844-847 (l'antenne n'est PAS abonnée, motif antenna_persistence_unavailable) et main.py:856-860 (le worker est démarré SANS bus, motif fractal_causal_clock_unassigned — « il continue son travail local SANS émission »). La matière monte dans des caches ; rien n'en sort sur le bus. | |
| 16 | atom_positions — la jointure (world × identité), et elle A un producteur monté4 lignes en production, « et les quatre sont des sondes de test » — chiffre repris de memory/contrat-habitabilite-lieu-pilote.md:23, DATÉ et NON re-vérifié par moi (il exigerait une requête sur atom_db). 2 routes écrivent ; v82_260 < v82_264 → la table existe en productionbackend/alembic/versions/v82_260_atom_positions.py:51-82 (DDL, index ix_atom_positions_identite / _world / _world_identite) ; écrivain backend/app/services/position_registry.py:161-167 (INSERT … ON CONFLICT) ; appelé par backend/app/routers/trinity_geo_router.py:167 (enregistrer) et :262 (enregistrer_ancrage), routeur monté backend/app/main.py:2303 · non confirmé dans le code⚑ CORRECTION : la collecte disait « aucun CORPS ». Le producteur existe et sa route est montée. Le maillon manquant est ailleurs : AUCUN chemin de naissance n'écrit atom_positions — les deux seuls écrivains sont des routes HTTP de géolocalisation appelées à la main, d'où des lignes qui sont des sondes. La colonne `scope` (:62) n'a aucun CHECK, et `identite` est nullable (:59). | |
| 17 | point0_de() — le point 0 par observateur existe, comme fonction pure, et il est atteignable1 appelant direct, 2 arbres fouillés ; la chaîne jusqu'à une surface montée fait 4 maillons et ils sont tous présentsbackend/app/services/fractal_position_resolver.py:111-155 (dérivation déterministe, préfixe 'p0:') ; 1 appelant de production : _lecture() au même fichier :548 ; _lecture est atteint via resolve_position, appelé par backend/app/services/mcp_carte_tools.py:194 et :428, dispatché par backend/app/services/mcp_server.py:680-685, handler HTTP monté backend/app/main.py:2573-2575 · confirmé dans le codeLe point 0 par observateur ne vit que dans un champ de RÉPONSE. point0_de() n'écrit nulle part, ne filtre rien, et n'est atteignable que par la surface MCP — jamais par une route /api/v2 du produit. La docstring l'assume : « AUCUNE TABLE N'EST REQUISE » (:147). | |
| 18 | LA MAILLE (fréquentation N:N) — fail-close bâti, zéro écrivain, zéro ligne0 appelant de production pour add_relation (git grep sur les deux arbres backend/, hors tests → seul relation_service.py). 2 lecteurs. v82_254 < v82_264 → la table existe en production, et une fiche datée la donne à 0 ligne (memory/conseil-9-respiration-trois-axes.md:24, non re-vérifiée par moi)backend/alembic/versions/v82_254_community_relation.py (table community_relation) ; backend/app/services/relation_service.py:78-150 (add_relation, INSERT :132) ; lecteurs : backend/app/services/projection_scope_context_service.py:36 et backend/app/services/relation_mutuelle_service.py:214 · confirmé dans le codeL'écrivain. Rien dans le dépôt n'appelle add_relation : la maille a sa table, son refus nommé et deux lecteurs, et aucune arête ne peut y naître. relation_service.py:102 renvoie même explicitement 'abrite' vers scope_membership — l'arbre et la maille sont bien séparés, mais seul l'arbre a un écrivain. | |
| 19 | LA FENÊTRE MESHMAP — chargée par deux pages SEULEMENT, pas par le chargeur2 pages la chargent. 0 entrée dans GOVERNANCE_CONFIG.scripts : git grep 'atom-meshmap' -- frontend/js/governance-init.js → 1 seule occurrence, ligne 1320, et c'est TIER3_PATTERNS — une règle de tier qui ne correspond à aucun script du tableaufrontend/js/atom-meshmap.js (2051 lignes) ; chargée par balise directe : frontend/meshmap.html:15 et frontend/design-center.html:27 ; fail-close 4 clés : atom-meshmap.js:1838-1841 (node_id, world_id, point0_ref, fractal_address) + refus nommés 'missing_canonical_projection_identity' (:1830), 'incomplete_canonical_node' (:1842), 'duplicate_canonical_node' (:1844) · confirmé dans le codeDeux maillons. (1) Le motif de tier existe sans le script : la règle CLAUDE.md (« ajouter aux DEUX tableaux ») est violée dans le sens inverse de l'habituel — le tier est là, le chargement non. (2) Sa source est projection_nodes, mesurée à 0 ligne en base : le fail-close est réel et il garde une fenêtre sur du vide. | |
| 20 | scope_trinity — la deuxième représentation des 3 portées, et elle a DEUX défauts différents2 défauts distincts, pas un. 0 garde : aucun `if` de backend/app/ ni de frontend/js/ (hors tests) ne lit scope_trinity pour REFUSER quoi que ce soit — la seule exploitation est backend/app/services/babel/temple_canonical_extractor.py:783-787, qui le réduit à une portée dominantebackend/alembic/versions/v82_057_world_canon_projection_contract.py:65 — projection_nodes.scope_trinity JSONB NOT NULL DEFAULT '["indiv","commu","civ"]' ; :114 — projection_zones.scope_trinity JSONB NOT NULL DEFAULT '["commu","civ"]' ; ORM backend/app/models/world_canon_projection.py:59 et :139 · confirmé dans le codeLe lecteur décisionnaire. Le champ est écrit par défaut, transporté (threads.py:489-499, world_canon.py:448), re-sérialisé, et n'ouvre ni ne ferme rien. ⚑ Précision contre la collecte : le défaut n'est pas « toutes » partout — un NŒUD naît avec les trois portées, une ZONE naît sans indiv. | |
| 21 | ⚑ LE FOSSÉ COMMIT ↔ PRODUCTION — 35 migrations, et la révision de production n'est pas celle de CLAUDE.md35 migrations de retard — COMPTE CONFIRMÉ par moi : marche du graphe alembic (304 révisions, fusion v82_259 résolue, une seule tête réelle v82_299) depuis v82_264 → 35 révisions. ⚠ Depuis le v82_260 qu'annonce CLAUDE.md, le même calcul rend 39 : le chiffre 35 n'est juste QUE sous la révision v82_264, et la phrase doit le direRévision de production mesurée v82_264_coquille_reglage — memory/api-est-superutilisateur-rls-inerte.md:25 (relevé 2026-09-04, hôte 138.197.132.63, conteneur compose-atom-db-1, base atom_db, rôle atom_user) et confirmée memory/sch0-trois-schemas-qui-divergent.md:166 (2026-09-07). Tête du dépôt : backend/alembic/versions/v82_299_scope_membership_node_kind.py · confirmé dans le codeCe que ce fossé emporte, nommément : v82_299 (node_kind) → les 4 types de nœuds n'existent pas en base ; v82_291 (person_position_bindings) → l'écrivain des personnes est sans table ; v82_281/283/289 (chaîne enclosure) ; v82_293 (armure_owner_observation) ; v82_297 (world_blueprint_position_bindings). ⚠ Et je n'ai PAS vérifié la révision moi-même : le dernier relevé a 29 jours. | |
| 22 | ⚑ L'ORM ET LE SCHÉMA NE DÉCRIVENT PAS LA MÊME TABLE — node_kind manque au mapping0 attribut node_kind sur ScopeMembershipRecord ; 3/3 écrivains passent par du SQL brut (text()), aucun n'utilise l'ORMbackend/app/models/scope_membership_contract.py:24-48 — sept colonnes mappées (id, entity_id, tree_scope, parent_entity_id, meta, created_at, updated_at), AUCUN node_kind ; la colonne est créée par backend/alembic/versions/v82_299_scope_membership_node_kind.py:24 · confirmé dans le codeLe mapping ORM. Toute lecture ORM de scope_membership est aveugle au type de nœud que Jonathan a tranché le 2026-10-01. C'est un cas SCH-0 neuf, non listé par la collecte précédente. | |
| 23 | enclosure_place_membership_authority — troisième écrivain, sans aucun appelant0 appelant de production. Règle : git grep 'EnclosurePlaceMembershipAuthority|enclosure_place_membership_authority' sur TOUT le dépôt → 10 occurrences dans backend/tests/unit/test_enclosure_place_membership_authority.py, 6 dans docs/, 0 ailleurs. Les deux arbres backend/ fouillésbackend/app/services/enclosure_place_membership_authority.py:139-157 (insert, sans node_kind) · confirmé dans le code | |
| 24 | LES 7 LAYERS/MONDES — énumération fermée, et l'organe qui la tient n'a aucun appelant7 mondes exactement (recompté sur le frozenset). 0 appelant de production pour WorldBlueprintPositionAuthority : git grep sur TOUT le dépôt hors tests/docs/leaves → 0. Le docstring l'assume : « There is deliberately no HTTP route or memory fallback here » (:5)backend/app/services/world_blueprint_position_authority.py:25-27 — frozenset({'terre','terre-jumelle','mirror-earth','qg','corpus','code','agents'}) ; table v82_297_world_blueprint_position_binding.py:19 · confirmé dans le code⚑ DÉGRADÉ de PARTIEL à ABSENT. L'énum des 7 est juste, mais l'autorité qui la ferme n'est appelée par personne et ne porte aucune route : c'est une surface sans producteur. De plus v82_297 est postérieure à la production v82_264 → la table n'existe pas en base. Et le dépôt porte un TROISIÈME vocabulaire de 'mondes', à 3 valeurs et sans rapport : VALID_MONDES = {mon_monde, notre_monde, le_monde} dans backend/app/routers/geo.py:70, membrane.py:49 et stigmergy.py:46. | |
| 25 | ⚑ point0_ref N'EST JAMAIS UN FILTRE — re-vérifié sur les deux arbres0 WHERE, 0 filter_by, 0 GROUP BY, 0 jointure sur point0_ref dans backend/app/ comme dans les 278 .py hors app/ ; la colonne est écrite (world_canon.py:700, :855, :1007), transportée (:424, :447) et jamais interrogéegit grep 'point0_ref' sur tout le dépôt, filtré sur where/filter/GROUP BY/comparaison : les SEULES occurrences sont les deux UPDATE de remplissage de la migration elle-même, backend/alembic/versions/v82_057_world_canon_projection_contract.py:168 et :326 · confirmé dans le code | |
| 26 | L'EMBOÎTEMENT ENTRE QG — pas de colonne, donc pas de trait0 colonne de parenté entre mondes (ni parent_world_id, ni parent_node_id à ce niveau). Et projection_edges porte un world_id UNIQUE, ce qui rend toute arête intra-monde par constructionbackend/alembic/versions/v82_057_world_canon_projection_contract.py:32-48 — le DDL complet de world_blueprints : id, world_id, name, world_type, point0_ref, root_fractal_address, civilization_theme, geometry_seed, style_bible, meta, status, created_by, created_at, updated_at · confirmé dans le codeLa seule table de liaison qui existe (v82_297_world_blueprint_position_bindings) relie un QG à une PORTÉE-MONDE, jamais un QG à un autre QG — et son autorité a zéro appelant. | |
| 27 | LES 4 NIVEAUX L1–L4 — 911 modules déclarent, et le SEUL lecteur n'est chargé par aucune page vivante1073 fichiers de frontend/js (hors __tests__) portent un MALLEABILITY_CONTRACT, dont 911 déclarent un level L0–L4 ; 1032 occurrences de `level: 'L0..L4'` dans frontend/js hors tests. Règle : git ls-files frontend/js, extension .js, exclusion de __tests__, regex `level\s*:\s*['"]L[0-4]['"]`. ⚑ Le chiffre 1824 annoncé par la collecte n'est pas reproductible sur cette règle (2029 en comptant TOUT le dépôt, y compris leaves/ et leaf-flows/, qui ne sont pas des modules)Lecteur unique : frontend/js/boot-optimizer.js:195-197 (`if (mod.MALLEABILITY_CONTRACT && mod.MALLEABILITY_CONTRACT.level) level = …`, défaut 'L4' :194). Chargement : ABSENT de frontend/js/governance-init.js (0 occurrence de 'boot-optimizer') ; seule balise script du dépôt = frontend/archives/orphan-pages/test-v3-modules.html:142. Son propre catalogue le dit : frontend/js/CATALOGUE-MODULES-JS.md:182 « boot-optimizer (DORMANT) émet dans le vide » · confirmé dans le code⚑ DÉGRADÉ de PARTIEL à ABSENT. « Un seul lecteur » est exact — et ce lecteur n'est chargé sur aucune page vivante : zéro lecteur au runtime. Pire, CINQ modules fabriquent la valeur quand elle manque : `ref.MALLEABILITY_CONTRACT.level = … || 'L2'` à frontend/js/atom-mapping-engine.js:1063, donut-radar.js:829, i18n.js:717, narrative-notes.js:537, zama-engine.js:759. Le niveau n'est donc pas une mesure là où il est absent : il est inventé à L2, et personne ne le lit. | |
| 28 | ⚑ LE COMPTE « 3862 feuilles sur 3862 » — NON REPRODUCTIBLE aujourd'huibackend/app/services/fractal_position_resolver.py:99-104 — le chiffre ne vit QUE dans un commentaire (« Mesuré le 2026-08-09 ») ; repris dans docs/coordination/VERDICT-ORDRE-DES-TRAVAUX-2026-08-09.md:1753 · non confirmé dans le codeCe qui manque pour l'établir : une requête `SELECT point0_ref, count(*) FROM projection_nodes GROUP BY 1` contre atom_db sur 138.197.132.63 — et la phrase devra NOMMER l'hôte et la base. Le même verdict de 2026-08-09 rend par ailleurs projection_nodes à 0 ligne, ce qui rend le dénominateur 3862 lui-même douteux. |
On ne remplace pas le nom canon, on le double : le terme reste l’autorité, la glose est une poignée. Le lexique entier est sur sa propre page.
Matière : PLANCHES-MATIERE-1-TECHNIQUE-2026-10-03.json (sha256 b29a3dc78614) — planche de matière « Les portées et les layers : un arbre peuplé, une descente qui n'existe pas ». Générée par scripts/generer-planches-ancrage.py ; la version « avant » (avant le passage du sceptique) que la matière conserve n’est pas dessinée — c’est la version dégradée au doute qui l’est, et les marges portent les dégradations.