L'architecture bilatérale — le joint interne/externe
ouvrir la planche en plein écran → · 21 pièces · 17 traverses · 12 marges
Les deux côtés sont bâtis et chacun nomme l'autre ; les trois traverses qui devaient les joindre ne tiennent pas — l'une n'a aucun appelant, l'une a son écrivain sans importateur, et la troisième n'existe que dans l'arbre de travail, non commitée, branchée sur le mauvais axe.
Ce que cette collecte N'A PAS pu voir. (1) AUCUNE BASE INTERROGÉE : zéro requête sur `compose-atom-db-1/atom_db` (138.197.132.63) ni ailleurs. Donc je ne sais pas si v82_291 est appliquée en production, ni combien de lignes portent `person_position_bindings`, ni si `atom_positions` est encore vide, ni si `scope_membership` contient réellement les 5216 nœuds de l'épine. Le 5216 que je rends est un compte de FICHIERS (data/countries/), recalculé par moi — pas un compte de base. (2) AUCUN SERVEUR SONDÉ : aucune route n'a été appelée. « Monté dans main.py » n'est pas « répond 200 » — `register_router` avale les ImportError, donc un routeur listé peut être absent à l'exécution ; je n'ai pas lancé le serveur pour le vérifier. (3) AUCUN BANC LANCÉ : je n'ai exécuté aucun test. Quand je dis « testé », je dis « un fichier de test existe et le nomme », pas « il passe ». (4) LE DEUXIÈME ARBRE, FOUILLÉ PAR NOMS CHOISIS : j'ai cherché `amark_face_authoritative`, `adecider`, `PassageDecisionAuthority`, `passage_decision`, `place_projection_binding`, `world_blueprint_position`, `inner_world`, `outer_world` dans les 29 racines hors `backend/app/`, et je les ai nommées une à une. Je n'ai PAS inventorié ce que ces 29 racines contiennent par ailleurs : un porteur de face pourrait y vivre sous un nom que je n'ai pas deviné. (5) LE FRONTEND PAR CHARGEMENT, PAS PAR EXÉCUTION : j'ai vérifié la présence dans les deux tableaux de `governance-init.js` et les balises `<script>` des pages. Je n'ai pas ouvert un navigateur : un module listé peut échouer à l'initialisation. Et je n'ai lu que `governance-init.js` et `onboarding.html` ; les ~120 autres pages HTML pourraient charger directement un module que je déclare ABSENT — je n'ai grepé que les noms de fichier des deux modules de l'Arche. (6) `exposition_externe` : les 61 occurrences sont comptées sur `backend/app/` seulement, et mes « 2 gardes » ne retiennent que les comparaisons à la constante `EXPOSITION_EXTERNE` ; une garde écrite autrement (comparaison à un littéral, truthiness) m'échapperait. (7) LES FICHES DE MÉMOIRE : aucune n'a servi de source à un chiffre rendu ici. Les seuls nombres que j'avance viennent du dépôt, et le 5216 a été recalculé par exécution.
| atom-ancrage.js — le seul appelant frontend de /ancrer, et il est honnête appelle | → | POST /api/v2/trinity-geo/ancrer — l'ancrage du corps sur « terre » (côté DEHORS du joint individuel)frontend/js/atom-ancrage.js:48 + :130 (atomPost) ; déclenché par frontend/onboarding.html:1144-1146 | |
| POST /api/v2/trinity-geo/ancrer — l'ancrage du corps sur « terre » (côté DEHORS du joint individuel) alimente | → | person_position_bindings — le dossier à deux faces, en basetrinity_geo_router.py:263 appelle enregistrer_ancrage → position_registry.py:87, qui écrit atom_positions. Aucune ligne de trinity_geo_router.py ne mentionne person_position_bindings ni PositionFace : les deux organes ne se touchent pas. | |
| amark_face_authoritative — la seule porte de promotion d'une face alimente | → | person_position_bindings — le dossier à deux faces, en baseperson_position_membership_authority.py:889 → :458 (INSERT) / :505 (UPDATE). Le trait existe en code ; il n'est jamais emprunté : 0 appelant de production des deux arbres. | |
| La face NUMÉRIQUE — refusée trois fois, dont une par le code de la porte elle-même traverse | → | amark_face_authoritative — la seule porte de promotion d'une faceperson_position_membership_authority.py:896 — la porte refuse NUMERICAL par 409 `numerical_position_authority_absent`. Le trait est fermé à la source. | |
| L'épine des lieux — 5216 entités (côté DEHORS du joint communautaire) contient | → | commu:atom — la racine communautaire (côté DEDANS du joint communautaire)country_spine_importer.py:64 `add(CIV_ROOT, "civ", None, ...)` — la racine est civ:atom. Mesure refaite : 5215 nœuds commu, aucun nommé commu:atom. Les 5215 pendent directement d'une racine civ. | |
| PlaceProjectionBindingAuthority.abind — l'écrivain du joint civilisationnel autorise | → | L'épine des lieux — 5216 entités (côté DEHORS du joint communautaire)place_projection_binding_authority.py:218 ; 0 importateur du module dans les deux arbres. Le trait n'est câblé nulle part. | |
| measure_cascade (Babel) appelle | → | salle_machines_connector.py — l'orchestrateur du jointgit show HEAD:backend/app/services/babel/measure_cascade.py:608-609 — l'appel existe au commit, mais sous `try: ... except Exception: pass` : tout échec de l'orchestrateur est invisible. | |
| salle_machines_connector.py — l'orchestrateur du joint appelle | → | cube_venus.py — la barre transversale ANKH : le joint est NOMMÉ dans sa docstring, et nulle part dans le code commitésalle_machines_connector.py:191 `venus.declare_joint(portee)` — non commité, et portee y arrive toujours None (measure_cascade: `getattr(result, 'portee', None)`, commentaire du code : « CascadeResult ne produit pas encore de portée »). | |
| declare_joint + VALID_PORTEES — un joint neuf, non commité, et il passe par le mauvais axe traverse | → | PositionFace {physical, numerical} — l'énum de l'axe bilatéralcube_venus.py:295 importe VALID_PORTEES depuis app.services.event_bus — jamais PositionFace. Le joint neuf ne touche pas l'axe bilatéral. | |
| passage_decision.py — le SEUL organe du dépôt qui EXIGE une face, et personne n'y entre autorise | → | PositionFace {physical, numerical} — l'énum de l'axe bilatéralpassage_decision.py:66 (import), :330, :346-347 (refus de type), :463/:468 (les deux faces du contrat), :506-507. Le trait entre l'organe et l'énum est réel et typé strictement (`type(x) is not PositionFace`). | |
| passage_decision.py — le SEUL organe du dépôt qui EXIGE une face, et personne n'y entre traverse | → | backend/app/main.py (la surface atteignable)0 routeur ne construit une DemandePassage ; `adecider` (:1161) et `construire_autorite_par_defaut` (:1296) ont 0 appelant de production dans les deux arbres. | |
| /ws/resonance — la sortie vers les navigateurs, et elle a bien une entrée traverse | → | exposition_externe — le drapeau de frontière : partout déclaré, deux fois luHEAD main.py :3128+71 (`type == "geo_coherence"`) → main.py:3375 `get_geo_coherence_service().ingest(...)` → geo_coherence_service.py:98, la garde `is not EXPOSITION_EXTERNE`. C'est la seule traverse vivante mesurée entre le dehors (navigateur) et une garde de frontière. | |
| atom-realtime-client.js appelle | → | /ws/resonance — la sortie vers les navigateurs, et elle a bien une entréegit show HEAD:frontend/js/governance-init.js:254 et :1101 (chargé dans LES DEUX tableaux) ; frontend/js/atom-realtime-client.js:30 construit l'URL wss://…/ws/resonance | |
| cosmic_circuit.py — le circuit α↔Ω, branché au bus et aveugle aux faces traverse | → | exposition_externe — le drapeau de frontière : partout déclaré, deux fois luHEAD main.py:1023-1024 attache le circuit au bus ; cosmic_circuit.py:224 compare `circulation.get("exposition_externe") is EXPOSITION_EXTERNE` | |
| g4_emission_guard — le garde d'émission, bâti et appelé, sur l'axe monétaire autorise | → | PositionFace {physical, numerical} — l'énum de l'axe bilatéral0 occurrence de PositionFace dans backend/app/services/babel/g4_emission_guard.py. Le seul garde d'émission réellement appelé du dépôt ne connaît pas l'axe bilatéral : il garde la monnaie, pas la frontière. | |
| external_proxies_router.py — le sas sortant, monté et conditionnel traverse | → | exposition_externe — le drapeau de frontière : partout déclaré, deux fois lu0 occurrence d'`exposition_externe` dans backend/app/routers/external_proxies_router.py. Le sas qui SORT vraiment ne consulte pas le drapeau de frontière ; ses gardes sont les clés d'environnement (:696-1001). | |
| black-box-recorder.js — le coffre qui garde (la moitié DEDANS de la figure de l'Arche) alimente | → | village-map-generator.js / le QG-Djed — le couvercle qui publie (la moitié DEHORS)aucun des deux n'est listé dans frontend/js/governance-init.js ; les deux ne cohabitent que dans frontend/archives/orphan-pages/keli-dashboard.html. Les deux moitiés de la figure sont sur le disque et aucune n'est chargée. |
| 1 | PositionFace {physical, numerical} — l'énum de l'axe bilatéral2 valeurs ; 11 déclarations de champ `face: PositionFace` dans le même fichier ; 1 CHECK en base déclaré (v82_291:160-162) ; 1 seul autre module de production l'importe : passage_decision.py:66backend/app/services/person_position_membership_authority.py:46-48 (présent au commit 8addf1c94) · confirmé dans le code | |
| 2 | POST /api/v2/trinity-geo/ancrer — l'ancrage du corps sur « terre » (côté DEHORS du joint individuel)8 routes dans le fichier (/locate :148, /ancrer :204, /correspondances/{identite} :285, /bascule :350, /mondes :357, /health :378) ; world="terre" et scope="indiv" sont écrits en dur (:255-256)backend/app/routers/trinity_geo_router.py:204 ; monté au commit : git show HEAD:backend/app/main.py → ligne 2303 `register_router("app.routers.trinity_geo_router", "", ["Trinity Geo"], "trinity_geo")` · confirmé dans le code | |
| 3 | atom-ancrage.js — le seul appelant frontend de /ancrer, et il est honnête1 seul appelant HTTP de /trinity-geo/ancrer dans frontend/ (les 4 autres occurrences sont : un commentaire device-master.js:239, 2 tests, et le déclencheur UI onboarding.html:1144) ; il lit `persiste` et le répercute (:150-157)frontend/js/atom-ancrage.js:48 (ROUTE) ; listé au commit dans LES DEUX tableaux de chargement : git show HEAD:frontend/js/governance-init.js → :482 et :1169 ; chargé aussi en direct par frontend/onboarding.html:34 (cette page ne charge PAS governance-init.js, dit son propre commentaire :33) · confirmé dans le code | |
| 4 | L'épine des lieux — 5216 entités (côté DEHORS du joint communautaire)5216 — RE-MESURÉ par moi en exécutant la même lecture sur data/countries/ : 1 racine (civ:atom) + 217 pays (profiles.json) + 3567 subdivisions (admin_divisions.json) + 1431 villes (major_cities.json) = 5216 ; portées : commu 5215, civ 1backend/app/services/country_spine_importer.py:45 (`extraire_epine`, fonction pure) ; amorcée au commit : git show HEAD:backend/app/main.py → `_amorcer_epine_lieu` défini :1090, `extraire_epine()` :1100, `amorcer_epine_lieu(db=...)` :1122, lancé par `asyncio.create_task` :1195 ; exposé par /health :2642 · confirmé dans le code | |
| 5 | /ws/resonance — la sortie vers les navigateurs, et elle a bien une entréeCORRECTION : 5 types de messages ENTRANTS traités au commit — ping, situer, subscribe, unsubscribe, geo_coherence (HEAD main.py, décalages +34/+36/+53/+62/+71 après :3128). Ce n'est pas « aucune entrée permanente » : l'entrée existe, elle est chargée dans les deux tableaux de governance-init.js, et c'est par elle que passe la seule lecture vivante d'exposition_externegit show HEAD:backend/app/main.py → :3128 `@app.websocket("/ws/resonance")` ; relais poussé vers elle à :1234 ; client permanent chargé au commit : git show HEAD:frontend/js/governance-init.js → :254 et :1101 `/js/atom-realtime-client.js` (qui s'y connecte, atom-realtime-client.js:30) ; repli de kernel-bridge.js:67 · confirmé dans le code | |
| 6 | g4_emission_guard — le garde d'émission, bâti et appelé, sur l'axe monétaire11 fonctions publiques (compute_theta :55, compute_allowance :66, rate_limit_ok :86, reset_rate_limit_state :95, grants_au_ledger :134, reserve_emission_in_transaction :190, record_committed_grant :279, emission_allowance :284, …) ; governed_mint est lui-même appelé par 4 consommateurs (babel_fractal_treasury_consumer:593, babel_temple_treasury_consumer:291, forge_energy_consumer:407, mission_reward_consumer:103) ; 0 occurrence de PositionFacebackend/app/services/babel/g4_emission_guard.py ; appelé au commit depuis git show HEAD:backend/app/services/babel/governed_mint.py:447 et git show HEAD:backend/app/routers/babel/emission_state_router.py:282 ; routeur monté au commit main.py:1988 · confirmé dans le code | |
| 7 | person_position_bindings — le dossier à deux faces, en baserevision = v82_291_person_position_membership_authority, down_revision = v82_290_enclosure_mandate_preparationsbackend/alembic/versions/v82_291_person_position_membership_authority.py:24 (CREATE TABLE), :97 index, :257 et :324 déclencheurs ; écritures ppma.py:458 (INSERT), :505 (UPDATE), lecture :684 (SELECT) · confirmé dans le codeDÉGRADÉ depuis BÂTI : la table est déclarée, écrite et relue en code, mais son existence EN PRODUCTION n'est pas établie par cette collecte. La seule révision de production nommée est `v82_260_atom_positions` (CLAUDE.md, mesure du 2026-08-08), antérieure de 31 révisions à v82_291. Aucune base n'a été interrogée ici. Le maillon manquant est la preuve d'application de la migration. | |
| 8 | amark_face_authoritative — la seule porte de promotion d'une face16 appels mesurés, TOUS dans backend/tests/unit/test_person_position_membership_authority_g1.py. 0 appelant de production — les DEUX arbres fouillés : backend/app/ et les 29 racines hors app/ (agents, audit, causal_engine, core, core_engines, deploy, education, enterprise, entertainment, feedback, frontiers, governance, industrialisation, library, middleware, models, modules, schemas, scholar, scripts, security, services, slot_fill, systems, verticals, workspace_integration, world_engine, xr_pack, xr_ui)backend/app/services/person_position_membership_authority.py:889 · confirmé dans le codel'appelant. La fonction est complète et testée ; rien dans le dépôt ne l'invoque hors du banc. | |
| 9 | PlaceProjectionBindingAuthority.abind — l'écrivain du joint civilisationnel0 importateur. Le nom de module `place_projection_binding_authority` n'apparaît dans AUCUN fichier de backend/app/ hors le sien, et dans aucune des 29 racines du second arbre. Seule référence du dépôt : backend/tests/services/test_place_projection_binding_authority.pybackend/app/services/place_projection_binding_authority.py:214 (classe), :218 (abind) — présent au commit · confirmé dans le codel'importateur. Ce n'est pas seulement « l'écrivain est absent » : personne ne charge même le module. | |
| 10 | cosmic_circuit.py — le circuit α↔Ω, branché au bus et aveugle aux faces5 occurrences de `exposition_externe` dans le fichier, dont 1 seule est une garde (:224) ; 0 occurrence de PositionFacebackend/app/services/cosmic_circuit.py ; attaché au commit : git show HEAD:backend/app/main.py → :1023-1024 `attach_to_bus()` ; exposé par backend/app/routers/qg_fractalization_router.py:1350 (routeur monté main.py:2240) · confirmé dans le codela face. Le circuit tourne et lit le drapeau de frontière, mais ne voit jamais PositionFace. Et son attache est dans un try/except non-fatal (main.py:1029-1030) : un échec au démarrage est un avertissement journalisé, pas un refus. | |
| 11 | cube_venus.py — la barre transversale ANKH : le joint est NOMMÉ dans sa docstring, et nulle part dans le code commité0 occurrence de `declare_joint` dans git show HEAD:backend/app/services/babel/cube_venus.py ; le fichier est modifié non commité (+13 lignes) ; la docstring annonce « API publique (6 fonctions) » et declare_joint serait la 7ᵉ, non annoncéebackend/app/services/babel/cube_venus.py:3-4 — « entre Métatron (externe) et Mercure (interne) dans l'anatomie ANKH ☥ » ; `declare_joint` à :293 dans l'ARBRE DE TRAVAIL seulement · confirmé dans le codele joint lui-même au commit. Et dans l'arbre de travail il travaille sur VALID_PORTEES (indiv/commu/civ), pas sur PositionFace : l'axe des PORTÉES, pas celui des FACES. | |
| 12 | salle_machines_connector.py — l'orchestrateur du jointDÉGRADÉ depuis BÂTI. Au COMMIT : 0 occurrence de `portee` et 0 de `declare_joint` dans le connecteur — il n'orchestre aucun joint. Les 7 lignes qui le font sont non commitées. Et l'appel depuis measure_cascade est enfermé dans `try: ... except Exception: pass` (« never break cascade »)backend/app/services/babel/salle_machines_connector.py (333 lignes au commit, 340 dans l'arbre) ; appelé au commit : git show HEAD:backend/app/services/babel/measure_cascade.py → :608-609 · confirmé dans le codedeux maillons. (1) Au commit le connecteur ne porte pas de joint du tout. (2) Dans l'arbre de travail il est nourri par `portee=getattr(result, 'portee', None)` — et le commentaire du code dit lui-même « CascadeResult ne produit pas encore de portée : None reste None », donc declare_joint reçoit toujours None et rend toujours joint=None. | |
| 13 | passage_decision.py — le SEUL organe du dépôt qui EXIGE une face, et personne n'y entre0 appelant de production de `adecider` et de `construire_autorite_par_defaut` — les DEUX arbres fouillés (backend/app/ et les 29 racines hors app/). Son aval `passage_outbox.py` : 0 appelant de production aussi (seules références hors tests : la migration v82_294). Les seuls appelants sont 2 bancs : test_passage_decision_p3.py, test_passage_outbox_p4.pybackend/app/services/passage_decision.py:330 (`face: PositionFace`), :346-347 (`raise TypeError("face de position doit etre un PositionFace")`), :463/:468 (source_position_face / target_position_face du contrat), :1096 (PassageDecisionAuthority), :1161 (adecider), :1296 (construire_autorite_par_defaut) · confirmé dans le codela porte d'entrée. Aucune route, aucun service ne construit une DemandePassage. L'exigence de face est réelle et ne s'applique à rien. | |
| 14 | exposition_externe — le drapeau de frontière : partout déclaré, deux fois lu61 occurrences / 20 fichiers / 2 gardes. Les plus denses : stone_decoder/temple_fractal_connector.py 12, stone_decoder/temple_control_center.py 8, qg_fractalization_router.py 8, cosmic_circuit.py 5, coherence/temple_coherence_witness.py 561 occurrences dans 20 fichiers de backend/app/ ; les 2 SEULES lignes qui le comparent : backend/app/services/cosmic_circuit.py:224 et backend/app/services/geo_coherence_service.py:98 · confirmé dans le codela lecture. CORRECTION dans l'autre sens : les 2 gardes ne sont pas mortes — geo_coherence_service est atteint depuis /ws/resonance (main.py:3375) et depuis canon_coherence_router.py:147/291. Le drapeau garde vraiment, mais 2 portes sur 61 mentions. | |
| 15 | external_proxies_router.py — le sas sortant, monté et conditionnelles sorties dépendent de clés d'environnement lues à :696-698, :727, :762, :801-803, :831, :865, :966, :996-1001 ; 2 refus 503 déclarés (:51, :455) ; 1 lecture générique de variable à :144backend/app/routers/external_proxies_router.py (1019 lignes au commit) ; monté au commit : git show HEAD:backend/app/main.py → :2444 · confirmé dans le codeles clés. Le sas existe et est atteignable ; sans variable d'environnement il refuse (503). Le canal sortant est donc réel et conditionnel, pas bâti au sens d'un flux qui coule. | |
| 16 | declare_joint + VALID_PORTEES — un joint neuf, non commité, et il passe par le mauvais axe0 occurrence de `declare_joint` ET 0 de `VALID_PORTEES` dans le COMMIT (vérifié par git show HEAD sur cube_venus.py, salle_machines_connector.py et event_bus.py). Le joint dépend donc d'un nom qui n'existe pas non plus au commit. Il rend `f"{portee}↔matrix"` — un joint portée↔matrix, jamais face↔face4 fichiers modifiés NON COMMITÉS : backend/app/services/event_bus.py:299 (`VALID_PORTEES = frozenset({"indiv","commu","civ"})`, +14 lignes), babel/cube_venus.py:293 (declare_joint, +13), babel/salle_machines_connector.py:191 (appel, +7), babel/measure_cascade.py (+2) · confirmé dans le codedeux maillons. (1) Le commit : rien de tout cela n'y est. (2) L'axe : declare_joint valide contre VALID_PORTEES (indiv/commu/civ) et non contre PositionFace (physical/numerical) — il nomme un joint sur l'axe des portées, pas sur l'axe bilatéral que la planche doit montrer. | |
| 17 | La face NUMÉRIQUE — refusée trois fois, dont une par le code de la porte elle-même0 écrivain de production d'une face NUMERICAL ; 2 refus explicites en code ; les seules occurrences de PositionFace.NUMERICAL hors ces refus sont 2 lignes de test (test_passage_decision_p3.py:1032-1033)backend/app/services/person_position_membership_authority.py:896 et :1473 — `if proof.face is PositionFace.NUMERICAL: raise self._error("numerical_position_authority_absent", 409, ...)` ; et trinity_geo_router.py:255 écrit world="terre" en dur · confirmé dans le code | |
| 18 | commu:atom — la racine communautaire (côté DEDANS du joint communautaire)0 occurrence de `commu:atom` ; l'épine que j'ai recalculée produit 1 nœud de portée `civ` et 5215 de portée `commu`, et aucun d'eux ne s'appelle `commu:atom`mesure négative : 0 occurrence de la chaîne `commu:atom` dans backend/app/**.py et frontend/js/**.js. La seule racine déclarée est `CIV_ROOT = "civ:atom"`, en deux endroits : backend/app/services/country_spine_importer.py:27 et person_position_membership_authority.py:40 · confirmé dans le code | |
| 19 | black-box-recorder.js — le coffre qui garde (la moitié DEDANS de la figure de l'Arche)0 des 2 tableaux de chargement de governance-init.js le mentionne ; 1 page le référence, et elle est sous archives/orphan-pages/frontend/js/black-box-recorder.js existe sur disque ; 0 entrée dans frontend/js/governance-init.js (ni au commit, ni dans l'arbre) ; seule référence HTML du dépôt : frontend/archives/orphan-pages/keli-dashboard.html · confirmé dans le code | |
| 20 | village-map-generator.js / le QG-Djed — le couvercle qui publie (la moitié DEHORS)même mesure que le coffre : 0 entrée de chargement, 1 page orpheline archivéefrontend/js/village-map-generator.js existe sur disque ; 0 entrée dans frontend/js/governance-init.js ; seule référence HTML : frontend/archives/orphan-pages/keli-dashboard.html · confirmé dans le code | |
| 21 | inner_world / outer_world — le vocabulaire de la thèse n'a aucun porteur, et c'est MESURÉ0 / 0. CORRECTION d'état : ce n'était pas NON ÉTABLI — c'est établi, et ça vaut zéro. La FONCTION, elle, est bien portée, sous quatre autres noms : exposition_externe (le drapeau), external_proxies_router (le sas), PositionFace.PHYSICAL/NUMERICAL (les deux faces), et « Métatron (externe) / Mercure (interne) » dans cube_venus.py:3-4mesure négative exhaustive : 0 occurrence de `inner_world` et de `outer_world` dans backend/**.py (les deux arbres) et 0 dans frontend/js/**.js · confirmé dans le code |
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 « L'architecture bilatérale — le joint interne/externe ». 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.